sqrtminusone.github.io/configs/emacs/index.html
2025-04-20 21:50:25 +00:00

12071 lines
1.8 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.

<!DOCTYPE html>
<html lang=""><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Emacs config</title>
<meta name="description" content="Freedom is a state of mind">
<meta name="author" content='SqrtMinusOne'>
<link href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous">
<link rel="stylesheet" href="/sass/researcher.min.css">
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
<script defer data-domain="sqrtminusone.xyz" src="https://plausible.sqrtminusone.xyz/js/plausible.js"></script>
</head>
<body><div class="container mt-5">
<nav class="navbar navbar-expand-sm flex-column flex-sm-row text-nowrap p-0">
<a class="navbar-brand mx-0 mr-sm-auto" href="https://sqrtminusone.xyz/" title="SqrtMinusOne">
SqrtMinusOne
</a>
<div class="navbar-nav flex-row flex-wrap justify-content-center">
<a class="nav-item nav-link" href="/" title="Index">
Index
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/posts/" title="Posts">
Posts
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/configs/readme" title="Configs">
Configs
</a>
<span class="nav-item navbar-text mx-1">/</span>
<a class="nav-item nav-link" href="/emacs-packages/" title="Emacs packages">
Emacs packages
</a>
</div>
</nav>
</div>
<hr>
<div id="content">
<script defer language="javascript" type="text/javascript" src="/js/dynamic-toc.js"></script>
<div class="root">
<h1 id="title-small-screen">
Emacs config
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=dotfiles&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
</h1>
<div class="container" id="actual-content">
<h1 id="title-large-screen" class="dotfiles-title">
Emacs config
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=dotfiles&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
</h1>
<blockquote>
<p>One day we won&rsquo;t hate one another, no young boy will march to war and I will clean up my Emacs config. But that day isn&rsquo;t today.</p></blockquote>
<ul>
<li>Me, <span class="timestamp-wrapper"><span class="timestamp">&lt;2021-05-27 Thu 17:35&gt; </span></span> in commit 93a0573. Adapted from <a href="https://www.youtube.com/watch?v=pIdBinlW40E">The Dark Element - &ldquo;The Pallbearer Walks Alone&rdquo;</a>. T_T</li>
</ul>
<h2 id="introduction">Introduction</h2>
<p>My configuration of <a href="https://www.gnu.org/software/emacs/">GNU Emacs</a>, an awesome <del>text editor</del> piece of software that can do almost anything.</p>
<p>At the moment of writing this, that &ldquo;almost anything&rdquo; includes:</p>
<ul>
<li><strong>Programming environment</strong>. With LSP &amp; Co, Emacs is as good as many IDEs and is certainly on par with editors like VS Code.<br />
Emacs is also particularly great at writing Lisp code, e.g. Clojure, Common Lisp, and of course, Emacs Lisp.</li>
<li><strong>Org Mode</strong> is useful for a lot of things. My use cases include:
<ul>
<li><strong><a href="https://leanpub.com/lit-config/read">Literate configuration</a></strong></li>
<li><strong>Interactive programming</strong> à la Jupyter Notebook</li>
<li><strong>Task / project management</strong></li>
<li><strong>Formatting documents</strong>. I&rsquo;ve written my Master&rsquo;s Thesis in Org Mode.</li>
<li><strong>Notetaking</strong>, mostly with org-roam and org-journal</li>
</ul>
</li>
<li><strong>File management</strong>. Dired is my primary file manager.</li>
<li><strong>Email</strong>, with notmuch.</li>
<li><strong>Multimedia management</strong>, with EMMS.</li>
<li><strong>RSS feed reader</strong>, with elfeed.</li>
<li><strong>Managing passwords</strong>, with pass.</li>
<li><strong>Messengers</strong>:
<ul>
<li><strong>IRC</strong>, with ERC.</li>
<li><strong>Telegram</strong>, with telega.el</li>
</ul>
</li>
<li><strong>X Window management</strong>, with EXWM. I literally live in Emacs.</li>
<li>&hellip;</li>
</ul>
<p>As I mentioned above, this document is a piece of literate configuration, i.e. program code interwoven with (occasionally semi-broken) English-language commentary.</p>
<p>I find that approach helpful for maintaining the configuration, but the quality and quantity of comments may vary. I also usually incorporate my Emacs-related blog posts back into this config.</p>
<p>So, you might extract something of value from here if you&rsquo;re an avid Emacs user, but probably not if you&rsquo;re a newcomer to the Elisp wonderland. If the latter applies to you, I&rsquo;d advise checking out David Wilson&rsquo;s <a href="https://www.youtube.com/c/SystemCrafters">System Crafters</a> YouTube channel.</p>
<h2 id="some-remarks">Some remarks</h2>
<p>I decided not to keep configs for features that I do not use anymore because this config is already huge. But here are the last commits that had these features presented.</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Last commit</th>
</tr>
</thead>
<tbody>
<tr>
<td>ytel</td>
<td>327340a95c4ff9cffd171f6bd937c6041f63add7</td>
</tr>
<tr>
<td>org-roam dailies</td>
<td>d2648918fcc338bd5c1cd6d5c0aa60a65077ccf7</td>
</tr>
<tr>
<td>org-roam projects</td>
<td>025278a1e180e86f3aade20242e4ac1cdc1a2f13</td>
</tr>
<tr>
<td>treemacs</td>
<td>3d87852745caacc0863c747f1fa9871d367240d2</td>
</tr>
<tr>
<td>tab-bar.el</td>
<td>19ff54db9fe21fd5bdf404a8d2612176baa8a6f5</td>
</tr>
<tr>
<td>spaceline</td>
<td>19ff54db9fe21fd5bdf404a8d2612176baa8a6f5</td>
</tr>
<tr>
<td>code compass</td>
<td>8594d6f53e42c70bbf903e168607841854818a38</td>
</tr>
<tr>
<td>vue-mode</td>
<td>8594d6f53e42c70bbf903e168607841854818a38</td>
</tr>
<tr>
<td>svelte-mode</td>
<td>8594d6f53e42c70bbf903e168607841854818a38</td>
</tr>
<tr>
<td>pomidor</td>
<td>8594d6f53e42c70bbf903e168607841854818a38</td>
</tr>
<tr>
<td>elfeed-score</td>
<td>8e591e0d2afd909ae5be00caf17f9b17c6cd8b61</td>
</tr>
<tr>
<td>org-trello</td>
<td>3f5967a5f63928ea9c8567d8d9f31e84cdbbc21f</td>
</tr>
<tr>
<td>jabber</td>
<td>9b0e73a4703ff35a2d30fd704200052888191217</td>
</tr>
<tr>
<td>wallabag</td>
<td>9b0e73a4703ff35a2d30fd704200052888191217</td>
</tr>
<tr>
<td>conda</td>
<td>609fc84e439b11ea5064f3a948079daebb654aca</td>
</tr>
<tr>
<td>notmuch tags keybindings</td>
<td>eac134c5456051171c1c777254f503cc71ce12cd</td>
</tr>
<tr>
<td>expand-region</td>
<td>ab0d01c525f2b44dd64ec09747daf0fced4bd9c7</td>
</tr>
<tr>
<td>org-latex-impatient</td>
<td>ab0d01c525f2b44dd64ec09747daf0fced4bd9c7</td>
</tr>
<tr>
<td>dired-single</td>
<td>ab0d01c525f2b44dd64ec09747daf0fced4bd9c7</td>
</tr>
<tr>
<td>progidy</td>
<td>ab0d01c525f2b44dd64ec09747daf0fced4bd9c7</td>
</tr>
<tr>
<td>tree-sitter</td>
<td>1920a48aec49837d63fa88ca315928dc4e9d14c2</td>
</tr>
<tr>
<td>org-roam-protocol</td>
<td>2f0c20eb01b8899d00d129cc7ca5c6b263c69c65</td>
</tr>
<tr>
<td>eshell-info-banner</td>
<td>4ccc0bbc412b68e1401533264d801d86b1fc8cc7</td>
</tr>
<tr>
<td>aweshell</td>
<td>4ccc0bbc412b68e1401533264d801d86b1fc8cc7</td>
</tr>
<tr>
<td>link tasks to meetings</td>
<td>23496bfacc31ffedf2092da04e4e602b71373425</td>
</tr>
</tbody>
</table>
<h2 id="initial-setup">Initial setup</h2>
<p>Setting up the environment, performance tuning and a few basic settings.</p>
<p>First things first, lexical binding.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;;; -*- lexical-binding: t -*-</span>
</span></span></code></pre></div><h3 id="packages">Packages</h3>
<h4 id="straight-dot-el">straight.el</h4>
<p>Straight.el is my Emacs package manager of choice. Its advantages &amp; disadvantages over other options are listed pretty thoroughly in the README file in the repo.</p>
<p>The following is the bootstrap script of <code>straight.el</code>.</p>
<p>References:</p>
<ul>
<li><a href="https://github.com/raxod502/straight.el">straight.el repo</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">bootstrap-version</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">let</span> ((<span style="color:#19177c">bootstrap-file</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">&#34;straight/repos/straight.el/bootstrap.el&#34;</span> <span style="color:#19177c">user-emacs-directory</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">bootstrap-version</span> <span style="color:#666">5</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">bootstrap-file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url-retrieve-synchronously</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;silent</span> <span style="color:#19177c">&#39;inhibit-cookies</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-max</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">eval-print-last-sexp</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">load</span> <span style="color:#19177c">bootstrap-file</span> <span style="color:#800">nil</span> <span style="color:#19177c">&#39;nomessage</span>))
</span></span></code></pre></div><h4 id="use-package">use-package</h4>
<p>A macro to simplify package specification &amp; configuration. Integrates with straight.el.</p>
<p>Set <code>use-package-verbose</code> to <code>t</code> to print out loading times for individual packages.</p>
<p>References:</p>
<ul>
<li><a href="https://github.com/jwiegley/use-package">use-package repo</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">straight-use-package</span> <span style="color:#19177c">&#39;use-package</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">eval-when-compile</span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;use-package</span>))
</span></span></code></pre></div><h3 id="variables-and-environment">Variables &amp; environment</h3>
<p>This section is about optioning the Emacs config.</p>
<p>The following is true is Emacs is run on a remote server where I don&rsquo;t need stuff like my org workflow</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/remote-server</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">string=</span> (<span style="color:#19177c">getenv</span> <span style="color:#ba2121">&#34;IS_REMOTE&#34;</span>) <span style="color:#ba2121">&#34;true&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string=</span> (<span style="color:#00f">system-name</span>) <span style="color:#ba2121">&#34;dev-digital&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string=</span> (<span style="color:#00f">system-name</span>) <span style="color:#ba2121">&#34;viridian&#34;</span>)))
</span></span></code></pre></div><p>And the following is true if Emacs is run from termux on Android.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/is-termux</span> (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> (<span style="color:#00f">*</span> <span style="color:#19177c">nonl</span>) <span style="color:#ba2121">&#34;com.termux&#34;</span> (<span style="color:#00f">*</span> <span style="color:#19177c">nonl</span>)) (<span style="color:#19177c">getenv</span> <span style="color:#ba2121">&#34;HOME&#34;</span>)))
</span></span></code></pre></div><p>Custom system name logic because on termux it&rsquo;s always &ldquo;localhost&rdquo;.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/system-name</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">getenv</span> <span style="color:#ba2121">&#34;ANDROID_NAME&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">system-name</span>)))
</span></span></code></pre></div><p>Also, I sometimes need to know if a program is running inside Emacs (say, inside a terminal emulator). And sometimes I need to know if I&rsquo;m running a nested Emacs session. To do that, I set the following environment variable:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/nested-emacs</span> (<span style="color:#008000">and</span> (<span style="color:#19177c">getenv</span> <span style="color:#ba2121">&#34;IS_EMACS&#34;</span>) <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">setenv</span> <span style="color:#ba2121">&#34;IS_EMACS&#34;</span> <span style="color:#ba2121">&#34;true&#34;</span>)
</span></span></code></pre></div><p>Finally, I want to have a minimal Emacs config for debugging purposes. This has just straight.el, use-packages, and evil.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span><span style="color:#19177c">&lt;&lt;minimal&gt;&gt;</span>
</span></span></code></pre></div><p>To launch Emacs with this config, run</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>emacs -q -l ~/.emacs.d/init-minimal.el
</span></span></code></pre></div><h3 id="performance">Performance</h3>
<h4 id="measure-startup-speed">Measure startup speed</h4>
<p>A small function to print out the loading time and number of GCs during the loading. Can be useful as a point of data for optimizing Emacs startup time.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/emacs-started</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;emacs-startup-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;*** Emacs loaded in %s with %d garbage collections.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%.2f seconds&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">float-time</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">time-subtract</span> <span style="color:#19177c">after-init-time</span> <span style="color:#19177c">before-init-time</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">gcs-done</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/emacs-started</span> <span style="color:#800">t</span>)))
</span></span></code></pre></div><p>Set the following to <code>t</code> to print debug information during the startup. This will include package loading order and time.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">use-package-verbose</span> <span style="color:#800">nil</span>)
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">use-package-compute-statistics</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h4 id="garbage-collection">Garbage collection</h4>
<p>Just setting <code>gc-cons-treshold</code> to a larger value.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">gc-cons-threshold</span> <span style="color:#666">80000000</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">read-process-output-max</span> (<span style="color:#00f">*</span> <span style="color:#666">1024</span> <span style="color:#666">1024</span>))
</span></span></code></pre></div><h4 id="run-garbage-collection-when-emacs-is-unfocused">Run garbage collection when Emacs is unfocused</h4>
<p>Run GC when Emacs loses focus. <del>Time will tell if that&rsquo;s a good idea.</del></p>
<p>I still don&rsquo;t know if there is any quantifiable advantage to this, but it doesn&rsquo;t hurt.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;emacs-startup-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">boundp</span> <span style="color:#19177c">&#39;after-focus-change-function</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-function</span> <span style="color:#008000">:after</span> <span style="color:#19177c">after-focus-change-function</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">frame-focus-state</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">garbage-collect</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;after-focus-change-function</span> <span style="color:#19177c">&#39;garbage-collect</span>))))
</span></span></code></pre></div><h4 id="measure-ram-usage">Measure RAM usage</h4>
<p>I&rsquo;ve noticed that Emacs occasionally eats a lot of RAM, especially when used with EXWM. This is my attempt to measure RAM usage.</p>
<p>I have some concerns that <code>ps -o rss</code> may be unrepresentative because of <a href="https://stackoverflow.com/questions/131303/how-can-i-measure-the-actual-memory-usage-of-an-application-or-process">shared memory</a>, but I guess this shouldn&rsquo;t be a problem here because there&rsquo;s only one process of Emacs.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/get-ram-usage-async</span> (<span style="color:#19177c">callback</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">temp-buffer</span> (<span style="color:#19177c">generate-new-buffer</span> <span style="color:#ba2121">&#34;*ps*&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">proc</span> (<span style="color:#00f">start-process</span> <span style="color:#ba2121">&#34;ps&#34;</span> <span style="color:#19177c">temp-buffer</span> <span style="color:#ba2121">&#34;ps&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;-p&#34;</span> (<span style="color:#00f">number-to-string</span> (<span style="color:#00f">emacs-pid</span>)) <span style="color:#ba2121">&#34;-o&#34;</span> <span style="color:#ba2121">&#34;rss&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-process-sentinel</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">proc</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">process</span> <span style="color:#19177c">_msg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">eq</span> (<span style="color:#00f">process-status</span> <span style="color:#19177c">process</span>) <span style="color:#19177c">&#39;exit</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">output</span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">temp-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-string</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">usage</span> (<span style="color:#00f">string-to-number</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">output</span> <span style="color:#ba2121">&#34;\n&#34;</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">ignore-errors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">callback</span> <span style="color:#19177c">usage</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">kill-buffer</span> <span style="color:#19177c">temp-buffer</span>))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ram-usage</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/get-ram-usage-async</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;%f Gb&#34;</span> (<span style="color:#00f">/</span> (<span style="color:#00f">float</span> <span style="color:#19177c">data</span>) <span style="color:#666">1024</span> <span style="color:#666">1024</span>)))))
</span></span></code></pre></div><h3 id="micromamba">Micromamba</h3>
<p><a href="https://github.com/mamba-org/mamba">mamba</a> is a faster alternative to <a href="https://www.anaconda.com/">Anaconda</a>, a package and environment manager. <code>micromamba</code> is a tiny version that provides a subset of mamba commands.</p>
<p><a href="https://github.com/SqrtMinusOne/micromamba.el">micromamba.el</a> is my package to interact with the latter.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">micromamba</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">executable-find</span> <span style="color:#ba2121">&#34;micromamba&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">micromamba-activate</span> <span style="color:#ba2121">&#34;general&#34;</span>))
</span></span></code></pre></div><h3 id="config-files">Config files</h3>
<h4 id="custom-file-location">Custom file location</h4>
<p>By default, <code>custom</code> writes stuff to <code>init.el</code>, which is somewhat annoying. The following makes it write to a separate file <code>custom.el</code></p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">custom-file</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">user-emacs-directory</span> <span style="color:#ba2121">&#34;custom.el&#34;</span>))
</span></span><span style="display:flex;"><span>(<span style="color:#00f">load</span> <span style="color:#19177c">custom-file</span> <span style="color:#19177c">&#39;noerror</span>)
</span></span></code></pre></div><h4 id="authinfo">authinfo</h4>
<p>Use only the gpg-encrypted version of the file.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">auth-source-debug</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">auth-sources</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;~/.authinfo.gpg&#34;</span>))
</span></span></code></pre></div><h4 id="private-config">Private config</h4>
<p>I have some variables which I don&rsquo;t commit to the repo, e.g. my current location. They are stored in <code>private.el</code></p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">let</span> ((<span style="color:#19177c">private-file</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">&#34;private.el&#34;</span> <span style="color:#19177c">user-emacs-directory</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">private-file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">load-file</span> <span style="color:#19177c">private-file</span>)))
</span></span></code></pre></div><h4 id="no-littering">No littering</h4>
<p>By default Emacs and its packages create a lot files in <code>.emacs.d</code> and in other places. <a href="https://github.com/emacscollective/no-littering">no-littering</a> is a collective effort to redirect all of that to two folders in <code>user-emacs-directory</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">no-littering</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h3 id="helper-functions">Helper functions</h3>
<h4 id="run-command-in-background">Run command in background</h4>
<p>I think I&rsquo;ve copied it from somewhere.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/run-in-background</span> (<span style="color:#19177c">command</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">command-parts</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">command</span> <span style="color:#ba2121">&#34;[ ]+&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#00f">#&#39;call-process</span> <span style="color:#666">`</span>(<span style="color:#666">,</span>(<span style="color:#00f">car</span> <span style="color:#19177c">command-parts</span>) <span style="color:#800">nil</span> <span style="color:#666">0</span> <span style="color:#800">nil</span> <span style="color:#666">,@</span>(<span style="color:#00f">cdr</span> <span style="color:#19177c">command-parts</span>)))))
</span></span></code></pre></div><h4 id="close-buffer-and-its-windows">Close buffer and its windows</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/quit-window-and-buffer</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">quit-window</span> <span style="color:#800">t</span>))
</span></span></code></pre></div><h3 id="prevent-emacs-from-closing">Prevent Emacs from closing</h3>
<p>This adds a confirmation to avoid accidental Emacs closing.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">confirm-kill-emacs</span> <span style="color:#19177c">&#39;y-or-n-p</span>)
</span></span></code></pre></div><h3 id="scratch-buffer">Scratch buffer</h3>
<p>I have a problem with <code>emacs-lisp-mode</code> as <code>initial-major-mode</code> because in my config it loads <code>lispy</code>, which loads <code>org-mode</code>.</p>
<p>So until I&rsquo;ve made a better loading screen, this will do.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">initial-major-mode</span> <span style="color:#19177c">&#39;fundamental-mode</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">initial-scratch-message</span> <span style="color:#ba2121">&#34;Hello there &lt;3\n\n&#34;</span>)
</span></span></code></pre></div><h2 id="general-settings">General settings</h2>
<h3 id="keybindings">Keybindings</h3>
<h4 id="general-dot-el">general.el</h4>
<p>general.el provides a convenient interface to manage Emacs keybindings.</p>
<p>References:</p>
<ul>
<li><a href="https://github.com/noctuid/general.el">general.el repo</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">general</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-evil-setup</span>))
</span></span></code></pre></div><h4 id="which-key">which-key</h4>
<p>A package that displays the available keybindings in a popup. The package is pretty useful, as Emacs seems to have more keybindings than I can remember at any given point.</p>
<p>References:</p>
<ul>
<li><a href="https://github.com/justbur/emacs-which-key">which-key repo</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">which-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">which-key-idle-delay</span> <span style="color:#666">0.3</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">which-key-popup-type</span> <span style="color:#19177c">&#39;frame</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">which-key-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">which-key-setup-side-window-bottom</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-face-attribute</span> <span style="color:#19177c">&#39;which-key-local-map-description-face</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:weight</span> <span style="color:#19177c">&#39;bold</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h5 id="dump-keybindings">dump keybindings</h5>
<p>A function to dump keybindings starting with a prefix to a buffer in a tree-like form.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dump-bindings-recursive</span> (<span style="color:#19177c">prefix</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">level</span> <span style="color:#19177c">buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">key</span> (<span style="color:#19177c">which-key--get-bindings</span> (<span style="color:#19177c">kbd</span> <span style="color:#19177c">prefix</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">level</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">make-string</span> <span style="color:#19177c">level</span> <span style="color:#ba2121">? </span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">apply</span> <span style="color:#00f">#&#39;format</span> <span style="color:#ba2121">&#34;%s%s%s\n&#34;</span> <span style="color:#19177c">key</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">string-match-p</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;+&#34;</span> (<span style="color:#00f">*</span> <span style="color:#19177c">nonl</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring-no-properties</span> (<span style="color:#00f">elt</span> <span style="color:#19177c">key</span> <span style="color:#666">2</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/dump-bindings-recursive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">prefix</span> <span style="color:#ba2121">&#34; &#34;</span> (<span style="color:#00f">substring-no-properties</span> (<span style="color:#00f">car</span> <span style="color:#19177c">key</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">+</span> <span style="color:#666">2</span> (<span style="color:#008000">or</span> <span style="color:#19177c">level</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">buffer</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dump-bindings</span> (<span style="color:#19177c">prefix</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Dump keybindings starting with PREFIX in a tree-like form.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#ba2121">&#34;sPrefix: &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">buffer</span> (<span style="color:#00f">get-buffer-create</span> <span style="color:#ba2121">&#34;bindings&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">erase-buffer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/dump-bindings-recursive</span> <span style="color:#19177c">prefix</span> <span style="color:#666">0</span> <span style="color:#19177c">buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-min</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">buffer-read-only</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">switch-to-buffer-other-window</span> <span style="color:#19177c">buffer</span>)))
</span></span></code></pre></div><h4 id="evil">Evil</h4>
<p>An entire ecosystem of packages that emulates the main features of Vim. Probably the best vim emulator out there.</p>
<p>The only problem is that the package name makes it hard to google anything by just typing &ldquo;evil&rdquo;.</p>
<p>References:</p>
<ul>
<li><a href="https://github.com/emacs-evil/evil">evil repo</a></li>
<li><a href="https://www.youtube.com/watch?v=JWD1Fpdd4Pc">(YouTube) Evil Mode: Or, How I Learned to Stop Worrying and Love Emacs</a></li>
</ul>
<h5 id="evil-mode">Evil-mode</h5>
<p>Basic evil configuration.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">evil</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">evil-want-integration</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">evil-want-C-u-scroll</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">evil-want-keybinding</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">evil-search-module</span> <span style="color:#19177c">&#39;evil-search</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">evil-split-window-below</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">evil-vsplit-window-right</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">display-graphic-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">evil-want-C-i-jump</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (setq evil-respect-visual-line-mode t)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">fboundp</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">undo-tree-undo</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-set-undo-system</span> <span style="color:#19177c">&#39;undo-tree</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">fboundp</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">general-define-key</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">motion</span>))))
</span></span></code></pre></div><h5 id="addons">Addons</h5>
<p><a href="https://github.com/emacs-evil/evil-surround">evil-surround</a> emulates one of my favorite vim plugins, surround.vim. Adds a lot of parentheses management options.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">evil-surround</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">evil</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">global-evil-surround-mode</span> <span style="color:#666">1</span>))
</span></span></code></pre></div><p><a href="https://github.com/linktohack/evil-commentary">evil-commentary</a> emulates commentary.vim. It provides actions for quick insertion and deletion of comments.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">evil-commentary</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">evil</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-commentary-mode</span>))
</span></span></code></pre></div><p><a href="https://github.com/blorbx/evil-quickscope">evil-quickscope</a> emulates quickscope.vim. It highlights certain target characters for f, F, t, T keys.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">evil-quickscope</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">evil</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> ((<span style="color:#19177c">prog-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">turn-on-evil-quickscope-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">LaTeX-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">turn-on-evil-quickscope-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">turn-on-evil-quickscope-mode</span>)))
</span></span></code></pre></div><p><a href="https://github.com/cofi/evil-numbers">evil-numbers</a> allows incrementing and decrementing numbers at point.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">evil-numbers</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">evil-numbers/inc-at-pt</span> <span style="color:#19177c">evil-numbers/dec-at-pt</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-nmap</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;g+&#34;</span> <span style="color:#19177c">&#39;evil-numbers/inc-at-pt</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;g-&#34;</span> <span style="color:#19177c">&#39;evil-numbers/dec-at-pt</span>))
</span></span></code></pre></div><p><a href="https://github.com/edkolev/evil-lion">evil-lion</a> provides alignment operators, somewhat similar to vim-easyalign.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">evil-lion</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">evil-lion-left-align-key</span> (<span style="color:#19177c">kbd</span> <span style="color:#ba2121">&#34;g a&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">evil-lion-right-align-key</span> (<span style="color:#19177c">kbd</span> <span style="color:#ba2121">&#34;g A&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-lion-mode</span>))
</span></span></code></pre></div><p><a href="https://github.com/redguardtoo/evil-matchit">evil-matchit</a> makes &ldquo;%&rdquo; to match things like tags. It doesn&rsquo;t work perfectly, so I <del>occasionally</del> turn it off.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">evil-matchit</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">global-evil-matchit-mode</span> <span style="color:#666">1</span>))
</span></span></code></pre></div><h5 id="my-additions">My additions</h5>
<p>Do ex search in other buffer. Like <code>*</code>, but switch to other buffer and search there.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/evil-ex-search-word-forward-other-window</span> (<span style="color:#19177c">count</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">symbol</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> (<span style="color:#00f">prefix-numeric-value</span> <span style="color:#19177c">current-prefix-arg</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">evil-symbol-word-search</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-ex-start-word-search</span> <span style="color:#800">nil</span> <span style="color:#19177c">&#39;forward</span> <span style="color:#19177c">count</span> <span style="color:#19177c">symbol</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">other-window</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-ex-search-next</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&amp;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/evil-ex-search-word-forward-other-window</span>)
</span></span></code></pre></div><h5 id="evil-collection">evil-collection</h5>
<p><a href="https://github.com/emacs-evil/evil-collection">evil-collection</a> is a package that provides evil bindings for a lot of different packages. One can see the complete list in the <a href="https://github.com/emacs-evil/evil-collection/tree/master/modes">modes</a> folder.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">evil-collection</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">evil</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-collection-init</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">eww</span> <span style="color:#19177c">devdocs</span> <span style="color:#19177c">proced</span> <span style="color:#19177c">emms</span> <span style="color:#19177c">pass</span> <span style="color:#19177c">calendar</span> <span style="color:#19177c">dired</span> <span style="color:#19177c">debug</span> <span style="color:#19177c">guix</span> <span style="color:#19177c">calc</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">docker</span> <span style="color:#19177c">ibuffer</span> <span style="color:#19177c">geiser</span> <span style="color:#19177c">pdf</span> <span style="color:#19177c">info</span> <span style="color:#19177c">elfeed</span> <span style="color:#19177c">edebug</span> <span style="color:#19177c">bookmark</span> <span style="color:#19177c">company</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">vterm</span> <span style="color:#19177c">flycheck</span> <span style="color:#19177c">profiler</span> <span style="color:#19177c">cider</span> <span style="color:#19177c">explain-pause-mode</span> <span style="color:#19177c">notmuch</span> <span style="color:#19177c">custom</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">xref</span> <span style="color:#19177c">eshell</span> <span style="color:#19177c">helpful</span> <span style="color:#19177c">compile</span> <span style="color:#19177c">comint</span> <span style="color:#19177c">git-timemachine</span> <span style="color:#19177c">magit</span> <span style="color:#19177c">prodigy</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">slime</span> <span style="color:#19177c">forge</span> <span style="color:#19177c">deadgrep</span> <span style="color:#19177c">vc-annonate</span> <span style="color:#19177c">telega</span> <span style="color:#19177c">doc-view</span> <span style="color:#19177c">gnus</span> <span style="color:#19177c">outline</span>)))
</span></span></code></pre></div><h4 id="my-keybindings">My keybindings</h4>
<p>Various keybinding settings that I can&rsquo;t put anywhere else.</p>
<h5 id="escape-key">Escape key</h5>
<p><del>Use the escape key instead of <code>C-g</code> whenever possible</del> No, not really after 2 years&hellip; But I&rsquo;ll keep this fragment.</p>
<p>I must have copied it from somewhere, but as I googled to find out the source, I discovered quite a number of variations of the following code over time. I wonder if Richard Dawkins was inspired by something like this a few decades ago.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">minibuffer-keyboard-quit</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Abort recursive edit.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">In Delete Selection mode, if the mark is active, just deactivate it;
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">then it takes a second \\[keyboard-quit] to abort the minibuffer.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">and</span> <span style="color:#19177c">delete-selection-mode</span> <span style="color:#19177c">transient-mark-mode</span> <span style="color:#19177c">mark-active</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">deactivate-mark</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">get-buffer</span> <span style="color:#ba2121">&#34;*Completions*&#34;</span>) (<span style="color:#19177c">delete-windows-on</span> <span style="color:#ba2121">&#34;*Completions*&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">abort-recursive-edit</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/escape-key</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-ex-nohighlight</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">keyboard-quit</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">visual</span> <span style="color:#19177c">global</span>)
</span></span><span style="display:flex;"><span> [<span style="color:#19177c">escape</span>] <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/escape-key</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">minibuffer-local-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">minibuffer-local-ns-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">minibuffer-local-completion-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">minibuffer-local-must-match-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">minibuffer-local-isearch-map</span>)
</span></span><span style="display:flex;"><span> [<span style="color:#19177c">escape</span>] <span style="color:#19177c">&#39;minibuffer-keyboard-quit</span>)
</span></span></code></pre></div><h5 id="home-and-end">Home &amp; end</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">general-def</span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#00f">insert</span> <span style="color:#19177c">visual</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;home&gt;&#34;</span> <span style="color:#19177c">&#39;beginning-of-line</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;end&gt;&#34;</span> <span style="color:#19177c">&#39;end-of-line</span>)
</span></span></code></pre></div><h5 id="my-leader">My leader</h5>
<p>Using the <code>SPC</code> key as a leader key, like in Doom Emacs or Spacemacs.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">general-create-definer</span> <span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;override</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:prefix</span> <span style="color:#ba2121">&#34;SPC&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">motion</span> <span style="color:#19177c">emacs</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-def</span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">motion</span> <span style="color:#19177c">emacs</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;SPC&#34;</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-SPC&#34;</span> (<span style="color:#19177c">general-key</span> <span style="color:#ba2121">&#34;SPC&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-def</span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#00f">insert</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-SPC&#34;</span> (<span style="color:#19177c">general-key</span> <span style="color:#ba2121">&#34;SPC&#34;</span> <span style="color:#008000">:state</span> <span style="color:#19177c">&#39;normal</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;?&#34;</span> <span style="color:#19177c">&#39;which-key-show-top-level</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;E&#34;</span> <span style="color:#19177c">&#39;eval-expression</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-def</span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#00f">insert</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;f1&gt; e&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">eval-expression</span>)
</span></span></code></pre></div><p><code>general.el</code> has a nice integration with which-key, so I use that to show more descriptive annotations for certain groups of keybindings (the default annotation is just <code>prefix</code>).</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;a&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;apps&#34;</span>))
</span></span></code></pre></div><h5 id="universal-argument">Universal argument</h5>
<p>Change the universal argument to <code>M-u</code>. I use <code>C-u</code> to scroll up, as I&rsquo;m used to from vim.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">general-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;universal-argument-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-u&#34;</span> <span style="color:#19177c">&#39;universal-argument-more</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;override</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">motion</span> <span style="color:#19177c">emacs</span> <span style="color:#00f">insert</span> <span style="color:#19177c">visual</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-u&#34;</span> <span style="color:#19177c">&#39;universal-argument</span>)
</span></span></code></pre></div><h5 id="profiler">Profiler</h5>
<p>The built-in profiler is a magnificent tool to troubleshoot performance issues.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;P&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;profiler&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#19177c">&#39;profiler-start</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;e&#34;</span> <span style="color:#19177c">&#39;profiler-stop</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;p&#34;</span> <span style="color:#19177c">&#39;profiler-report</span>)
</span></span></code></pre></div><h5 id="buffer-switching">Buffer switching</h5>
<p>Some keybindings I used in vim to switch buffers and can&rsquo;t let go of. But I think I started to use these less since I made an attempt in <a href="#i3-integration">i3 integration</a>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;override</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-&lt;right&gt;&#34;</span> <span style="color:#19177c">&#39;evil-window-right</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-&lt;left&gt;&#34;</span> <span style="color:#19177c">&#39;evil-window-left</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-&lt;up&gt;&#34;</span> <span style="color:#19177c">&#39;evil-window-up</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-&lt;down&gt;&#34;</span> <span style="color:#19177c">&#39;evil-window-down</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-h&#34;</span> <span style="color:#19177c">&#39;evil-window-left</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-l&#34;</span> <span style="color:#19177c">&#39;evil-window-right</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-k&#34;</span> <span style="color:#19177c">&#39;evil-window-up</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-j&#34;</span> <span style="color:#19177c">&#39;evil-window-down</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-x h&#34;</span> <span style="color:#19177c">&#39;previous-buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-x l&#34;</span> <span style="color:#19177c">&#39;next-buffer</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;evil-window-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;x&#34;</span> <span style="color:#19177c">&#39;kill-buffer-and-window</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#19177c">&#39;kill-current-buffer</span>)
</span></span></code></pre></div><p><code>winner-mode</code> to keep the history of window states.</p>
<p>It doesn&rsquo;t play too well with perspective.el, that is it has a single history list for all of the perspectives. But it is still quite usable.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">winner-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;evil-window-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;u&#34;</span> <span style="color:#19177c">&#39;winner-undo</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;U&#34;</span> <span style="color:#19177c">&#39;winner-redo</span>)
</span></span></code></pre></div><h5 id="buffer-management">Buffer management</h5>
<p>The following is necessary since my scratch buffer isn&rsquo;t lisp-interaction.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/lisp-interaction-buffer</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">buf</span> (<span style="color:#00f">get-buffer-create</span> <span style="color:#ba2121">&#34;*lisp-interaction*&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buf</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">lisp-interaction-mode</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">switch-to-buffer</span> <span style="color:#19177c">buf</span>)))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;b&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;buffers&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">my/lisp-interaction-buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;*lisp-interaction*&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;m&#34;</span> <span style="color:#666">&#39;</span>((<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">persp-switch-to-buffer</span> <span style="color:#ba2121">&#34;*Messages*&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;*Messages*&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;l&#34;</span> <span style="color:#19177c">&#39;next-buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;h&#34;</span> <span style="color:#19177c">&#39;previous-buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;k&#34;</span> <span style="color:#19177c">&#39;kill-buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; &#34;b&#34; &#39;persp-ivy-switch-buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;b&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">persp-switch-to-buffer*</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#19177c">&#39;revert-buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;u&#34;</span> <span style="color:#19177c">&#39;ibuffer</span>)
</span></span></code></pre></div><h5 id="xref">xref</h5>
<p>Some keybindings for xref and go to definition.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">general-nmap</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gD&#34;</span> <span style="color:#19177c">&#39;xref-find-definitions-other-window</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gr&#34;</span> <span style="color:#19177c">&#39;xref-find-references</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gd&#34;</span> <span style="color:#19177c">&#39;evil-goto-definition</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;fx&#34;</span> <span style="color:#19177c">&#39;xref-find-apropos</span>)
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">xref</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:type</span> <span style="color:#19177c">built-in</span>))
</span></span></code></pre></div><h5 id="folding">Folding</h5>
<p>There are multiple ways to fold text in Emacs.</p>
<p>The most versatile is the built-in <code>hs-minor-mode</code>, which seems to work out of the box for Lisps, C-like languages, and Python. <code>outline-minor-mode</code> works for org-mode, LaTeX and the like. There is a 3rd-party solution <a href="https://github.com/elp-revive/origami.el">origami.el</a>, which I found to be somewhat less stable.</p>
<p>Evil does a pretty good job of abstracting all these packages with a set of vim-like keybindings. I was using <code>SPC</code> in vim, but as now this isn&rsquo;t an option, I set <code>TAB</code> to toggle folding.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">require</span> <span style="color:#19177c">&#39;hideshow</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">hs-minor-mode-map</span> <span style="color:#19177c">outline-minor-mode-map</span> <span style="color:#19177c">outline-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">motion</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;TAB&#34;</span> <span style="color:#19177c">&#39;evil-toggle-fold</span>)
</span></span></code></pre></div><h5 id="zoom-ui">Zoom UI</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/zoom-in</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Increase font size by 10 points&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-face-attribute</span> <span style="color:#19177c">&#39;default</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:height</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">+</span> (<span style="color:#19177c">face-attribute</span> <span style="color:#19177c">&#39;default</span> <span style="color:#008000">:height</span>) <span style="color:#666">10</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/zoom-out</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Decrease font size by 10 points&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-face-attribute</span> <span style="color:#19177c">&#39;default</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:height</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">-</span> (<span style="color:#19177c">face-attribute</span> <span style="color:#19177c">&#39;default</span> <span style="color:#008000">:height</span>) <span style="color:#666">10</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; change font size, interactively</span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">global-set-key</span> (<span style="color:#19177c">kbd</span> <span style="color:#ba2121">&#34;C-+&#34;</span>) <span style="color:#19177c">&#39;my/zoom-in</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">global-set-key</span> (<span style="color:#19177c">kbd</span> <span style="color:#ba2121">&#34;C-=&#34;</span>) <span style="color:#19177c">&#39;my/zoom-out</span>)
</span></span></code></pre></div><h4 id="termux">Termux</h4>
<p>For some reason my ONYX device has the tilde and escape wrong.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">when</span> (<span style="color:#008000">and</span> <span style="color:#19177c">my/is-termux</span> (<span style="color:#19177c">not</span> (<span style="color:#00f">equal</span> (<span style="color:#19177c">my/system-name</span>) <span style="color:#ba2121">&#34;snow&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">define-key</span> <span style="color:#19177c">key-translation-map</span> (<span style="color:#19177c">kbd</span> <span style="color:#ba2121">&#34;`&#34;</span>) (<span style="color:#19177c">kbd</span> <span style="color:#ba2121">&#34;&lt;escape&gt;&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">define-key</span> <span style="color:#19177c">key-translation-map</span> (<span style="color:#19177c">kbd</span> <span style="color:#ba2121">&#34;&lt;escape&gt;&#34;</span>) (<span style="color:#19177c">kbd</span> <span style="color:#ba2121">&#34;`&#34;</span>)))
</span></span></code></pre></div><p>And the screen is less wide.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">when</span> <span style="color:#19177c">my/is-termux</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">split-width-threshold</span> <span style="color:#666">90</span>))
</span></span></code></pre></div><h3 id="i3-integration-1">i3 integration</h3>
<p>UPD <span class="timestamp-wrapper"><span class="timestamp">&lt;2021-11-27 Sat&gt;</span></span>. I have finally switched to EXWM as my window manager, but as long as I keep i3 as a backup solution, this section persists. Check out the <a href="https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/">post</a> for a somewhat better presentation.</p>
<p>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 <a href="https://i3wm.org">i3wm</a>, 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.</p>
<p>But why not just use EXWM? One key reason is that to my taste (and perhaps on my hardware) EXWM didn&rsquo;t feel snappy enough. Also, I really like i3&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 <a href="https://xmonad.org/">XMonad</a>, for instance.</p>
<p>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, <a href="http://www.qtile.org/">Qtile</a>, <a href="https://awesomewm.org/">Awesome</a>, etc. But I think i3&rsquo;s extensibility is underappreciated, although the contents of this section may lie closer to the limits of how far one can go there.</p>
<p>The basic idea is to launch a normal i3 command with <code>i3-msg</code> in case the current window is not Emacs, otherwise pass that command to Emacs with <code>emacsclient</code>. In Emacs, execute the command if possible, otherwise pass the command back to i3.</p>
<p>This may seem like a lot of overhead, but I didn&rsquo;t feel it even in the worst case (i3 -&gt; Emacs -&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.</p>
<p>One interesting observation here is that Emacs windows and X windows are sort of one-level entities, so I can talk just about &ldquo;windows&rdquo;.</p>
<p>At any rate, we need a script to do the i3 -&gt; Emacs part:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">if</span> <span style="color:#666">[[</span> <span style="color:#008000;font-weight:bold">$(</span>xdotool getactivewindow getwindowname<span style="color:#008000;font-weight:bold">)</span> <span style="color:#666">=</span>~ ^emacs<span style="color:#666">(</span>:.*<span style="color:#666">)</span>?@.* <span style="color:#666">]]</span>; <span style="color:#008000;font-weight:bold">then</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">command</span><span style="color:#666">=</span><span style="color:#ba2121">&#34;(my/emacs-i3-integration \&#34;</span><span style="color:#19177c">$@</span><span style="color:#ba2121">\&#34;)&#34;</span>
</span></span><span style="display:flex;"><span> emacsclient -e <span style="color:#ba2121">&#34;</span><span style="color:#19177c">$command</span><span style="color:#ba2121">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">else</span>
</span></span><span style="display:flex;"><span> i3-msg <span style="color:#19177c">$@</span>
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">fi</span>
</span></span></code></pre></div><p>This script is being run from the <a href="/configs/desktop/#i3wm">i3 configuration</a>.</p>
<p>For this to work, we need to make sure that Emacs starts a server, so here is an expression to do just that:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">unless</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/remote-server</span> <span style="color:#19177c">my/nested-emacs</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;after-init-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">server-start</span>))
</span></span></code></pre></div><p>And here is a simple macro to do the Emacs -&gt; i3 part:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defmacro</span> <span style="color:#19177c">i3-msg</span> (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">args</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#00f">start-process</span> <span style="color:#ba2121">&#34;emacs-i3-windmove&#34;</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;i3-msg&#34;</span> <span style="color:#666">,@</span><span style="color:#19177c">args</span>))
</span></span></code></pre></div><p>Now we have to handle the required set of i3 commands. It is worth noting here that I&rsquo;m not trying to implement a general mechanism to apply i3 commands to Emacs, rather I&rsquo;m implementing a small subset that I use in my i3 configuration and that maps reasonably to the Emacs concepts.</p>
<p>Also, I use <a href="https://github.com/emacs-evil/evil">evil-mode</a> and generally configure the software to have vim-style bindings where possible. So if you don&rsquo;t use evil-mode you&rsquo;d have to detangle the given functions from evil, but then, I guess, you do not use super+hjkl to manage windows either.</p>
<p>First, for the <code>focus</code> 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 windmove have the same names for directions, so the function is rather straightforward.</p>
<p>One caveat here is that the minibuffer is always the bottom-most Emacs window, so it is necessary to check for that as well.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/emacs-i3-windmove</span> (<span style="color:#19177c">dir</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">other-window</span> (<span style="color:#19177c">windmove-find-other-window</span> <span style="color:#19177c">dir</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">or</span> (<span style="color:#00f">null</span> <span style="color:#19177c">other-window</span>) (<span style="color:#00f">window-minibuffer-p</span> <span style="color:#19177c">other-window</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">i3-msg</span> <span style="color:#ba2121">&#34;focus&#34;</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">dir</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">windmove-do-window-select</span> <span style="color:#19177c">dir</span>))))
</span></span></code></pre></div><p>For the <code>move</code> I want the following behavior:</p>
<ul>
<li>if there is space in the required direction, move the Emacs window there;</li>
<li>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;</li>
<li>otherwise, move an X window (Emacs frame).</li>
</ul>
<p>For the first part, <code>window-swap-states</code> with <code>windmove-find-other-window</code> do well enough.</p>
<p><code>evil-move-window</code> works well for the second part. By itself it doesn&rsquo;t behave quite like i3, for instance, <code>(evil-move-window 'right)</code> 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.</p>
<p>So here is a simple predicate which checks whether there is space in the given direction.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/emacs-i3-direction-exists-p</span> (<span style="color:#19177c">dir</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-some</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">dir</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">win</span> (<span style="color:#19177c">windmove-find-other-window</span> <span style="color:#19177c">dir</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span> <span style="color:#19177c">win</span> (<span style="color:#19177c">not</span> (<span style="color:#00f">window-minibuffer-p</span> <span style="color:#19177c">win</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">dir</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;width</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">left</span> <span style="color:#19177c">right</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;height</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">up</span> <span style="color:#19177c">down</span>)))))
</span></span></code></pre></div><p>And the implementation of the move command.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/emacs-i3-move-window</span> (<span style="color:#19177c">dir</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">other-window</span> (<span style="color:#19177c">windmove-find-other-window</span> <span style="color:#19177c">dir</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">other-direction</span> (<span style="color:#19177c">my/emacs-i3-direction-exists-p</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">dir</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;up</span> <span style="color:#19177c">&#39;width</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;down</span> <span style="color:#19177c">&#39;width</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;left</span> <span style="color:#19177c">&#39;height</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;right</span> <span style="color:#19177c">&#39;height</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">and</span> <span style="color:#19177c">other-window</span> (<span style="color:#19177c">not</span> (<span style="color:#00f">window-minibuffer-p</span> <span style="color:#19177c">other-window</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">window-swap-states</span> (<span style="color:#00f">selected-window</span>) <span style="color:#19177c">other-window</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">other-direction</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-move-window</span> <span style="color:#19177c">dir</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> (<span style="color:#19177c">i3-msg</span> <span style="color:#ba2121">&#34;move&#34;</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">dir</span>))))))
</span></span></code></pre></div><p>Next on the line are <code>resize grow</code> and <code>resize shrink</code>. <code>evil-window-</code> functions do nicely for this task.</p>
<p>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.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/emacs-i3-resize-window</span> (<span style="color:#19177c">dir</span> <span style="color:#19177c">kind</span> <span style="color:#19177c">value</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">one-window-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">my/emacs-i3-direction-exists-p</span> <span style="color:#19177c">dir</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">i3-msg</span> <span style="color:#ba2121">&#34;resize&#34;</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">kind</span>) (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">dir</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%s px or %s ppt&#34;</span> <span style="color:#19177c">value</span> <span style="color:#19177c">value</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">value</span> (<span style="color:#00f">/</span> <span style="color:#19177c">value</span> <span style="color:#666">2</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">kind</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;shrink</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">dir</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;width</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-window-decrease-width</span> <span style="color:#19177c">value</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;height</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-window-decrease-height</span> <span style="color:#19177c">value</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;grow</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">dir</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;width</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-window-increase-width</span> <span style="color:#19177c">value</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;height</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-window-increase-height</span> <span style="color:#19177c">value</span>)))))))
</span></span></code></pre></div><p><a href="https://github.com/emacsorphanage/transpose-frame">transpose-frame</a> is a package to &ldquo;transpose&rdquo; the current frame layout, which behaves someone similar to the <code>layout toggle split</code> command in i3, so I&rsquo;ll use it as well.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">transpose-frame</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">transpose-frame</span>))
</span></span></code></pre></div><p>Finally, the entrypoint for the Emacs integration. In addition to the commands defined above, it processes <code>split</code> and <code>kill</code> commands and passes every other command back to i3.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/emacs-i3-integration</span> (<span style="color:#19177c">command</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">command</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;focus&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/emacs-i3-windmove</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">intern</span> (<span style="color:#00f">elt</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">command</span>) <span style="color:#666">1</span>))))
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;move&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/emacs-i3-move-window</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">intern</span> (<span style="color:#00f">elt</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">command</span>) <span style="color:#666">1</span>))))
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;resize&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/emacs-i3-resize-window</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">intern</span> (<span style="color:#00f">elt</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">command</span>) <span style="color:#666">2</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">intern</span> (<span style="color:#00f">elt</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">command</span>) <span style="color:#666">1</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">string-to-number</span> (<span style="color:#00f">elt</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">command</span>) <span style="color:#666">3</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;layout toggle split&#34;</span> (<span style="color:#19177c">transpose-frame</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;split h&#34;</span> (<span style="color:#19177c">evil-window-split</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;split v&#34;</span> (<span style="color:#19177c">evil-window-vsplit</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;kill&#34;</span> (<span style="color:#19177c">evil-quit</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">-</span> (<span style="color:#19177c">i3-msg</span> <span style="color:#19177c">command</span>))))
</span></span></code></pre></div><h3 id="editing-text">Editing text</h3>
<p>Various packages, tricks, and settings that help with the central task of Emacs - editing text.</p>
<h4 id="indentation-and-whitespace">Indentation &amp; whitespace</h4>
<h5 id="aggressive-indent">Aggressive Indent</h5>
<p>A package to keep the code intended.</p>
<p>Doesn&rsquo;t work too well with many ecosystems because the LSP-based indentation is rather slow but nice for Lisps.</p>
<p>References:</p>
<ul>
<li><a href="https://github.com/Malabarba/aggressive-indent-mode">aggressive-indent-mode repo</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">aggressive-indent</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">aggressive-indent-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h5 id="delete-trailing-whitespace">Delete trailing whitespace</h5>
<p>Delete trailing whitespace on save, unless in particular modes where trailing whitespace is important, like Markdown.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/trailing-whitespace-modes</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">markdown-mode</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">require</span> <span style="color:#19177c">&#39;cl-extra</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;before-save-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">cl-some</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">derived-mode-p</span> <span style="color:#19177c">my/trailing-whitespace-modes</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">delete-trailing-whitespace</span>))))
</span></span></code></pre></div><h5 id="tabs">Tabs</h5>
<p>Some default settings to manage tabs.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">tab-always-indent</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq-default</span> <span style="color:#19177c">default-tab-width</span> <span style="color:#666">4</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq-default</span> <span style="color:#19177c">tab-width</span> <span style="color:#666">4</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq-default</span> <span style="color:#19177c">evil-indent-convert-tabs</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq-default</span> <span style="color:#19177c">indent-tabs-mode</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq-default</span> <span style="color:#19177c">evil-shift-round</span> <span style="color:#800">nil</span>)
</span></span></code></pre></div><h4 id="settings">Settings</h4>
<h5 id="scrolling">Scrolling</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">scroll-conservatively</span> <span style="color:#19177c">scroll-margin</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">scroll-step</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">scroll-preserve-screen-position</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">scroll-error-top-bottom</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">mouse-wheel-progressive-speed</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">mouse-wheel-inhibit-click-time</span> <span style="color:#800">nil</span>)
</span></span></code></pre></div><h5 id="clipboard">Clipboard</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">select-enable-clipboard</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">mouse-yank-at-point</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h5 id="backups">Backups</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">backup-inhibited</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">auto-save-default</span> <span style="color:#800">nil</span>)
</span></span></code></pre></div><h4 id="undo-tree">Undo Tree</h4>
<p>Replaces Emacs built-in sequential undo system with a tree-based one. Probably one of the greatest options of Emacs as a text editor.</p>
<p>References:</p>
<ul>
<li><a href="https://www.emacswiki.org/emacs/UndoTree">UndoTree on EmacsWiki</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">undo-tree</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">global-undo-tree-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-set-undo-system</span> <span style="color:#19177c">&#39;undo-tree</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">undo-tree-visualizer-diff</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">undo-tree-visualizer-timestamps</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">undo-tree-auto-save-history</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;u&#34;</span> <span style="color:#19177c">&#39;undo-tree-visualize</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">fset</span> <span style="color:#19177c">&#39;undo-auto-amalgamate</span> <span style="color:#19177c">&#39;ignore</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">undo-limit</span> <span style="color:#666">6710886400</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">undo-strong-limit</span> <span style="color:#666">100663296</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">undo-outer-limit</span> <span style="color:#666">1006632960</span>))
</span></span></code></pre></div><h4 id="snippets">Snippets</h4>
<p>A snippet system for Emacs and a collection of pre-built snippets.</p>
<p><code>yasnippet-snippets</code> has to be loaded before <code>yasnippet</code> for user snippets to override the pre-built ones.</p>
<p>Edit <span class="timestamp-wrapper"><span class="timestamp">&lt;2022-04-11 Mon&gt; </span></span> I don&rsquo;t really use <code>yasnippet-snippets</code>, so I&rsquo;d rather write stuff manually.</p>
<p>References:</p>
<ul>
<li><a href="http://joaotavora.github.io/yasnippet/">yasnippet documentation</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">yasnippet-snippets</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">yasnippet</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">yas-snippet-dirs</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,</span>(<span style="color:#00f">concat</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#19177c">user-emacs-directory</span>) <span style="color:#ba2121">&#34;snippets&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; yasnippet-snippets-dir</span>
</span></span><span style="display:flex;"><span> ))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">yas-triggers-in-field</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">yas-global-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;yas-minor-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;es&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:wk</span> <span style="color:#ba2121">&#34;yasnippet&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;n&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">yas-new-snippet</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">yas-insert-snippet</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;v&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">yas-visit-snippet-file</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-imap</span> <span style="color:#ba2121">&#34;M-TAB&#34;</span> <span style="color:#19177c">&#39;company-yasnippet</span>)
</span></span></code></pre></div><h4 id="input-method">Input Method</h4>
<blockquote>
<p>I have to switch layouts all the time, especially in LaTeX documents, because for some reason the Bolsheviks abandoned the idea of replacing Russian Cyrillic letters with Latin ones.</p></blockquote>
<ul>
<li>Me, <span class="timestamp-wrapper"><span class="timestamp">[2021-04-24 Sat]</span></span>, in a commit to <a href="https://github.com/SystemCrafters/crafter-configs">SystemCrafters/crafter-configs</a>.</li>
</ul>
<p>Fortunately, Emacs offers a way out of the above with input methods.</p>
<p>References:</p>
<ul>
<li><a href="https://protesilaos.com/codelog/2023-12-12-emacs-multilingual-editing/">https://protesilaos.com/codelog/2023-12-12-emacs-multilingual-editing/</a> - A video by Prot from which I learned about this feature.</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">default-input-method</span> <span style="color:#ba2121">&#34;russian-computer&#34;</span>)
</span></span></code></pre></div><p>I also want to call <code>xkb-switch</code> in EXWM buffers with the same keybindig.</p>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>xkb-switch</td>
</tr>
</tbody>
</table>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/toggle-input-method</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">derived-mode-p</span> <span style="color:#19177c">&#39;exwm-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/run-in-background</span> <span style="color:#ba2121">&#34;xkb-switch -n&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">executable-find</span> <span style="color:#ba2121">&#34;xkb-switch&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">equal</span> (<span style="color:#19177c">string-trim</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shell-command-to-string</span> <span style="color:#ba2121">&#34;xkb-switch -p&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;us&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">toggle-input-method</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/run-in-background</span> <span style="color:#ba2121">&#34;xkb-switch -s us&#34;</span>))))
</span></span></code></pre></div><p><code>M-x delete-horizontal-space</code> doesn&rsquo;t feel that useful to me.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;global</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-\\&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/toggle-input-method</span>)
</span></span></code></pre></div><h4 id="other-small-packages">Other small packages</h4>
<h5 id="managing-parentheses--smartparens">Managing parentheses (smartparens)</h5>
<p>A minor mode to deal with pairs. Its functionality overlaps with evil-surround, but smartparens provides the most comfortable way to do stuff like automatically insert pairs.</p>
<p>References:</p>
<ul>
<li><a href="https://github.com/Fuco1/smartparens">smartparens repo</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">smartparens</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h5 id="visual-fill-column-mode">Visual fill column mode</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">visual-fill-column</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">visual-fill-column-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; How did it get here?</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (add-hook &#39;visual-fill-column-mode-hook</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (lambda () (setq visual-fill-column-center-text t)))</span>
</span></span><span style="display:flex;"><span> )
</span></span></code></pre></div><h5 id="accents">Accents</h5>
<p>Input accented characters.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/default-accents</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">a</span> <span style="color:#666">.</span> <span style="color:#19177c">ä</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">o</span> <span style="color:#666">.</span> <span style="color:#19177c">ö</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">u</span> <span style="color:#666">.</span> <span style="color:#19177c">ü</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">s</span> <span style="color:#666">.</span> <span style="color:#19177c">ß</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">A</span> <span style="color:#666">.</span> <span style="color:#19177c">Ä</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">O</span> <span style="color:#666">.</span> <span style="color:#19177c">Ö</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">U</span> <span style="color:#666">.</span> <span style="color:#19177c">Ü</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">S</span> <span style="color:#666">.</span> <span style="color:#19177c">ẞ</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/accent</span> (<span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#ba2121">&#34;P&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;accent</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;%s&#34;</span> <span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">after?</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">accent-position</span> <span style="color:#19177c">&#39;after</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">char</span> (<span style="color:#008000">if</span> <span style="color:#19177c">after?</span> (<span style="color:#00f">char-after</span>) (<span style="color:#00f">char-before</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">curr</span> (<span style="color:#00f">intern</span> (<span style="color:#00f">string</span> <span style="color:#19177c">char</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">default-diac</span> (<span style="color:#00f">cdr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">curr</span> <span style="color:#19177c">my/default-accents</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">and</span> <span style="color:#19177c">default-diac</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">arg</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">delete-char</span> (<span style="color:#008000">if</span> <span style="color:#19177c">after?</span> <span style="color:#666">1</span> <span style="color:#666">-1</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%c&#34;</span> <span style="color:#19177c">default-diac</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">call-interactively</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">accent-company</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">accent</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;eliascotto/accent&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gs&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">accent-company</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#00f">insert</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-n&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/accent</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">accent-menu</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;popup-menu-keymap</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-j&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">popup-next</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-k&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">popup-previous</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-j&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">popup-next</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-k&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">popup-previous</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">accent-custom</span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">a</span> (<span style="color:#19177c">ā</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">A</span> (<span style="color:#19177c">Ā</span>)))))
</span></span></code></pre></div><h4 id="random-editing-tricks">Random editing tricks</h4>
<h5 id="round-number-at-point">Round number at point</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/round-number-at-point</span> (<span style="color:#19177c">word</span> <span style="color:#19177c">signs</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#008000">or</span> (<span style="color:#008000">when</span> (<span style="color:#19177c">region-active-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-substring-no-properties</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">region-beginning</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">region-end</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thing-at-point</span> <span style="color:#19177c">&#39;number</span> <span style="color:#19177c">&#39;no-properties</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">read-number</span> <span style="color:#ba2121">&#34;Decimal signs: &#34;</span> <span style="color:#666">2</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">stringp</span> <span style="color:#19177c">word</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">word</span> (<span style="color:#00f">string-to-number</span> <span style="color:#19177c">word</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">number</span> (<span style="color:#00f">/</span> (<span style="color:#00f">float</span> (<span style="color:#00f">round</span> (<span style="color:#00f">*</span> (<span style="color:#00f">expt</span> <span style="color:#666">10</span> <span style="color:#19177c">signs</span>) <span style="color:#19177c">word</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">expt</span> <span style="color:#666">10</span> <span style="color:#19177c">signs</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-string-in-region</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">number-to-string</span> <span style="color:#19177c">word</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">number-to-string</span> <span style="color:#19177c">number</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">line-beginning-position</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">line-end-position</span>)))))
</span></span></code></pre></div><h3 id="working-with-projects">Working with projects</h3>
<p>Packages related to managing projects.</p>
<p>I used to have <a href="https://github.com/Alexander-Miller/treemacs">Treemacs</a> here, but in the end decided that dired with <a href="https://github.com/jojojames/dired-sidebar">dired-sidebar</a> does a better job. Dired has its separate section in &ldquo;Applications&rdquo;.</p>
<h4 id="projectile">Projectile</h4>
<p><a href="https://github.com/bbatsov/projectile">Projectile</a> gives a bunch of useful functions for managing projects, like finding files within a project, fuzzy-find, replace, etc.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">projectile</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">projectile-mode</span> <span style="color:#666">+1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">projectile-project-search-path</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;~/Code&#34;</span> <span style="color:#ba2121">&#34;~/Documents&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;projectile-command-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;b&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">consult-project-buffer</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;p&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:keymap</span> <span style="color:#19177c">projectile-command-map</span> <span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;projectile&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-nmap</span> <span style="color:#ba2121">&#34;C-p&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">projectile-find-file</span>)
</span></span></code></pre></div><h4 id="git-and-magit">Git &amp; Magit</h4>
<p><a href="https://magit.vc/">Magit</a> is a git interface for Emacs.</p>
<p>A few CLI alternatives:</p>
<ul>
<li><a href="https://github.com/jesseduffield/lazygit">lazygit</a>. I used it before Emacs</li>
<li><a href="https://github.com/altsem/gitu">gitu</a>. A CLI magit clone</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">magit</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">magit-status</span> <span style="color:#19177c">magit-file-dispatch</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;m&#34;</span> <span style="color:#19177c">&#39;magit</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M&#34;</span> <span style="color:#19177c">&#39;magit-file-dispatch</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;forge</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">magit-blame-styles</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">headings</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">heading-format</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;%-20a %C %s\n&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">highlight</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">highlight-face</span> <span style="color:#666">.</span> <span style="color:#19177c">magit-blame-highlight</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">lines</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">show-lines</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">show-message</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)))))
</span></span></code></pre></div><p><a href="https://github.com/emacsorphanage/git-gutter">git-gutter</a> is shows git changes for each line (added/changed/deleted lines).</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">git-gutter</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">global-git-gutter-mode</span> <span style="color:#666">+1</span>))
</span></span></code></pre></div><p><a href="https://github.com/emacsmirror/git-timemachine">git-timemachine</a> allows visiting previous versions of a file.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">git-timemachine</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">git-timemachine</span>))
</span></span></code></pre></div><table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>difftastic-bin</td>
</tr>
</tbody>
</table>
<p><a href="https://github.com/pkryger/difftastic.el">difftastic.el</a> is a wrapper package for <a href="https://difftastic.wilfred.me.uk/">difftastic</a>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">difftastic</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">difftastic-magit-diff</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">difftastic-magit-show</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">difftastic-files</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">difftastic-buffers</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;magit-diff</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">transient-append-suffix</span> <span style="color:#19177c">&#39;magit-diff</span> <span style="color:#666">&#39;</span>(<span style="color:#666">-1</span> <span style="color:#666">-1</span>)
</span></span><span style="display:flex;"><span> [(<span style="color:#ba2121">&#34;D&#34;</span> <span style="color:#ba2121">&#34;Difftastic diff (dwim)&#34;</span> <span style="color:#19177c">difftastic-magit-diff</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;S&#34;</span> <span style="color:#ba2121">&#34;Difftastic show&#34;</span> <span style="color:#19177c">difftastic-magit-show</span>)])
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;magit-blame-read-only-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#19177c">&#39;normal</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;D&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">difftastic-magit-show</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;S&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">difftastic-magit-show</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">difftastic-executable</span> (<span style="color:#19177c">executable-find</span> <span style="color:#ba2121">&#34;difft&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;difftastic-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gr&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">difftastic-rerun</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">kill-buffer-and-window</span>))
</span></span></code></pre></div><p>My screen isn&rsquo;t wide enough to run <code>difftastic</code> in vertical split, so&hellip;</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/difftastic-pop-at-bottom</span> (<span style="color:#19177c">buffer-or-name</span> <span style="color:#19177c">_requested-width</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">window</span> (<span style="color:#19177c">split-window-below</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">select-window</span> <span style="color:#19177c">window</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-move-window</span> <span style="color:#19177c">&#39;below</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-window-buffer</span> (<span style="color:#00f">selected-window</span>) <span style="color:#19177c">buffer-or-name</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">difftastic-display-buffer-function</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/difftastic-pop-at-bottom</span>)
</span></span></code></pre></div><p>And I suspect the built-in window width function doesn&rsquo;t work as intended because of <code>global-display-line-numbers-mode</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">difftastic-requested-window-width-function</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> () (<span style="color:#00f">-</span> (<span style="color:#19177c">frame-width</span>) <span style="color:#666">4</span>)))
</span></span></code></pre></div><h4 id="forge-and-code-review">Forge and code-review</h4>
<p><a href="https://github.com/magit/forge">forge</a> provides integration with forges, such as GitHub and GitLab.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">forge</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">magit</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;forge-alist</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;gitlab.etu.ru&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gitlab.etu.ru/api/v4&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gitlab.etu.ru&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">forge-gitlab-repository</span>)))
</span></span></code></pre></div><p><code>forge</code> depends on a package called <a href="https://github.com/magit/ghub">ghub</a>. I don&rsquo;t like that it uses <code>auth-source</code> to store the token so I&rsquo;ll advise it to use <code>password-store</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/password-store-get-field</span> (<span style="color:#19177c">entry</span> <span style="color:#19177c">field</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">if-let</span> (<span style="color:#19177c">field</span> (<span style="color:#19177c">password-store-get-field</span> <span style="color:#19177c">entry</span> <span style="color:#19177c">field</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">field</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/password-store-get-field</span> <span style="color:#19177c">entry</span> <span style="color:#19177c">field</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ghub--token</span> (<span style="color:#19177c">host</span> <span style="color:#19177c">username</span> <span style="color:#19177c">package</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">nocreate</span> <span style="color:#19177c">forge</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span> ((<span style="color:#008000">and</span> (<span style="color:#008000">or</span> (<span style="color:#00f">equal</span> <span style="color:#19177c">host</span> <span style="color:#ba2121">&#34;gitlab.etu.ru/api/v4&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">equal</span> <span style="color:#19177c">host</span> <span style="color:#ba2121">&#34;gitlab.etu.ru/api&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">equal</span> <span style="color:#19177c">username</span> <span style="color:#ba2121">&#34;pvkorytov&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/password-store-get-field</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Job/Digital/Infrastructure/gitlab.etu.ru&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%s-token&#34;</span> <span style="color:#19177c">package</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> (<span style="color:#d2413a;font-weight:bold">error</span> <span style="color:#ba2121">&#34;Don&#39;t know token: %s %s %s&#34;</span> <span style="color:#19177c">host</span> <span style="color:#19177c">username</span> <span style="color:#19177c">package</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;ghub</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ghub--token</span> <span style="color:#008000">:override</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/ghub--token</span>))
</span></span></code></pre></div><p><a href="https://github.com/wandersoncferreira/code-review">code-review</a> is a package that implements code review in Emacs. The main branch is broken, <a href="https://github.com/wandersoncferreira/code-review/pull/246">but this PR</a> works.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">code-review</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;phelrine/code-review&#34;</span> <span style="color:#008000">:branch</span> <span style="color:#ba2121">&#34;fix/closql-update&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">forge</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">code-review-auth-login-marker</span> <span style="color:#19177c">&#39;forge</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">code-review-gitlab-base-url</span> <span style="color:#ba2121">&#34;gitlab.etu.ru&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">code-review-gitlab-host</span> <span style="color:#ba2121">&#34;gitlab.etu.ru/api&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">code-review-gitlab-graphql-host</span> <span style="color:#ba2121">&#34;gitlab.etu.ru/api&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">visual</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">code-review-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;RET&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">code-review-comment-add-or-edit</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gr&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">code-review-reload</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">code-review-transient-api</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">code-review-comment-code-suggestion</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">code-review-submit-single-diff-comment-at-point</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;TAB&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">magit-section-toggle</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">forge-topic-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-RET&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">code-review-forge-pr-at-point</span>))
</span></span></code></pre></div><p>Fix issue <a href="https://github.com/wandersoncferreira/code-review/issues/253">253</a>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/code-review-comment-quit</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Quit the comment window.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">magit-mode-quit-window</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> (<span style="color:#00f">get-buffer</span> <span style="color:#19177c">code-review-buffer-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> <span style="color:#19177c">code-review-comment-cursor-pos</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">code-review-comment-reset-global-vars</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;code-review</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">code-review-comment-quit</span> <span style="color:#008000">:override</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/code-review-comment-quit</span>))
</span></span></code></pre></div><h4 id="editorconfig">Editorconfig</h4>
<p>Editorconfig support for Emacs.</p>
<p>References:</p>
<ul>
<li><a href="https://editorconfig.org/">Editorconfig reference</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">editorconfig</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;editorconfig-indentation-alist</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">emmet-mode</span> <span style="color:#19177c">emmet-indentation</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">editorconfig-mode</span>))
</span></span></code></pre></div><h4 id="editing-files">Editing files</h4>
<p>A minor mode to remember recently edited files.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">recentf-mode</span> <span style="color:#666">1</span>)
</span></span></code></pre></div><p>Save the last place visited in the file.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">save-place-mode</span> <span style="color:#800">nil</span>)
</span></span></code></pre></div><h4 id="deadgrep">Deadgrep</h4>
<p><a href="https://github.com/Wilfred/deadgrep">deadgrep</a> is a nice Emacs interface for <a href="https://github.com/BurntSushi/ripgrep">ripgrep</a>. Running <code>ivy-occur</code> in <code>counsel-rg</code> does something a bit similar, but the deadgrep is more full-featured.</p>
<p>Somehow I couldn&rsquo;t hook <code>toogle-truncate-lines</code> into the existing package hooks, so here goes advice.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/deadgrep-fix-buffer-advice</span> (<span style="color:#19177c">fun</span> <span style="color:#008000">&amp;rest</span> <span style="color:#19177c">args</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">buf</span> (<span style="color:#00f">apply</span> <span style="color:#19177c">fun</span> <span style="color:#19177c">args</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buf</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">toggle-truncate-lines</span> <span style="color:#666">1</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">buf</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">deadgrep</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">deadgrep</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">deadgrep--buffer</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/deadgrep-fix-buffer-advice</span>))
</span></span></code></pre></div><h3 id="navigation">Navigation</h3>
<p>Things to navigate in Emacs.</p>
<h4 id="registers">Registers</h4>
<p>References:</p>
<ul>
<li><a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Registers.html">Registers (GNU Emacs Manual)</a></li>
</ul>
<p>Somehow there&rsquo;s no built-in function to clear a register.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/register-clear</span> (<span style="color:#19177c">register</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> (<span style="color:#19177c">register-read-with-preview</span> <span style="color:#ba2121">&#34;Clear register: &#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">register-alist</span> (<span style="color:#00f">delq</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">register</span> <span style="color:#19177c">register-alist</span>) <span style="color:#19177c">register-alist</span>)))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">register-preview-delay</span> <span style="color:#19177c">which-key-idle-delay</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;g&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:wk</span> <span style="color:#ba2121">&#34;registers &amp; marks&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;y&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">copy-to-register</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;p&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">insert-register</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">point-to-register</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/register-clear</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">jump-to-register</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;R&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">consult-register</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;w&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">window-configuration-to-register</span>)
</span></span></code></pre></div><h4 id="marks">Marks</h4>
<p>References:</p>
<ul>
<li><a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Mark.html">The Mark and the Region (GNU Emacs Manual)</a></li>
<li><a href="https://www.masteringemacs.org/article/fixing-mark-commands-transient-mark-mode">Fixing the mark commands in transient mark mode - Mastering Emacs</a></li>
</ul>
<p><code>transient-mark-mode</code> makes using marks for navigation a bit more cumbersome, but I&rsquo;m not sure of potential side effects of disabling it&hellip; As of now, I want only to push a mark without activating it, so here&rsquo;s a function for that (taken from Mickey Peterson&rsquo;s article):</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/push-mark-no-activate</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Pushes </span><span style="color:#19177c">`point&#39;</span><span style="color:#ba2121"> to </span><span style="color:#19177c">`mark-ring&#39;</span><span style="color:#ba2121"> and does not activate the region
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"> Equivalent to \\[set-mark-command] when \\[transient-mark-mode] is disabled&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">push-mark</span> (<span style="color:#00f">point</span>) <span style="color:#800">t</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Pushed mark to ring&#34;</span>))
</span></span></code></pre></div><p>Also a function to clear the current mark ring.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/mark-ring-clear</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">mark-ring</span> <span style="color:#800">nil</span>))
</span></span></code></pre></div><p>Keybindings:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;g&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;G&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">consult-global-mark</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;g&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">consult-mark</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/mark-ring-clear</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;m&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/push-mark-no-activate</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;global</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-SPC&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/push-mark-no-activate</span>)
</span></span></code></pre></div><h4 id="avy">Avy</h4>
<p><a href="https://github.com/abo-abo/avy">Avy</a> is a package that helps navigate Emacs in a tree-like manner.</p>
<p>References:</p>
<ul>
<li><a href="https://karthinks.com/software/avy-can-do-anything/">Avy can do anything</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">avy</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">avy-timeout-seconds</span> <span style="color:#666">0.5</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">avy-ignored-modes</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">image-mode</span> <span style="color:#19177c">doc-view-mode</span> <span style="color:#19177c">pdf-view-mode</span> <span style="color:#19177c">exwm-mode</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">motion</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;-&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">avy-goto-char-timer</span>))
</span></span></code></pre></div><p>Integrate avy with embark:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">avy-action-embark</span> (<span style="color:#19177c">pt</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unwind-protect</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> <span style="color:#19177c">pt</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">embark-act</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">select-window</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span> (<span style="color:#19177c">ring-ref</span> <span style="color:#19177c">avy-ring</span> <span style="color:#666">0</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;avy</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#ba2121">?.</span> <span style="color:#19177c">avy-dispatch-alist</span>) <span style="color:#19177c">&#39;avy-action-embark</span>))
</span></span></code></pre></div><p><a href="https://github.com/abo-abo/ace-link">ace-link</a> is a package to jump to links with avy.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ace-link</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">ace-link-info</span> <span style="color:#19177c">ace-link-help</span> <span style="color:#19177c">ace-link-woman</span> <span style="color:#19177c">ace-link-eww</span>))
</span></span></code></pre></div><h3 id="completion">Completion</h3>
<h4 id="vertico">vertico</h4>
<p><a href="https://github.com/minad/vertico">vertico</a> is a vertical completion framework. I switched to it from <a href="https://github.com/abo-abo/swiper">Ivy</a> (and to Ivy from <a href="https://github.com/emacs-helm/helm">Helm</a>).</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">vertico</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">enable-recursive-minibuffers</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">vertico-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-j&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">vertico-next</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-k&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">vertico-previous</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;TAB&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">minibuffer-complete</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">vertico-mode</span>))
</span></span></code></pre></div><p>Add prompt indicator to <code>completing-read-multiple</code>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">crm-indicator</span> (<span style="color:#19177c">args</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;[CRM%s] %s&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp-in-string</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\\`\\[.*?]\\*\\|\\[.*?]\\*\\&#39;&#34;</span> <span style="color:#ba2121">&#34;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">crm-separator</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">car</span> <span style="color:#19177c">args</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">args</span>)))
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;crm</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">completing-read-multiple</span> <span style="color:#008000">:filter-args</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">crm-indicator</span>))
</span></span></code></pre></div><p>Persist history over Emacs restarts.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">savehist</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">savehist-mode</span>))
</span></span></code></pre></div><h4 id="vertico-extensions">vertico extensions</h4>
<p>Vertico has a lot of extensions.</p>
<p><a href="https://github.com/minad/vertico/blob/main/extensions/vertico-directory.el">vertico-directory</a> simplifies directory navigation.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">vertico-directory</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">vertico</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">vertico-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;RET&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">vertico-directory-enter</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;DEL&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">vertico-directory-delete-char</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;rfn-eshadow-update-overlay-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">vertico-directory-tidy</span>))
</span></span></code></pre></div><p><a href="https://github.com/minad/vertico/blob/main/extensions/vertico-grid.el">vertico-grid</a> enabled grid display. It is useful when there are no annotations in the completion buffer.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">vertico-grid</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">vertico</span>))
</span></span></code></pre></div><p><a href="https://github.com/minad/vertico/blob/main/extensions/vertico-multiform.el">vertico-multiform</a> enables per-mode configuration.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/sort-directories-first</span> (<span style="color:#19177c">files</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">files</span> (<span style="color:#19177c">vertico-sort-alpha</span> <span style="color:#19177c">files</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">nconc</span> (<span style="color:#19177c">seq-filter</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">x</span>) (<span style="color:#19177c">string-suffix-p</span> <span style="color:#ba2121">&#34;/&#34;</span> <span style="color:#19177c">x</span>)) <span style="color:#19177c">files</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-remove</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">x</span>) (<span style="color:#19177c">string-suffix-p</span> <span style="color:#ba2121">&#34;/&#34;</span> <span style="color:#19177c">x</span>)) <span style="color:#19177c">files</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">vertico-multiform</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">vertico</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">vertico-multiform-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymap</span> <span style="color:#19177c">&#39;vertico-multiform-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-b&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">vertico-multiform-buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-g&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">vertico-multiform-grid</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">vertico-multiform-categories</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">file</span> (<span style="color:#19177c">vertico-sort-function</span> <span style="color:#666">.</span> <span style="color:#19177c">my/sort-directories-first</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">password-store-pass</span> <span style="color:#19177c">grid</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">vertico-multiform-commands</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">eshell-atuin-history</span> (<span style="color:#19177c">vertico-sort-function</span> <span style="color:#666">.</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index-nav</span> (<span style="color:#19177c">vertico-sort-function</span> <span style="color:#666">.</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-ql-view</span> (<span style="color:#19177c">vertico-sort-function</span> <span style="color:#666">.</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/consult-line</span> (<span style="color:#19177c">vertico-sort-function</span> <span style="color:#666">.</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-msg-add-reaction</span> <span style="color:#19177c">grid</span>))))
</span></span></code></pre></div><p><a href="https://github.com/minad/vertico/blob/main/extensions/vertico-quick.el">vertico-quick</a> enables ivy-like bindings to choose candidates.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">vertico-quick</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">vertico</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">vertico-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">vertico-quick-insert</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">vertico-quick-exit</span>))
</span></span></code></pre></div><h4 id="orderless">orderless</h4>
<p><a href="https://github.com/oantolin/orderless">orderless</a> is a flexible completion style framework. Completion style refers to the way entries are filtered in the completion buffer.</p>
<p>I used to use <a href="https://github.com/radian-software/prescient.el">prescient.el</a> with Ivy; unlike prescient, orderless doesn&rsquo;t sort completion entries.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">orderless</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">completion-styles</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">orderless</span> <span style="color:#19177c">basic</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">completion-category-defaults</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">completion-category-overrides</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">file</span> (<span style="color:#19177c">styles</span> <span style="color:#19177c">partial-completion</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">orderless-matching-styles</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">orderless-literal</span> <span style="color:#19177c">orderless-initialism</span> <span style="color:#19177c">orderless-regexp</span>)))
</span></span></code></pre></div><p>Disable orderless for company:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">company-completion-styles</span> (<span style="color:#19177c">capf-fn</span> <span style="color:#008000">&amp;rest</span> <span style="color:#19177c">args</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">completion-styles</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">basic</span> <span style="color:#19177c">partial-completion</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#19177c">capf-fn</span> <span style="color:#19177c">args</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;company</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#19177c">&#39;company-capf</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">company-completion-styles</span>))
</span></span></code></pre></div><h4 id="consult">consult</h4>
<p><a href="https://github.com/minad/consult">consult</a> provides various commands based on the <code>completing-read</code> API.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">consult</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">consult-preview-excluded-files</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#ba2121">&#34;\\`/[^/|:]+:&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;html&#34;</span> <span style="color:#19177c">eos</span>))))
</span></span></code></pre></div><h4 id="marginalia">marginalia</h4>
<p><a href="https://github.com/minad/marginalia">marginalia</a> provides annotations in the completion interface.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">marginalia</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">marginalia-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">projectile-find-file</span> <span style="color:#666">.</span> <span style="color:#19177c">file</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">marginalia-command-categories</span>))
</span></span></code></pre></div><h4 id="embark">embark</h4>
<p><a href="https://github.com/oantolin/embark">embark</a> provides minibuffer actions.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">embark</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">embark-act</span> <span style="color:#19177c">embark-dwim</span> <span style="color:#19177c">embark-bindings</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-e&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">embark-act</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">embark-consult</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">embark</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;embark-collect-mode</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">consult-preview-at-point-mode</span>))
</span></span></code></pre></div><p>Use <code>which-key</code> like indicator. Take from the <a href="https://github.com/oantolin/embark/wiki/Additional-Configuration#use-which-key-like-a-key-menu-prompt">Embark wiki</a>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">embark-which-key-indicator</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;An embark indicator that displays keymaps using which-key.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The which-key help message will show the type and value of the
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">current target followed by an ellipsis if there are further
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">targets.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#008000">&amp;optional</span> <span style="color:#19177c">keymap</span> <span style="color:#19177c">targets</span> <span style="color:#19177c">prefix</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">null</span> <span style="color:#19177c">keymap</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">which-key--hide-popup-ignore-command</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">which-key--show-keymap</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">eq</span> (<span style="color:#00f">plist-get</span> (<span style="color:#00f">car</span> <span style="color:#19177c">targets</span>) <span style="color:#008000">:type</span>) <span style="color:#19177c">&#39;embark-become</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Become&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;Act on %s &#39;%s&#39;%s&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">plist-get</span> (<span style="color:#00f">car</span> <span style="color:#19177c">targets</span>) <span style="color:#008000">:type</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">embark--truncate-target</span> (<span style="color:#00f">plist-get</span> (<span style="color:#00f">car</span> <span style="color:#19177c">targets</span>) <span style="color:#008000">:target</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">targets</span>) <span style="color:#ba2121">&#34;…&#34;</span> <span style="color:#ba2121">&#34;&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">prefix</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> (<span style="color:#00f">lookup-key</span> <span style="color:#19177c">keymap</span> <span style="color:#19177c">prefix</span> <span style="color:#19177c">&#39;accept-default</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">and</span> (<span style="color:#19177c">pred</span> <span style="color:#00f">keymapp</span>) <span style="color:#19177c">km</span>) <span style="color:#19177c">km</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">_</span> (<span style="color:#00f">key-binding</span> <span style="color:#19177c">prefix</span> <span style="color:#19177c">&#39;accept-default</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">keymap</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#800">t</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">binding</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-suffix-p</span> <span style="color:#ba2121">&#34;-argument&#34;</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">binding</span>))))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">embark-hide-which-key-indicator</span> (<span style="color:#19177c">fn</span> <span style="color:#008000">&amp;rest</span> <span style="color:#19177c">args</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Hide the which-key indicator immediately when using the completing-read prompter.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">which-key--hide-popup-ignore-command</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">embark-indicators</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">remq</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">embark-which-key-indicator</span> <span style="color:#19177c">embark-indicators</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#19177c">fn</span> <span style="color:#19177c">args</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;embark</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">embark-completing-read-prompter</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">embark-hide-which-key-indicator</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">embark-indicators</span> (<span style="color:#00f">delq</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">embark-mixed-indicator</span> <span style="color:#19177c">embark-indicators</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">embark-which-key-indicator</span> <span style="color:#19177c">embark-indicators</span>))
</span></span></code></pre></div><h4 id="keybindings-1">keybindings</h4>
<p>Setting up quick access to various completions.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;f&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;various completions&#34;</span>)<span style="color:#666">&#39;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;b&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">persp-switch-to-buffer*</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;e&#34;</span> <span style="color:#19177c">&#39;micromamba-activate</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#19177c">&#39;project-find-file</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#19177c">&#39;consult-yank-pop</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;a&#34;</span> <span style="color:#19177c">&#39;consult-ripgrep</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#19177c">&#39;deadgrep</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#00f">insert</span> <span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-y&#34;</span> <span style="color:#19177c">&#39;consult-yank-pop</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/consult-line</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">current-prefix-arg</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">call-interactively</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">consult-line-multi</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">consult-line</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (my-leader-def &#34;SPC SPC&#34; &#39;ivy-resume)</span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#19177c">&#39;my/consult-line</span>)
</span></span></code></pre></div><h4 id="company">company</h4>
<p>A completion framework for Emacs.</p>
<p>References:</p>
<ul>
<li><a href="http://company-mode.github.io/">company homepage</a></li>
<li><a href="https://github.com/sebastiencs/company-box">company-box homepage</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">company</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">global-company-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">company-idle-delay</span> <span style="color:#666">0.2</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">company-dabbrev-downcase</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">company-show-numbers</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-imap</span> <span style="color:#ba2121">&#34;C-SPC&#34;</span> <span style="color:#19177c">&#39;company-complete</span>)
</span></span></code></pre></div><p>A company frontend with nice icons.</p>
<p><del>Disabled since the base company got icons support and since company-box has some issues with spaceline.</del> Enabled back because I didn&rsquo;t like spaceline.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">company-box</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">display-graphic-p</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">company</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> (<span style="color:#19177c">company-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">company-box-mode</span>))
</span></span></code></pre></div><h3 id="help">Help</h3>
<ul>
<li><strong>CREDIT</strong>: Thanks @phundrak on the System Crafters Discord for suggesting <code>help-map</code></li>
</ul>
<p><a href="https://github.com/Wilfred/helpful">helpful</a> package improves the <code>*help*</code> buffer.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">helpful</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">helpful-callable</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">helpful-variable</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">helpful-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">helpful-macro</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">helpful-function</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">helpful-command</span>))
</span></span></code></pre></div><p>As I use <code>C-h</code> to switch buffers, I moved the help to <code>SPC-h</code> with the code below.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;h&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:keymap</span> <span style="color:#19177c">help-map</span> <span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;help&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;h&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;help&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;h&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:keymap</span> <span style="color:#19177c">help-map</span> <span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;help-map&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#19177c">&#39;helpful-function</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;k&#34;</span> <span style="color:#19177c">&#39;helpful-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;v&#34;</span> <span style="color:#19177c">&#39;helpful-variable</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#19177c">&#39;helpful-symbol</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;i&#34;</span> <span style="color:#19177c">&#39;info</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;help-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#19177c">&#39;helpful-function</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;k&#34;</span> <span style="color:#19177c">&#39;helpful-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;v&#34;</span> <span style="color:#19177c">&#39;helpful-variable</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#19177c">&#39;helpful-symbol</span>)
</span></span></code></pre></div><h3 id="time-trackers">Time trackers</h3>
<p>Time trackers I happen to use.</p>
<p>References:</p>
<ul>
<li><a href="https://wakatime.com">WakaTime</a></li>
<li><a href="https://activitywatch.net/">ActivityWatch</a></li>
</ul>
<h4 id="wakatime">WakaTime</h4>
<p>Before I figure out how to package this for Guix:</p>
<ul>
<li>Clone <a href="https://github.com/wakatime/wakatime-cli">the repo</a></li>
<li>Run <code>go build</code></li>
<li>Copy the binary to the <code>~/bin</code> folder</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">wakatime-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;SqrtMinusOne/wakatime-mode&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/remote-server</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">wakatime-ignore-exit-codes</span> <span style="color:#666">&#39;</span>(<span style="color:#666">0</span> <span style="color:#666">1</span> <span style="color:#666">102</span> <span style="color:#666">112</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#19177c">&#39;wakatime-init</span> <span style="color:#008000">:after</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">wakatime-cli-path</span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">executable-find</span> <span style="color:#ba2121">&#34;wakatime-cli&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">&#34;~/bin/wakatime-cli&#34;</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#ba2121">&#34;~/.wakatime.cfg&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">wakatime-api-key</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-trim</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shell-command-to-string</span> <span style="color:#ba2121">&#34;awk &#39;/api-key/{print $NF}&#39; ~/.wakatime.cfg&#34;</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (setq wakatime-cli-path (executable-find &#34;wakatime&#34;))</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">global-wakatime-mode</span>))
</span></span></code></pre></div><h4 id="activitywatch">ActivityWatch</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">request</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:defer</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">activity-watch-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/is-termux</span> <span style="color:#19177c">my/remote-server</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">global-activity-watch-mode</span>))
</span></span></code></pre></div><h2 id="ui-settings">UI settings</h2>
<h3 id="general-settings-1">General settings</h3>
<h4 id="miscellaneous">Miscellaneous</h4>
<p>Disable GUI elements</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">unless</span> <span style="color:#19177c">my/is-termux</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tool-bar-mode</span> <span style="color:#666">-1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">menu-bar-mode</span> <span style="color:#666">-1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">scroll-bar-mode</span> <span style="color:#666">-1</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">when</span> <span style="color:#19177c">my/is-termux</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">menu-bar-mode</span> <span style="color:#666">-1</span>))
</span></span></code></pre></div><p>Transparency. Not setting it here, as I used to use <a href="/configs/desktop/#picom">picom</a> with i3, and EXWM config has its own settings.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (set-frame-parameter (selected-frame) &#39;alpha &#39;(90 . 90))</span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (add-to-list &#39;default-frame-alist &#39;(alpha . (90 . 90)))</span>
</span></span></code></pre></div><p>Prettify symbols. Also not setting it, ligatures seem to be enough for me.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (global-prettify-symbols-mode)</span>
</span></span></code></pre></div><p>Do not show GUI dialogs</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">use-dialog-box</span> <span style="color:#800">nil</span>)
</span></span></code></pre></div><p>No start screen</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">inhibit-startup-screen</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><p>Visual bell</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">visible-bell</span> <span style="color:#666">0</span>)
</span></span></code></pre></div><p>y or n instead of yes or no</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defalias</span> <span style="color:#19177c">&#39;yes-or-no-p</span> <span style="color:#19177c">&#39;y-or-n-p</span>)
</span></span></code></pre></div><p>Hide mouse cursor while typing</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">make-pointer-invisible</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><p>Show pairs</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">show-paren-mode</span> <span style="color:#666">1</span>)
</span></span></code></pre></div><p>Highlight the current line</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">global-hl-line-mode</span> <span style="color:#666">1</span>)
</span></span></code></pre></div><h4 id="line-numbers">Line numbers</h4>
<p>Line numbers. There seems to be a catch with the relative number setting:</p>
<ul>
<li><code>visual</code> doesn&rsquo;t take folding into account but also doesn&rsquo;t take wrapped lines into account (i.e. there are multiple numbers for a single wrapped line)</li>
<li><code>relative</code> makes a single number for a wrapped line, but counts folded lines.</li>
</ul>
<p><code>visual</code> option seems to be less of a problem in most cases.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">global-display-line-numbers-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">line-number-mode</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">display-line-numbers-type</span> <span style="color:#19177c">&#39;visual</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">column-number-mode</span>)
</span></span></code></pre></div><h4 id="word-wrapping">Word wrapping</h4>
<p>Word wrapping. These settings aren&rsquo;t too obvious compared to <code>:set wrap</code> from vim:</p>
<ul>
<li><code>word-wrap</code> means just &ldquo;don&rsquo;t split one word between two lines&rdquo;. So, if there isn&rsquo;t enough place to put a word at the end of the line, it will be put on a new one. Run <code>M-x toggle-word-wrap</code> to toggle that.</li>
<li><code>visual-line-mode</code> seems to be a superset of <code>word-wrap</code>. It also enables some editing commands to work on visual lines instead of logical ones, hence the naming.</li>
<li><code>auto-fill-mode</code> does the same as <code>word-wrap</code>, except it actually <strong>edits the buffer</strong> to make lines break in the appropriate places.</li>
<li><code>truncate-lines</code> truncates long lines instead of continuing them. Run <code>M-x toggle-truncate-lines</code> to toggle that. I find that <code>truncate-lines</code> behaves strangely when <code>visual-line-mode</code> is on, so I use one or another.</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">word-wrap</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">global-visual-line-mode</span> <span style="color:#666">1</span>)
</span></span></code></pre></div><h4 id="custom-frame-format">Custom frame format</h4>
<p>Title format, which used to look something like <code>emacs:project@hostname</code>. Now it&rsquo;s just <code>emacs</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq-default</span> <span style="color:#19177c">frame-title-format</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;emacs&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (:eval</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (let ((project-name (projectile-project-name)))</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (if (not (string= &#34;-&#34; project-name))</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (format &#34;:%s@%s&#34; project-name (system-name))</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (format &#34;@%s&#34; (system-name)))))</span>
</span></span><span style="display:flex;"><span> ))
</span></span></code></pre></div><h4 id="olivetti">Olivetti</h4>
<p><a href="https://github.com/rnkn/olivetti">Olivetti</a> is a package that limits the current text body width. It&rsquo;s pretty nice to use when writing texts.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">olivetti</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">display-graphic-p</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">olivetti-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-default</span> <span style="color:#19177c">olivetti-body-width</span> <span style="color:#666">86</span>))
</span></span></code></pre></div><h4 id="keycast">Keycast</h4>
<p>Showing the last pressed key. Occasionally useful.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">keycast</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">define-minor-mode</span> <span style="color:#19177c">keycast-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Keycast mode&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:global</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">keycast-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;global-mode-string</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;&#34;</span> <span style="color:#19177c">keycast-mode-line</span> <span style="color:#ba2121">&#34; &#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;pre-command-hook</span> <span style="color:#19177c">&#39;keycast--update</span> <span style="color:#800">t</span>) )
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">remove-hook</span> <span style="color:#19177c">&#39;pre-command-hook</span> <span style="color:#19177c">&#39;keycast--update</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">global-mode-string</span> (<span style="color:#00f">delete</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;&#34;</span> <span style="color:#19177c">keycast-mode-line</span> <span style="color:#ba2121">&#34; &#34;</span>) <span style="color:#19177c">global-mode-string</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">keycast--update</span>))
</span></span></code></pre></div><h3 id="themes-and-colors">Themes and colors</h3>
<h4 id="theme-packages">Theme packages</h4>
<p>My colorschemes of choice.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">doom-themes</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Not deferring becuase I want `doom-themes-visual-bell-config&#39;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">doom-themes-enable-bold</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">doom-themes-enable-italic</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (if my/remote-server</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (load-theme &#39;doom-gruvbox t)</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (load-theme &#39;doom-palenight t))</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">doom-themes-visual-bell-config</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">doom-themes-treemacs-theme</span> <span style="color:#ba2121">&#34;doom-colors&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">doom-themes-treemacs-config</span>))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">modus-themes</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><p>Let&rsquo;s see&hellip;</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ef-themes</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ef-duo-light-palette-overrides</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">constant</span> <span style="color:#19177c">green</span>))))
</span></span></code></pre></div><h4 id="custom-theme-1">Custom theme</h4>
<p>Here I define a few things on the top of Emacs theme, because:</p>
<ul>
<li>Occasionally I want to have more theme-derived faces</li>
<li>I also want Emacs theme to be applied to the rest of the system (see the <a href="/configs/desktop/">Desktop</a> config on that)</li>
</ul>
<p>Theme-derived faces have to placed in a custom theme, because if one calls <code>custom-set-faces</code> and <code>custom-set-variables</code> in code, whenever a variable is changed and saved in a customize buffer, data from all calls of these functions is saved as well.</p>
<h5 id="get-color-values">Get color values</h5>
<p>Here&rsquo;s a great package with various color tools:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ct</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><p>As of now I want this to support <code>doom-themes</code> and <code>modus-themes</code>. So, let&rsquo;s get which one is enabled:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/doom-p</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-find</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">x</span>) (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;doom&#34;</span>) (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">x</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">custom-enabled-themes</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/modus-p</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-find</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">x</span>) (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;modus&#34;</span>) (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">x</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">custom-enabled-themes</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ef-p</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-find</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">x</span>) (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;ef&#34;</span>) (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">x</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">custom-enabled-themes</span>))
</span></span></code></pre></div><p>I also want to know if the current theme is light or not:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/light-p</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ct-light-p</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;bg</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dark-p</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">my/light-p</span>)))
</span></span></code></pre></div><p>Now, let&rsquo;s get the current color from <code>doom</code>. <code>doom-themes</code> provide <code>doom-color</code>, but I also want to:</p>
<ul>
<li>override some colors</li>
<li>add <code>black</code>, <code>white</code>, <code>light-*</code> and <code>border</code></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defconst</span> <span style="color:#19177c">my/theme-override</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">doom-palenight</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">red</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;#f07178&#34;</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/alpha-for-light</span> <span style="color:#666">7</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/doom-color</span> (<span style="color:#19177c">color</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">doom-color</span> <span style="color:#19177c">&#39;bg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">override</span> (<span style="color:#19177c">alist-get</span> (<span style="color:#19177c">my/doom-p</span>) <span style="color:#19177c">my/theme-override</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">color-name</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">color</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">is-light</span> (<span style="color:#19177c">ct-light-p</span> (<span style="color:#19177c">doom-color</span> <span style="color:#19177c">&#39;bg</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">color</span> <span style="color:#19177c">override</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">eq</span> <span style="color:#19177c">&#39;black</span> <span style="color:#19177c">color</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">is-light</span> (<span style="color:#19177c">doom-color</span> <span style="color:#19177c">&#39;fg</span>) (<span style="color:#19177c">doom-color</span> <span style="color:#19177c">&#39;bg</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">eq</span> <span style="color:#19177c">&#39;white</span> <span style="color:#19177c">color</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">is-light</span> (<span style="color:#19177c">doom-color</span> <span style="color:#19177c">&#39;bg</span>) (<span style="color:#19177c">doom-color</span> <span style="color:#19177c">&#39;fg</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">eq</span> <span style="color:#19177c">&#39;border</span> <span style="color:#19177c">color</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">is-light</span> (<span style="color:#19177c">doom-color</span> <span style="color:#19177c">&#39;base0</span>) (<span style="color:#19177c">doom-color</span> <span style="color:#19177c">&#39;base8</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;light-&#34;</span>) <span style="color:#19177c">color-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ct-edit-hsl-l-inc</span> (<span style="color:#19177c">my/doom-color</span> (<span style="color:#00f">intern</span> (<span style="color:#00f">substring</span> <span style="color:#19177c">color-name</span> <span style="color:#666">6</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/alpha-for-light</span>))
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;dark-&#34;</span>) <span style="color:#19177c">color-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">doom-color</span> <span style="color:#19177c">color</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ct-edit-hsl-l-dec</span> (<span style="color:#19177c">my/doom-color</span> (<span style="color:#00f">intern</span> (<span style="color:#00f">substring</span> <span style="color:#19177c">color-name</span> <span style="color:#666">5</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/alpha-for-light</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> (<span style="color:#19177c">doom-color</span> <span style="color:#19177c">color</span>)))))))
</span></span></code></pre></div><p>And the same for <code>modus-themes</code>. <code>my/modus-color</code> has to accept the same arguments as I use for <code>my/doom-color</code> for backward compatibility, which requires a bit more tuning.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/modus-get-base</span> (<span style="color:#19177c">color</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">base-value</span> (<span style="color:#00f">string-to-number</span> (<span style="color:#00f">substring</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">color</span>) <span style="color:#666">4</span> <span style="color:#666">5</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">base-start</span> (<span style="color:#19177c">cadr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">&#39;bg-main</span> (<span style="color:#19177c">modus-themes--current-theme-palette</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">base-end</span> (<span style="color:#19177c">cadr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">&#39;fg-dim</span> (<span style="color:#19177c">modus-themes--current-theme-palette</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">nth</span> <span style="color:#19177c">base-value</span> (<span style="color:#19177c">ct-gradient</span> <span style="color:#666">9</span> <span style="color:#19177c">base-start</span> <span style="color:#19177c">base-end</span> <span style="color:#800">t</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/prot-color</span> (<span style="color:#19177c">color</span> <span style="color:#19177c">palette</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">is-light</span> (<span style="color:#19177c">ct-light-p</span> (<span style="color:#19177c">cadr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">&#39;bg-main</span> <span style="color:#19177c">palette</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">member</span> <span style="color:#19177c">color</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">black</span> <span style="color:#19177c">white</span> <span style="color:#19177c">light-black</span> <span style="color:#19177c">light-white</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">bg-main</span> (<span style="color:#19177c">cadr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">&#39;bg-main</span> <span style="color:#19177c">palette</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">fg-main</span> (<span style="color:#19177c">cadr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">&#39;fg-main</span> <span style="color:#19177c">palette</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">color</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;black</span> (<span style="color:#008000">if</span> <span style="color:#19177c">is-light</span> <span style="color:#19177c">fg-main</span> <span style="color:#19177c">bg-main</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;white</span> (<span style="color:#008000">if</span> <span style="color:#19177c">is-light</span> <span style="color:#19177c">bg-main</span> <span style="color:#19177c">fg-main</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;light-black</span> (<span style="color:#19177c">ct-edit-hsl-l-inc</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">is-light</span> <span style="color:#19177c">fg-main</span> <span style="color:#19177c">bg-main</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">15</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;light-white</span> (<span style="color:#19177c">ct-edit-hsl-l-inc</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">is-light</span> <span style="color:#19177c">bg-main</span> <span style="color:#19177c">fg-main</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">15</span>)))))
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">or</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">color</span> <span style="color:#19177c">&#39;bg</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cadr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">&#39;bg-main</span> <span style="color:#19177c">palette</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">or</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">color</span> <span style="color:#19177c">&#39;fg</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cadr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">&#39;fg-main</span> <span style="color:#19177c">palette</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">eq</span> <span style="color:#19177c">color</span> <span style="color:#19177c">&#39;bg-alt</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cadr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">&#39;bg-dim</span> <span style="color:#19177c">palette</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">eq</span> <span style="color:#19177c">color</span> <span style="color:#19177c">&#39;violet</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cadr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">&#39;magenta-cooler</span> <span style="color:#19177c">palette</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;base&#34;</span> <span style="color:#19177c">digit</span>) (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">color</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/modus-get-base</span> <span style="color:#19177c">color</span>))
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;dark-&#34;</span>) (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">color</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cadr</span> (<span style="color:#00f">assoc</span> (<span style="color:#00f">intern</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%s-cooler&#34;</span> (<span style="color:#00f">substring</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">color</span>) <span style="color:#666">5</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">palette</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">eq</span> <span style="color:#19177c">color</span> <span style="color:#19177c">&#39;grey</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/modus-get-base</span> <span style="color:#19177c">&#39;base5</span>))
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;light-&#34;</span>) (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">color</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cadr</span> (<span style="color:#00f">assoc</span> (<span style="color:#00f">intern</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%s-intense&#34;</span> (<span style="color:#00f">substring</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">color</span>) <span style="color:#666">6</span>))) <span style="color:#19177c">palette</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cadr</span> (<span style="color:#00f">assoc</span> (<span style="color:#00f">intern</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;bg-%s-intense&#34;</span> (<span style="color:#00f">substring</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">color</span>) <span style="color:#666">6</span>))) <span style="color:#19177c">palette</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> (<span style="color:#19177c">cadr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">color</span> <span style="color:#19177c">palette</span>))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/modus-color</span> (<span style="color:#19177c">color</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/prot-color</span> <span style="color:#19177c">color</span> (<span style="color:#19177c">modus-themes--current-theme-palette</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ef-color</span> (<span style="color:#19177c">color</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/prot-color</span> <span style="color:#19177c">color</span> (<span style="color:#19177c">ef-themes--current-theme-palette</span>)))
</span></span></code></pre></div><p>Test the three functions.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defconst</span> <span style="color:#19177c">my/test-colors-list</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">black</span> <span style="color:#19177c">red</span> <span style="color:#19177c">green</span> <span style="color:#19177c">yellow</span> <span style="color:#19177c">blue</span> <span style="color:#19177c">magenta</span> <span style="color:#19177c">cyan</span> <span style="color:#19177c">white</span> <span style="color:#19177c">light-black</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">dark-red</span> <span style="color:#19177c">dark-green</span> <span style="color:#19177c">dark-yellow</span> <span style="color:#19177c">dark-blue</span> <span style="color:#19177c">dark-magenta</span> <span style="color:#19177c">dark-cyan</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">light-red</span> <span style="color:#19177c">light-green</span> <span style="color:#19177c">light-yellow</span> <span style="color:#19177c">light-blue</span> <span style="color:#19177c">light-magenta</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">light-cyan</span> <span style="color:#19177c">light-white</span> <span style="color:#19177c">bg</span> <span style="color:#19177c">bg-alt</span> <span style="color:#19177c">fg</span> <span style="color:#19177c">fg-alt</span> <span style="color:#19177c">violet</span> <span style="color:#19177c">grey</span> <span style="color:#19177c">base0</span> <span style="color:#19177c">base1</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">base2</span> <span style="color:#19177c">base3</span> <span style="color:#19177c">base4</span> <span style="color:#19177c">base5</span> <span style="color:#19177c">base6</span> <span style="color:#19177c">base7</span> <span style="color:#19177c">base8</span> <span style="color:#19177c">border</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/test-colors</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">buf</span> (<span style="color:#19177c">generate-new-buffer</span> <span style="color:#ba2121">&#34;*colors-test*&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buf</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%-20s %-10s %-10s %-10s&#34;</span> <span style="color:#ba2121">&#34;Color&#34;</span> <span style="color:#ba2121">&#34;Doom&#34;</span> <span style="color:#ba2121">&#34;Modus&#34;</span> <span style="color:#ba2121">&#34;Ef&#34;</span>) <span style="color:#ba2121">&#34;\n&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">color</span> <span style="color:#19177c">in</span> <span style="color:#19177c">my/test-colors-list</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">insert</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%-20s %-10s %-10s %-10s\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">prin1-to-string</span> <span style="color:#19177c">color</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/doom-color</span> <span style="color:#19177c">color</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/modus-color</span> <span style="color:#19177c">color</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/ef-color</span> <span style="color:#19177c">color</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">special-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">rainbow-mode</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">switch-to-buffer</span> <span style="color:#19177c">buf</span>)))
</span></span></code></pre></div><p>Finally, one function to get the value of a color in the current theme.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/color-value</span> (<span style="color:#19177c">color</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">stringp</span> <span style="color:#19177c">color</span>) (<span style="color:#19177c">my/color-value</span> (<span style="color:#00f">intern</span> <span style="color:#19177c">color</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">eq</span> <span style="color:#19177c">color</span> <span style="color:#19177c">&#39;bg-other</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;bg-dim</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">color</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;bg</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">ct-light-p</span> <span style="color:#19177c">color</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ct-edit-hsl-l-dec</span> <span style="color:#19177c">color</span> <span style="color:#666">2</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ct-edit-hsl-l-dec</span> <span style="color:#19177c">color</span> <span style="color:#666">3</span>)))))
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">eq</span> <span style="color:#19177c">color</span> <span style="color:#19177c">&#39;modeline</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;bg-mode-line-active</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;bg-mode-line</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">my/light-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ct-edit-hsl-l-dec</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;bg-alt</span>) <span style="color:#666">10</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ct-edit-hsl-l-inc</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;bg-alt</span>) <span style="color:#666">15</span>))))
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">my/doom-p</span>) (<span style="color:#19177c">my/doom-color</span> <span style="color:#19177c">color</span>))
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">my/modus-p</span>) (<span style="color:#19177c">my/modus-color</span> <span style="color:#19177c">color</span>))
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">my/ef-p</span>) (<span style="color:#19177c">my/ef-color</span> <span style="color:#19177c">color</span>))))
</span></span></code></pre></div><p>And a few more functions</p>
<h5 id="custom-theme">Custom theme</h5>
<p>So, the custom theme:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">deftheme</span> <span style="color:#19177c">my-theme-1</span>)
</span></span></code></pre></div><p>A macro to simplify defining custom colors.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/my-theme-update-color-params</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defmacro</span> <span style="color:#19177c">my/use-colors</span> (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">,@</span>(<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">i</span> <span style="color:#19177c">in</span> <span style="color:#19177c">data</span> <span style="color:#19177c">collect</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;,</span>(<span style="color:#00f">car</span> <span style="color:#19177c">i</span>) <span style="color:#19177c">my/my-theme-update-color-params</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> <span style="color:#666">,@</span>(<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> (<span style="color:#19177c">key</span> <span style="color:#19177c">value</span>) <span style="color:#19177c">on</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">i</span>) <span style="color:#19177c">by</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">cddr</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">append</span> <span style="color:#666">`</span>(<span style="color:#666">,</span><span style="color:#19177c">key</span> <span style="color:#19177c">&#39;,value</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">and</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">my/doom-p</span>) (<span style="color:#19177c">my/modus-p</span>)) <span style="color:#19177c">my/emacs-started</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/update-my-theme</span>))))
</span></span></code></pre></div><p>This macro puts lambdas to <code>my/my-theme-update-colors-hook</code> that updates faces in <code>my-theme-1</code>. Now I have to call this hook:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/update-my-theme</span> (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">_</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> (<span style="color:#19177c">face</span> <span style="color:#666">.</span> <span style="color:#19177c">values</span>) <span style="color:#19177c">in</span> <span style="color:#19177c">my/my-theme-update-color-params</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#19177c">custom-theme-set-faces</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;my-theme-1</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,</span><span style="color:#19177c">face</span> ((<span style="color:#800">t</span> <span style="color:#666">,@</span>(<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> (<span style="color:#19177c">key</span> <span style="color:#19177c">value</span>) <span style="color:#19177c">on</span> <span style="color:#19177c">values</span> <span style="color:#19177c">by</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">cddr</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> <span style="color:#19177c">key</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#00f">eval</span> <span style="color:#19177c">value</span>)))))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">enable-theme</span> <span style="color:#19177c">&#39;my-theme-1</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">unless</span> <span style="color:#19177c">my/is-termux</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#19177c">&#39;load-theme</span> <span style="color:#008000">:after</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/update-my-theme</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;emacs-startup-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/update-my-theme</span>))
</span></span></code></pre></div><p>Defining colors for <code>tab-bar.el</code>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my/use-colors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tab-bar-tab</span> <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;bg</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;yellow</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:underline</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;yellow</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tab-bar</span> <span style="color:#008000">:background</span> <span style="color:#19177c">&#39;unspecified</span> <span style="color:#008000">:foreground</span> <span style="color:#19177c">&#39;unspecified</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">magit-section-secondary-heading</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;blue</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:weight</span> <span style="color:#19177c">&#39;bold</span>))
</span></span></code></pre></div><h5 id="switch-theme">Switch theme</h5>
<p>The built-in <code>load-theme</code> does not deactivate the previous theme, so here&rsquo;s a function that does that:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/switch-theme</span> (<span style="color:#19177c">theme</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#00f">intern</span> (<span style="color:#00f">completing-read</span> <span style="color:#ba2121">&#34;Load custom theme: &#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> <span style="color:#00f">#&#39;symbol-name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">custom-available-themes</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">enabled-theme</span> <span style="color:#19177c">in</span> <span style="color:#19177c">custom-enabled-themes</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">enabled-theme</span> <span style="color:#19177c">&#39;my-theme-1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">eq</span> <span style="color:#19177c">enabled-theme</span> <span style="color:#19177c">theme</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#19177c">disable-theme</span> <span style="color:#19177c">enabled-theme</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">load-theme</span> <span style="color:#19177c">theme</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">current-prefix-arg</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/regenerate-desktop</span>)))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">if</span> <span style="color:#19177c">my/is-termux</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/switch-theme</span> <span style="color:#19177c">&#39;modus-operandi-tinted</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/switch-theme</span> <span style="color:#19177c">&#39;ef-duo-light</span>))
</span></span></code></pre></div><h5 id="extending-current-theme">Extending current theme</h5>
<p>Colors that aren&rsquo;t set in themes.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;transient</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/use-colors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">transient-key-exit</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;dark-red</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">transient-key-noop</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;grey</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">transient-key-return</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;yellow</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">transient-key-stay</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;green</span>))))
</span></span></code></pre></div><h4 id="dim-inactive-buffers">Dim inactive buffers</h4>
<p>Dim inactive buffers.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">auto-dim-other-buffers</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">display-graphic-p</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">auto-dim-other-buffers-mode</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/use-colors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">auto-dim-other-buffers-face</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;bg-other</span>))))
</span></span></code></pre></div><h4 id="ansi-colors">ANSI colors</h4>
<p><code>ansi-color.el</code> is a built-in Emacs package that translates ANSI color escape codes into faces.</p>
<p>It is used by many other packages but doesn&rsquo;t seem to have an integration with <code>doom-themes</code>, so here is one.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;ansi-color</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/use-colors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-black</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;base2</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;base0</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-red</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;red</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;red</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-green</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;green</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;green</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-yellow</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;yellow</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;yellow</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-blue</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;dark-blue</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;dark-blue</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-magenta</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;violet</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;violet</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-cyan</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;dark-cyan</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;dark-cyan</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-white</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;base8</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;base8</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-bright-black</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;base5</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;base5</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-bright-red</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;orange</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;orange</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-bright-green</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;teal</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;teal</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-bright-yellow</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;yellow</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;yellow</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-bright-blue</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;blue</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;blue</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-bright-magenta</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;magenta</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;magenta</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-bright-cyan</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;cyan</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;cyan</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-bright-white</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;fg</span>) <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;fg</span>))))
</span></span></code></pre></div><h3 id="fonts">Fonts</h3>
<h4 id="frame-font">Frame font</h4>
<p>To install a font, download the font and unpack it into the <code>.local/share/fonts</code> directory. Create one if it doesn&rsquo;t exist.</p>
<p>As I use nerd fonts elsewhere, I use one in Emacs as well.</p>
<p>References:</p>
<ul>
<li><a href="https://nerdfonts.com">nerd fonts homepage</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">when</span> (<span style="color:#19177c">display-graphic-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">x-list-fonts</span> <span style="color:#ba2121">&#34;JetBrainsMono Nerd Font&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">font</span> <span style="color:#ba2121">&#34;-JB -JetBrainsMono Nerd Font-medium-normal-normal-*-17-*-*-*-m-0-iso10646-1&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-frame-font</span> <span style="color:#19177c">font</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;default-frame-alist</span> <span style="color:#666">`</span>(<span style="color:#19177c">font</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">font</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Install JetBrainsMono Nerd Font!&#34;</span>)))
</span></span></code></pre></div><p>To make the icons work (e.g. in the Doom Modeline), run <code>M-x all-the-icons-install-fonts</code>. The package definition is somewhere later in the config.</p>
<h4 id="other-fonts">Other fonts</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">when</span> (<span style="color:#19177c">display-graphic-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-face-attribute</span> <span style="color:#19177c">&#39;variable-pitch</span> <span style="color:#800">nil</span> <span style="color:#008000">:family</span> <span style="color:#ba2121">&#34;Cantarell&#34;</span> <span style="color:#008000">:height</span> <span style="color:#666">1.0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-face-attribute</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;italic</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:family</span> <span style="color:#ba2121">&#34;JetBrainsMono Nerd Font&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:weight</span> <span style="color:#19177c">&#39;regular</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:slant</span> <span style="color:#19177c">&#39;italic</span>))
</span></span></code></pre></div><h4 id="ligatures">Ligatures</h4>
<p>Ligature setup for the JetBrainsMono font.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ligature</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;mickeynp/ligature.el&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">display-graphic-p</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ligature-set-ligatures</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(
</span></span><span style="display:flex;"><span> <span style="color:#19177c">typescript-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">typescript-ts-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">js2-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">javascript-ts-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">vue-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">svelte-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">scss-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">php-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">python-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">python-ts-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">js-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">markdown-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">clojure-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">go-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">sh-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">haskell-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">web-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;--&#34;</span> <span style="color:#ba2121">&#34;---&#34;</span> <span style="color:#ba2121">&#34;==&#34;</span> <span style="color:#ba2121">&#34;===&#34;</span> <span style="color:#ba2121">&#34;!=&#34;</span> <span style="color:#ba2121">&#34;!==&#34;</span> <span style="color:#ba2121">&#34;=!=&#34;</span> <span style="color:#ba2121">&#34;=:=&#34;</span> <span style="color:#ba2121">&#34;=/=&#34;</span> <span style="color:#ba2121">&#34;&lt;=&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&gt;=&#34;</span> <span style="color:#ba2121">&#34;&amp;&amp;&#34;</span> <span style="color:#ba2121">&#34;&amp;&amp;&amp;&#34;</span> <span style="color:#ba2121">&#34;&amp;=&#34;</span> <span style="color:#ba2121">&#34;++&#34;</span> <span style="color:#ba2121">&#34;+++&#34;</span> <span style="color:#ba2121">&#34;***&#34;</span> <span style="color:#ba2121">&#34;;;&#34;</span> <span style="color:#ba2121">&#34;!!&#34;</span> <span style="color:#ba2121">&#34;??&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;?:&#34;</span> <span style="color:#ba2121">&#34;?.&#34;</span> <span style="color:#ba2121">&#34;?=&#34;</span> <span style="color:#ba2121">&#34;&lt;:&#34;</span> <span style="color:#ba2121">&#34;:&lt;&#34;</span> <span style="color:#ba2121">&#34;:&gt;&#34;</span> <span style="color:#ba2121">&#34;&gt;:&#34;</span> <span style="color:#ba2121">&#34;&lt;&gt;&#34;</span> <span style="color:#ba2121">&#34;&lt;&lt;&lt;&#34;</span> <span style="color:#ba2121">&#34;&gt;&gt;&gt;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;&lt;&#34;</span> <span style="color:#ba2121">&#34;&gt;&gt;&#34;</span> <span style="color:#ba2121">&#34;||&#34;</span> <span style="color:#ba2121">&#34;-|&#34;</span> <span style="color:#ba2121">&#34;_|_&#34;</span> <span style="color:#ba2121">&#34;|-&#34;</span> <span style="color:#ba2121">&#34;||-&#34;</span> <span style="color:#ba2121">&#34;|=&#34;</span> <span style="color:#ba2121">&#34;||=&#34;</span> <span style="color:#ba2121">&#34;##&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;###&#34;</span> <span style="color:#ba2121">&#34;####&#34;</span> <span style="color:#ba2121">&#34;#{&#34;</span> <span style="color:#ba2121">&#34;#[&#34;</span> <span style="color:#ba2121">&#34;]#&#34;</span> <span style="color:#ba2121">&#34;#(&#34;</span> <span style="color:#ba2121">&#34;#?&#34;</span> <span style="color:#ba2121">&#34;#_&#34;</span> <span style="color:#ba2121">&#34;#_(&#34;</span> <span style="color:#ba2121">&#34;#:&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;#!&#34;</span> <span style="color:#ba2121">&#34;#=&#34;</span> <span style="color:#ba2121">&#34;^=&#34;</span> <span style="color:#ba2121">&#34;&lt;$&gt;&#34;</span> <span style="color:#ba2121">&#34;&lt;$&#34;</span> <span style="color:#ba2121">&#34;$&gt;&#34;</span> <span style="color:#ba2121">&#34;&lt;+&gt;&#34;</span> <span style="color:#ba2121">&#34;&lt;+&#34;</span> <span style="color:#ba2121">&#34;+&gt;&#34;</span> <span style="color:#ba2121">&#34;&lt;*&gt;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;*&#34;</span> <span style="color:#ba2121">&#34;*&gt;&#34;</span> <span style="color:#ba2121">&#34;&lt;/&#34;</span> <span style="color:#ba2121">&#34;&lt;/&gt;&#34;</span> <span style="color:#ba2121">&#34;/&gt;&#34;</span> <span style="color:#ba2121">&#34;&lt;!--&#34;</span> <span style="color:#ba2121">&#34;&lt;#--&#34;</span> <span style="color:#ba2121">&#34;--&gt;&#34;</span> <span style="color:#ba2121">&#34;-&gt;&#34;</span> <span style="color:#ba2121">&#34;-&gt;&gt;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;&lt;-&#34;</span> <span style="color:#ba2121">&#34;&lt;-&#34;</span> <span style="color:#ba2121">&#34;&lt;=&lt;&#34;</span> <span style="color:#ba2121">&#34;=&lt;&lt;&#34;</span> <span style="color:#ba2121">&#34;&lt;&lt;=&#34;</span> <span style="color:#ba2121">&#34;&lt;==&#34;</span> <span style="color:#ba2121">&#34;&lt;=&gt;&#34;</span> <span style="color:#ba2121">&#34;&lt;==&gt;&#34;</span> <span style="color:#ba2121">&#34;==&gt;&#34;</span> <span style="color:#ba2121">&#34;=&gt;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;=&gt;&gt;&#34;</span> <span style="color:#ba2121">&#34;&gt;=&gt;&#34;</span> <span style="color:#ba2121">&#34;&gt;&gt;=&#34;</span> <span style="color:#ba2121">&#34;&gt;&gt;-&#34;</span> <span style="color:#ba2121">&#34;&gt;-&#34;</span> <span style="color:#ba2121">&#34;&gt;--&#34;</span> <span style="color:#ba2121">&#34;-&lt;&#34;</span> <span style="color:#ba2121">&#34;-&lt;&lt;&#34;</span> <span style="color:#ba2121">&#34;&gt;-&gt;&#34;</span> <span style="color:#ba2121">&#34;&lt;-&lt;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;-|&#34;</span> <span style="color:#ba2121">&#34;&lt;=|&#34;</span> <span style="color:#ba2121">&#34;|=&gt;&#34;</span> <span style="color:#ba2121">&#34;|-&gt;&#34;</span> <span style="color:#ba2121">&#34;&lt;-&gt;&#34;</span> <span style="color:#ba2121">&#34;&lt;~~&#34;</span> <span style="color:#ba2121">&#34;&lt;~&#34;</span> <span style="color:#ba2121">&#34;&lt;~&gt;&#34;</span> <span style="color:#ba2121">&#34;~~&#34;</span> <span style="color:#ba2121">&#34;~~&gt;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;~&gt;&#34;</span> <span style="color:#ba2121">&#34;~-&#34;</span> <span style="color:#ba2121">&#34;-~&#34;</span> <span style="color:#ba2121">&#34;~@&#34;</span> <span style="color:#ba2121">&#34;[||]&#34;</span> <span style="color:#ba2121">&#34;|]&#34;</span> <span style="color:#ba2121">&#34;[|&#34;</span> <span style="color:#ba2121">&#34;|}&#34;</span> <span style="color:#ba2121">&#34;{|&#34;</span> <span style="color:#ba2121">&#34;[&lt;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&gt;]&#34;</span> <span style="color:#ba2121">&#34;|&gt;&#34;</span> <span style="color:#ba2121">&#34;&lt;|&#34;</span> <span style="color:#ba2121">&#34;||&gt;&#34;</span> <span style="color:#ba2121">&#34;&lt;||&#34;</span> <span style="color:#ba2121">&#34;|||&gt;&#34;</span> <span style="color:#ba2121">&#34;&lt;|||&#34;</span> <span style="color:#ba2121">&#34;&lt;|&gt;&#34;</span> <span style="color:#ba2121">&#34;...&#34;</span> <span style="color:#ba2121">&#34;..&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;.=&#34;</span> <span style="color:#ba2121">&#34;.-&#34;</span> <span style="color:#ba2121">&#34;..&lt;&#34;</span> <span style="color:#ba2121">&#34;.?&#34;</span> <span style="color:#ba2121">&#34;::&#34;</span> <span style="color:#ba2121">&#34;:::&#34;</span> <span style="color:#ba2121">&#34;:=&#34;</span> <span style="color:#ba2121">&#34;::=&#34;</span> <span style="color:#ba2121">&#34;:?&#34;</span> <span style="color:#ba2121">&#34;:?&gt;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;//&#34;</span> <span style="color:#ba2121">&#34;///&#34;</span> <span style="color:#ba2121">&#34;/*&#34;</span> <span style="color:#ba2121">&#34;*/&#34;</span> <span style="color:#ba2121">&#34;/=&#34;</span> <span style="color:#ba2121">&#34;//=&#34;</span> <span style="color:#ba2121">&#34;/==&#34;</span> <span style="color:#ba2121">&#34;@_&#34;</span> <span style="color:#ba2121">&#34;__&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">global-ligature-mode</span> <span style="color:#800">t</span>))
</span></span></code></pre></div><h4 id="icons">Icons</h4>
<p>I switched to <a href="https://github.com/rainstormstudio/nerd-icons.el">nerd-icons</a> from <a href="https://github.com/domtronn/all-the-icons.el">all-the-icons</a>.</p>
<p>Run <code>M-x all-the-icons-install-fonts</code> at first setup.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">nerd-icons</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h3 id="text-highlight">Text highlight</h3>
<p>Highlight indent guides. I used <a href="https://github.com/DarthFennec/highlight-indent-guides">highlight-indent-guides</a> before but <a href="https://github.com/jdtsmith/indent-bars">indent-bars</a> seems to work better, and it doesn&rsquo;t break with <code>treesit-fold</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">indent-bars</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;jdtsmith/indent-bars&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/remote-server</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> ((<span style="color:#19177c">prog-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">indent-bars-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">LaTeX-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">indent-bars-mode</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;indent-bars-ts</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">setopt</span> <span style="color:#19177c">indent-bars-no-descend-lists</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">indent-bars-treesit-support</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">indent-bars-width-frac</span> <span style="color:#666">0.3</span>))
</span></span></code></pre></div><p>Rainbow parentheses.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">rainbow-delimiters</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> ((<span style="color:#19177c">prog-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">rainbow-delimiters-mode</span>)))
</span></span></code></pre></div><p>Highlight colors</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">rainbow-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">rainbow-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><p>Highlight TODOs and stuff</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">hl-todo</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> (<span style="color:#19177c">prog-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">hl-todo-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h3 id="doom-modeline">Doom Modeline</h3>
<p>A modeline from Doom Emacs. A big advantage of this package is that it just works out of the box and does not require much customization.</p>
<p>I tried a bunch of other options, including <a href="https://github.com/TheBB/spaceline">spaceline</a>, but in the end, decided that Doom Modeline works best for me.</p>
<p>References:</p>
<ul>
<li><a href="https://github.com/seagle0128/doom-modeline">Doom Modeline</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">doom-modeline</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; :if (not (display-graphic-p))</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">doom-modeline-env-enable-python</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">doom-modeline-env-enable-go</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">doom-modeline-buffer-encoding</span> <span style="color:#19177c">&#39;nondefault</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">doom-modeline-hud</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">doom-modeline-persp-icon</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">doom-modeline-persp-name</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">doom-modeline-display-misc-in-all-mode-lines</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">my/is-termux</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">setopt</span> <span style="color:#19177c">doom-modeline-icon</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">doom-modeline-minor-modes</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">doom-modeline-irc</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">doom-modeline-buffer-state-icon</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">doom-modeline-mode</span> <span style="color:#666">1</span>))
</span></span></code></pre></div><h4 id="doom-modeline-as-tab-bar">Doom Modeline as Tab Bar</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/tab-bar-mode-line--format</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">derived-mode-p</span> <span style="color:#19177c">&#39;company-box-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-letf</span> (((<span style="color:#00f">symbol-function</span> <span style="color:#19177c">&#39;window-pixel-width</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;frame-pixel-width</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">symbol-function</span> <span style="color:#19177c">&#39;window-margins</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">_</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> <span style="color:#800">nil</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">doom-modeline-window-width-limit</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">doom-modeline--limited-width-p</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format-mode-line</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;%e&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:eval</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">doom-modeline-format--main</span>))))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/hide-mode-line-if-only-window</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">windows</span> (<span style="color:#00f">window-list</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">hide-mode-line-p</span> (<span style="color:#19177c">length=</span> <span style="color:#19177c">windows</span> <span style="color:#666">1</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">win</span> <span style="color:#19177c">windows</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> (<span style="color:#00f">window-buffer</span> <span style="color:#19177c">win</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">hide-mode-line-p</span> <span style="color:#19177c">hide-mode-line-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">hide-mode-line-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">hide-mode-line-p</span> <span style="color:#666">+1</span> <span style="color:#666">-1</span>)))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">define-minor-mode</span> <span style="color:#19177c">my/tab-bar-mode-line-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Use tab-bar as mode line mode.&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:global</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">my/tab-bar-mode-line-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tab-bar-mode</span> <span style="color:#666">+1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">tab-bar-format</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">my/tab-bar-mode-line--format</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-face-attribute</span> <span style="color:#19177c">&#39;tab-bar</span> <span style="color:#800">nil</span> <span style="color:#008000">:inherit</span> <span style="color:#19177c">&#39;mode-line</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;window-configuration-change-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/hide-mode-line-if-only-window</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">buf</span> (<span style="color:#00f">buffer-list</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buf</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">doom-modeline-set-modeline</span> <span style="color:#19177c">&#39;minimal</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">doom-modeline-set-modeline</span> <span style="color:#19177c">&#39;minimal</span> <span style="color:#19177c">&#39;default</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">frame</span> (<span style="color:#00f">frame-list</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-selected-frame</span> <span style="color:#19177c">frame</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/hide-mode-line-if-only-window</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let</span> (<span style="color:#19177c">cb-frame</span> (<span style="color:#19177c">company-box--get-frame</span> <span style="color:#19177c">frame</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-frame-parameter</span> <span style="color:#19177c">cb-frame</span> <span style="color:#19177c">&#39;tab-bar-lines</span> <span style="color:#666">0</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">setenv</span> <span style="color:#ba2121">&#34;POLYBAR_BOTTOM&#34;</span> <span style="color:#ba2121">&#34;false&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">fboundp</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/exwm-run-polybar</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/exwm-run-polybar</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tab-bar-mode</span> <span style="color:#666">-1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">tab-bar-format</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">tab-bar-format-history</span> <span style="color:#19177c">tab-bar-format-tabs</span> <span style="color:#19177c">tab-bar-separator</span> <span style="color:#19177c">tab-bar-format-add-tab</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-face-attribute</span> <span style="color:#19177c">&#39;tab-bar</span> <span style="color:#800">nil</span> <span style="color:#008000">:inherit</span> <span style="color:#19177c">&#39;default</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">remove-hook</span> <span style="color:#19177c">&#39;window-configuration-change-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/hide-mode-line-if-only-window</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">global-hide-mode-line-mode</span> <span style="color:#666">-1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">buf</span> (<span style="color:#00f">buffer-list</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buf</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">doom-modeline-set-modeline</span> <span style="color:#19177c">&#39;main</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">doom-modeline-set-modeline</span> <span style="color:#19177c">&#39;main</span> <span style="color:#19177c">&#39;default</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">setenv</span> <span style="color:#ba2121">&#34;POLYBAR_BOTTOM&#34;</span> <span style="color:#ba2121">&#34;true&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">fboundp</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/exwm-run-polybar</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/exwm-run-polybar</span>))))
</span></span></code></pre></div><h3 id="perspective-dot-el">perspective.el</h3>
<p><a href="https://github.com/nex3/perspective-el">perspective.el</a> is a package that groups buffers in &ldquo;perspectives&rdquo;.</p>
<p><code>tab-bar.el</code> can be configured to behave in a similar way, but I&rsquo;m too invested in this package already.</p>
<p>One thing I don&rsquo;t like is that the list perspectives is displayed in the modeline, but I&rsquo;ll probably look how to move them to the bar at the top of the frame at some point.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">perspective</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (setq persp-show-modestring &#39;header)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">persp-sort</span> <span style="color:#19177c">&#39;created</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">persp-suppress-no-prefix-key-warning</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">persp-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;x&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:keymap</span> <span style="color:#19177c">perspective-map</span> <span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;perspective&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;override</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">emacs</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gt&#34;</span> <span style="color:#19177c">&#39;persp-next</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gT&#34;</span> <span style="color:#19177c">&#39;persp-prev</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gn&#34;</span> <span style="color:#19177c">&#39;persp-switch</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gN&#34;</span> <span style="color:#19177c">&#39;persp-kill</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;perspective-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;b&#34;</span> <span style="color:#19177c">&#39;persp-switch-to-buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;x&#34;</span> <span style="color:#19177c">&#39;persp-switch-to-buffer*</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;u&#34;</span> <span style="color:#19177c">&#39;persp-ibuffer</span>))
</span></span></code></pre></div><h4 id="functions-to-manage-buffers">Functions to manage buffers</h4>
<p>Move the current buffer to a perspective and switch to it.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/persp-move-window-and-switch</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">buffer</span> (<span style="color:#00f">current-buffer</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">call-interactively</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">persp-switch</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">persp-set-buffer</span> (<span style="color:#00f">buffer-name</span> <span style="color:#19177c">buffer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">switch-to-buffer</span> <span style="color:#19177c">buffer</span>)))
</span></span></code></pre></div><p>Copy the current buffer to a perspective and switch to it.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/persp-copy-window-and-switch</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">buffer</span> (<span style="color:#00f">current-buffer</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">call-interactively</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">persp-switch</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">persp-add-buffer</span> (<span style="color:#00f">buffer-name</span> <span style="color:#19177c">buffer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">switch-to-buffer</span> <span style="color:#19177c">buffer</span>)))
</span></span></code></pre></div><p>Add keybindings to the default map.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;perspective</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;perspective-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;m&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/persp-move-window-and-switch</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/persp-copy-window-and-switch</span>))
</span></span></code></pre></div><h4 id="automating-perspectives">Automating perspectives</h4>
<p>Out-of-the-box, <code>perspective.el</code> doesn&rsquo;t feature much (or any) capacity for automation. We&rsquo;re supposed to manually assign buffers to perspectives, which kinda makes sense&hellip; But I still want automation.</p>
<p>First, let&rsquo;s define a variable with &ldquo;rules&rdquo;:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/perspective-assign-alist</span> <span style="color:#666">&#39;</span>())
</span></span></code></pre></div><p>One rule looks as follows:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>(major-mode workspace-index persp-name)
</span></span></code></pre></div><p>And a function to act on these rules.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/perspective-assign-ignore</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;If non-nil, ignore </span><span style="color:#19177c">`my/perspective-assign&#39;</span><span style="color:#ba2121">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/perspective-assign</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let*</span> ((<span style="color:#19177c">_</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/perspective-assign-ignore</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">rule</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">major-mode</span> <span style="color:#19177c">my/perspective-assign-alist</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">workspace-index</span> (<span style="color:#00f">car</span> <span style="color:#19177c">rule</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">persp-name</span> (<span style="color:#19177c">cadr</span> <span style="color:#19177c">rule</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">buffer</span> (<span style="color:#00f">current-buffer</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">fboundp</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">perspective-exwm-assign-window</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">perspective-exwm-assign-window</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:workspace-index</span> <span style="color:#19177c">workspace-index</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:persp-name</span> <span style="color:#19177c">persp-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">workspace-index</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">exwm-workspace-switch</span> <span style="color:#19177c">workspace-index</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">persp-name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">persp-switch</span> <span style="color:#19177c">persp-name</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">with-perspective</span> <span style="color:#19177c">persp-name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">persp-set-buffer</span> <span style="color:#19177c">buffer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">persp-switch-to-buffer</span> <span style="color:#19177c">buffer</span>)))))
</span></span></code></pre></div><p>Also advise to ignore the assignment:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/perspective-assign-ignore-advice</span> (<span style="color:#19177c">fun</span> <span style="color:#008000">&amp;rest</span> <span style="color:#19177c">args</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">my/perspective-assign-ignore</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#19177c">fun</span> <span style="color:#19177c">args</span>)))
</span></span></code></pre></div><p>If EXWM is available, then so is mine <code>perspective-exwm</code> package, which features a convenient procedure called <code>perspective-exwm-assign-window</code>. Otherwise, we just work with perspectives.</p>
<p>Now, we have to put this function somewhere, and <code>after-change-major-mode-hook</code> seems like a perfect place for it.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;after-change-major-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/perspective-assign</span>)
</span></span></code></pre></div><p>And here is a simple macro to add rules to the list.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defmacro</span> <span style="color:#19177c">my/persp-add-rule</span> (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">body</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">declare</span> (<span style="color:#19177c">indent</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">=</span> (<span style="color:#00f">%</span> (<span style="color:#00f">length</span> <span style="color:#19177c">body</span>) <span style="color:#666">3</span>) <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">error</span> <span style="color:#ba2121">&#34;Malformed body in my/persp-add-rule&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> (<span style="color:#19177c">result</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">while</span> <span style="color:#19177c">body</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">major-mode</span> (<span style="color:#008000">pop</span> <span style="color:#19177c">body</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">workspace-index</span> (<span style="color:#008000">pop</span> <span style="color:#19177c">body</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">persp-name</span> (<span style="color:#008000">pop</span> <span style="color:#19177c">body</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;my/perspective-assign-alist</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#666">,</span><span style="color:#19177c">major-mode</span> <span style="color:#666">.</span> (<span style="color:#666">,</span><span style="color:#19177c">workspace-index</span> <span style="color:#666">,</span><span style="color:#19177c">persp-name</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">result</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">,@</span><span style="color:#19177c">result</span>)))
</span></span></code></pre></div><p>Also, the logic above works only for cases when the buffer is created. Occasionally, packages run <code>switch-to-buffer</code>, which screws both EXWM workspaces and perspectives; to work around that, I define a macro that runs a command in the context of a given perspective and workspace.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defmacro</span> <span style="color:#19177c">my/command-in-persp</span> (<span style="color:#19177c">command-name</span> <span style="color:#19177c">persp-name</span> <span style="color:#19177c">workspace-index</span> <span style="color:#008000">&amp;rest</span> <span style="color:#19177c">args</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">`&#39;</span>((<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">and</span> <span style="color:#666">,</span><span style="color:#19177c">workspace-index</span> (<span style="color:#00f">fboundp</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">exwm-workspace-switch-create</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">exwm-workspace-switch-create</span> <span style="color:#666">,</span><span style="color:#19177c">workspace-index</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">persp-switch</span> <span style="color:#666">,</span><span style="color:#19177c">persp-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">delete-other-windows</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,@</span><span style="color:#19177c">args</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:wk</span> <span style="color:#666">,</span><span style="color:#19177c">command-name</span>))
</span></span></code></pre></div><p>This is meant to be used in the definitions of <code>general.el</code>.</p>
<h2 id="programming">Programming</h2>
<h3 id="general-setup">General setup</h3>
<h4 id="treemacs">Treemacs</h4>
<p><a href="https://github.com/Alexander-Miller/treemacs">Treemacs</a> is a rather large &amp; powerful package, but as of now I&rsquo;ve replaced it with dired. I still have a small configuration because lsp-mode and dap-mode depend on it.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">treemacs</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:defer</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (setq treemacs-follow-mode nil)</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (setq treemacs-follow-after-init nil)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">treemacs-space-between-root-nodes</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (treemacs-git-mode &#39;extended)</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (add-to-list &#39;treemacs-pre-file-insert-predicates #&#39;treemacs-is-file-git-ignored?)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;treemacs-mode-map</span>
</span></span><span style="display:flex;"><span> [<span style="color:#19177c">mouse-1</span>] <span style="color:#00f">#&#39;</span><span style="color:#19177c">treemacs-single-click-expand-action</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-l&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">treemacs-root-down</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-h&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">treemacs-root-up</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">treemacs-quit</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;treemacs-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">emacs</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#19177c">&#39;treemacs-quit</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">treemacs-evil</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">treemacs</span> <span style="color:#19177c">evil</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h4 id="lsp">LSP</h4>
<p>LSP-mode provides an IDE-like experience for Emacs - real-time diagnostics, code actions, intelligent autocompletion, etc.</p>
<p>References:</p>
<ul>
<li><a href="https://emacs-lsp.github.io/lsp-mode/">lsp-mode homepage</a></li>
</ul>
<h5 id="setup">Setup</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">lsp-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/is-termux</span> <span style="color:#19177c">my/remote-server</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> (
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">typescript-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">lsp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">js-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">lsp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">vue-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">lsp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">go-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">lsp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">svelte-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">lsp</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (python-mode . lsp)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">json-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">lsp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">haskell-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">lsp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">haskell-literate-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">lsp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">java-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">lsp</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (csharp-mode . lsp)</span>
</span></span><span style="display:flex;"><span> )
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> <span style="color:#19177c">lsp</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-keymap-prefix</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-idle-delay</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-eslint-server-command</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;node&#34;</span> <span style="color:#ba2121">&#34;/home/pavel/.emacs.d/.cache/lsp/eslint/unzipped/extension/server/out/eslintServer.js&#34;</span> <span style="color:#ba2121">&#34;--stdio&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-eslint-run</span> <span style="color:#ba2121">&#34;onSave&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-signature-render-documentation</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (lsp-headerline-breadcrumb-mode nil)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-headerline-breadcrumb-enable</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-modeline-code-actions-enable</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-modeline-diagnostics-enable</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-volar-take-over-mode</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;lsp-language-id-configuration</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">svelte-mode</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;svelte&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">lsp-ui</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> <span style="color:#19177c">lsp-ui-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-ui-doc-delay</span> <span style="color:#666">2</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-ui-sideline-show-hover</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">all-the-icons</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h5 id="keybindings-2">Keybindings</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;l&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;lsp&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#19177c">&#39;lsp-ui-peek-find-definitions</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#19177c">&#39;lsp-rename</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;u&#34;</span> <span style="color:#19177c">&#39;lsp-ui-peek-find-references</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#19177c">&#39;lsp-ui-find-workspace-symbol</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;l&#34;</span> <span style="color:#19177c">&#39;lsp-execute-code-action</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;e&#34;</span> <span style="color:#19177c">&#39;list-flycheck-errors</span>)
</span></span></code></pre></div><h5 id="ui">UI</h5>
<p>I don&rsquo;t like how some language servers print the full filename in the progress indicator.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/lsp--progress-status</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Returns the status of the progress for the current workspaces.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">-let</span> ((<span style="color:#19177c">progress-status</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">s-join</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;|&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">-keep</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">workspace</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">tokens</span> (<span style="color:#19177c">lsp--workspace-work-done-tokens</span> <span style="color:#19177c">workspace</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">ht-empty?</span> <span style="color:#19177c">tokens</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapconcat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">-lambda</span> ((<span style="color:#19177c">&amp;WorkDoneProgressBegin</span> <span style="color:#008000">:message?</span> <span style="color:#008000">:title</span> <span style="color:#008000">:percentage?</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> (<span style="color:#008000">if</span> <span style="color:#19177c">percentage?</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">numberp</span> <span style="color:#19177c">percentage?</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%.0f%%%% &#34;</span> <span style="color:#19177c">percentage?</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%s%%%% &#34;</span> <span style="color:#19177c">percentage?</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">msg</span> (<span style="color:#19177c">url-unhex-string</span> (<span style="color:#008000">or</span> <span style="color:#19177c">message\?</span> <span style="color:#19177c">title</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;\\`file:///&#34;</span> <span style="color:#19177c">msg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-name-nondirectory</span> <span style="color:#19177c">msg</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ht-values</span> <span style="color:#19177c">tokens</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;|&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">lsp-workspaces</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">s-blank?</span> <span style="color:#19177c">progress-status</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">lsp-progress-prefix</span> <span style="color:#19177c">progress-status</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;lsp-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#19177c">&#39;lsp--progress-status</span> <span style="color:#008000">:override</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/lsp--progress-status</span>))
</span></span></code></pre></div><h5 id="fix-vue-semantic-server">Fix vue-semantic-server</h5>
<p>Somehow, for me <a href="https://github.com/vuejs/language-tools">vue-semantic-server</a> sends an empty <code>textDocument/publishDiagnostics</code> message a second or two after the real one, causing the diagnostics to disappear.</p>
<p>For now, I&rsquo;ve advised this away by ignoring empty messages unless they show up more than 5 seconds after a non-empty message.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/lsp--vue-diagnostics-last-update</span> (<span style="color:#00f">make-hash-table</span> <span style="color:#008000">:test</span> <span style="color:#00f">#&#39;equal</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/lsp--on-diagnostics</span> (<span style="color:#19177c">fn</span> <span style="color:#19177c">workspace</span> <span style="color:#19177c">params</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">equal</span> (<span style="color:#00f">gethash</span> <span style="color:#19177c">&#39;vue-semantic-server</span> <span style="color:#19177c">lsp-clients</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">lsp--workspace-client</span> <span style="color:#19177c">workspace</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">is-empty</span> (<span style="color:#19177c">seq-empty-p</span> (<span style="color:#00f">gethash</span> <span style="color:#ba2121">&#34;diagnostics&#34;</span> <span style="color:#19177c">params</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">uri</span> (<span style="color:#00f">gethash</span> <span style="color:#ba2121">&#34;uri&#34;</span> <span style="color:#19177c">params</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">last-update</span> (<span style="color:#00f">gethash</span> <span style="color:#19177c">uri</span> <span style="color:#19177c">my/lsp--vue-diagnostics-last-update</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">current-update</span> (<span style="color:#19177c">time-convert</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">integer</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">is-empty</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">puthash</span> <span style="color:#19177c">uri</span> <span style="color:#19177c">current-update</span> <span style="color:#19177c">my/lsp--vue-diagnostics-last-update</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">is-empty</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> <span style="color:#19177c">last-update</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">&gt;</span> (<span style="color:#00f">-</span> <span style="color:#19177c">current-update</span> (<span style="color:#008000">or</span> <span style="color:#19177c">last-update</span> <span style="color:#666">0</span>)) <span style="color:#666">5</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">fn</span> <span style="color:#19177c">workspace</span> <span style="color:#19177c">params</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">fn</span> <span style="color:#19177c">workspace</span> <span style="color:#19177c">params</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;lsp</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">lsp--on-diagnostics</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/lsp--on-diagnostics</span>))
</span></span></code></pre></div><h4 id="flycheck">Flycheck</h4>
<p>A syntax checking extension for Emacs. Integrates with LSP-mode, but can also use various standalone checkers.</p>
<p>References:</p>
<ul>
<li><a href="https://www.flycheck.org/en/latest/">Flycheck homepage</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">flycheck</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">global-flycheck-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">flycheck-check-syntax-automatically</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">save</span> <span style="color:#19177c">idle-buffer-switch</span> <span style="color:#19177c">mode-enabled</span>))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (add-hook &#39;evil-insert-state-exit-hook</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (lambda ()</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (if flycheck-checker</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (flycheck-buffer))</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; ))</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#19177c">&#39;flycheck-eslint-config-exists-p</span> <span style="color:#008000">:override</span> (<span style="color:#008000">lambda</span>() <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;display-buffer-alist</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,</span>(<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;*Flycheck errors*&#34;</span> <span style="color:#19177c">eos</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-buffer-reuse-window</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">display-buffer-in-side-window</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">side</span> <span style="color:#666">.</span> <span style="color:#19177c">bottom</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">reusable-frames</span> <span style="color:#666">.</span> <span style="color:#19177c">visible</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">window-height</span> <span style="color:#666">.</span> <span style="color:#666">0.33</span>))))
</span></span></code></pre></div><h4 id="general-additional-config">General additional config</h4>
<p>Have to put this before tree-sitter because I need <code>my/set-smartparens-indent</code> there.</p>
<p>Make smartparens behave the way I like for C-like languages.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/set-smartparens-indent</span> (<span style="color:#19177c">mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">sp-local-pair</span> <span style="color:#19177c">mode</span> <span style="color:#ba2121">&#34;{&#34;</span> <span style="color:#800">nil</span> <span style="color:#008000">:post-handlers</span> <span style="color:#666">&#39;</span>((<span style="color:#ba2121">&#34;|| &#34;</span> <span style="color:#ba2121">&#34;SPC&#34;</span>) (<span style="color:#ba2121">&#34;||\n[i]&#34;</span> <span style="color:#ba2121">&#34;RET&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">sp-local-pair</span> <span style="color:#19177c">mode</span> <span style="color:#ba2121">&#34;[&#34;</span> <span style="color:#800">nil</span> <span style="color:#008000">:post-handlers</span> <span style="color:#666">&#39;</span>((<span style="color:#ba2121">&#34;|| &#34;</span> <span style="color:#ba2121">&#34;SPC&#34;</span>) (<span style="color:#ba2121">&#34;||\n[i]&#34;</span> <span style="color:#ba2121">&#34;RET&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">sp-local-pair</span> <span style="color:#19177c">mode</span> <span style="color:#ba2121">&#34;(&#34;</span> <span style="color:#800">nil</span> <span style="color:#008000">:post-handlers</span> <span style="color:#666">&#39;</span>((<span style="color:#ba2121">&#34;|| &#34;</span> <span style="color:#ba2121">&#34;SPC&#34;</span>) (<span style="color:#ba2121">&#34;||\n[i]&#34;</span> <span style="color:#ba2121">&#34;RET&#34;</span>))))
</span></span></code></pre></div><p>Override flycheck checker with eslint.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/set-flycheck-eslint</span>()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Override flycheck checker with eslint.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">lsp-diagnostic-package</span> <span style="color:#008000">:none</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">flycheck-checker</span> <span style="color:#19177c">&#39;javascript-eslint</span>))
</span></span></code></pre></div><h4 id="tree-sitter">Tree-sitter</h4>
<p>References:</p>
<ul>
<li><a href="https://tree-sitter.github.io/tree-sitter/using-parsers#query-syntax">Tree sitter query syntax</a></li>
<li><a href="https://www.gnu.org/software/emacs//manual/html_node/elisp/Parsing-Program-Source.html">treesit.el documentation</a></li>
</ul>
<h5 id="treesit-dot-el">treesit.el</h5>
<p>Tree-Sitter integration with Emacs 29.</p>
<p>References:</p>
<ul>
<li><a href="https://www.masteringemacs.org/article/how-to-get-started-tree-sitter">How to Get Started with Tree-Sitter - Mastering Emacs</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">treesit</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:type</span> <span style="color:#19177c">built-in</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#008000">featurep</span> <span style="color:#19177c">&#39;treesit</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">treesit-language-source-alist</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">item</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">lang</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">item</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">item</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">rev</span> (<span style="color:#00f">nth</span> <span style="color:#666">2</span> <span style="color:#19177c">item</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">source-dir</span> (<span style="color:#00f">nth</span> <span style="color:#666">3</span> <span style="color:#19177c">item</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,</span><span style="color:#19177c">lang</span> <span style="color:#666">,</span><span style="color:#19177c">url</span> <span style="color:#666">,</span><span style="color:#19177c">rev</span> <span style="color:#666">,</span><span style="color:#19177c">source-dir</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#19177c">executable-find</span> <span style="color:#ba2121">&#34;gcc&#34;</span>) <span style="color:#666">,</span>(<span style="color:#19177c">executable-find</span> <span style="color:#ba2121">&#34;c++&#34;</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">bash</span> <span style="color:#ba2121">&#34;https://github.com/tree-sitter/tree-sitter-bash&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cmake</span> <span style="color:#ba2121">&#34;https://github.com/uyha/tree-sitter-cmake&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">css</span> <span style="color:#ba2121">&#34;https://github.com/tree-sitter/tree-sitter-css&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elisp</span> <span style="color:#ba2121">&#34;https://github.com/Wilfred/tree-sitter-elisp&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">go</span> <span style="color:#ba2121">&#34;https://github.com/tree-sitter/tree-sitter-go&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">html</span> <span style="color:#ba2121">&#34;https://github.com/tree-sitter/tree-sitter-html&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">javascript</span> <span style="color:#ba2121">&#34;https://github.com/tree-sitter/tree-sitter-javascript&#34;</span> <span style="color:#ba2121">&#34;master&#34;</span> <span style="color:#ba2121">&#34;src&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">json</span> <span style="color:#ba2121">&#34;https://github.com/tree-sitter/tree-sitter-json&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">make</span> <span style="color:#ba2121">&#34;https://github.com/alemuller/tree-sitter-make&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">markdown</span> <span style="color:#ba2121">&#34;https://github.com/ikatyang/tree-sitter-markdown&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">python</span> <span style="color:#ba2121">&#34;https://github.com/tree-sitter/tree-sitter-python&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">toml</span> <span style="color:#ba2121">&#34;https://github.com/tree-sitter/tree-sitter-toml&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tsx</span> <span style="color:#ba2121">&#34;https://github.com/tree-sitter/tree-sitter-typescript&#34;</span> <span style="color:#ba2121">&#34;master&#34;</span> <span style="color:#ba2121">&#34;tsx/src&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">typescript</span> <span style="color:#ba2121">&#34;https://github.com/tree-sitter/tree-sitter-typescript&#34;</span> <span style="color:#ba2121">&#34;master&#34;</span> <span style="color:#ba2121">&#34;typescript/src&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">yaml</span> <span style="color:#ba2121">&#34;https://github.com/ikatyang/tree-sitter-yaml&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">treesit-font-lock-level</span> <span style="color:#666">4</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">major-mode-remap-alist</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">typescript-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">typescript-ts-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">js-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">javascript-ts-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">python-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">python-ts-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">json-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">json-ts-mode</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> (<span style="color:#19177c">old-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">new-mode</span>) <span style="color:#19177c">in</span> <span style="color:#19177c">major-mode-remap-alist</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">new-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">set</span> (<span style="color:#00f">intern</span> (<span style="color:#00f">concat</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">new-mode</span>) <span style="color:#ba2121">&#34;-hook&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">eval</span> <span style="color:#666">`</span>(<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#00f">run-hooks</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;,</span>(<span style="color:#00f">intern</span> (<span style="color:#00f">concat</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">old-mode</span>) <span style="color:#ba2121">&#34;-hook&#34;</span>)))))))))
</span></span></code></pre></div><h5 id="treesit-fold">treesit-fold</h5>
<p><a href="https://github.com/emacs-tree-sitter/treesit-fold">treesit-fold</a> uses treesit.el for folding.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">treesit-fold</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#19177c">treesit-fold</span> <span style="color:#008000">:type</span> <span style="color:#19177c">git</span> <span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;emacs-tree-sitter/treesit-fold&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">treesit-fold-mode</span>))
</span></span></code></pre></div><h6 id="hide-children-of-current-node">Hide children of current node</h6>
<p>A function to hide children of the current foldable node. This is somewhat similar to <code>hs-hide-level</code>, which I got used to.</p>
<p>First, find all foldable nodes:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/treesit-fold--get-nodes-to-fold</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let*</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">node</span> (<span style="color:#008000">ignore-errors</span> (<span style="color:#19177c">treesit-buffer-root-node</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">patterns</span> (<span style="color:#19177c">seq-mapcat</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">fold-range</span>) <span style="color:#666">`</span>((<span style="color:#666">,</span>(<span style="color:#00f">car</span> <span style="color:#19177c">fold-range</span>)) <span style="color:#19177c">@name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">major-mode</span> <span style="color:#19177c">treesit-fold-range-alist</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> (<span style="color:#008000">ignore-errors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">treesit-query-compile</span> (<span style="color:#19177c">treesit-node-language</span> <span style="color:#19177c">node</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">patterns</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">nodes-to-fold</span> (<span style="color:#19177c">treesit-query-capture</span> <span style="color:#19177c">node</span> <span style="color:#19177c">query</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mode-ranges</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">major-mode</span> <span style="color:#19177c">treesit-fold-range-alist</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">nodes-to-fold</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-remove-if</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">node</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">treesit-fold--non-foldable-node-p</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">node</span>) <span style="color:#19177c">mode-ranges</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">nodes-to-fold</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">nodes-to-fold</span>))
</span></span></code></pre></div><p>Then filter children of the current foldable node and fold them:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/treesit-fold-hide-children</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">current-node</span> (<span style="color:#19177c">treesit-fold--foldable-node-at-pos</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">all-nodes-to-fold</span> (<span style="color:#19177c">my/treesit-fold--get-nodes-to-fold</span>))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Find foldable children of `current-node&#39;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">target-nodes-to-fold</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">n</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-block</span> <span style="color:#19177c">tree-iter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">while</span> <span style="color:#19177c">n</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">n</span> (<span style="color:#19177c">treesit-node-parent</span> <span style="color:#19177c">n</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">equal</span> <span style="color:#19177c">n</span> <span style="color:#19177c">current-node</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-return-from</span> <span style="color:#19177c">tree-iter</span> <span style="color:#800">t</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> <span style="color:#00f">#&#39;cdr</span> <span style="color:#19177c">all-nodes-to-fold</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">node</span> <span style="color:#19177c">target-nodes-to-fold</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">treesit-fold-close</span> <span style="color:#19177c">node</span>))))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/evil-fold-hide-level</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">hs-minor-mode</span> (<span style="color:#19177c">hs-hide-level</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">treesit-fold-mode</span> (<span style="color:#19177c">my/treesit-fold-hide-children</span>))))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;treesit-fold</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;ze&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/evil-fold-hide-level</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">keymap-unset</span> <span style="color:#19177c">evil-motion-state-map</span> <span style="color:#ba2121">&#34;z e&#34;</span> <span style="color:#800">t</span>))
</span></span></code></pre></div><h5 id="combobulate">combobulate</h5>
<p><a href="https://github.com/mickeynp/combobulate">combobulate</a> is Mickey Peterson&rsquo;s package that uses <code>tree-sitter</code> for structural navigation.</p>
<p>I&rsquo;m not actually using that, but its query editor is pretty useful to debug <code>tree-sitter</code> queries.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">combobulate</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;mickeynp/combobulate&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">combobulate</span>))
</span></span></code></pre></div><h4 id="dap">DAP</h4>
<p>An Emacs client for Debugger Adapter Protocol.</p>
<p>Okay, so, I tried to use it many times&hellip; Chrome DevTools and ipdb / pudb are just better for me. Maybe I&rsquo;ll check out RealGUD instead&hellip; Will see.</p>
<p>References:</p>
<ul>
<li><a href="https://emacs-lsp.github.io/dap-mode/">dap-mode homepage</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">dap-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/remote-server</span> <span style="color:#19177c">my/is-termux</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">dap-debug</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-enable-dap-auto-configure</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">dap-ui-variable-length</span> <span style="color:#666">100</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">dap-auto-show-output</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;dap-node</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dap-node-setup</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;dap-chrome</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dap-chrome-setup</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;dap-python</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;dap-php</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dap-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dap-ui-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dap-tooltip-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tooltip-mode</span> <span style="color:#666">1</span>))
</span></span></code></pre></div><h5 id="controls">Controls</h5>
<p>I don&rsquo;t like some keybindings in the built-in hydra, and there seems to be no easy way to modify the existing hydra, so I create my own. I tried to use transient, but the transient buffer seems to conflict with special buffers of DAP, and hydra does not.</p>
<p>Also, I want the hydra to toggle UI windows instead of just opening them, so here is a macro that defines such functions:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;dap-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defmacro</span> <span style="color:#19177c">my/define-dap-ui-window-toggler</span> (<span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#008000">defun</span> <span style="color:#666">,</span>(<span style="color:#00f">intern</span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;my/dap-ui-toggle-&#34;</span> <span style="color:#19177c">name</span>)) ()
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;Toggle DAP &#34;</span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;buffer&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">if-let</span> (<span style="color:#19177c">window</span> (<span style="color:#00f">get-buffer-window</span> <span style="color:#666">,</span>(<span style="color:#00f">intern</span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;dap-ui--&#34;</span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;-buffer&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">quit-window</span> <span style="color:#800">nil</span> <span style="color:#19177c">window</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#00f">intern</span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;dap-ui-&#34;</span> <span style="color:#19177c">name</span>))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/define-dap-ui-window-toggler</span> <span style="color:#ba2121">&#34;locals&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/define-dap-ui-window-toggler</span> <span style="color:#ba2121">&#34;expressions&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/define-dap-ui-window-toggler</span> <span style="color:#ba2121">&#34;sessions&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/define-dap-ui-window-toggler</span> <span style="color:#ba2121">&#34;breakpoints&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/define-dap-ui-window-toggler</span> <span style="color:#ba2121">&#34;repl&#34;</span>))
</span></span></code></pre></div><p>And here is the hydra:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">defhydra</span> <span style="color:#19177c">my/dap-hydra</span> (<span style="color:#008000">:color</span> <span style="color:#19177c">pink</span> <span style="color:#008000">:hint</span> <span style="color:#800">nil</span> <span style="color:#008000">:foreign-keys</span> <span style="color:#19177c">run</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">^Stepping^ ^UI^ ^Switch^ ^Breakpoints^ ^Debug^ ^Expressions
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">^^^^^^^^------------------------------------------------------------------------------------------------------------------------------------------
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">_n_: Next _uc_: Controls _ss_: Session _bb_: Toggle _dd_: Debug _ee_: Eval
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">_i_: Step in _ue_: Expressions _st_: Thread _bd_: Delete _dr_: Debug recent _er_: Eval region
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">_o_: Step out _ul_: Locals _sf_: Stack frame _ba_: Add _dl_: Debug last _es_: Eval thing at point
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">_c_: Continue _ur_: REPL _su_: Up stack frame _bc_: Set condition _de_: Edit debug template _ea_: Add expression
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">_r_: Restart frame _uo_: Output _sd_: Down stack frame _bh_: Set hit count _Q_: Disconnect _ed_: Remove expression
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"> _us_: Sessions _sF_: Stack frame filtered _bl_: Set log message _eu_: Refresh expressions
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"> _ub_: Breakpoints &#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;n&#34;</span> <span style="color:#19177c">dap-next</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;i&#34;</span> <span style="color:#19177c">dap-step-in</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#19177c">dap-step-out</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#19177c">dap-continue</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#19177c">dap-restart-frame</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;uc&#34;</span> <span style="color:#19177c">dap-ui-controls-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ue&#34;</span> <span style="color:#19177c">my/dap-ui-toggle-expressions</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ul&#34;</span> <span style="color:#19177c">my/dap-ui-toggle-locals</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ur&#34;</span> <span style="color:#19177c">my/dap-ui-toggle-repl</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;uo&#34;</span> <span style="color:#19177c">dap-go-to-output-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;us&#34;</span> <span style="color:#19177c">my/dap-ui-toggle-sessions</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ub&#34;</span> <span style="color:#19177c">my/dap-ui-toggle-breakpoints</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ss&#34;</span> <span style="color:#19177c">dap-switch-session</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;st&#34;</span> <span style="color:#19177c">dap-switch-thread</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;sf&#34;</span> <span style="color:#19177c">dap-switch-stack-frame</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;sF&#34;</span> <span style="color:#19177c">my/dap-switch-stack-frame</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;su&#34;</span> <span style="color:#19177c">dap-up-stack-frame</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;sd&#34;</span> <span style="color:#19177c">dap-down-stack-frame</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;bb&#34;</span> <span style="color:#19177c">dap-breakpoint-toggle</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ba&#34;</span> <span style="color:#19177c">dap-breakpoint-add</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;bd&#34;</span> <span style="color:#19177c">dap-breakpoint-delete</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;bc&#34;</span> <span style="color:#19177c">dap-breakpoint-condition</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;bh&#34;</span> <span style="color:#19177c">dap-breakpoint-hit-condition</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;bl&#34;</span> <span style="color:#19177c">dap-breakpoint-log-message</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;dd&#34;</span> <span style="color:#19177c">dap-debug</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;dr&#34;</span> <span style="color:#19177c">dap-debug-recent</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;dl&#34;</span> <span style="color:#19177c">dap-debug-last</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;de&#34;</span> <span style="color:#19177c">dap-debug-edit-template</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ee&#34;</span> <span style="color:#19177c">dap-eval</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ea&#34;</span> <span style="color:#19177c">dap-ui-expressions-add</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;er&#34;</span> <span style="color:#19177c">dap-eval-region</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;es&#34;</span> <span style="color:#19177c">dap-eval-thing-at-point</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ed&#34;</span> <span style="color:#19177c">dap-ui-expressions-remove</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;eu&#34;</span> <span style="color:#19177c">dap-ui-expressions-refresh</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;quit&#34;</span> <span style="color:#008000">:color</span> <span style="color:#19177c">blue</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;Q&#34;</span> <span style="color:#19177c">dap-disconnect</span> <span style="color:#008000">:color</span> <span style="color:#19177c">red</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/dap-hydra/body</span>)
</span></span></code></pre></div><h5 id="ui-fixes">UI Fixes</h5>
<p>There are some problems with DAP UI in my setup.</p>
<p>First, DAP uses Treemacs buffers quite extensively, and they hide the doom modeline for some reason, so I can&rsquo;t tell which buffer is active and can&rsquo;t see borders between buffers.</p>
<p>Second, lines are truncated in some strange way, but calling <code>toggle-truncate-lines</code> seems to fix that.</p>
<p>So I define a macro that creates a function that I can further use in advices.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/dap-mode-buffer-fixed</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;dap-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defmacro</span> <span style="color:#19177c">my/define-dap-tree-buffer-fixer</span> (<span style="color:#19177c">buffer-var</span> <span style="color:#00f">buffer-name</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#008000">defun</span> <span style="color:#666">,</span>(<span style="color:#00f">intern</span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;my/fix-dap-ui-&#34;</span> <span style="color:#00f">buffer-name</span> <span style="color:#ba2121">&#34;-buffer&#34;</span>)) (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">_</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#666">,</span><span style="color:#19177c">buffer-var</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">my/dap-mode-buffer-fixed</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">toggle-truncate-lines</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">doom-modeline-set-modeline</span> <span style="color:#19177c">&#39;info</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">my/dap-mode-buffer-fixed</span> <span style="color:#800">t</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/define-dap-tree-buffer-fixer</span> <span style="color:#19177c">dap-ui--locals-buffer</span> <span style="color:#ba2121">&#34;locals&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/define-dap-tree-buffer-fixer</span> <span style="color:#19177c">dap-ui--expressions-buffer</span> <span style="color:#ba2121">&#34;expressions&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/define-dap-tree-buffer-fixer</span> <span style="color:#19177c">dap-ui--sessions-buffer</span> <span style="color:#ba2121">&#34;sessions&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/define-dap-tree-buffer-fixer</span> <span style="color:#19177c">dap-ui--breakpoints-buffer</span> <span style="color:#ba2121">&#34;breakpoints&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#19177c">&#39;dap-ui-locals</span> <span style="color:#008000">:after</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/fix-dap-ui-locals-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#19177c">&#39;dap-ui-expressions</span> <span style="color:#008000">:after</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/fix-dap-ui-expressions-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#19177c">&#39;dap-ui-sessions</span> <span style="color:#008000">:after</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/fix-dap-ui-sessions-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#19177c">&#39;dap-ui-breakpoints</span> <span style="color:#008000">:after</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/fix-dap-ui-breakpoints-buffer</span>))
</span></span></code></pre></div><h5 id="helper-functions-1">Helper functions</h5>
<p>Some helper functions that make debugging with DAP easier.</p>
<p>DAP seems to mess with window parameters from time to time. This function clears &ldquo;bad&rdquo; window parameters.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/clear-bad-window-parameters</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Clear window parameters that interrupt my workflow.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">window</span> (<span style="color:#00f">get-buffer-window</span> (<span style="color:#00f">current-buffer</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-window-parameter</span> <span style="color:#19177c">window</span> <span style="color:#19177c">&#39;no-delete-other-windows</span> <span style="color:#800">nil</span>)))
</span></span></code></pre></div><p>A function to kill a value from a treemacs node.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dap-yank-value-at-point</span> (<span style="color:#19177c">node</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> (<span style="color:#19177c">treemacs-node-at-point</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">kill-new</span> (<span style="color:#00f">message</span> (<span style="color:#00f">plist-get</span> (<span style="color:#19177c">button-get</span> <span style="color:#19177c">node</span> <span style="color:#008000">:item</span>) <span style="color:#008000">:value</span>))))
</span></span></code></pre></div><p>A function to open a value from a treemacs node in a new buffer.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dap-display-value</span> (<span style="color:#19177c">node</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> (<span style="color:#19177c">treemacs-node-at-point</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">value</span> (<span style="color:#00f">plist-get</span> (<span style="color:#19177c">button-get</span> <span style="color:#19177c">node</span> <span style="color:#008000">:item</span>) <span style="color:#008000">:value</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">value</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">buffer</span> (<span style="color:#19177c">generate-new-buffer</span> <span style="color:#ba2121">&#34;dap-value&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#19177c">value</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">select-window</span> (<span style="color:#19177c">display-buffer</span> <span style="color:#19177c">buffer</span>))))))
</span></span></code></pre></div><h5 id="switch-to-stack-frame-with-filter">Switch to stack frame with filter</h5>
<p>One significant improvement over Chrome Inspector for my particular stack is an ability to filter the stack frame list, for instance, to see only frames that relate to my current project.</p>
<p>So, here are functions that customize the filters:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;dap-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/dap-stack-frame-filters</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#ba2121">&#34;node_modules,node:internal&#34;</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#008000">rx</span> (<span style="color:#008000">or</span> <span style="color:#ba2121">&#34;node_modules&#34;</span> <span style="color:#ba2121">&#34;node:internal&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;node_modules&#34;</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#008000">rx</span> (<span style="color:#008000">or</span> <span style="color:#ba2121">&#34;node_modules&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;node:internal&#34;</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#008000">rx</span> (<span style="color:#008000">or</span> <span style="color:#ba2121">&#34;node:internal&#34;</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/dap-stack-frame-current-filter</span> (<span style="color:#19177c">cdar</span> <span style="color:#19177c">my/dap-stack-frame-filters</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defun</span> <span style="color:#19177c">my/dap-stack-frame-filter-set</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/dap-stack-frame-current-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">assoc</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">completing-read</span> <span style="color:#ba2121">&#34;Filter: &#34;</span> <span style="color:#19177c">my/dap-stack-frame-filters</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/dap-stack-frame-filters</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defun</span> <span style="color:#19177c">my/dap-stack-frame-filter</span> (<span style="color:#19177c">frame</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let</span> (<span style="color:#19177c">path</span> (<span style="color:#19177c">dap--get-path-for-frame</span> <span style="color:#19177c">frame</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#00f">string-match</span> <span style="color:#19177c">my/dap-stack-frame-current-filter</span> <span style="color:#19177c">path</span>)))))
</span></span></code></pre></div><p>And here is a version of <code>dap-switch-stack-frame</code> that uses the said filter.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dap-switch-stack-frame</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Switch stackframe by selecting another stackframe stackframes from current thread.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">dap--cur-session</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">error</span> <span style="color:#ba2121">&#34;There is no active session&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">-if-let</span> (<span style="color:#19177c">thread-id</span> (<span style="color:#19177c">dap--debug-session-thread-id</span> (<span style="color:#19177c">dap--cur-session</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">-if-let</span> (<span style="color:#19177c">stack-frames</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">gethash</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">thread-id</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dap--debug-session-thread-stack-frames</span> (<span style="color:#19177c">dap--cur-session</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">index</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">stack-framces-filtered</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">-filter</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/dap-stack-frame-filter</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">stack-frames</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">new-stack-frame</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dap--completing-read</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Select active frame: &#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">stack-framces-filtered</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">-lambda</span> ((<span style="color:#19177c">frame</span> <span style="color:#19177c">&amp;as</span> <span style="color:#19177c">&amp;hash</span> <span style="color:#ba2121">&#34;name&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">if-let</span> (<span style="color:#19177c">frame-path</span> (<span style="color:#19177c">dap--get-path-for-frame</span> <span style="color:#19177c">frame</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%s: %s (in %s)&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-incf</span> <span style="color:#19177c">index</span>) <span style="color:#19177c">name</span> <span style="color:#19177c">frame-path</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%s: %s&#34;</span> (<span style="color:#008000">cl-incf</span> <span style="color:#19177c">index</span>) <span style="color:#19177c">name</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dap--go-to-stack-frame</span> (<span style="color:#19177c">dap--cur-session</span>) <span style="color:#19177c">new-stack-frame</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">-&gt;&gt;</span> (<span style="color:#19177c">dap--cur-session</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">dap--debug-session-name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;Current session %s is not stopped&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#d2413a;font-weight:bold">error</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">error</span> <span style="color:#ba2121">&#34;No thread is currently active %s&#34;</span> (<span style="color:#19177c">dap--debug-session-name</span> (<span style="color:#19177c">dap--cur-session</span>)))))
</span></span></code></pre></div><h5 id="smarter-switch-to-stack-frame">Smarter switch to stack frame</h5>
<ul>
<li><strong>CREDIT</strong>: Thanks @yyoncho on the Emacs LSP Discord for helping me with this!</li>
</ul>
<p>By default, when a breakpoint is hit, dap always pop us the buffer in the active EXWM workspace and in the active perspective. I&rsquo;d like it to switch to an existing buffer instead.</p>
<p>So first we need to locate EXWM workspace for the file with <code>path</code>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/exwm-perspective-find-buffer</span> (<span style="color:#19177c">path</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Find a buffer with PATH in all EXWM perspectives.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Returns (&lt;buffer&gt; . &lt;workspace-index&gt;) or nil.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">buf</span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">buf</span> <span style="color:#19177c">being</span> <span style="color:#19177c">buffers</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#008000">and</span> (<span style="color:#00f">buffer-file-name</span> <span style="color:#19177c">buf</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">f-equal-p</span> (<span style="color:#00f">buffer-file-name</span> <span style="color:#19177c">buf</span>) <span style="color:#19177c">path</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">return</span> <span style="color:#19177c">buf</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">target-workspace</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span> <span style="color:#19177c">buf</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">frame</span> <span style="color:#19177c">in</span> <span style="color:#19177c">exwm-workspace--list</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#008000">with-selected-frame</span> <span style="color:#19177c">frame</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">persp-name</span> <span style="color:#19177c">being</span> <span style="color:#19177c">the</span> <span style="color:#19177c">hash-keys</span> <span style="color:#19177c">of</span> (<span style="color:#19177c">perspectives-hash</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#00f">member</span> <span style="color:#19177c">buf</span> (<span style="color:#19177c">persp-buffers</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">gethash</span> <span style="color:#19177c">persp-name</span> (<span style="color:#19177c">perspectives-hash</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#008000">return</span> <span style="color:#19177c">persp-name</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">return</span> (<span style="color:#19177c">cl-position</span> <span style="color:#19177c">frame</span> <span style="color:#19177c">exwm-workspace--list</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">target-workspace</span> (<span style="color:#00f">cons</span> <span style="color:#19177c">buf</span> <span style="color:#19177c">target-workspace</span>))))
</span></span></code></pre></div><p>And override <code>dap--go-to-stack-frame</code> to take that into account. For some reason, evaluating this before <code>dap-mode</code> doesn&rsquo;t work.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dap--go-to-stack-frame-override</span> (<span style="color:#19177c">debug-session</span> <span style="color:#19177c">stack-frame</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Make STACK-FRAME the active STACK-FRAME of DEBUG-SESSION.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">with-lsp-workspace</span> (<span style="color:#19177c">dap--debug-session-workspace</span> <span style="color:#19177c">debug-session</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">stack-frame</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">-let*</span> (((<span style="color:#19177c">&amp;hash</span> <span style="color:#ba2121">&#34;line&#34;</span> <span style="color:#19177c">line</span> <span style="color:#ba2121">&#34;column&#34;</span> <span style="color:#19177c">column</span> <span style="color:#ba2121">&#34;name&#34;</span> <span style="color:#19177c">name</span>) <span style="color:#19177c">stack-frame</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">path</span> (<span style="color:#19177c">dap--get-path-for-frame</span> <span style="color:#19177c">stack-frame</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">dap--debug-session-active-frame</span> <span style="color:#19177c">debug-session</span>) <span style="color:#19177c">stack-frame</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; If we have a source file with path attached, open it and</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; position the point in the line/column referenced in the</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; stack trace.</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">and</span> <span style="color:#19177c">path</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">path</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">exwm-target</span> (<span style="color:#19177c">my/exwm-perspective-find-buffer</span> <span style="color:#19177c">path</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">exwm-target</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">=</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">exwm-target</span>) <span style="color:#19177c">exwm-workspace-current-index</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">exwm-workspace-switch</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">exwm-target</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">persp-switch-to-buffer</span> (<span style="color:#00f">car</span> <span style="color:#19177c">exwm-target</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">select-window</span> (<span style="color:#19177c">get-mru-window</span> (<span style="color:#00f">selected-frame</span>) <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">find-file</span> <span style="color:#19177c">path</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-min</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">forward-line</span> (<span style="color:#00f">1-</span> <span style="color:#19177c">line</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">forward-char</span> <span style="color:#19177c">column</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;No source code for %s. Cursor at %s:%s.&#34;</span> <span style="color:#19177c">name</span> <span style="color:#19177c">line</span> <span style="color:#19177c">column</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">run-hook-with-args</span> <span style="color:#19177c">&#39;dap-stack-frame-changed-hook</span> <span style="color:#19177c">debug-session</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;exwm</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;dap-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dap--go-to-stack-frame</span> <span style="color:#008000">:override</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/dap--go-to-stack-frame-override</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (advice-remove #&#39;dap--go-to-stack-frame #&#39;my/dap--go-to-stack-frame-override)</span>
</span></span></code></pre></div><h5 id="debug-templates">Debug templates</h5>
<p>Some debug templates I frequently use.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;dap-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dap-register-debug-template</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Node::Nest.js&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> <span style="color:#008000">:type</span> <span style="color:#ba2121">&#34;node&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:request</span> <span style="color:#ba2121">&#34;attach&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:name</span> <span style="color:#ba2121">&#34;Node::Attach&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:port</span> <span style="color:#666">9229</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:outFiles</span> [<span style="color:#ba2121">&#34;${workspaceFolder}/dist/**/*.js&#34;</span>]
</span></span><span style="display:flex;"><span> <span style="color:#008000">:sourceMaps</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:program</span> <span style="color:#ba2121">&#34;${workspaceFolder}/src/app.ts&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dap-register-debug-template</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Node::Babel&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> <span style="color:#008000">:type</span> <span style="color:#ba2121">&#34;node&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:request</span> <span style="color:#ba2121">&#34;attach&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:name</span> <span style="color:#ba2121">&#34;Node::Attach&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:port</span> <span style="color:#666">9229</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:program</span> <span style="color:#ba2121">&#34;${workspaceFolder}/dist/bin/www.js&#34;</span>)))
</span></span></code></pre></div><h4 id="reformatter">Reformatter</h4>
<p>A general-purpose package to run formatters on files. While the most popular formatters are already packaged for Emacs, those that aren&rsquo;t can be invoked with this package.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">reformatter</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h4 id="copilot">copilot</h4>
<p><a href="https://copilot.github.com/">GitHub Copilot</a> is a project of GitHub and OpenAI that provides code completions. It&rsquo;s somewhat controversial in the Emacs community but I opt in for now.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/copilot-tab</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">copilot-accept-completion</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">my/should-run-emmet-p</span>) (<span style="color:#19177c">my/emmet-or-tab</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">and</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">evil-state</span> <span style="color:#19177c">&#39;normal</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> <span style="color:#19177c">hs-minor-mode</span> <span style="color:#19177c">treesit-fold-mode</span> <span style="color:#19177c">outline-minor-mode</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-toggle-fold</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">indent-for-tab-command</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">copilot</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;copilot-emacs/copilot.el&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">copilot-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;emacs-startup-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;prog-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">copilot-mode</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">copilot</span>) <span style="color:#19177c">warning-suppress-types</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">copilot-node-executable</span> <span style="color:#ba2121">&#34;/home/pavel/.guix-extra-profiles/dev/dev/bin/node&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;company-active-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;backtab&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/copilot-tab</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;copilot-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;tab&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/copilot-tab</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-j&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">copilot-accept-completion-by-line</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-l&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">copilot-accept-completion-by-word</span>))
</span></span></code></pre></div><h3 id="web-development">Web development</h3>
<p>Configs for various web development technologies I&rsquo;m using.</p>
<h4 id="emmet">Emmet</h4>
<p><a href="//emmet.io/">Emmet</a> is a toolkit which greatly speeds up typing HTML &amp; CSS.</p>
<table>
<thead>
<tr>
<th>Type</th>
<th>Note</th>
</tr>
</thead>
<tbody>
<tr>
<td>TODO</td>
<td>make expand div[disabled] as &lt;div disabled&gt;&lt;/div&gt;</td>
</tr>
</tbody>
</table>
<p>My bit of config here:</p>
<ul>
<li>makes <code>TAB</code> the only key I have to use</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/should-run-emmet-p</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span> (<span style="color:#19177c">bound-and-true-p</span> <span style="color:#19177c">emmet-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#008000">and</span> (<span style="color:#19177c">derived-mode-p</span> <span style="color:#19177c">&#39;web-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">member</span> (<span style="color:#19177c">web-mode-language-at-pos</span>) <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;html&#34;</span> <span style="color:#ba2121">&#34;css&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">derived-mode-p</span> <span style="color:#19177c">&#39;web-mode</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">emmet-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> ((<span style="color:#19177c">vue-html-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">emmet-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">svelte-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">emmet-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">web-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">emmet-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">html-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">emmet-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">css-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">emmet-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">scss-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">emmet-mode</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defun</span> <span style="color:#19177c">my/emmet-or-tab</span> (<span style="color:#008000">&amp;optional</span> <span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">my/should-run-emmet-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">emmet-expand-line</span> <span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">emmet-go-to-edit-point</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">indent-for-tab-command</span> <span style="color:#19177c">arg</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">indent-for-tab-command</span> <span style="color:#19177c">arg</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-imap</span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;emmet-mode-keymap</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;TAB&#34;</span> <span style="color:#19177c">&#39;my/emmet-or-tab</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;backtab&gt;&#34;</span> <span style="color:#19177c">&#39;emmet-prev-edit-point</span>))
</span></span></code></pre></div><h4 id="prettier">Prettier</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">prettier</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">prettier-prettify</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">js-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">web-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">typescript-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">typescript-ts-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">vue-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">svelte-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;rr&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">prettier-prettify</span>))
</span></span></code></pre></div><h4 id="typescript">TypeScript</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">typescript-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.ts\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;typescript-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;typescript-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">rainbow-delimiters-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;typescript-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">treesit-fold-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">&#39;typescript-mode</span>))
</span></span></code></pre></div><h4 id="javascript">JavaScript</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;js-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;js-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">treesit-fold-mode</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">&#39;js-mode</span>)
</span></span></code></pre></div><h4 id="jest">Jest</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">jest-test-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> ((<span style="color:#19177c">typescript-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">jest-test-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">js-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">jest-test-mode</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;jest-test-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;t&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;t&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">jest-test-run-at-point</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">jest-test-debug-run-at-point</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">jest-test-run</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;a&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">jest-test-run-all-tests</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defmacro</span> <span style="color:#19177c">my/jest-test-with-debug-flags</span> (<span style="color:#19177c">form</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Execute FORM with debugger flags set.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">declare</span> (<span style="color:#19177c">indent</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#008000">let</span> ((<span style="color:#19177c">jest-test-options</span> (<span style="color:#19177c">seq-concatenate</span> <span style="color:#19177c">&#39;list</span> <span style="color:#19177c">jest-test-options</span> (<span style="color:#00f">list</span> <span style="color:#ba2121">&#34;--runInBand&#34;</span>) ))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">jest-test-npx-options</span> (<span style="color:#19177c">seq-concatenate</span> <span style="color:#19177c">&#39;list</span> <span style="color:#19177c">jest-test-npx-options</span> (<span style="color:#00f">list</span> <span style="color:#ba2121">&#34;--node-options&#34;</span> <span style="color:#ba2121">&#34;--inspect-brk&#34;</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span><span style="color:#19177c">form</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defun</span> <span style="color:#19177c">my/jest-test-debug</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Run the test with an inline debugger attached.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/jest-test-with-debug-flags</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">jest-test-run</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defun</span> <span style="color:#19177c">my/jest-test-debug-rerun-test</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Run the test with an inline debugger attached.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/jest-test-with-debug-flags</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">jest-test-rerun-test</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defun</span> <span style="color:#19177c">my/jest-test-debug-run-at-point</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Run the test with an inline debugger attached.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/jest-test-with-debug-flags</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">jest-test-run-at-point</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">jest-test-debug</span> <span style="color:#008000">:override</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/jest-test-debug</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">jest-test-debug-rerun-test</span> <span style="color:#008000">:override</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/jest-test-debug-rerun-test</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">jest-test-debug-run-at-point</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:override</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/jest-test-debug-run-at-point</span>))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/jest-test-run-at-point-copy</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Run the top level describe block of the current buffer&#39;s point.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">filename</span> (<span style="color:#19177c">jest-test-find-file</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">example</span> (<span style="color:#19177c">jest-test-unit-at-point</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">and</span> <span style="color:#19177c">filename</span> <span style="color:#19177c">example</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">jest-test-from-project-directory</span> <span style="color:#19177c">filename</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">jest-test-options</span> (<span style="color:#19177c">seq-concatenate</span> <span style="color:#19177c">&#39;list</span> <span style="color:#19177c">jest-test-options</span> (<span style="color:#00f">list</span> <span style="color:#ba2121">&#34;-t&#34;</span> <span style="color:#19177c">example</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">kill-new</span> (<span style="color:#19177c">jest-test-command</span> <span style="color:#19177c">filename</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#19177c">jest-test-not-found-message</span>))))
</span></span></code></pre></div><h4 id="web-mode">web-mode</h4>
<p><a href="https://web-mode.org/">web-mode.el</a> is a major mode to edit various web templates.</p>
<p>Trying this one out instead of vue-mode and svelte-mode, because this one seems to have better support for tree-sitter and generally less problems.</p>
<p>Set <code>web-mode-auto-pairs</code> not <code>nil</code> because smartparens already fulfills that role.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">web-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">web-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;auto-mode-alist</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;\\.svelte\\&#39;&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">web-mode</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;auto-mode-alist</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;\\.vue\\&#39;&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">web-mode</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;web-mode-hook</span> <span style="color:#19177c">&#39;smartparens-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;web-mode-hook</span> <span style="color:#19177c">&#39;hs-minor-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">&#39;web-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;editorconfig</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;standard-indent</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;web-mode</span> <span style="color:#19177c">editorconfig-indentation-alist</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">web-mode-auto-pairs</span> <span style="color:#800">nil</span>))
</span></span></code></pre></div><p>Hooking this up with lsp.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/web-mode-lsp-extensions</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,</span>(<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;.svelte&#34;</span> <span style="color:#19177c">eos</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;.vue&#34;</span> <span style="color:#19177c">eos</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/web-mode-lsp</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">seq-some</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">regex</span>) (<span style="color:#19177c">string-match-p</span> <span style="color:#19177c">regex</span> (<span style="color:#00f">buffer-file-name</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/web-mode-lsp-extensions</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">lsp-deferred</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;web-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/web-mode-lsp</span>)
</span></span></code></pre></div><p>Vue settings</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/web-mode-vue-setup</span> (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">_</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">filename</span> (<span style="color:#00f">buffer-file-name</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">and</span> (<span style="color:#00f">stringp</span> <span style="color:#19177c">filename</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;.vue&#34;</span> <span style="color:#19177c">eos</span>) <span style="color:#19177c">filename</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">web-mode-script-padding</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">web-mode-style-padding</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">create-lockfiles</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">web-mode-enable-auto-pairing</span> <span style="color:#800">nil</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;web-mode-hook</span> <span style="color:#19177c">&#39;my/web-mode-vue-setup</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;editorconfig-after-apply-functions</span> <span style="color:#19177c">&#39;my/web-mode-vue-setup</span>)
</span></span></code></pre></div><h4 id="scss">SCSS</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;scss-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;scss-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">hs-minor-mode</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">&#39;scss-mode</span>)
</span></span></code></pre></div><h4 id="php">PHP</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">php-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.php\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;php-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;php-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">lsp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">&#39;php-mode</span>))
</span></span></code></pre></div><h3 id="latex">LaTeX</h3>
<h4 id="auctex">AUCTeX</h4>
<p>The best LaTeX editing environment I&rsquo;ve found so far.</p>
<p>References:</p>
<ul>
<li><a href="https://www.gnu.org/software/auctex/">AUCTeX homepage</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">tex</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#19177c">auctex</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:defer</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-default</span> <span style="color:#19177c">TeX-auto-save</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-default</span> <span style="color:#19177c">TeX-parse-self</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">TeX-PDF-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Use XeLaTeX &amp; stuff</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-default</span> <span style="color:#19177c">TeX-engine</span> <span style="color:#19177c">&#39;xetex</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-default</span> <span style="color:#19177c">TeX-command-extra-options</span> <span style="color:#ba2121">&#34;-shell-escape&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-default</span> <span style="color:#19177c">TeX-source-correlate-method</span> <span style="color:#19177c">&#39;synctex</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">TeX-source-correlate-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-default</span> <span style="color:#19177c">TeX-source-correlate-start-server</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-default</span> <span style="color:#19177c">LaTeX-math-menu-unicode</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-default</span> <span style="color:#19177c">font-latex-fontify-sectioning</span> <span style="color:#666">1.3</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Scale preview for my DPI</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-default</span> <span style="color:#19177c">preview-scale-function</span> <span style="color:#666">1.4</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">boundp</span> <span style="color:#19177c">&#39;tex--prettify-symbols-alist</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">assoc-delete-all</span> <span style="color:#ba2121">&#34;--&#34;</span> <span style="color:#19177c">tex--prettify-symbols-alist</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">assoc-delete-all</span> <span style="color:#ba2121">&#34;---&#34;</span> <span style="color:#19177c">tex--prettify-symbols-alist</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;LaTeX-mode-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">TeX-fold-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">outline-minor-mode</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;TeX-view-program-selection</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">output-pdf</span> <span style="color:#ba2121">&#34;Zathura&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Do not run lsp within templated TeX files</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;LaTeX-mode-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">string-match</span> <span style="color:#ba2121">&#34;\.hogan\.tex$&#34;</span> (<span style="color:#00f">buffer-name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">lsp</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">lsp-diagnostic-package</span> <span style="color:#008000">:none</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">flycheck-checker</span> <span style="color:#19177c">&#39;tex-chktex</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;LaTeX-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">rainbow-delimiters-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;LaTeX-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;LaTeX-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">prettify-symbols-mode</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">&#39;LaTeX-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;smartparens-latex</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-nmap</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">LaTeX-mode-map</span> <span style="color:#19177c">latex-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;RET&#34;</span> <span style="color:#19177c">&#39;TeX-command-run-all</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c t&#34;</span> <span style="color:#19177c">&#39;orgtbl-mode</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&lt;&lt;init-greek-latex-snippets&gt;&gt;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&lt;&lt;init-english-latex-snippets&gt;&gt;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&lt;&lt;init-math-latex-snippets&gt;&gt;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&lt;&lt;init-section-latex-snippets&gt;&gt;</span>)
</span></span></code></pre></div><h4 id="import-dot-sty">Import *.sty</h4>
<p>A function to import <code>.sty</code> files to the LaTeX document.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/list-sty</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#00f">reverse</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">sort</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>) (<span style="color:#008000">if</span> (<span style="color:#00f">string-match</span> <span style="color:#ba2121">&#34;.*\.sty$&#34;</span> <span style="color:#19177c">file</span>) <span style="color:#666">1</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-files</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-some</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">dir</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">and</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">f-directory-p</span> <span style="color:#19177c">dir</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-some</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>) (<span style="color:#00f">string-match</span> <span style="color:#ba2121">&#34;.*\.sty$&#34;</span> <span style="color:#19177c">file</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-files</span> <span style="color:#19177c">dir</span>))
</span></span><span style="display:flex;"><span> ) <span style="color:#19177c">dir</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> <span style="color:#ba2121">&#34;./styles&#34;</span> <span style="color:#ba2121">&#34;../styles/&#34;</span> <span style="color:#ba2121">&#34;.&#34;</span> <span style="color:#ba2121">&#34;..&#34;</span>)) <span style="color:#008000">:full</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f1</span> <span style="color:#19177c">f2</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">f1b</span> (<span style="color:#19177c">file-name-base</span> <span style="color:#19177c">f1</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">f1b</span> (<span style="color:#19177c">file-name-base</span> <span style="color:#19177c">f2</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;.*BibTex&#34;</span> <span style="color:#19177c">f1</span>) <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">and</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;.*Locale&#34;</span> <span style="color:#19177c">f1</span>) (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;.*BibTex&#34;</span> <span style="color:#19177c">f2</span>))) <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;.*Preamble&#34;</span> <span style="color:#19177c">f2</span>) <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> (<span style="color:#00f">string-lessp</span> <span style="color:#19177c">f1</span> <span style="color:#19177c">f2</span>))))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/import-sty</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#00f">#&#39;concat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>) (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;\\usepackage{&#34;</span> (<span style="color:#19177c">file-name-sans-extension</span> (<span style="color:#19177c">file-relative-name</span> <span style="color:#19177c">file</span> <span style="color:#19177c">default-directory</span>)) <span style="color:#ba2121">&#34;}\n&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/list-sty</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/import-sty-org</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#00f">#&#39;concat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>) (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;#+LATEX_HEADER: \\usepackage{&#34;</span> (<span style="color:#19177c">file-name-sans-extension</span> (<span style="color:#19177c">file-relative-name</span> <span style="color:#19177c">file</span> <span style="color:#19177c">default-directory</span>)) <span style="color:#ba2121">&#34;}\n&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/list-sty</span>)))))
</span></span></code></pre></div><h4 id="snippets-1">Snippets</h4>
<table>
<thead>
<tr>
<th>Note</th>
<th>Type</th>
</tr>
</thead>
<tbody>
<tr>
<td>TODO</td>
<td>Move yasnippet snippets here? Maybe extract to a separate file?</td>
</tr>
</tbody>
</table>
<h5 id="greek-letters">Greek letters</h5>
<p>Autogenerate snippets for greek letters. I have a few blocks like this because it&rsquo;s faster &amp; more flexible than usual yasnippet snippets.</p>
<p>Noweb points to the AUCTeX config block.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/greek-alphabet</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#ba2121">&#34;a&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\alpha&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;b&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\beta&#34;</span> )
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;g&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\gamma&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\delta&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;e&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\epsilon&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;z&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\zeta&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;h&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\eta&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\theta&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;i&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\iota&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;k&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\kappa&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;l&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\lambda&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;m&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\mu&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;n&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\nu&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;x&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\xi&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;p&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\pi&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\rho&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\sigma&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;t&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\tau&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;u&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\upsilon&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\phi&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\chi&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;v&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\psi&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;g&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\omega&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/latex-greek-prefix</span> <span style="color:#ba2121">&#34;&#39;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; The same for capitalized letters</span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">dolist</span> (<span style="color:#19177c">elem</span> <span style="color:#19177c">my/greek-alphabet</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">key</span> (<span style="color:#00f">car</span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">value</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">elem</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">string-equal</span> <span style="color:#19177c">key</span> (<span style="color:#00f">downcase</span> <span style="color:#19177c">key</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;my/greek-alphabet</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">capitalize</span> (<span style="color:#00f">car</span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span> <span style="color:#19177c">value</span> <span style="color:#666">0</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">capitalize</span> (<span style="color:#00f">substring</span> <span style="color:#19177c">value</span> <span style="color:#666">1</span> <span style="color:#666">2</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span> <span style="color:#19177c">value</span> <span style="color:#666">2</span>)))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">yas-define-snippets</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;latex-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">my/latex-greek-prefix</span> (<span style="color:#00f">car</span> <span style="color:#19177c">elem</span>)) (<span style="color:#00f">cdr</span> <span style="color:#19177c">elem</span>) (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;Greek letter &#34;</span> (<span style="color:#00f">car</span> <span style="color:#19177c">elem</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/greek-alphabet</span>))
</span></span></code></pre></div><h5 id="english-letters">English letters</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/english-alphabet</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;a&#34;</span> <span style="color:#ba2121">&#34;b&#34;</span> <span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#ba2121">&#34;e&#34;</span> <span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#ba2121">&#34;g&#34;</span> <span style="color:#ba2121">&#34;h&#34;</span> <span style="color:#ba2121">&#34;i&#34;</span> <span style="color:#ba2121">&#34;j&#34;</span> <span style="color:#ba2121">&#34;k&#34;</span> <span style="color:#ba2121">&#34;l&#34;</span> <span style="color:#ba2121">&#34;m&#34;</span> <span style="color:#ba2121">&#34;n&#34;</span> <span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#ba2121">&#34;p&#34;</span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#ba2121">&#34;t&#34;</span> <span style="color:#ba2121">&#34;u&#34;</span> <span style="color:#ba2121">&#34;v&#34;</span> <span style="color:#ba2121">&#34;w&#34;</span> <span style="color:#ba2121">&#34;x&#34;</span> <span style="color:#ba2121">&#34;y&#34;</span> <span style="color:#ba2121">&#34;z&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">dolist</span> (<span style="color:#19177c">elem</span> <span style="color:#19177c">my/english-alphabet</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">string-equal</span> <span style="color:#19177c">elem</span> (<span style="color:#00f">downcase</span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;my/english-alphabet</span> (<span style="color:#00f">upcase</span> <span style="color:#19177c">elem</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/latex-mathbb-prefix</span> <span style="color:#ba2121">&#34;`&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">yas-define-snippets</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;latex-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">my/latex-mathbb-prefix</span> <span style="color:#19177c">elem</span>) (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;\\mathbb{&#34;</span> <span style="color:#19177c">elem</span> <span style="color:#ba2121">&#34;}&#34;</span>) (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;Mathbb letter &#34;</span> <span style="color:#19177c">elem</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/english-alphabet</span>))
</span></span></code></pre></div><h5 id="math-symbols">Math symbols</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/latex-math-symbols</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#ba2121">&#34;x&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\times&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;.&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\cdot&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;v&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\forall&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\sum_{$1}^{$2}$0&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;p&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\prod_{$1}^{$2}$0&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\partial&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;e&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\exists&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;i&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\int_{$1}^{$2}$0&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\cap&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;u&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\cup&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;0&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\emptyset&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;^&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\widehat{$1}$0&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;_&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\overline{$1}$0&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;~&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\sim&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;|&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\mid&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;_|&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\perp&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/latex-math-prefix</span> <span style="color:#ba2121">&#34;;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">yas-define-snippets</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;latex-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">key</span> (<span style="color:#00f">car</span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">value</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">elem</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">my/latex-math-prefix</span> <span style="color:#19177c">key</span>) <span style="color:#19177c">value</span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;Math symbol &#34;</span> <span style="color:#19177c">value</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/latex-math-symbols</span>))
</span></span></code></pre></div><h5 id="section-snippets">Section snippets</h5>
<p>Section snippets. The code turned out to be more complicated than just writing the snippets by hand.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/latex-section-snippets</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#ba2121">&#34;ch&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\chapter{$1}&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;sec&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\section{$1}&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ssec&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\subsection{$1}&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;sssec&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\subsubsection{$1}&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;par&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\paragraph{$1}}&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/latex-section-snippets</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,</span>(<span style="color:#00f">car</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">cdr</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">string-match</span> <span style="color:#ba2121">&#34;[a-z]+&#34;</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">match-string</span> <span style="color:#666">0</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">elem</span>)))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/latex-section-snippets</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">dolist</span> (<span style="color:#19177c">elem</span> <span style="color:#19177c">my/latex-section-snippets</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">key</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">value</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">desc</span> (<span style="color:#00f">nth</span> <span style="color:#666">2</span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">star-index</span> (<span style="color:#00f">string-match</span> <span style="color:#ba2121">&#34;\{\$1\}&#34;</span> <span style="color:#19177c">value</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;my/latex-section-snippets</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,</span>(<span style="color:#00f">concat</span> <span style="color:#19177c">key</span> <span style="color:#ba2121">&#34;*&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span> <span style="color:#19177c">value</span> <span style="color:#666">0</span> <span style="color:#19177c">star-index</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;*&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span> <span style="color:#19177c">value</span> <span style="color:#19177c">star-index</span>))
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">concat</span> <span style="color:#19177c">desc</span> <span style="color:#ba2121">&#34; with *&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;my/latex-section-snippets</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,</span>(<span style="color:#00f">concat</span> <span style="color:#19177c">key</span> <span style="color:#ba2121">&#34;l&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">concat</span> <span style="color:#19177c">value</span> <span style="color:#ba2121">&#34;%\n\\label{sec:$2}&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">concat</span> <span style="color:#19177c">desc</span> <span style="color:#ba2121">&#34; with label&#34;</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">dolist</span> (<span style="color:#19177c">elem</span> <span style="color:#19177c">my/latex-section-snippets</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">elem</span>) (<span style="color:#00f">concat</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">elem</span>) <span style="color:#ba2121">&#34;\n$0&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">yas-define-snippets</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;latex-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/latex-section-snippets</span>)
</span></span></code></pre></div><h3 id="markup-and-natural-languages">Markup &amp; natural languages</h3>
<h4 id="markdown">Markdown</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">markdown-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.md\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">markdown-command</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;pandoc&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34; --from=markdown --to=html&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34; --standalone --mathjax --highlight-style=pygments&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34; --css=pandoc.css&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34; --quiet&#34;</span>
</span></span><span style="display:flex;"><span> ))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">markdown-live-preview-delete-export</span> <span style="color:#19177c">&#39;delete-on-export</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">markdown-asymmetric-header</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">markdown-open-command</span> <span style="color:#ba2121">&#34;/home/pavel/bin/scripts/chromium-sep&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;markdown-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;markdown-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-&lt;left&gt;&#34;</span> <span style="color:#19177c">&#39;markdown-promote</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-&lt;right&gt;&#34;</span> <span style="color:#19177c">&#39;markdown-demote</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (use-package livedown</span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; :straight (:host github :repo &#34;shime/emacs-livedown&#34;)</span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; :commands livedown-preview</span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; :config</span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (setq livedown-browser &#34;qutebrowser&#34;))</span>
</span></span></code></pre></div><h4 id="ascii-doc">Ascii Doc</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">adoc-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> (<span style="color:#008000">rx</span> (<span style="color:#19177c">|</span> <span style="color:#ba2121">&#34;.asciidoc&#34;</span>) <span style="color:#19177c">eos</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h4 id="plantuml">PlantUML</h4>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>plantuml</td>
</tr>
</tbody>
</table>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">plantuml-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;(\\.\\(plantuml?\\|uml\\|puml\\)\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">plantuml-executable-path</span> <span style="color:#ba2121">&#34;/home/pavel/.guix-extra-profiles/emacs/emacs/bin/plantuml&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">plantuml-default-exec-mode</span> <span style="color:#19177c">&#39;executable</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">plantuml-indent-level</span> <span style="color:#666">2</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/plantuml-indent-regexp-return</span> <span style="color:#ba2121">&#34;^\s*return\s+.+$&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#408080;font-style:italic">;; (add-to-list</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; &#39;plantuml-indent-regexp-end</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; my/plantuml-indent-regexp-return)</span>
</span></span><span style="display:flex;"><span> )
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;auto-mode-alist</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;\\.plantuml\\&#39;&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">plantuml-mode</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;auto-mode-alist</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;\\.uml\\&#39;&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">plantuml-mode</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;plantuml-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-nmap</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;plantuml-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;RET&#34;</span> <span style="color:#19177c">&#39;plantuml-preview</span>))
</span></span></code></pre></div><h4 id="subtitles">Subtitles</h4>
<p>A major mode to work with subtitles.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">subed</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;rndusr/subed&#34;</span> <span style="color:#008000">:files</span> (<span style="color:#ba2121">&#34;subed/*.el&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:build</span> (<span style="color:#008000">:not</span> <span style="color:#19177c">native-compile</span>))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (cons (rx (| &#34;srt&#34; &#34;vtt&#34; &#34;ass&#34;) eos) #&#39;subed-mode)</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> (<span style="color:#ba2121">&#34;\\(?:ass\\|\\(?:sr\\|vt\\)t\\)\\&#39;&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">subed-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">subed-mode-map</span> <span style="color:#19177c">subed-vtt-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gp&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">subed-mpv-toggle-pause</span>))
</span></span></code></pre></div><h4 id="ltex">LTeX</h4>
<p><a href="https://github.com/valentjn/ltex-ls">ltex-ls</a> is a tool that wraps LanguageTool into a language server.</p>
<p>It takes maybe 10 seconds to run on my Master&rsquo;s thesis file (<code>M-x count words</code>: 13453 words and 117566 characters), but it&rsquo;s totally worth it. And it&rsquo;s much faster on smaller files. The good thing is that it supports markup syntaxes like Org and Markdown, whereas LanguageTool by itself produces a lot of false positives on these files.</p>
<p>It shouldn&rsquo;t be too hard to package that for guix, but I&rsquo;ve installed the nix version for now.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">lsp-ltex</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">lsp</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-ltex-version</span> <span style="color:#ba2121">&#34;15.2.0&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-ltex-check-frequency</span> <span style="color:#ba2121">&#34;save&#34;</span>))
</span></span></code></pre></div><p>A function to switch the current language.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ltex-lang</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-ltex-language</span> (<span style="color:#00f">completing-read</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Language: &#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;en-GB&#34;</span> <span style="color:#ba2121">&#34;ru-RU&#34;</span> <span style="color:#ba2121">&#34;de-DE&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">lsp-workspace-restart</span> (<span style="color:#19177c">lsp--read-workspace</span>)))
</span></span></code></pre></div><p>Check whether it&rsquo;s necessary to run LTeX:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ltex-need-p</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">file-name</span> (<span style="color:#00f">buffer-file-name</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/is-termux</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">null</span> <span style="color:#19177c">file-name</span>) <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;/home/pavel/&#34;</span> (<span style="color:#00f">+</span> <span style="color:#19177c">alnum</span>) <span style="color:#ba2121">&#34;.org&#34;</span> <span style="color:#19177c">eos</span>) <span style="color:#19177c">file-name</span>) <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> (<span style="color:#19177c">literal</span> <span style="color:#19177c">org-directory</span>) <span style="color:#ba2121">&#34;/&#34;</span> (<span style="color:#008000">or</span> <span style="color:#ba2121">&#34;roam&#34;</span> <span style="color:#ba2121">&#34;inbox-notes&#34;</span> <span style="color:#ba2121">&#34;literature-notes&#34;</span> <span style="color:#ba2121">&#34;journal&#34;</span>)) <span style="color:#19177c">file-name</span>) <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> (<span style="color:#19177c">literal</span> <span style="color:#19177c">org-directory</span>)) <span style="color:#19177c">file-name</span>) <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> (<span style="color:#19177c">literal</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#19177c">user-emacs-directory</span>))) <span style="color:#19177c">file-name</span>) <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> <span style="color:#800">t</span>))))
</span></span></code></pre></div><p>To use it in <code>text-mode-hook</code></p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/text-mode-lsp-maybe</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">my/ltex-need-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">lsp</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (add-hook &#39;text-mode-hook #&#39;my/text-mode-lsp-maybe)</span>
</span></span></code></pre></div><h4 id="languagetool">LanguageTool</h4>
<p>LanguageTool is a great offline spell checker. For some reason, the download link is nowhere to be found on the home page, so it is listed in the references as well.</p>
<p>References:</p>
<ul>
<li><a href="https://languagetool.org/">LanguageTool homepage</a></li>
<li><a href="https://dev.languagetool.org/http-server">LanguageTool http server</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">langtool</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">langtool-check</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">langtool-language-tool-server-jar</span> <span style="color:#ba2121">&#34;/home/pavel/bin/LanguageTool-6.4/languagetool-server.jar&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">langtool-mother-tongue</span> <span style="color:#ba2121">&#34;ru&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">langtool-default-language</span> <span style="color:#ba2121">&#34;ru-RU&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;L&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;languagetool&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#19177c">&#39;langtool-check</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#19177c">&#39;langtool-server-stop</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#19177c">&#39;langtool-check-done</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;n&#34;</span> <span style="color:#19177c">&#39;langtool-goto-next-error</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;p&#34;</span> <span style="color:#19177c">&#39;langtool-goto-previous-error</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;l&#34;</span> <span style="color:#19177c">&#39;langtool-correct-buffer</span>)
</span></span></code></pre></div><h4 id="reverso">Reverso</h4>
<p><a href="https://github.com/SqrtMinusOne/reverso.el">reverso.el</a> is a package of mine that provides Emacs interface for <a href="https://reverso.net">https://reverso.net</a>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">reverso</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;SqrtMinusOne/reverso.el&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ar&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">reverso</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">reverso</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">reverso-languages</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">russian</span> <span style="color:#19177c">english</span> <span style="color:#19177c">german</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">reverso-history-mode</span>))
</span></span></code></pre></div><h3 id="lisp">Lisp</h3>
<figure><img src="/ox-hugo/lisp_cycles.png">
</figure>
<h4 id="meta-lisp">Meta Lisp</h4>
<p>Some packages for editing various Lisps.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">lispy</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">lispy-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">lispyville</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> (<span style="color:#19177c">lispy-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">lispyville-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">sp-with-modes</span> <span style="color:#19177c">sp-lisp-modes</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">sp-local-pair</span> <span style="color:#ba2121">&#34;&#39;&#34;</span> <span style="color:#800">nil</span> <span style="color:#008000">:actions</span> <span style="color:#800">nil</span>))
</span></span></code></pre></div><h4 id="emacs-lisp">Emacs Lisp</h4>
<h5 id="package-lint">Package Lint</h5>
<p>A package that checks for the metadata in Emacs Lisp packages.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">flycheck-package</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:defer</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defun</span> <span style="color:#19177c">my/flycheck-package-setup</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;flycheck-package</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">flycheck-package-setup</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">remove-hook</span> <span style="color:#19177c">&#39;emacs-lisp-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/flycheck-package-setup</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;emacs-lisp-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/flycheck-package-setup</span>))
</span></span></code></pre></div><h5 id="general-settings-2">General settings</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;emacs-lisp-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">aggressive-indent-mode</span>)
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (add-hook &#39;emacs-lisp-mode-hook #&#39;smartparens-strict-mode)</span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;emacs-lisp-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">lispy-mode</span>)
</span></span></code></pre></div><h5 id="helper-functions-2">Helper functions</h5>
<p>Remove all advice from function. Source: <a href="https://emacs.stackexchange.com/questions/24657/unadvise-a-function-remove-all-advice-from-it">https://emacs.stackexchange.com/questions/24657/unadvise-a-function-remove-all-advice-from-it</a></p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">advice-unadvice</span> (<span style="color:#19177c">sym</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Remove all advices from symbol SYM.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#ba2121">&#34;aFunction symbol: &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-mapc</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">advice</span> <span style="color:#19177c">_props</span>) (<span style="color:#19177c">advice-remove</span> <span style="color:#19177c">sym</span> <span style="color:#19177c">advice</span>)) <span style="color:#19177c">sym</span>))
</span></span></code></pre></div><h5 id="ielm">IELM</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;inferior-emacs-lisp-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;bi&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ielm</span>)
</span></span></code></pre></div><h4 id="common-lisp">Common lisp</h4>
<h5 id="slime">SLIME</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">slime</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">slime</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">inferior-lisp-program</span> <span style="color:#ba2121">&#34;sbcl&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;slime-repl-mode</span> <span style="color:#19177c">&#39;smartparens-mode</span>))
</span></span></code></pre></div><h5 id="general-settings-3">General settings</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;lisp-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">aggressive-indent-mode</span>)
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (add-hook &#39;emacs-lisp-mode-hook #&#39;smartparens-strict-mode)</span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;lisp-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">lispy-mode</span>)
</span></span></code></pre></div><h4 id="clojure">Clojure</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">clojure-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.clj[sc]?\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (add-hook &#39;clojure-mode-hook #&#39;smartparens-strict-mode)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;clojure-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">lispy-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;clojure-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">aggressive-indent-mode</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">cider</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">clojure-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h4 id="hy">Hy</h4>
<p>Python requirements:</p>
<ul>
<li><code>hy</code></li>
<li><code>jedhy</code></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">hy-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.hy\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;hy-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">lispy-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;hy-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">aggressive-indent-mode</span>))
</span></span></code></pre></div><h4 id="scheme">Scheme</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">geiser</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">geiser</span> <span style="color:#19177c">run-geiser</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">geiser-default-implementation</span> <span style="color:#19177c">&#39;guile</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">geiser-guile</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">geiser</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;scheme-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">aggressive-indent-mode</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;scheme-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">lispy-mode</span>)
</span></span></code></pre></div><h4 id="clips">CLIPS</h4>
<p>An honorary Lisp.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">clips-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.cl\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;clips-mode</span> <span style="color:#19177c">&#39;lispy-mode</span>))
</span></span></code></pre></div><h3 id="python">Python</h3>
<h4 id="ein">ein</h4>
<p><a href="https://github.com/millejoh/emacs-ipython-notebook">ein</a> is a package that allows for running Jupyter notebooks in Emacs.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ein</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">ein:run</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h4 id="pyright">pyright</h4>
<p>For some reason it doesn&rsquo;t use pipenv python executable, so here is a small workaround.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/pipenv-python-alist</span> <span style="color:#666">&#39;</span>())
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/get-pipenv-python</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">default-directory</span> (<span style="color:#19177c">projectile-project-root</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#ba2121">&#34;Pipfile&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">asc</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">default-directory</span> <span style="color:#19177c">my/pipenv-python-alist</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">asc</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">asc</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">python-executable</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-trim</span> (<span style="color:#19177c">shell-command-to-string</span> <span style="color:#ba2121">&#34;PIPENV_IGNORE_VIRTUALENVS=1 pipenv run which python 2&gt;/dev/null&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;.*not found.*&#34;</span> <span style="color:#19177c">python-executable</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Pipfile found, but not pipenv executable!&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;Found pipenv python: %s&#34;</span> <span style="color:#19177c">python-executable</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;my/pipenv-python-alist</span> (<span style="color:#00f">cons</span> <span style="color:#19177c">default-directory</span> <span style="color:#19177c">python-executable</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">python-executable</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;python&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">lsp-pyright</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:defer</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> (<span style="color:#19177c">python-mode</span> <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;lsp-pyright</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">lsp-pyright-python-executable-cmd</span> (<span style="color:#19177c">my/get-pipenv-python</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">lsp</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;python-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;python-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">treesit-fold-mode</span>)
</span></span></code></pre></div><h4 id="pipenv">pipenv</h4>
<p><a href="https://github.com/pypa/pipenv">Pipenv</a> is a package manager for Python.</p>
<p>Automatically creates &amp; manages virtualenvs and stores data in <code>Pipfile</code> and <code>Pipfile.lock</code> (like npm&rsquo;s <code>package.json</code> and <code>package-lock.json</code>).</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">pipenv</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> (<span style="color:#19177c">python-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">pipenv-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">pipenv-projectile-after-switch-function</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">pipenv-projectile-after-switch-extended</span>))
</span></span></code></pre></div><h4 id="off--yapf"><span class="org-todo done OFF">OFF</span> (OFF) yapf</h4>
<p><a href="https://github.com/google/yapf">yapf</a> is a formatter for Python files.</p>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>python-yapf</td>
</tr>
</tbody>
</table>
<p>References:</p>
<ul>
<li><a href="https://github.com/google/yapf">yapf repo</a></li>
<li><a href="https://github.com/JorisE/yapfify">yapfify.el repo</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">yapfify</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;JorisE/yapfify&#34;</span> <span style="color:#008000">:host</span> <span style="color:#19177c">github</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">yapfify-region</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">yapfify-buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">yapfify-region-or-buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">yapf-mode</span>))
</span></span></code></pre></div><p>Global config:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ini" data-lang="ini"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">[style]</span>
</span></span><span style="display:flex;"><span><span style="color:#7d9029">based_on_style</span> <span style="color:#666">=</span> <span style="color:#ba2121">facebook</span>
</span></span><span style="display:flex;"><span><span style="color:#7d9029">column_limit</span> <span style="color:#666">=</span> <span style="color:#ba2121">80</span>
</span></span></code></pre></div><h4 id="black">black</h4>
<p><a href="https://github.com/psf/black">black</a> is a formatter for Python files.</p>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>python-black</td>
</tr>
</tbody>
</table>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">python-black</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">python-black-buffer</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">python-black-command</span> <span style="color:#ba2121">&#34;black&#34;</span>))
</span></span></code></pre></div><h4 id="isort">isort</h4>
<p><a href="https://github.com/PyCQA/isort">isort</a> is a Python package to sort Python imports.</p>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>python-isort</td>
</tr>
</tbody>
</table>
<p>References:</p>
<ul>
<li><a href="https://pycqa.github.io/isort/">isort docs</a></li>
<li><a href="https://github.com/paetzke/py-isort.el">py-isort.el repo</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">py-isort</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">py-isort-buffer</span> <span style="color:#19177c">py-isort-region</span>))
</span></span></code></pre></div><p>The following binding calls yapf &amp; isort on the buffer</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">python-mode-map</span> <span style="color:#19177c">python-ts-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;rr&#34;</span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#008000">and</span> (<span style="color:#00f">fboundp</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-src-edit-buffer-p</span>) (<span style="color:#19177c">org-src-edit-buffer-p</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">py-isort-buffer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">python-black-buffer</span>)))
</span></span></code></pre></div><h4 id="sphinx-doc"><span class="org-todo done OFF">OFF</span> sphinx-doc</h4>
<p>A package to generate sphinx-compatible docstrings.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">sphinx-doc</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> (<span style="color:#19177c">python-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">sphinx-doc-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;sphinx-doc-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;rd&#34;</span> <span style="color:#19177c">&#39;sphinx-doc</span>))
</span></span></code></pre></div><h4 id="numpydoc">numpydoc</h4>
<p><a href="https://github.com/douglasdavis/numpydoc.el">numpydoc.el</a> is a package to generate docstring in Python functions.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">numpydoc</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">numpydoc-generate</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;python-ts-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;rd&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">numpydoc-generate</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">numpydoc-insertion-style</span> <span style="color:#19177c">&#39;prompt</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">numpydoc-insert-return-without-typehint</span> <span style="color:#800">nil</span>))
</span></span></code></pre></div><h4 id="pytest">pytest</h4>
<p><a href="https://docs.pytest.org/en/6.2.x/">pytest</a> is a unit testing framework for Python.</p>
<p>Once again a function to set pytest executable from pipenv.</p>
<p>References:</p>
<ul>
<li><a href="https://docs.pytest.org/en/6.2.x/">pytest docs</a></li>
<li><a href="https://github.com/wbolster/emacs-python-pytest">emacs-python-pytest</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/set-pipenv-pytest</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">python-pytest-executable</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> (<span style="color:#19177c">my/get-pipenv-python</span>) <span style="color:#ba2121">&#34; -m pytest&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">python-pytest</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">python-pytest-dispatch</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;python-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;t&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;t&#34;</span> <span style="color:#19177c">&#39;python-pytest-dispatch</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&lt;&lt;override-pytest-run&gt;&gt;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;python-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/set-pipenv-pytest</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">derived-mode-p</span> <span style="color:#19177c">&#39;python-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/set-pipenv-pytest</span>)))
</span></span></code></pre></div><h5 id="fix-comint-buffer-width">Fix comint buffer width</h5>
<p>For some reason, the default comint output width is way too large.</p>
<p>To fix that, I&rsquo;ve modified the following function in the <code>python-pytest</code> package.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">cl-defun</span> <span style="color:#19177c">python-pytest--run-as-comint</span> (<span style="color:#008000">&amp;key</span> <span style="color:#19177c">command</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Run a pytest comint session for COMMAND.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">buffer</span> (<span style="color:#19177c">python-pytest--get-buffer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">process</span> (<span style="color:#00f">get-buffer-process</span> <span style="color:#19177c">buffer</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">comint-check-proc</span> <span style="color:#19177c">buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#008000">or</span> <span style="color:#19177c">compilation-always-kill</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">yes-or-no-p</span> <span style="color:#ba2121">&#34;Kill running pytest process?&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Aborting; pytest still running&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">process</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">delete-process</span> <span style="color:#19177c">process</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">inhibit-read-only</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">erase-buffer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">major-mode</span> <span style="color:#19177c">&#39;python-pytest-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">python-pytest-mode</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">compilation-forget-errors</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-buffer</span> <span style="color:#19177c">buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">command</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;export COLUMNS=%s; %s&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">-</span> (<span style="color:#19177c">window-width</span> (<span style="color:#00f">get-buffer-window</span> <span style="color:#19177c">buffer</span>)) <span style="color:#666">5</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">command</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;cwd: %s\ncmd: %s\n\n&#34;</span> <span style="color:#19177c">default-directory</span> <span style="color:#19177c">command</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">python-pytest--current-command</span> <span style="color:#19177c">command</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">python-pytest-pdb-track</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;comint-output-filter-functions</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;python-pdbtrack-comint-output-filter-function</span>
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">run-hooks</span> <span style="color:#19177c">&#39;python-pytest-setup-hook</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">make-comint-in-buffer</span> <span style="color:#ba2121">&#34;pytest&#34;</span> <span style="color:#19177c">buffer</span> <span style="color:#ba2121">&#34;bash&#34;</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;-c&#34;</span> <span style="color:#19177c">command</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">run-hooks</span> <span style="color:#19177c">&#39;python-pytest-started-hook</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">process</span> (<span style="color:#00f">get-buffer-process</span> <span style="color:#19177c">buffer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-process-sentinel</span> <span style="color:#19177c">process</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">python-pytest--process-sentinel</span>))))
</span></span></code></pre></div><h4 id="code-cells">code-cells</h4>
<p>Support for text with magic comments.</p>
<table>
<thead>
<tr>
<th>Guix dependency</th>
<th>Disabled</th>
</tr>
</thead>
<tbody>
<tr>
<td>python-jupytext</td>
<td>t</td>
</tr>
</tbody>
</table>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">code-cells</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">code-cells-mode</span> <span style="color:#19177c">code-cells-convert-ipynb</span>))
</span></span></code></pre></div><h4 id="tensorboard">tensorboard</h4>
<p>A function to start up <a href="https://www.tensorflow.org/tensorboard">TensorBoard</a>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/tensorboard-buffer</span> <span style="color:#ba2121">&#34;TensorBoard-out&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/tensorboard</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">start-process</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;tensorboard&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/tensorboard-buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;tensorboard&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;serve&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;--logdir&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">car</span> (<span style="color:#19177c">find-file-read-args</span> <span style="color:#ba2121">&#34;Directory: &#34;</span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-buffer</span> <span style="color:#19177c">my/tensorboard-buffer</span>))
</span></span></code></pre></div><h3 id="data-serialization">Data serialization</h3>
<h4 id="json">JSON</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">json-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.json\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;json-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;json-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">treesit-fold-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">&#39;json-mode</span>))
</span></span></code></pre></div><h4 id="csv">CSV</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">csv-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.csv\\&#39;&#34;</span>)
</span></span></code></pre></div><h4 id="yaml">YAML</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">yaml-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.yml\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;yaml-mode-hook</span> <span style="color:#19177c">&#39;smartparens-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (add-hook &#39;yaml-mode-hook &#39;highlight-indent-guides-mode)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;auto-mode-alist</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;\\.yml\\&#39;&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">yaml-mode</span>)))
</span></span></code></pre></div><h3 id="configuration">Configuration</h3>
<h4 id="dot-env">.env</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">dotenv-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.env\\..*\\&#39;&#34;</span>)
</span></span></code></pre></div><h4 id="dot-gitignore">.gitignore</h4>
<p>A package to quickly create <code>.gitignore</code> files.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">gitignore-templates</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">gitignore-templates-insert</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">gitignore-templates-new-file</span>))
</span></span></code></pre></div><h4 id="docker">Docker</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">dockerfile-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;Dockerfile\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;dockerfile-mode</span> <span style="color:#19177c">&#39;smartparens-mode</span>))
</span></span></code></pre></div><h4 id="jenkins">Jenkins</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">jenkinsfile-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;Jenkinsfile\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;jenkinsfile-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">&#39;jenkinsfile-mode</span>))
</span></span></code></pre></div><h4 id="crontab">crontab</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">crontab-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;/crontab\\(\\.X*[[:alnum:]]+\\)?\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h4 id="nginx">nginx</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">nginx-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">&#39;nginx-mode</span>))
</span></span></code></pre></div><h4 id="hcl">HCL</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">hcl-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.hcl\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h3 id="shell">Shell</h3>
<h4 id="sh">sh</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;sh-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span></code></pre></div><h4 id="fish">fish</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">fish-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.fish\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;fish-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>))
</span></span></code></pre></div><h3 id="query-languages">Query languages</h3>
<h4 id="sql">SQL</h4>
<p><a href="https://github.com/zeroturnaround/sql-formatter">sql-formatter</a> is a nice JavaScript package for pretty-printing SQL queries. It is not packaged for Emacs, so the easiest way to use it seems to be to define a custom formatter via <a href="https://github.com/purcell/emacs-reformatter">reformatter</a>.</p>
<p>Also, I&rsquo;ve made a simple function to switch dialects because I often alternate between them.</p>
<p>So far I didn&rsquo;t find a nice SQL client for Emacs, but I occasionally run SQL queries in Org Mode, so this quite package is handy.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/sqlformatter-dialect-choice</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;db2&#34;</span> <span style="color:#ba2121">&#34;mariadb&#34;</span> <span style="color:#ba2121">&#34;mysql&#34;</span> <span style="color:#ba2121">&#34;n1ql&#34;</span> <span style="color:#ba2121">&#34;plsql&#34;</span> <span style="color:#ba2121">&#34;postgresql&#34;</span> <span style="color:#ba2121">&#34;redshift&#34;</span> <span style="color:#ba2121">&#34;spark&#34;</span> <span style="color:#ba2121">&#34;sql&#34;</span> <span style="color:#ba2121">&#34;tsql&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/sqlformatter-dialect</span> <span style="color:#ba2121">&#34;postgresql&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/sqlformatter-set-dialect</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Set dialect for sql-formatter&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/sqlformatter-dialect</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">completing-read</span> <span style="color:#ba2121">&#34;Dialect: &#34;</span> <span style="color:#19177c">my/sqlformatter-dialect-choice</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">reformatter-define</span> <span style="color:#19177c">sqlformat</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:program</span> (<span style="color:#19177c">executable-find</span> <span style="color:#ba2121">&#34;sql-formatter&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:args</span> <span style="color:#666">`</span>(<span style="color:#ba2121">&#34;-l&#34;</span> <span style="color:#666">,</span><span style="color:#19177c">my/sqlformatter-dialect</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">sql-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;rr&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sqlformat-buffer</span>)
</span></span></code></pre></div><h4 id="sparql">SPARQL</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">sparql-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.sparql\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h4 id="graphql">GraphQL</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">graphql-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> (<span style="color:#008000">rx</span> (<span style="color:#19177c">|</span> <span style="color:#ba2121">&#34;gql&#34;</span> <span style="color:#ba2121">&#34;grapql&#34;</span>) <span style="color:#19177c">eos</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h3 id="documents">Documents</h3>
<h4 id="docview">DocView</h4>
<p>Don&rsquo;t know about this.</p>
<p><code>doc-view</code> doesn&rsquo;t look great with the default <code>doc-view-resolution</code> of 100. 300 is fine, but then it becomes slow.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/doc-view-setup</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-line-numbers-mode</span> <span style="color:#666">-1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">undo-tree-mode</span> <span style="color:#666">-1</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">doc-view</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:type</span> <span style="color:#19177c">built-in</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">doc-view-resolution</span> <span style="color:#666">300</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;doc-view-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/doc-view-setup</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">doc-view-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;j&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">doc-view-next-line-or-next-page</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;k&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">doc-view-previous-line-or-previous-page</span>))
</span></span></code></pre></div><h3 id="gnuplot">Gnuplot</h3>
<p>Emacs integration for <a href="http://gnuplot.info/">gnuplot</a>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">gnuplot</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">gnuplot-mode</span> <span style="color:#19177c">gnuplot-make-buffer</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;auto-mode-alist</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;\\.gp\\&#39;&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">gnuplot-mode</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;gnuplot-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c C-c&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">gnuplot-send-buffer-to-gnuplot</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;gnuplot-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;RET&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">gnuplot-send-buffer-to-gnuplot</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;gnuplot-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>))
</span></span></code></pre></div><h3 id="x509">x509</h3>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">x509-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">x509-dwim</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;jobbflykt/x509-mode&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:build</span> (<span style="color:#008000">:not</span> <span style="color:#19177c">native-compile</span>)))
</span></span></code></pre></div><h3 id="java">Java</h3>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">lsp-java</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">lsp</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-java-jdt-download-url</span> <span style="color:#ba2121">&#34;https://download.eclipse.org/jdtls/milestones/0.57.0/jdt-language-server-0.57.0-202006172108.tar.gz&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;java-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (add-hook &#39;java-mode-hook #&#39;hs-minor-mode)</span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">&#39;java-mode</span>)
</span></span></code></pre></div><h3 id="go">Go</h3>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">go-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.go\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">&#39;go-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;go-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;go-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">treesit-fold-mode</span>))
</span></span></code></pre></div><h3 id="dot-net">.NET</h3>
<h4 id="c">C#</h4>
<table>
<thead>
<tr>
<th>Guix dependencies</th>
<th>Disabled</th>
</tr>
</thead>
<tbody>
<tr>
<td>omnisharp</td>
<td>t</td>
</tr>
<tr>
<td>dotnet</td>
<td>t</td>
</tr>
</tbody>
</table>
<p>Disabled that for now because it depends on the old tree sitter.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">csharp-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.cs\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lsp-csharp-server-path</span> (<span style="color:#19177c">executable-find</span> <span style="color:#ba2121">&#34;omnisharp-wrapper&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;csharp-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">csharp-tree-sitter-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;csharp-tree-sitter-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;csharp-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">treesit-fold-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">&#39;csharp-tree-sitter-mode</span>))
</span></span></code></pre></div><h4 id="msbuild">MSBuild</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">csproj-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.csproj\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;csproj-mode</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>))
</span></span></code></pre></div><h3 id="haskell">Haskell</h3>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">haskell-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.hs\\&#39;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">lsp-haskell</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">lsp</span> <span style="color:#19177c">haskell-mode</span>))
</span></span></code></pre></div><h3 id="nix">nix</h3>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">nix-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.nix\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;nix-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">smartparens-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">&#39;nix-mode</span>))
</span></span></code></pre></div><h3 id="lua">Lua</h3>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">lua-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.lua\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> (<span style="color:#19177c">lua-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">smartparens-mode</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my/set-smartparens-indent</span> <span style="color:#19177c">&#39;lua-mode</span>)
</span></span></code></pre></div><h2 id="org-mode">Org Mode</h2>
<p><strong>Org mode</strong> is a tool that leverages plain-text files for tasks like making notes, literate programming, task management, etc.</p>
<p>References:</p>
<ul>
<li><a href="https://orgmode.org/">Org Mode homepage</a></li>
<li><a href="https://orgmode.org/manual/">Manual</a></li>
</ul>
<h3 id="installation-and-basic-settings">Installation &amp; basic settings</h3>
<p>Use the built-in org mode (<code>:type built-in</code>).</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">org-directory</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">&#34;~/30-39 Life/32 org-mode&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:type</span> <span style="color:#19177c">built-in</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:defer</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">org-directory</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mkdir</span> <span style="color:#19177c">org-directory</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-startup-indented</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/is-termux</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-return-follows-link</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-src-tab-acts-natively</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-mode-hook</span> <span style="color:#19177c">&#39;smartparens-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-agenda-mode-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">visual-line-mode</span> <span style="color:#666">-1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">toggle-truncate-lines</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-line-numbers-mode</span> <span style="color:#666">0</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-mode-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">rainbow-delimiters-mode</span> <span style="color:#666">-1</span>))))
</span></span></code></pre></div><h4 id="encryption">Encryption</h4>
<p>Setting up <code>org-crypt</code> to encrypt parts of file.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;org-crypt</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-crypt-use-before-save-magic</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-tags-exclude-from-inheritance</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;crypt&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-crypt-key</span> <span style="color:#ba2121">&#34;C1EC867E478472439CC82410DE004F32AFA00205&#34;</span>))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;epg</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">epg-gpg-program</span> <span style="color:#ba2121">&#34;gpg&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">epg-config--program-alist</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#19177c">OpenPGP</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">epg-gpg-program</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (&#34;gpg2&#34; . ,epg-gpg2-minimum-version)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;gpg&#34;</span> <span style="color:#666">.</span> ((<span style="color:#666">,</span><span style="color:#19177c">epg-gpg-minimum-version</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;2.0&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span><span style="color:#19177c">epg-gpg2-minimum-version</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">CMS</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">epg-gpgsm-program</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;gpgsm&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;2.0.4&#34;</span>)))))
</span></span></code></pre></div><p>This enables encryption for Org segments tagged <code>:crypt:</code>.</p>
<p>Another way to encrypt Org files is to save them with the extension <code>.org.gpg</code>. However, by default <a href="https://www.gnu.org/software/emacs/manual/html_mono/epa.html">EPA</a> always prompts for the key, which is not what I want when there is only one key to select. Hence the following advice:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/epa--select-keys-around</span> (<span style="color:#19177c">fun</span> <span style="color:#19177c">prompt</span> <span style="color:#19177c">keys</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">=</span> (<span style="color:#19177c">seq-length</span> <span style="color:#19177c">keys</span>) <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">keys</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">fun</span> <span style="color:#19177c">prompt</span> <span style="color:#19177c">keys</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;epa</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">epa--select-keys</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/epa--select-keys-around</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">unless</span> <span style="color:#19177c">my/remote-server</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">epa-file-encrypt-to</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;DE004F32AFA00205&#34;</span>)))
</span></span></code></pre></div><h4 id="org-contrib">org-contrib</h4>
<p><code>org-contrib</code> is a package with various additions to Org. I use the following:</p>
<ul>
<li><code>ox-extra</code> - extensions for org export</li>
</ul>
<p>This used to have <code>org-contacts</code> and <code>ol-notmuch</code> at some point, but they have since been migrated to separate repos.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-contrib</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#19177c">org-contrib</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:type</span> <span style="color:#19177c">git</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;https://git.sr.ht/~bzg/org-contrib&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:build</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;ox-extra</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ox-extras-activate</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">latex-header-blocks</span> <span style="color:#19177c">ignore-headlines</span>)))
</span></span></code></pre></div><h4 id="ol-notmuch">ol-notmuch</h4>
<p><a href="https://git.sr.ht/~tarsius/ol-notmuch">ol-notmuch</a> is a package that adds Org links to notmuch messages.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">unless</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/remote-server</span> <span style="color:#19177c">my/is-termux</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">use-package</span> <span style="color:#19177c">ol-notmuch</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span> <span style="color:#19177c">notmuch</span>)))
</span></span></code></pre></div><h4 id="org-tempo">org-tempo</h4>
<p><code>org-tempo</code> is a convinient package that provides snippets for various org blocks.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;org-tempo</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;org-structure-template-alist</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;el&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;src emacs-lisp&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;org-structure-template-alist</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;py&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;src python&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;org-structure-template-alist</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;sq&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;src sql&#34;</span>)))
</span></span></code></pre></div><h4 id="evil-org">evil-org</h4>
<p>Better integration with evil-mode.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">evil-org</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> (<span style="color:#19177c">org-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">evil-org-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;evil-org-mode-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-org-set-key-theme</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">navigation</span> <span style="color:#00f">insert</span> <span style="color:#19177c">textobjects</span> <span style="color:#19177c">additional</span> <span style="color:#19177c">calendar</span> <span style="color:#19177c">todo</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;evil-emacs-state-modes</span> <span style="color:#19177c">&#39;org-agenda-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;evil-org-agenda</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-org-agenda-set-keys</span>))
</span></span></code></pre></div><h4 id="support-for-relative-urls">Support for relative URLs</h4>
<p>Source: <a href="https://emacs.stackexchange.com/questions/9807/org-mode-dont-change-relative-urls">https://emacs.stackexchange.com/questions/9807/org-mode-dont-change-relative-urls</a></p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/export-rel-url</span> (<span style="color:#19177c">path</span> <span style="color:#19177c">desc</span> <span style="color:#00f">format</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-case</span> <span style="color:#00f">format</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">html</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;&lt;a href=\&#34;%s\&#34;&gt;%s&lt;/a&gt;&#34;</span> <span style="color:#19177c">path</span> (<span style="color:#008000">or</span> <span style="color:#19177c">desc</span> <span style="color:#19177c">path</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">latex</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;\\href{%s}{%s}&#34;</span> <span style="color:#19177c">path</span> (<span style="color:#008000">or</span> <span style="color:#19177c">desc</span> <span style="color:#19177c">path</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">otherwise</span> <span style="color:#19177c">path</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-link-set-parameters</span> <span style="color:#ba2121">&#34;rel&#34;</span> <span style="color:#008000">:follow</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">browse-url</span> <span style="color:#008000">:export</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/export-rel-url</span>))
</span></span></code></pre></div><h3 id="keybindings-and-stuff">Keybindings &amp; stuff</h3>
<p>I&rsquo;ve moved this block above because the <code>my-leader-def</code> expression in the next block seems to override the previous ones. So it has to be on the top.</p>
<h4 id="general-keybindings">General keybindings</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/outline-prev-or-up-heading</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">outline-on-heading-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">outline-up-heading</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">outline-previous-visible-heading</span> <span style="color:#666">1</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;org-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c d&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-decrypt-entry</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c e&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-encrypt-entry</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-p&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-latex-preview</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-o&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-redisplay-inline-images</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;org-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">emacs</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;L&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-shiftright</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;H&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-shiftleft</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;S-&lt;next&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-next-visible-heading</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;S-&lt;prior&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-previous-visible-heading</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-0&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-next-visible-heading</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-9&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-previous-visible-heading</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-0&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-forward-heading-same-level</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-9&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-backward-heading-same-level</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;(&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/outline-prev-or-up-heading</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-]&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-babel-next-src-block</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-[&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-babel-previous-src-block</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;org-agenda-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-]&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-agenda-later</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-[&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-agenda-earlier</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-nmap</span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;org-mode-map</span> <span style="color:#ba2121">&#34;RET&#34;</span> <span style="color:#19177c">&#39;org-ctrl-c-ctrl-c</span>))
</span></span></code></pre></div><h4 id="copy-a-link">Copy a link</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-link-copy</span> (<span style="color:#008000">&amp;optional</span> <span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Extract URL from org-mode link and add it to kill ring.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#ba2121">&#34;P&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">link</span> (<span style="color:#19177c">org-element-lineage</span> (<span style="color:#19177c">org-element-context</span>) <span style="color:#666">&#39;</span>(<span style="color:#19177c">link</span>) <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">type</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:type</span> <span style="color:#19177c">link</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:path</span> <span style="color:#19177c">link</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">type</span> <span style="color:#ba2121">&#34;:&#34;</span> <span style="color:#19177c">url</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">kill-new</span> <span style="color:#19177c">url</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;Copied URL: &#34;</span> <span style="color:#19177c">url</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-nmap</span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;org-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-x C-l&#34;</span> <span style="color:#19177c">&#39;my/org-link-copy</span>))
</span></span></code></pre></div><h4 id="navigating-source-blocks">Navigating source blocks</h4>
<p>An idea born from discussing Org Mode navigation with @Infu.</p>
<p>Modifying <code>org-babel-next-src-block</code> and <code>org-babel-previous-src-block</code> to ignore hidden source blocks.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-babel-next-visible-src-block</span> (<span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Move to the next visible source block.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">With ARG, repeats or can move backward if negative.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#ba2121">&#34;p&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">regexp</span> <span style="color:#19177c">org-babel-src-block-regexp</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">&lt;</span> <span style="color:#19177c">arg</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">beginning-of-line</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">end-of-line</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">while</span> (<span style="color:#008000">and</span> (<span style="color:#00f">&lt;</span> <span style="color:#19177c">arg</span> <span style="color:#666">0</span>) (<span style="color:#00f">re-search-backward</span> <span style="color:#19177c">regexp</span> <span style="color:#800">nil</span> <span style="color:#008000">:move</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">bobp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">while</span> (<span style="color:#008000">pcase</span> (<span style="color:#00f">get-char-property-and-overlay</span> (<span style="color:#00f">point</span>) <span style="color:#19177c">&#39;invisible</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#666">`</span>(<span style="color:#19177c">outline</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">o</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">overlay-start</span> <span style="color:#19177c">o</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">re-search-backward</span> <span style="color:#19177c">regexp</span> <span style="color:#800">nil</span> <span style="color:#008000">:move</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">_</span> <span style="color:#800">nil</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-incf</span> <span style="color:#19177c">arg</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">while</span> (<span style="color:#008000">and</span> (<span style="color:#00f">&gt;</span> <span style="color:#19177c">arg</span> <span style="color:#666">0</span>) (<span style="color:#00f">re-search-forward</span> <span style="color:#19177c">regexp</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">while</span> (<span style="color:#008000">pcase</span> (<span style="color:#00f">get-char-property-and-overlay</span> (<span style="color:#00f">point</span>) <span style="color:#19177c">&#39;invisible</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#666">`</span>(<span style="color:#19177c">outline</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">o</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">overlay-end</span> <span style="color:#19177c">o</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">re-search-forward</span> <span style="color:#19177c">regexp</span> <span style="color:#800">nil</span> <span style="color:#008000">:move</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">_</span> (<span style="color:#00f">end-of-line</span>) <span style="color:#800">nil</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">re-search-backward</span> <span style="color:#19177c">regexp</span> <span style="color:#800">nil</span> <span style="color:#008000">:move</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-decf</span> <span style="color:#19177c">arg</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">&gt;</span> <span style="color:#19177c">arg</span> <span style="color:#666">0</span>) (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-max</span>)) (<span style="color:#00f">beginning-of-line</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-babel-previous-visible-src-block</span> (<span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Move to the prevous visible source block.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">With ARG, repeats or can move backward if negative.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#ba2121">&#34;p&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-babel-next-visible-src-block</span> (<span style="color:#00f">-</span> <span style="color:#19177c">arg</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;org-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">emacs</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-]&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-babel-next-visible-src-block</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-[&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-babel-previous-visible-src-block</span>))
</span></span></code></pre></div><h4 id="open-a-file-from-org-directory">Open a file from <code>org-directory</code></h4>
<p>A function to open a file from <code>org-directory</code>, excluding a few directories like <code>roam</code> and <code>journal</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-file-open</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">files</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;projects&#34;</span> <span style="color:#ba2121">&#34;misc&#34;</span> <span style="color:#ba2121">&#34;learning&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-files</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/&#34;</span> <span style="color:#19177c">f</span>) <span style="color:#800">t</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;.org&#34;</span> <span style="color:#19177c">eos</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#00f">#&#39;append</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-replace</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/&#34;</span>) <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#19177c">file</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">append</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;inbox.org&#34;</span> <span style="color:#ba2121">&#34;contacts.org&#34;</span> <span style="color:#ba2121">&#34;recurring.org&#34;</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">find-file</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">completing-read</span> <span style="color:#ba2121">&#34;Org file: &#34;</span> <span style="color:#19177c">files</span>)))))
</span></span></code></pre></div><h3 id="ui-1">UI</h3>
<h4 id="latex-fragments">LaTeX fragments</h4>
<p>A function to enable LaTeX native highlighting. Not setting this as default, because it loads LaTeX stuff.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/enable-org-latex</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">customize-set-variable</span> <span style="color:#19177c">&#39;org-highlight-latex-and-related</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">native</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-mode-hook</span> (<span style="color:#008000">lambda</span> () (<span style="color:#19177c">yas-activate-extra-mode</span> <span style="color:#19177c">&#39;LaTeX-mode</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">sp-local-pair</span> <span style="color:#19177c">&#39;org-mode</span> <span style="color:#ba2121">&#34;$&#34;</span> <span style="color:#ba2121">&#34;$&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">sp--remove-local-pair</span> <span style="color:#ba2121">&#34;&#39;&#34;</span>))
</span></span></code></pre></div><p>Call the function before opening an org file or reopen a buffer after calling the function.</p>
<p>Scale latex fragments preview.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/org-latex-scale</span> <span style="color:#666">1.75</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-format-latex-options</span> (<span style="color:#00f">plist-put</span> <span style="color:#19177c">org-format-latex-options</span> <span style="color:#008000">:scale</span> <span style="color:#19177c">my/org-latex-scale</span>)))
</span></span></code></pre></div><p>Also, LaTeX fragments preview tends to break whenever the are custom <code>#+LATEX_HEADER</code> entries. To circumvent this, I add a custom header and modify the <code>org-preview-latex-process-alist</code> variable</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/latex-preview-header</span> <span style="color:#ba2121">&#34;\\documentclass{article}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\\usepackage[usenames]{color}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\\usepackage{graphicx}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\\usepackage{grffile}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\\usepackage{longtable}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\\usepackage{wrapfig}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\\usepackage{rotating}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\\usepackage[normalem]{ulem}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\\usepackage{amsmath}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\\usepackage{textcomp}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\\usepackage{amssymb}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\\usepackage{capt-of}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\\usepackage{hyperref}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\\pagestyle{empty}&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-preview-latex-process-alist</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">item</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">car</span> <span style="color:#19177c">item</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">plist-put</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">item</span>) <span style="color:#008000">:latex-header</span> <span style="color:#19177c">my/latex-preview-header</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-preview-latex-process-alist</span>)))
</span></span></code></pre></div><h4 id="better-headers">Better headers</h4>
<p><a href="https://github.com/integral-dw/org-superstar-mode">org-superstar-mode</a> is a package that makes Org heading lines look a bit prettier.</p>
<p>Disabled it for now because of overlapping functionality with org-bars.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-superstar</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> (<span style="color:#19177c">org-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">org-superstar-mode</span>))
</span></span></code></pre></div><p><a href="https://github.com/tonyaldon/org-bars">org-bars</a> highlights Org indentation with bars.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-bars</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;tonyaldon/org-bars&#34;</span> <span style="color:#008000">:host</span> <span style="color:#19177c">github</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">display-graphic-p</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> (<span style="color:#19177c">org-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">org-bars-mode</span>))
</span></span></code></pre></div><p>Fallback to the standard <code>org-indent-mode</code> on terminal.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">unless</span> (<span style="color:#19177c">display-graphic-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-indent-mode</span>))
</span></span></code></pre></div><p>Remove the ellipsis at the end of folded headlines, as it seems unnecessary with <code>org-bars</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-no-ellipsis-in-headlines</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">remove-from-invisibility-spec</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">outline</span> <span style="color:#666">.</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-invisibility-spec</span> <span style="color:#19177c">&#39;outline</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org-bars</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-no-ellipsis-in-headlines</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">major-mode</span> <span style="color:#19177c">&#39;org-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-no-ellipsis-in-headlines</span>)))
</span></span></code></pre></div><h4 id="override-colors">Override colors</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my/use-colors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-block</span> <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;bg-other</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-block-begin-line</span> <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;bg-other</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;grey</span>)))
</span></span></code></pre></div><h4 id="hide-stuff-in-buffer">Hide stuff in buffer</h4>
<p><a href="https://github.com/awth13/org-appear">org-appear</a> is a package that toggles visibility of hidden elements upon entering and leaving them.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-appear</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><p><a href="https://github.com/io12/org-fragtog">org-fragtog</a> does the same for LaTeX fragment previews.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-fragtog</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h3 id="literate-programing">Literate programing</h3>
<h4 id="python-and-jupyter">Python &amp; Jupyter</h4>
<p>Use jupyter kernels for Org Mode.</p>
<p>References:</p>
<ul>
<li><a href="https://github.com/nnicandro/emacs-jupyter">emacs-jupyter repo</a></li>
<li><a href="https://github.com/jkitchin/scimax/blob/master/scimax.org">SCIMAX manual</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">jupyter</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/remote-server</span> <span style="color:#19177c">my/is-termux</span>)))
</span></span></code></pre></div><p>Refresh kernelspecs.</p>
<p>Kernelspecs by default are hashed, so even switching Anaconda environments doesn&rsquo;t change the kernel (i.e. kernel from the first environment is run after the switch to the second one).</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/jupyter-refresh-kernelspecs</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Refresh Jupyter kernelspecs&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">jupyter-available-kernelspecs</span> <span style="color:#800">t</span>))
</span></span></code></pre></div><p>Also, if some kernel wasn&rsquo;t present at the moment of the load of <code>emacs-jupyter</code>, it won&rsquo;t be added to the <code>org-src-lang-modes</code> list. E.g. I have Hy kernel installed in a separate Anaconda environment, so if Emacs hasn&rsquo;t been launched in this environment, I wouldn&rsquo;t be able to use <code>hy</code> in org-src blocks.</p>
<p>Fortunately, <code>emacs-jupyter</code> provides a function for that problem as well.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/jupyter-refesh-langs</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Refresh Jupyter languages&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-jupyter-aliases-from-kernelspecs</span> <span style="color:#800">t</span>))
</span></span></code></pre></div><p>A function to load <code>jupyter</code>. The problem with doing that on startup is that it tried to locate the <code>jupyter</code> executable, which I have only in an environment.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-load-jupyter</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-do-load-languages</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;org-babel-load-languages</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">jupyter</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/jupyter-refesh-langs</span>))
</span></span></code></pre></div><h4 id="hy-1">Hy</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ob-hy</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h4 id="view-html-in-browser">View HTML in browser</h4>
<p>Open HTML in the <code>begin_export</code> block with xdg-open.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/org-view-html-tmp-dir</span> <span style="color:#ba2121">&#34;/tmp/org-html-preview/&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">f</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-view-html</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">elem</span> (<span style="color:#19177c">org-element-at-point</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">temp-file-path</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">my/org-view-html-tmp-dir</span> (<span style="color:#00f">number-to-string</span> (<span style="color:#00f">random</span> (<span style="color:#00f">expt</span> <span style="color:#666">2</span> <span style="color:#666">32</span>))) <span style="color:#ba2121">&#34;.html&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">not</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">&#39;export-block</span> (<span style="color:#00f">car</span> <span style="color:#19177c">elem</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Not in an export block!&#34;</span>))
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">not</span> (<span style="color:#00f">string-equal</span> (<span style="color:#00f">plist-get</span> (<span style="color:#00f">car</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">elem</span>)) <span style="color:#008000">:type</span>) <span style="color:#ba2121">&#34;HTML&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Export block is not HTML!&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">f-mkdir</span> <span style="color:#19177c">my/org-view-html-tmp-dir</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">f-write</span> (<span style="color:#00f">plist-get</span> (<span style="color:#00f">car</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">elem</span>)) <span style="color:#008000">:value</span>) <span style="color:#19177c">&#39;utf-8</span> <span style="color:#19177c">temp-file-path</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">start-process</span> <span style="color:#ba2121">&#34;org-html-preview&#34;</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;xdg-open&#34;</span> <span style="color:#19177c">temp-file-path</span>))))))
</span></span></code></pre></div><h4 id="plantuml-1">PlantUML</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-plantuml-executable-path</span> <span style="color:#ba2121">&#34;/home/pavel/.guix-extra-profiles/emacs/emacs/bin/plantuml&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-plantuml-exec-mode</span> <span style="color:#19177c">&#39;plantuml</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;org-src-lang-modes</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;plantuml&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">plantuml</span>)))
</span></span></code></pre></div><h4 id="restclient">Restclient</h4>
<p><a href="https://github.com/pashky/restclient.el">restclient.el</a> is an Emacs package to send HTTP requests. <a href="https://github.com/alf/ob-restclient.el">ob-restclient</a> provides interaction with Org Babel.</p>
<p>References:</p>
<ul>
<li><a href="https://joseph8th.github.io/posts/wow-writing-literate-api-documentation-in-emacs-org-mode/">WOW! Writing Literate API Documentation in Emacs Org Mode</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">restclient</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> (<span style="color:#ba2121">&#34;\\.http\\&#39;&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">restclient-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;restclient-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">visual</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;RET&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">restclient-http-send-current</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-RET&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">restclient-http-send-current-stay-in-window</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;y&#34;</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-y&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">restclient-copy-curl-command</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;restclient-response-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">visual</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">quit-window</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ob-restclient</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span> <span style="color:#19177c">restclient</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h4 id="org-babel-setup">Org Babel Setup</h4>
<p>Enable languages</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-do-load-languages</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;org-babel-load-languages</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#19177c">emacs-lisp</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">python</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">sql</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">sqlite</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (typescript .t)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">hy</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shell</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">plantuml</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">octave</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">sparql</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">gnuplot</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-babel-after-execute-hook</span> <span style="color:#19177c">&#39;org-redisplay-inline-images</span>))
</span></span></code></pre></div><p>Use Jupyter block instead of built-in Python.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;ob-jupyter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-jupyter-override-src-block</span> <span style="color:#ba2121">&#34;python&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-jupyter-override-src-block</span> <span style="color:#ba2121">&#34;hy&#34;</span>))
</span></span></code></pre></div><p>Turn of some minor modes in source blocks.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-src-mode-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (hs-minor-mode -1)</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (electric-indent-local-mode -1)</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (rainbow-delimiters-mode -1)</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (highlight-indent-guides-mode -1)</span>
</span></span><span style="display:flex;"><span> ))
</span></span></code></pre></div><p>Async code blocks evaluations. Jupyter blocks have a built-in async, so they are set as ignored.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ob-async</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ob-async-no-async-languages-alist</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;python&#34;</span> <span style="color:#ba2121">&#34;hy&#34;</span> <span style="color:#ba2121">&#34;jupyter-python&#34;</span> <span style="color:#ba2121">&#34;jupyter-octave&#34;</span> <span style="color:#ba2121">&#34;restclient&#34;</span>)))
</span></span></code></pre></div><h4 id="managing-jupyter-kernels">Managing Jupyter kernels</h4>
<p>Functions for managing local Jupyter kernels.</p>
<p><code>my/insert-jupyter-kernel</code> inserts a path to an active Jupyter kernel to the buffer. Useful to quickly write a header like:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+PROPERTY: header-args:python :session &lt;path-to-kernel&gt;
</span></span></code></pre></div><p><code>my/jupyter-connect-repl</code> opens a <code>emacs-jupyter</code> REPL, connected to an active kernel. <code>my/jupyter-qtconsole</code> runs a standalone Jupyter QtConsole.</p>
<p>Requirements: <code>ss</code></p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/jupyter-runtime-folder</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">&#34;~/.local/share/jupyter/runtime&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/get-open-ports</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;string-to-number</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">split-string</span> (<span style="color:#19177c">shell-command-to-string</span> <span style="color:#ba2121">&#34;ss -tulpnH | awk &#39;{print $5}&#39; | sed -e &#39;s/.*://&#39;&#34;</span>) <span style="color:#ba2121">&#34;\n&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/list-jupyter-kernel-files</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>) (<span style="color:#00f">cons</span> (<span style="color:#00f">car</span> <span style="color:#19177c">file</span>) (<span style="color:#00f">cdr</span> (<span style="color:#00f">assq</span> <span style="color:#19177c">&#39;shell_port</span> (<span style="color:#19177c">json-read-file</span> (<span style="color:#00f">car</span> <span style="color:#19177c">file</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">sort</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-files-and-attributes</span> <span style="color:#19177c">my/jupyter-runtime-folder</span> <span style="color:#800">t</span> <span style="color:#ba2121">&#34;.*kernel.*json$&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">x</span> <span style="color:#19177c">y</span>) (<span style="color:#19177c">not</span> (<span style="color:#00f">time-less-p</span> (<span style="color:#00f">nth</span> <span style="color:#666">6</span> <span style="color:#19177c">x</span>) (<span style="color:#00f">nth</span> <span style="color:#666">6</span> <span style="color:#19177c">y</span>)))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/select-jupyter-kernel</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">ports</span> (<span style="color:#19177c">my/get-open-ports</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">files</span> (<span style="color:#19177c">my/list-jupyter-kernel-files</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">completing-read</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Jupyter kernels: &#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">member</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">file</span>) <span style="color:#19177c">ports</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">files</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/insert-jupyter-kernel</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Insert a path to an active Jupyter kernel into the buffer&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#19177c">my/select-jupyter-kernel</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/jupyter-connect-repl</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Open an emacs-jupyter REPL, connected to a Jupyter kernel&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">jupyter-connect-repl</span> (<span style="color:#19177c">my/select-jupyter-kernel</span>) <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/jupyter-qtconsole</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Open Jupyter QtConsole, connected to a Jupyter kernel&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">start-process</span> <span style="color:#ba2121">&#34;jupyter-qtconsole&#34;</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;setsid&#34;</span> <span style="color:#ba2121">&#34;jupyter&#34;</span> <span style="color:#ba2121">&#34;qtconsole&#34;</span> <span style="color:#ba2121">&#34;--existing&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-name-nondirectory</span> (<span style="color:#19177c">my/select-jupyter-kernel</span>))))
</span></span></code></pre></div><p>I&rsquo;ve also noticed that there are JSON files left in the runtime folder whenever the kernel isn&rsquo;t stopped correctly. So here is a cleanup function.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/jupyter-cleanup-kernels</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">ports</span> (<span style="color:#19177c">my/get-open-ports</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">files</span> (<span style="color:#19177c">my/list-jupyter-kernel-files</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">to-delete</span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#00f">member</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">file</span>) <span style="color:#19177c">ports</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">files</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">and</span> (<span style="color:#19177c">length&gt;</span> <span style="color:#19177c">to-delete</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">y-or-n-p</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;Delete %d files?&#34;</span> (<span style="color:#00f">length</span> <span style="color:#19177c">to-delete</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">file</span> <span style="color:#19177c">to-delete</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">delete-file</span> (<span style="color:#00f">car</span> <span style="color:#19177c">file</span>))))))
</span></span></code></pre></div><h4 id="output-post-processing">Output post-processing</h4>
<h5 id="do-not-wrap-the-output-in-emacs-jupyter">Do not wrap the output in emacs-jupyter</h5>
<p>Emacs-jupyter has its own insertion mechanisms, which always prepends output statements with <code>:</code>. That is not desirable in cases where a kernel supports only plain output, e.g. calysto_hy kernel.</p>
<p>So there we have a minor mode that overrides this behavior.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/jupyter-org-scalar</span> (<span style="color:#19177c">value</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">stringp</span> <span style="color:#19177c">value</span>) <span style="color:#19177c">value</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> (<span style="color:#19177c">jupyter-org-scalar</span> <span style="color:#19177c">value</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">define-minor-mode</span> <span style="color:#19177c">my/emacs-jupyter-raw-output</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Make emacs-jupyter do raw output&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/jupyter-org-scalar-around</span> (<span style="color:#19177c">fun</span> <span style="color:#19177c">value</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">my/emacs-jupyter-raw-output</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/jupyter-org-scalar</span> <span style="color:#19177c">value</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">fun</span> <span style="color:#19177c">value</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;jupyter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#19177c">&#39;jupyter-org-scalar</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/jupyter-org-scalar-around</span>))
</span></span></code></pre></div><h5 id="wrap-source-code-output">Wrap source code output</h5>
<p>A function to remove the :RESULTS: drawer from results. Once again, it&rsquo;s necessary because emacs-jupyter doesn&rsquo;t seem to respect <code>:results raw</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-strip-results</span> (<span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp-in-string</span> <span style="color:#ba2121">&#34;:\\(RESULTS\\|END\\):\n&#34;</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#19177c">data</span>))
</span></span></code></pre></div><p>And an all-in-one function to:</p>
<ul>
<li>prepend <code>#+NAME:</code> and <code>#+CAPTION:</code> to the source block output. Useful if the output is an image.</li>
<li>strip the :RESULTS: drawer from the output, if necessary</li>
<li>wrap results in the <code>src</code> block</li>
</ul>
<p>As for now, it looks sufficient to format source code outputs to get a tolerable LaTeX.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-caption-wrap</span> (<span style="color:#19177c">data</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">name</span> <span style="color:#19177c">caption</span> <span style="color:#19177c">attrs</span> <span style="color:#19177c">strip-drawer</span> <span style="color:#19177c">src-wrap</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">data-s</span> (<span style="color:#008000">if</span> (<span style="color:#008000">and</span> <span style="color:#19177c">strip-drawer</span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">strip-drawer</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-strip-results</span> <span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">data</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">drawer-start</span> (<span style="color:#008000">if</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;^:RESULTS:.*&#34;</span> <span style="color:#19177c">data-s</span>) <span style="color:#666">10</span> <span style="color:#666">0</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span> <span style="color:#19177c">data-s</span> <span style="color:#666">0</span> <span style="color:#19177c">drawer-start</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span> <span style="color:#19177c">name</span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">name</span>)) (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;#+NAME:&#34;</span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;\n&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span> <span style="color:#19177c">caption</span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">caption</span>)) (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;#+CAPTION:&#34;</span> <span style="color:#19177c">caption</span> <span style="color:#ba2121">&#34;\n&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span> <span style="color:#19177c">attrs</span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">attrs</span>)) (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;#+ATTR_LATEX:&#34;</span> <span style="color:#19177c">attrs</span> <span style="color:#ba2121">&#34;\n&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">and</span> <span style="color:#19177c">src-wrap</span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">src-wrap</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;#+begin_src &#34;</span> <span style="color:#19177c">src-wrap</span> <span style="color:#ba2121">&#34;\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span> <span style="color:#19177c">data-s</span> <span style="color:#19177c">drawer-start</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;.*\n&#34;</span> <span style="color:#19177c">data-s</span>)) <span style="color:#ba2121">&#34;\n&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;#+end_src&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span> <span style="color:#19177c">data-s</span> <span style="color:#19177c">drawer-start</span>)))))
</span></span></code></pre></div><p>To use, add the following snippet to the org file:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: out_wrap
</span></span><span style="display:flex;"><span>#+begin_src emacs-lisp :var data=&#34;&#34; caption=&#34;&#34; name=&#34;&#34; attrs=&#34;&#34; strip-drawer=&#34;&#34; src-wrap=&#34;&#34; :tangle no :exports none
</span></span><span style="display:flex;"><span>(my/org-caption-wrap data name caption attrs strip-drawer src-wrap)
</span></span><span style="display:flex;"><span>#+end_src
</span></span></code></pre></div><p>Example usage:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>:post out_wrap(name=&#34;fig:chart&#34;, caption=&#34;График&#34;, data=*this*)
</span></span></code></pre></div><h5 id="apply-ansi-color-codes">Apply ANSI color codes</h5>
<p><strong>SOURCE</strong>: <a href="https://emacs.stackexchange.com/questions/44664/apply-ansi-color-escape-sequences-for-org-babel-results">Apply ANSI color escape sequences for Org Babel results</a></p>
<p>A minor mode to apply ANSI color codes after execution.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/babel-ansi</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let</span> ((<span style="color:#19177c">beg</span> (<span style="color:#19177c">org-babel-where-is-src-block-result</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> <span style="color:#19177c">beg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">looking-at</span> <span style="color:#19177c">org-babel-result-regexp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">end</span> (<span style="color:#19177c">org-babel-result-end</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-context-region</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-apply-on-region</span> <span style="color:#19177c">beg</span> <span style="color:#19177c">end</span>))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">define-minor-mode</span> <span style="color:#19177c">org-babel-ansi-colors-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Apply ANSI color codes to Org Babel results.&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:global</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">org-babel-ansi-colors-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-babel-after-execute-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/babel-ansi</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">remove-hook</span> <span style="color:#19177c">&#39;org-babel-after-execute-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/babel-ansi</span>)))
</span></span></code></pre></div><h4 id="executing-stuff">Executing stuff</h4>
<p>A few convinient functions and keybindings to execute things in an org buffer.</p>
<p>First, execute things above and below the point:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-babel-execute-buffer-below</span> (<span style="color:#008000">&amp;optional</span> <span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#ba2121">&#34;P&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-eval-wipe-error-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#00f">point</span> (<span style="color:#00f">point</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-save-outline-visibility</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-map-executables</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">&gt;=</span> (<span style="color:#00f">point</span>) <span style="color:#00f">point</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">memq</span> (<span style="color:#19177c">org-element-type</span> (<span style="color:#19177c">org-element-context</span>))
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">babel-call</span> <span style="color:#19177c">inline-babel-call</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-lob-execute-maybe</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-execute-src-block</span> <span style="color:#19177c">arg</span>)))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-babel-execute-buffer-above</span> (<span style="color:#008000">&amp;optional</span> <span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#ba2121">&#34;P&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-eval-wipe-error-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#00f">point</span> (<span style="color:#00f">point</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-save-outline-visibility</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-map-executables</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">&lt;=</span> (<span style="color:#00f">point</span>) <span style="color:#00f">point</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">memq</span> (<span style="color:#19177c">org-element-type</span> (<span style="color:#19177c">org-element-context</span>))
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">babel-call</span> <span style="color:#19177c">inline-babel-call</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-lob-execute-maybe</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-execute-src-block</span> <span style="color:#19177c">arg</span>)))))))
</span></span></code></pre></div><p>Execute all code blocks marked with <code>:startup t</code>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-babel-execute-marked</span> (<span style="color:#008000">&amp;optional</span> <span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#ba2121">&#34;P&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> (<span style="color:#19177c">markers</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-map</span> (<span style="color:#19177c">org-element-parse-buffer</span>) <span style="color:#19177c">&#39;src-block</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">params</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:parameters</span> <span style="color:#19177c">elem</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">and</span> <span style="color:#19177c">params</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;startup t&#34;</span>) <span style="color:#19177c">params</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">m</span> (<span style="color:#00f">make-marker</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-marker</span> <span style="color:#19177c">m</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:begin</span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-marker-insertion-type</span> <span style="color:#19177c">m</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#19177c">m</span> <span style="color:#19177c">markers</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">markers</span> (<span style="color:#00f">nreverse</span> <span style="color:#19177c">markers</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">arg</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">markers</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">m</span>) (<span style="color:#00f">&gt;</span> (<span style="color:#00f">marker-position</span> <span style="color:#19177c">m</span>) (<span style="color:#00f">point</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">markers</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">m</span> <span style="color:#19177c">markers</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> <span style="color:#19177c">m</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">ignore-errors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-execute-src-block</span>)))))
</span></span></code></pre></div><p>Some keybindings:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;org-babel-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;B&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-babel-execute-buffer-below</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;A&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-babel-execute-buffer-above</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;org-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;SPC b&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:wk</span> <span style="color:#ba2121">&#34;org-babel&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;SPC b&#34;</span> <span style="color:#19177c">org-babel-map</span>))
</span></span></code></pre></div><h4 id="managing-a-literate-programming-project">Managing a literate programming project</h4>
<p>A few tricks to do literate programming. I actually have only one (<a href="https://github.com/SqrtMinusOne/sqrt-data">sqrt-data</a>), and I&rsquo;m not convinced in the benefits of the approach&hellip;</p>
<p>Anyway, Org files are better off in a separated directory (e.g. <code>org</code>). So I&rsquo;ve come up with the following solution to avoid manually prefixing the <code>:tangle</code> arguments.</p>
<p>Set up the following argument with the path to the project root:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+PROPERTY: PRJ-DIR ..
</span></span></code></pre></div><p>A function to do the prefixing:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-prj-dir</span> (<span style="color:#19177c">path</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">expand-file-name</span> <span style="color:#19177c">path</span> (<span style="color:#19177c">org-entry-get</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;PRJ-DIR&#34;</span> <span style="color:#800">t</span>)))
</span></span></code></pre></div><p>Example usage is as follows:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>:tangle (my/org-prj-dir &#34;sqrt_data/api/__init__.py&#34;)
</span></span></code></pre></div><h3 id="tools">Tools</h3>
<p>Various small packages.</p>
<h4 id="presentations">Presentations</h4>
<p>Doing presentations with <a href="https://github.com/rlister/org-present">org-present</a>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">hide-mode-line</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">hide-mode-line-mode</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/present-next-with-latex</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-present-next</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-latex-preview</span> <span style="color:#666">&#39;</span>(<span style="color:#666">16</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/present-prev-with-latex</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-present-prev</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-latex-preview</span> <span style="color:#666">&#39;</span>(<span style="color:#666">16</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-present</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;rlister/org-present&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">org-present</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;org-present-mode-keymap</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;next&gt;&#34;</span> <span style="color:#19177c">&#39;my/present-next-with-latex</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;prior&gt;&#34;</span> <span style="color:#19177c">&#39;my/present-prev-with-latex</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-present-mode-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">blink-cursor-mode</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-present-big</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-bars-mode</span> <span style="color:#666">-1</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (org-display-inline-images)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-present-hide-cursor</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-present-read-only</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-line-numbers-mode</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">hide-mode-line-mode</span> <span style="color:#666">+1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">org-format-latex-options</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">plist-put</span> <span style="color:#19177c">org-format-latex-options</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:scale</span> (<span style="color:#00f">*</span> <span style="color:#19177c">org-present-text-scale</span> <span style="color:#19177c">my/org-latex-scale</span> <span style="color:#666">0.5</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (org-latex-preview &#39;(16))</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; TODO ^somehow this stucks at running LaTeX^</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">olivetti-body-width</span> <span style="color:#666">60</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">olivetti-mode</span> <span style="color:#666">1</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-present-mode-quit-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">blink-cursor-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-present-small</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-bars-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (org-remove-inline-images)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-present-show-cursor</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-present-read-write</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-line-numbers-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">hide-mode-line-mode</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">org-format-latex-options</span> (<span style="color:#00f">plist-put</span> <span style="color:#19177c">org-format-latex-options</span> <span style="color:#008000">:scale</span> <span style="color:#19177c">my/org-latex-scale</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-latex-preview</span> <span style="color:#666">&#39;</span>(<span style="color:#666">64</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">olivetti-mode</span> <span style="color:#666">-1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">olivetti-body-width</span> (<span style="color:#00f">default-value</span> <span style="color:#19177c">&#39;olivetti-body-width</span>))))))
</span></span></code></pre></div><h4 id="toc">TOC</h4>
<p>Make a TOC inside the org file.</p>
<p>References:</p>
<ul>
<li><a href="https://github.com/alphapapa/org-make-toc">alphapapa/org-make-toc</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-make-toc</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-make-toc</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-make-toc-insert</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-make-toc-set</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-make-toc-at-point</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h4 id="screenshots">Screenshots</h4>
<p>A nice package to make screenshots and insert them to the Org document.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-attach-screenshot</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">org-attach-screenshot</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-attach-screenshot-auto-refresh</span> <span style="color:#19177c">&#39;never</span>))
</span></span></code></pre></div><h4 id="transclusion">Transclusion</h4>
<p>A package that implements transclusions in Org Mode, i.e. rendering part of one file inside another file.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-transclusion</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">org</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;nobiot/org-transclusion&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;org-transclusion-extensions</span> <span style="color:#19177c">&#39;org-transclusion-indent-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;org-transclusion-indent-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">org-transclusion-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;RET&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-transclusion-open-source</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gr&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-transclusion-refresh</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">org-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#19177c">&#39;normal</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c t a&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-transclusion-add</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c t A&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-transclusion-add-all</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c t t&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-transclusion-mode</span>))
</span></span></code></pre></div><h4 id="drawing">Drawing</h4>
<p>This package is unbelievably good. I would have never thought it&rsquo;s even possible to have this in Emacs.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">edraw-org</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;misohena/el-easydraw&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#008000">and</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/is-termux</span>) (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">edraw-org-setup-default</span>))
</span></span></code></pre></div><h4 id="managing-tables">Managing tables</h4>
<p>I use Org to manage some small tables which I want to process further. So here is a function that saves each table to a CSV file.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/export-org-tables-to-csv</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-table-map-tables</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">plist-get</span> (<span style="color:#19177c">cadr</span> (<span style="color:#19177c">org-element-at-point</span>)) <span style="color:#008000">:name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-table-export</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-name-directory</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-file-name</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;.csv&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;orgtbl-to-csv&#34;</span>)))))
</span></span></code></pre></div><h4 id="partial-scrolling">Partial scrolling</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">phscroll</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;misohena/phscroll&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">org-phscroll-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;org-phscroll</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-phscroll-deactivate</span>)))
</span></span></code></pre></div><h3 id="productivity-and-knowledge-management">Productivity &amp; Knowledge management</h3>
<p>My ongoing effort to <del>get a productivity setup</del> manage something in my life in Org.</p>
<p>Initial inspirations (<span class="timestamp-wrapper"><span class="timestamp">&lt;2021-06-30 Wed&gt;</span></span>):</p>
<ul>
<li><a href="https://www.labri.fr/perso/nrougier/GTD/index.html">Nicolas P. Rougier. Get Things Done with Emacs</a></li>
<li><a href="https://blog.jethro.dev/posts/org_mode_workflow_preview/">Jetro Kuan. Org-mode Workflow</a></li>
<li><a href="https://www.alexeyshmalko.com/how-i-note/">Alexey Shmalko: How I note</a></li>
<li><a href="https://rgoswami.me/posts/org-note-workflow/">Rohit Goswami: An Orgmode Note Workflow</a></li>
</ul>
<p>Current status of what I ended up using (<span class="timestamp-wrapper"><span class="timestamp">&lt;2023-12-16 Sat&gt;</span></span>):</p>
<ul>
<li><a href="#org-journal">org-journal</a> for keeping a journal</li>
<li><a href="#org-roam">org-roam</a> for a knowledge base.</li>
<li>org-agenda with org-clock for tasks</li>
</ul>
<h4 id="org-agenda-and-project-management">Org Agenda &amp; Project Management</h4>
<p>This section had seen a lot of experimentation over the last&hellip; well, years.</p>
<h5 id="agenda-and-refile-files">Agenda &amp; refile files</h5>
<p>All my project files live in the <code>/projects</code> directory, so here&rsquo;s a function to set up <code>org-agenda-files</code> and <code>org-refile-targets</code> accordingly.</p>
<p>Also, my project structure is somewhat chaotic, so I have an <code>.el</code> file in the org directory that defines some of the refile targets.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/update-org-agenda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">project-files</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">file-directory-p</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/projects&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span> <span style="color:#ba2121">&#34;/projects&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-files</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/projects/&#34;</span> <span style="color:#19177c">f</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#00f">file-directory-p</span> <span style="color:#19177c">f</span>))))))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-agenda-files</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span> <span style="color:#00f">#&#39;file-exists-p</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">append</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">project-files</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/&#34;</span> <span style="color:#19177c">f</span>))
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;inbox.org&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;misc/habit.org&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;contacts.org&#34;</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-refile-targets</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,@</span>(<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>) <span style="color:#666">`</span>(<span style="color:#666">,</span><span style="color:#19177c">f</span> <span style="color:#666">.</span> (<span style="color:#008000">:tag</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;refile&#34;</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">project-files</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,@</span>(<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>) <span style="color:#666">`</span>(<span style="color:#666">,</span><span style="color:#19177c">f</span> <span style="color:#666">.</span> (<span style="color:#008000">:regexp</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;Tasks&#34;</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">project-files</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">file-exists-p</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/scripts/refile.el&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">load-file</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/scripts/refile.el&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">run-hooks</span> <span style="color:#19177c">&#39;my/org-refile-hooks</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">org-roam-directory</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/roam&#34;</span>))
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;seq</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/update-org-agenda</span>))
</span></span></code></pre></div><p>Refile settings</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">org-refile-use-outline-path</span> <span style="color:#19177c">&#39;file</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">org-outline-path-complete-in-steps</span> <span style="color:#800">nil</span>)
</span></span></code></pre></div><p>My day ends late sometimes. Thanks John Wigley.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">org-extend-today-until</span> <span style="color:#666">4</span>)
</span></span></code></pre></div><h5 id="capture-templates">Capture templates</h5>
<p>Settings for Org capture mode. The goal here is to have a non-disruptive process to capture various ideas.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/generate-inbox-note-name</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;%s/inbox-notes/%s%s.org&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-directory</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format-time-string</span> <span style="color:#ba2121">&#34;%Y%m%d%H%M%S&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">note-name</span> (<span style="color:#00f">read-string</span> <span style="color:#ba2121">&#34;Note name: &#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">note-name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-replace</span> <span style="color:#ba2121">&#34; &#34;</span> <span style="color:#ba2121">&#34;-&#34;</span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;-&#34;</span> (<span style="color:#00f">downcase</span> <span style="color:#19177c">note-name</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">org-capture-templates</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#ba2121">&#34;i&#34;</span> <span style="color:#ba2121">&#34;Inbox&#34;</span> <span style="color:#19177c">entry</span> (<span style="color:#19177c">file</span> <span style="color:#ba2121">&#34;inbox.org&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;* TODO %?\n&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;/Entered on/ %U&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;e&#34;</span> <span style="color:#ba2121">&#34;email&#34;</span> <span style="color:#19177c">entry</span> (<span style="color:#19177c">file</span> <span style="color:#ba2121">&#34;inbox.org&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;* TODO %:from %:subject \n&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;/Entered on/ %U\n&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;/Received on/ %:date-timestamp-inactive\n&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;%a\n&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#ba2121">&#34;elfeed&#34;</span> <span style="color:#19177c">entry</span> (<span style="color:#19177c">file</span> <span style="color:#ba2121">&#34;inbox.org&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;* TODO %:elfeed-entry-title\n&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;/Entered on/ %U\n&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;%a\n&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;n&#34;</span> <span style="color:#ba2121">&#34;note&#34;</span> <span style="color:#19177c">plain</span> (<span style="color:#19177c">file</span> <span style="color:#19177c">my/generate-inbox-note-name</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;#+TODO: PROCESSED(p)\n&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\n&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;* %?\n&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;/Entered on/ %U&#34;</span>))))
</span></span></code></pre></div><h5 id="org-clock-and-org-clock-agg">org-clock &amp; org-clock-agg</h5>
<p><a href="https://orgmode.org/manual/Clocking-Work-Time.html">org-clock</a> allows for tracking time spent in Org entries. <a href="https://github.com/SqrtMinusOne/org-clock-agg">org-clock-agg</a> is my package for creating reports from org-clock records.</p>
<p>It&rsquo;s been somewhat complicated to integrate into my workflow, but I think it&rsquo;s been worth it because I can now create reports for:</p>
<ul>
<li>how much time i spent on which category of tasks (education / job / &hellip;);</li>
<li>time spent per activity, particularly time spent on meetings per category;</li>
<li>time spent per project</li>
<li>&hellip;</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-clock-agg</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;SqrtMinusOne/org-clock-agg&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">org-clock-agg</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ol&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-clock-agg</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-clock-agg-node-format</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;%-%(+ title-width)t %20c %8z %s/%S&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-clock-agg-node-title-width-delta</span> <span style="color:#666">47</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> <span style="color:#ba2121">&#34;Agenda+Archive&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">append</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-agenda-files</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span> <span style="color:#ba2121">&#34;/projects/archive&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-files</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/projects/archive/&#34;</span> <span style="color:#19177c">f</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#00f">file-directory-p</span> <span style="color:#19177c">f</span>)))))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-clock-agg-files-preset</span>))
</span></span></code></pre></div><p>The following enables org-clock persistence between Emacs sessions.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-clock-persist</span> <span style="color:#19177c">&#39;clock</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-clock-persistence-insinuate</span>))
</span></span></code></pre></div><p>Effort estimation. Not using this as of now.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;org-global-properties</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;Effort_ALL&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;0 0:05 0:10 0:15 0:30 0:45 1:00 1:30 2:00 4:00 8:00&#34;</span>)))
</span></span></code></pre></div><p>Log DONE time</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">org-log-done</span> <span style="color:#19177c">&#39;time</span>)
</span></span></code></pre></div><h6 id="custom-modeline-positioning">Custom modeline positioning</h6>
<p>I wanted <code>org-mode-line-string</code> to be prepended to <code>global-mode-string</code> rather than appended, but somehow the modeline stops working if <code>org-mode-line-string</code> is the first element&hellip; So I&rsquo;ll at least put it before my <code>exwm-modeline-segment</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-clock-in--fix-mode-line</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">memq</span> <span style="color:#19177c">&#39;org-mode-line-string</span> <span style="color:#19177c">global-mode-string</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> (<span style="color:#19177c">new-global-mode-string</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">appended</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">is-first</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">item</span> <span style="color:#19177c">global-mode-string</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">or</span> (<span style="color:#00f">equal</span> <span style="color:#19177c">item</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:eval</span> (<span style="color:#19177c">exwm-modeline-segment</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">equal</span> <span style="color:#19177c">item</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:eval</span> (<span style="color:#19177c">persp-mode-line</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">appended</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">is-first</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#19177c">new-global-mode-string</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#19177c">&#39;org-mode-line-string</span> <span style="color:#19177c">new-global-mode-string</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">appended</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#19177c">item</span> <span style="color:#19177c">new-global-mode-string</span>))
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">equal</span> <span style="color:#19177c">item</span> <span style="color:#19177c">&#39;org-mode-line-string</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#19177c">item</span> <span style="color:#19177c">new-global-mode-string</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">is-first</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">appended</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#19177c">&#39;org-mode-line-string</span> <span style="color:#19177c">new-global-mode-string</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">global-mode-string</span> (<span style="color:#00f">nreverse</span> <span style="color:#19177c">new-global-mode-string</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-clock-in-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-clock-in--fix-mode-line</span>)
</span></span></code></pre></div><h6 id="prompt-start-time-for-org-clock-in">Prompt start time for org-clock-in</h6>
<p>Support prompting for start time for <code>org-clock-in</code>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-clock-in-prompt-time</span> (<span style="color:#008000">&amp;optional</span> <span style="color:#19177c">select</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#ba2121">&#34;P&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-clock-in</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">select</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">encode-time</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-parse-time-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-read-date</span> <span style="color:#800">t</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;org-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;SPC&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;I&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-clock-in-prompt-time</span>))
</span></span></code></pre></div><h6 id="put-total-clocked-time-in-properties">Put total clocked time in properties</h6>
<p>By default, <code>org-clock</code> stores its results only in the <code>:LOGBOOK:</code> drawer, which doesn&rsquo;t get parsed by <code>org-element-at-point</code>. As such, clock resutls are inaccessible from <code>org-ql</code>.</p>
<p>This ensures that the total clocked time is also saved in the <code>:PROPERTIES:</code> drawer.</p>
<p>We can get the clocked value in minutes with <code>org-clock-sum</code>. This weird function stores what I need in buffer-local variables and text-properties.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-clock-get-total-minutes-at-point</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get total clocked time for heading at point.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">element</span> (<span style="color:#19177c">org-element-at-point-no-context</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">s</span> (<span style="color:#00f">buffer-substring-no-properties</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:begin</span> <span style="color:#19177c">element</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:end</span> <span style="color:#19177c">element</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#19177c">s</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-clock-sum</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-clock-file-total-minutes</span>)))
</span></span></code></pre></div><p>And use the function to set the total clocked time.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defconst</span> <span style="color:#19177c">my/org-clock-total-prop</span> <span style="color:#008000">:CLOCK_TOTAL</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-clock-set-total-clocked</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Set total clocked time for heading at point.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-back-to-heading</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-set-property</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">my/org-clock-total-prop</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-duration-from-minutes</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-clock-get-total-minutes-at-point</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-clock-in-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-clock-set-total-clocked</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-clock-out-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-clock-set-total-clocked</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-clock-cancel-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-clock-set-total-clocked</span>)
</span></span></code></pre></div><h6 id="switch-between-recently-clocked-items">Switch between recently clocked items</h6>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-clock-recent</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">entries</span> (<span style="color:#19177c">org-ql-query</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:select</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">element-with-markers</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:from</span> (<span style="color:#19177c">org-agenda-files</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:where</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">clocked</span> <span style="color:#008000">:from</span> <span style="color:#666">-1</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">entries-data</span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">e</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:raw-value</span> <span style="color:#19177c">e</span>) <span style="color:#19177c">e</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">entries</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">entries</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No recently clocked entries!&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">entries-data</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">entry</span> (<span style="color:#19177c">alist-get</span> (<span style="color:#00f">completing-read</span> <span style="color:#ba2121">&#34;Entry: &#34;</span> <span style="color:#19177c">entries-data</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">entries-data</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;equal</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">marker</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:org-marker</span> <span style="color:#19177c">entry</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">pop-to-buffer-same-window</span> (<span style="color:#00f">marker-buffer</span> <span style="color:#19177c">marker</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> <span style="color:#19177c">marker</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;org-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;SPC&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-clock-recent</span>))
</span></span></code></pre></div><h6 id="fix-tasks-without-task-kind">Fix tasks without TASK_KIND</h6>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-fix-task-kind</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">entries</span> (<span style="color:#19177c">org-ql-query</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:select</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">element-with-markers</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:from</span> (<span style="color:#00f">current-buffer</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:where</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">and</span> (<span style="color:#19177c">olp</span> <span style="color:#ba2121">&#34;Tasks&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">property</span> <span style="color:#ba2121">&#34;TASK_KIND&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">clocked</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-fold-show-all</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">entry</span> <span style="color:#19177c">entries</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">marker</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:org-marker</span> <span style="color:#19177c">entry</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-with-point-at</span> <span style="color:#19177c">marker</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">value</span> (<span style="color:#19177c">org-read-property-value</span> <span style="color:#ba2121">&#34;TASK_KIND&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-set-property</span> <span style="color:#ba2121">&#34;TASK_KIND&#34;</span> <span style="color:#19177c">value</span>)))))))
</span></span></code></pre></div><h5 id="org-super-agenda">org-super-agenda</h5>
<p><a href="https://github.com/alphapapa/org-super-agenda">org-super-agenda</a> is alphapapa&rsquo;s extension to group items in org-agenda. I don&rsquo;t use it instead of the standard agenda, but <code>org-ql</code> uses it for some of its views.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-super-agenda</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Alphapapa doesn&#39;t like evil</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">org-super-agenda-header-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;h&#34;</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;j&#34;</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;k&#34;</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;l&#34;</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-super-agenda--def-auto-group</span> <span style="color:#19177c">outline-path-file</span> <span style="color:#ba2121">&#34;their outline paths &amp; files&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:key-form</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-super-agenda--when-with-marker-buffer</span> (<span style="color:#19177c">org-super-agenda--get-marker</span> <span style="color:#19177c">item</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; org-ql depends on f and s anyway</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">s-join</span> <span style="color:#ba2121">&#34;/&#34;</span> (<span style="color:#00f">cons</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">f-filename</span> (<span style="color:#00f">buffer-file-name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-get-outline-path</span>))))))
</span></span></code></pre></div><p>It doesn&rsquo;t look great with org-bars mode, so&hellip;</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-super-agenda--make-agenda-header-around</span> (<span style="color:#19177c">fun</span> <span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">remove-text-properties</span> <span style="color:#666">0</span> (<span style="color:#00f">length</span> <span style="color:#19177c">name</span>) <span style="color:#666">&#39;</span>(<span style="color:#19177c">line-prefix</span> <span style="color:#800">nil</span>) <span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">remove-text-properties</span> <span style="color:#666">0</span> (<span style="color:#00f">length</span> <span style="color:#19177c">name</span>) <span style="color:#666">&#39;</span>(<span style="color:#19177c">wrap-prefix</span> <span style="color:#800">nil</span>) <span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">fun</span> (<span style="color:#00f">substring-no-properties</span> <span style="color:#19177c">name</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org-super-agenda</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#19177c">&#39;org-super-agenda--make-agenda-header</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-super-agenda--make-agenda-header-around</span>))
</span></span></code></pre></div><h5 id="org-ql">org-ql</h5>
<p><a href="https://github.com/alphapapa/org-ql">org-ql</a> is a package to query org files.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-ql</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-ql-ask-unsafe-queries</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; See https://github.com/alphapapa/org-ql/pull/237</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-ql-regexp-part-ts-time</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34; &#34;</span> (<span style="color:#19177c">repeat</span> <span style="color:#666">1</span> <span style="color:#666">2</span> <span style="color:#19177c">digit</span>) <span style="color:#ba2121">&#34;:&#34;</span> (<span style="color:#19177c">repeat</span> <span style="color:#666">2</span> <span style="color:#19177c">digit</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">optional</span> <span style="color:#ba2121">&#34;-&#34;</span> (<span style="color:#19177c">repeat</span> <span style="color:#666">1</span> <span style="color:#666">2</span> <span style="color:#19177c">digit</span>) <span style="color:#ba2121">&#34;:&#34;</span> (<span style="color:#19177c">repeat</span> <span style="color:#666">2</span> <span style="color:#19177c">digit</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;o&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;v&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-ql-view</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-ql-search</span>))
</span></span></code></pre></div><h6 id="recent-items">Recent items</h6>
<p>I just want to change the default grouping in <code>org-ql-view-recent-items</code>&hellip;</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">cl-defun</span> <span style="color:#19177c">my/org-ql-view-recent-items</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">&amp;key</span> <span style="color:#19177c">num-days</span> (<span style="color:#19177c">type</span> <span style="color:#19177c">&#39;ts</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">files</span> (<span style="color:#19177c">org-agenda-files</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">groups</span> <span style="color:#666">&#39;</span>((<span style="color:#008000">:auto-outline-path-file</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:auto-todo</span> <span style="color:#800">t</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Show items in FILES from last NUM-DAYS days with timestamps of TYPE.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">TYPE may be </span><span style="color:#19177c">`ts&#39;</span><span style="color:#ba2121">, </span><span style="color:#19177c">`ts-active&#39;</span><span style="color:#ba2121">, </span><span style="color:#19177c">`ts-inactive&#39;</span><span style="color:#ba2121">, </span><span style="color:#19177c">`clocked&#39;</span><span style="color:#ba2121">, or
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"></span><span style="color:#19177c">`closed&#39;</span><span style="color:#ba2121">.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> <span style="color:#008000">:num-days</span> (<span style="color:#19177c">read-number</span> <span style="color:#ba2121">&#34;Days: &#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:type</span> (<span style="color:#19177c">-&gt;&gt;</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">ts</span> <span style="color:#19177c">ts-active</span> <span style="color:#19177c">ts-inactive</span> <span style="color:#19177c">clocked</span> <span style="color:#19177c">closed</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">completing-read</span> <span style="color:#ba2121">&#34;Timestamp type: &#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#00f">intern</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; It doesn&#39;t make much sense to use other date-based selectors to</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; look into the past, so to prevent confusion, we won&#39;t allow them.</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">-let*</span> ((<span style="color:#19177c">query</span> (<span style="color:#008000">pcase-exhaustive</span> <span style="color:#19177c">type</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">or</span> <span style="color:#19177c">&#39;ts</span> <span style="color:#19177c">&#39;ts-active</span> <span style="color:#19177c">&#39;ts-inactive</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,</span><span style="color:#19177c">type</span> <span style="color:#008000">:from</span> <span style="color:#666">,</span>(<span style="color:#00f">-</span> <span style="color:#19177c">num-days</span>) <span style="color:#008000">:to</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">or</span> <span style="color:#19177c">&#39;clocked</span> <span style="color:#19177c">&#39;closed</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,</span><span style="color:#19177c">type</span> <span style="color:#008000">:from</span> <span style="color:#666">,</span>(<span style="color:#00f">-</span> <span style="color:#19177c">num-days</span>) <span style="color:#008000">:to</span> <span style="color:#666">0</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-ql-search</span> <span style="color:#19177c">files</span> <span style="color:#19177c">query</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:title</span> <span style="color:#ba2121">&#34;Recent items&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:sort</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">todo</span> <span style="color:#19177c">priority</span> <span style="color:#19177c">date</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:super-groups</span> <span style="color:#19177c">groups</span>)))
</span></span></code></pre></div><h6 id="return-all-todos">Return all TODOs</h6>
<p>A view to return all TODOs in a category.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-ql-all-todo</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; The hack I borrowed from notmuch to make &#34; &#34; a separator</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">crm-separator</span> <span style="color:#ba2121">&#34; &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">crm-local-completion-map</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">map</span> (<span style="color:#00f">make-sparse-keymap</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-keymap-parent</span> <span style="color:#19177c">map</span> <span style="color:#19177c">crm-local-completion-map</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">define-key</span> <span style="color:#19177c">map</span> <span style="color:#ba2121">&#34; &#34;</span> <span style="color:#19177c">&#39;self-insert-command</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">map</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">vertico-sort-function</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">categories</span> (<span style="color:#19177c">completing-read-multiple</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Categories: &#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;TEACH&#34;</span> <span style="color:#ba2121">&#34;EDU&#34;</span> <span style="color:#ba2121">&#34;JOB&#34;</span> <span style="color:#ba2121">&#34;LIFE&#34;</span> <span style="color:#ba2121">&#34;COMP&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-ql-search</span> (<span style="color:#19177c">org-agenda-files</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#008000">and</span> (<span style="color:#19177c">todo</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,@</span>(<span style="color:#008000">unless</span> (<span style="color:#19177c">seq-empty-p</span> <span style="color:#19177c">categories</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#19177c">category</span> <span style="color:#666">,@</span><span style="color:#19177c">categories</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:sort</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">priority</span> <span style="color:#19177c">todo</span> <span style="color:#19177c">deadline</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:super-groups</span> <span style="color:#666">&#39;</span>((<span style="color:#008000">:auto-outline-path-file</span> <span style="color:#800">t</span>)))))
</span></span></code></pre></div><h6 id="items-clocked-or-closed-today">Items clocked or closed today</h6>
<p>Some custom functions to account for <code>org-extend-today-until</code>. Needed because sometimes my daily reviews cross 00:00.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-ql-clocked-today</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">today</span> (<span style="color:#00f">format-time-string</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;%Y-%m-%d&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">days-to-time</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">-</span> (<span style="color:#19177c">org-today</span>) (<span style="color:#19177c">time-to-days</span> <span style="color:#666">0</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-ql-search</span> (<span style="color:#19177c">org-agenda-files</span>) <span style="color:#666">`</span>(<span style="color:#19177c">clocked</span> <span style="color:#008000">:from</span> <span style="color:#666">,</span><span style="color:#19177c">today</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:title</span> <span style="color:#ba2121">&#34;Clocked today&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:sort</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">todo</span> <span style="color:#19177c">priority</span> <span style="color:#19177c">date</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:super-groups</span> <span style="color:#666">&#39;</span>((<span style="color:#008000">:auto-outline-path-file</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:auto-todo</span> <span style="color:#800">t</span>)))))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-ql-closed-today</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">today</span> (<span style="color:#00f">format-time-string</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;%Y-%m-%d&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">days-to-time</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">-</span> (<span style="color:#19177c">org-today</span>) (<span style="color:#19177c">time-to-days</span> <span style="color:#666">0</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-ql-search</span> (<span style="color:#19177c">org-agenda-files</span>) <span style="color:#666">`</span>(<span style="color:#19177c">closed</span> <span style="color:#008000">:from</span> <span style="color:#666">,</span><span style="color:#19177c">today</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:title</span> <span style="color:#ba2121">&#34;Closed today&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:sort</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">todo</span> <span style="color:#19177c">priority</span> <span style="color:#19177c">date</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:super-groups</span> <span style="color:#666">&#39;</span>((<span style="color:#008000">:auto-outline-path-file</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:auto-todo</span> <span style="color:#800">t</span>)))))
</span></span></code></pre></div><h6 id="configuring-views">Configuring views</h6>
<p>Putting all the above in <code>org-ql-views</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">org-ql-views</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> <span style="color:#ba2121">&#34;Overview: All TODO&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-ql-all-todo</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> <span style="color:#ba2121">&#34;Review: Stale tasks&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> <span style="color:#008000">:buffers-files</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-agenda-files</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:query</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">and</span> (<span style="color:#19177c">todo</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">tags</span> <span style="color:#ba2121">&#34;nots&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">ts</span> <span style="color:#008000">:from</span> <span style="color:#666">-14</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:title</span> <span style="color:#ba2121">&#34;Review: Stale tasks&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:sort</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">todo</span> <span style="color:#19177c">priority</span> <span style="color:#19177c">date</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:super-groups</span> <span style="color:#666">&#39;</span>((<span style="color:#008000">:auto-outline-path-file</span> <span style="color:#800">t</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> <span style="color:#ba2121">&#34;Review: Unclocked tasks&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> <span style="color:#008000">:buffers-files</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-agenda-files</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:query</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">and</span> (<span style="color:#19177c">done</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ts</span> <span style="color:#008000">:from</span> <span style="color:#666">-14</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">clocked</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">tags</span> <span style="color:#ba2121">&#34;nots&#34;</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:title</span> <span style="color:#ba2121">&#34;Review: Unclocked tasks&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:sort</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">todo</span> <span style="color:#19177c">priority</span> <span style="color:#19177c">date</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:super-groups</span> <span style="color:#666">&#39;</span>((<span style="color:#008000">:auto-outline-path-file</span> <span style="color:#800">t</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> <span style="color:#ba2121">&#34;Review: Recently timestamped&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-ql-view-recent-items</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> <span style="color:#ba2121">&#34;Review: Clocked today&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-ql-clocked-today</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> <span style="color:#ba2121">&#34;Review: Closed today&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-ql-closed-today</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> <span style="color:#ba2121">&#34;Fix: tasks without TASK_KIND&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-ql-search</span> (<span style="color:#00f">current-buffer</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#008000">and</span> (<span style="color:#19177c">olp</span> <span style="color:#ba2121">&#34;Tasks&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">property</span> <span style="color:#ba2121">&#34;TASK_KIND&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">clocked</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:super-groups</span> <span style="color:#666">&#39;</span>((<span style="color:#008000">:auto-outline-path-file</span> <span style="color:#800">t</span>)))))))
</span></span></code></pre></div><h6 id="custom-format-element">Custom format element</h6>
<p>Changing the default <code>org-ql-view--format-element</code> to include effort estimation and the clocked time. I wish it were more configurable out-of-the-box.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-ql-view--format-element-override</span> (<span style="color:#19177c">element</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Format ELEMENT for </span><span style="color:#19177c">`org-ql-view&#39;</span><span style="color:#ba2121">.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Check </span><span style="color:#19177c">`org-ql-view--format-element&#39;</span><span style="color:#ba2121"> for the original implementation
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">and lots of comments which are too long for my Emacs config.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">element</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> <span style="color:#19177c">element</span> (<span style="color:#19177c">org-ql-view--resolve-element-properties</span> <span style="color:#19177c">element</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">properties</span> (<span style="color:#19177c">cadr</span> <span style="color:#19177c">element</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">properties</span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> (<span style="color:#19177c">key</span> <span style="color:#19177c">val</span>) <span style="color:#19177c">on</span> <span style="color:#19177c">properties</span> <span style="color:#19177c">by</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">cddr</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">symbol</span> <span style="color:#00f">=</span> (<span style="color:#00f">intern</span> (<span style="color:#19177c">cl-subseq</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">key</span>) <span style="color:#666">1</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">unless</span> (<span style="color:#00f">member</span> <span style="color:#19177c">symbol</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">parent</span>))
</span></span><span style="display:flex;"><span> <span style="color:#00f">append</span> (<span style="color:#00f">list</span> <span style="color:#19177c">symbol</span> <span style="color:#19177c">val</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">title</span> (<span style="color:#19177c">--&gt;</span> (<span style="color:#19177c">org-ql-view--add-faces</span> <span style="color:#19177c">element</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:raw-value</span> <span style="color:#19177c">it</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-link-display-format</span> <span style="color:#19177c">it</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">todo-keyword</span> (<span style="color:#19177c">-some--&gt;</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:todo-keyword</span> <span style="color:#19177c">element</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-ql-view--add-todo-face</span> <span style="color:#19177c">it</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tag-list</span> (<span style="color:#008000">if</span> <span style="color:#19177c">org-use-tag-inheritance</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">if-let</span> ((<span style="color:#19177c">marker</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:org-hd-marker</span> <span style="color:#19177c">element</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:org-marker</span> <span style="color:#19177c">element</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> (<span style="color:#00f">marker-buffer</span> <span style="color:#19177c">marker</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-with-wide-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> <span style="color:#19177c">marker</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">type</span> <span style="color:#19177c">in</span> (<span style="color:#19177c">org-ql--tags-at</span> <span style="color:#19177c">marker</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">unless</span> (<span style="color:#008000">or</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">&#39;org-ql-nil</span> <span style="color:#19177c">type</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> <span style="color:#19177c">type</span>))
</span></span><span style="display:flex;"><span> <span style="color:#00f">append</span> <span style="color:#19177c">type</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-warning</span> <span style="color:#19177c">&#39;org-ql</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;No marker found for item: %s&#34;</span> <span style="color:#19177c">title</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:tags</span> <span style="color:#19177c">element</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:tags</span> <span style="color:#19177c">element</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tag-string</span> (<span style="color:#008000">when</span> <span style="color:#19177c">tag-list</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">--&gt;</span> <span style="color:#19177c">tag-list</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">s-join</span> <span style="color:#ba2121">&#34;:&#34;</span> <span style="color:#19177c">it</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">s-wrap</span> <span style="color:#19177c">it</span> <span style="color:#ba2121">&#34;:&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-add-props</span> <span style="color:#19177c">it</span> <span style="color:#800">nil</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;org-tag</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (category (org-element-property :category element))</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">priority-string</span> (<span style="color:#19177c">-some-&gt;&gt;</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:priority</span> <span style="color:#19177c">element</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">char-to-string</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;[#%s]&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-ql-view--add-priority-face</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">clock-string</span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">effort</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:EFFORT</span> <span style="color:#19177c">element</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">clocked</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#19177c">my/org-clock-total-prop</span> <span style="color:#19177c">element</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">and</span> <span style="color:#19177c">clocked</span> <span style="color:#19177c">effort</span>) (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;[%s/%s]&#34;</span> <span style="color:#19177c">clocked</span> <span style="color:#19177c">effort</span>))
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">and</span> <span style="color:#19177c">clocked</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">effort</span>) (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;[%s]&#34;</span> <span style="color:#19177c">clocked</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">and</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">clocked</span>) <span style="color:#19177c">effort</span>) (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;[EST: %s]&#34;</span> <span style="color:#19177c">effort</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">habit-property</span> (<span style="color:#19177c">org-with-point-at</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:org-hd-marker</span> <span style="color:#19177c">element</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:org-marker</span> <span style="color:#19177c">element</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">org-is-habit-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-habit-parse-todo</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">due-string</span> (<span style="color:#008000">pcase</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:relative-due-date</span> <span style="color:#19177c">element</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;nil</span> <span style="color:#ba2121">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">string</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34; %s &#34;</span> (<span style="color:#19177c">org-add-props</span> <span style="color:#00f">string</span> <span style="color:#800">nil</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;org-ql-view-due-date</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">string</span> (<span style="color:#19177c">s-join</span> <span style="color:#ba2121">&#34; &#34;</span> (<span style="color:#19177c">-non-nil</span> (<span style="color:#00f">list</span> <span style="color:#19177c">todo-keyword</span> <span style="color:#19177c">priority-string</span> <span style="color:#19177c">title</span> <span style="color:#19177c">due-string</span> <span style="color:#19177c">clock-string</span> <span style="color:#19177c">tag-string</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">remove-list-of-text-properties</span> <span style="color:#666">0</span> (<span style="color:#00f">length</span> <span style="color:#00f">string</span>) <span style="color:#666">&#39;</span>(<span style="color:#19177c">line-prefix</span>) <span style="color:#00f">string</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">--&gt;</span> <span style="color:#00f">string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34; &#34;</span> <span style="color:#19177c">it</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-add-props</span> <span style="color:#19177c">it</span> <span style="color:#19177c">properties</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;org-agenda-type</span> <span style="color:#19177c">&#39;search</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;todo-state</span> <span style="color:#19177c">todo-keyword</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;tags</span> <span style="color:#19177c">tag-list</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;org-habit-p</span> <span style="color:#19177c">habit-property</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org-ql</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-ql-view--format-element</span> <span style="color:#008000">:override</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-ql-view--format-element-override</span>))
</span></span></code></pre></div><h5 id="tracking-habits">Tracking habits</h5>
<p>Let&rsquo;s see how this goes.</p>
<p>References:</p>
<ul>
<li><a href="https://orgmode.org/manual/Tracking-your-habits.html">https://orgmode.org/manual/Tracking-your-habits.html</a></li>
</ul>
<p><a href="https://github.com/ml729/org-habit-stats">org-habit-stats</a> is a pretty nice package. Using my fork until my PR is merged.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-habit-stats</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;ml729/org-habit-stats&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">org-habit-stats-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">emacs</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-habit-stats-exit</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-habit-stats-calendar-scroll-left</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-habit-stats-calendar-scroll-right</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;[&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-habit-stats-scroll-graph-left</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;]&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-habit-stats-scroll-graph-right</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;{&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-habit-stats-scroll-graph-left-big</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;}&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-habit-stats-scroll-graph-right-big</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;.&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-habit-stats-view-next-habit</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;,&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-habit-stats-view-previous-habit</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-after-todo-state-change-hook</span> <span style="color:#19177c">&#39;org-habit-stats-update-properties</span>))
</span></span></code></pre></div><h5 id="custom-agendas">Custom agendas</h5>
<p>Some custom agendas to fit my workflow.</p>
<p>See <a href="https://emacs.stackexchange.com/questions/18179/org-agenda-command-with-org-agenda-filter-by-tag-not-working">this answer</a> at Emacs StackExchange for filtering the <code>agenda</code> block by tag:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-match-at-point-p</span> (<span style="color:#19177c">match</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Return non-nil if headline at point matches MATCH.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Here MATCH is a match string of the same format used by
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"></span><span style="color:#19177c">`org-tags-view&#39;</span><span style="color:#ba2121">.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> (<span style="color:#00f">cdr</span> (<span style="color:#19177c">org-make-tags-matcher</span> <span style="color:#19177c">match</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-get-todo-state</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-get-tags-at</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-reduced-level</span> (<span style="color:#19177c">org-current-level</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-agenda-skip-without-match</span> (<span style="color:#19177c">match</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Skip current headline unless it matches MATCH.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Return nil if headline containing point matches MATCH (which
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">should be a match string of the same format used by
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"></span><span style="color:#19177c">`org-tags-view&#39;</span><span style="color:#ba2121">). If headline does not match, return the
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">position of the next headline in current buffer.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Intended for use with </span><span style="color:#19177c">`org-agenda-skip-function&#39;</span><span style="color:#ba2121">, where this will
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">skip exactly those headlines that do not match.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">org-at-heading-p</span>) (<span style="color:#19177c">org-back-to-heading</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">next-headline</span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">outline-next-heading</span>) (<span style="color:#00f">point-max</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">my/org-match-at-point-p</span> <span style="color:#19177c">match</span>) <span style="color:#800">nil</span> <span style="color:#19177c">next-headline</span>))))
</span></span></code></pre></div><p>And the agendas themselves:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-scheduled-get-time</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">scheduled</span> (<span style="color:#19177c">org-get-scheduled-time</span> (<span style="color:#00f">point</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">scheduled</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format-time-string</span> <span style="color:#ba2121">&#34;%Y-%m-%d&#34;</span> <span style="color:#19177c">scheduled</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">org-agenda-hide-tags-regexp</span> (<span style="color:#008000">rx</span> (<span style="color:#008000">or</span> <span style="color:#ba2121">&#34;org&#34;</span> <span style="color:#ba2121">&#34;refile&#34;</span> <span style="color:#ba2121">&#34;proj&#34;</span> <span style="color:#ba2121">&#34;habit&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">org-agenda-custom-commands</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#ba2121">&#34;p&#34;</span> <span style="color:#ba2121">&#34;My outline&#34;</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">agenda</span> <span style="color:#ba2121">&#34;&#34;</span> ((<span style="color:#19177c">org-agenda-skip-function</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">my/org-agenda-skip-without-match</span> <span style="color:#ba2121">&#34;-habit&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tags-todo</span> <span style="color:#ba2121">&#34;inbox&#34;</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">org-agenda-overriding-header</span> <span style="color:#ba2121">&#34;Inbox&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-agenda-prefix-format</span> <span style="color:#ba2121">&#34; %i %-12:c&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-agenda-hide-tags-regexp</span> <span style="color:#ba2121">&#34;.&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tags-todo</span> <span style="color:#ba2121">&#34;+waitlist+SCHEDULED&lt;=\&#34;&lt;+14d&gt;\&#34;&#34;</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">org-agenda-overriding-header</span> <span style="color:#ba2121">&#34;Waitlist&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-agenda-hide-tags-regexp</span> <span style="color:#ba2121">&#34;waitlist&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-agenda-prefix-format</span> <span style="color:#ba2121">&#34; %i %-12:c %-12(my/org-scheduled-get-time)&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tags-todo</span> <span style="color:#ba2121">&#34;habit+SCHEDULED&lt;=\&#34;&lt;+0d&gt;\&#34;&#34;</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">org-agenda-overriding-header</span> <span style="color:#ba2121">&#34;Habits&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-agenda-prefix-format</span> <span style="color:#ba2121">&#34; %i %-12:c&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-agenda-hide-tags-regexp</span> <span style="color:#ba2121">&#34;.&#34;</span>)))))))
</span></span></code></pre></div><h5 id="alerts">Alerts</h5>
<ul>
<li>Me at 10:00: <em>Open Org Agenga</em> oh, there&rsquo;s a meeting at 15:00</li>
<li>Me at 14:00: <em>Open Org Agenda</em> oh, there&rsquo;s a meeting at 15:00</li>
<li>Me at 14:45: Gotta remember to join in 15 minutes</li>
<li>Me at 14:55: Gotta remember to join in 5 minutes</li>
<li>Me at 15:05: Sh*t</li>
</ul>
<p>Okay, I will set up <del>org-alert</del> some custom alert system.</p>
<p>There&rsquo;s also <a href="https://gitlab.com/grinn.amy/org-yaap">org-yaap</a> by Amy Grinn, but I opt for my system for now.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-yaap</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#19177c">org-yaap</span> <span style="color:#008000">:type</span> <span style="color:#19177c">git</span> <span style="color:#008000">:host</span> <span style="color:#19177c">gitlab</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;SqrtMinusOne/org-yaap&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/nested-emacs</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-yaap-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-yaap-alert-before</span> <span style="color:#666">&#39;</span>(<span style="color:#666">10</span> <span style="color:#666">1</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-yaap-alert-title</span> <span style="color:#ba2121">&#34;PROXIMITY ALERT&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-yaap-todo-keywords-only</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;FUTURE&#34;</span>)))
</span></span></code></pre></div><p>I want to have multiple warnings, let it be 10 minutes in advance and 1 minute in advance for now.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/org-alert-notify-times</span> <span style="color:#666">&#39;</span>(<span style="color:#666">600</span> <span style="color:#666">60</span>))
</span></span></code></pre></div><p>And IDK if that makes much sense, but I&rsquo;ll try to avoid re-creating timers. So, here are functions to schedule showing some label at some time and to check whether the label is scheduled:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/org-alert--alerts</span> (<span style="color:#00f">make-hash-table</span> <span style="color:#008000">:test</span> <span style="color:#00f">#&#39;equal</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-alert--is-scheduled</span> (<span style="color:#19177c">label</span> <span style="color:#19177c">time</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Check if LABEL is scheduled to be shown an TIME.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">gethash</span> (<span style="color:#00f">cons</span> <span style="color:#19177c">label</span> <span style="color:#19177c">time</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/org-alert--alerts</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-alert--schedule</span> (<span style="color:#19177c">label</span> <span style="color:#19177c">time</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Schedule LABEL to be shown at TIME, unless it&#39;s already scheduled.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">my/org-alert--is-scheduled</span> <span style="color:#19177c">label</span> <span style="color:#19177c">time</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">puthash</span> (<span style="color:#00f">cons</span> <span style="color:#19177c">label</span> <span style="color:#19177c">time</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">run-at-time</span> <span style="color:#19177c">time</span>
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alert</span> <span style="color:#19177c">label</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:title</span> <span style="color:#ba2121">&#34;PROXIMITY ALERT&#34;</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/org-alert--alerts</span>)))
</span></span></code></pre></div><p>And unschedule items that need to be unscheduled:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-alert-cleanup</span> (<span style="color:#008000">&amp;optional</span> <span style="color:#19177c">keys</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Unschedule items that do not appear in KEYS.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">KEYS is a list of cons cells like (&lt;label&gt; . &lt;time&gt;).&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">existing-hash</span> (<span style="color:#00f">make-hash-table</span> <span style="color:#008000">:test</span> <span style="color:#00f">#&#39;equal</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">key</span> <span style="color:#19177c">in</span> <span style="color:#19177c">keys</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">puthash</span> <span style="color:#19177c">key</span> <span style="color:#800">t</span> <span style="color:#19177c">existing-hash</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">key</span> <span style="color:#19177c">being</span> <span style="color:#19177c">the</span> <span style="color:#19177c">hash-keys</span> <span style="color:#19177c">of</span> <span style="color:#19177c">my/org-alert--alerts</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">unless</span> (<span style="color:#00f">gethash</span> <span style="color:#19177c">key</span> <span style="color:#19177c">existing-hash</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cancel-timer</span> (<span style="color:#00f">gethash</span> <span style="color:#19177c">key</span> <span style="color:#19177c">my/org-alert--alerts</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">remhash</span> <span style="color:#19177c">key</span> <span style="color:#19177c">my/org-alert--alerts</span>)))))
</span></span></code></pre></div><p>And a function to extract the required items with <code>org-ql-query</code> and schedule them:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-alert--update-today-alerts</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let*</span> ((<span style="color:#19177c">files</span> (<span style="color:#19177c">org-agenda-files</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">items</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-ql-query</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:select</span> <span style="color:#19177c">&#39;element</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:from</span> <span style="color:#19177c">files</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:where</span> <span style="color:#666">`</span>(<span style="color:#008000">and</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">todo</span> <span style="color:#ba2121">&#34;FUTURE&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ts-active</span> <span style="color:#008000">:from</span> <span style="color:#666">,</span>(<span style="color:#00f">format-time-string</span> <span style="color:#ba2121">&#34;%Y-%m-%d %H:%M&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:to</span> <span style="color:#666">,</span>(<span style="color:#00f">format-time-string</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;%Y-%m-%d&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">time-add</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">current-time</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">*</span> <span style="color:#666">60</span> <span style="color:#666">60</span> <span style="color:#666">24</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:with-time</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:order-by</span> <span style="color:#19177c">&#39;date</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> (<span style="color:#19177c">scheduled-keys</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">item</span> <span style="color:#19177c">in</span> <span style="color:#19177c">items</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">scheduled</span> <span style="color:#00f">=</span> (<span style="color:#19177c">org-timestamp-to-time</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:scheduled</span> <span style="color:#19177c">item</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#008000">cl-loop</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">before-time</span> <span style="color:#19177c">in</span> <span style="color:#19177c">my/org-alert-notify-times</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">label</span> <span style="color:#00f">=</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%s at %s [%s min. remaining]&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:raw-value</span> <span style="color:#19177c">item</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format-time-string</span> <span style="color:#ba2121">&#34;%H:%M&#34;</span> <span style="color:#19177c">scheduled</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">number-to-string</span> (<span style="color:#00f">/</span> <span style="color:#19177c">before-time</span> <span style="color:#666">60</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">time</span> <span style="color:#00f">=</span> (<span style="color:#19177c">time-convert</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">+</span> (<span style="color:#19177c">time-convert</span> <span style="color:#19177c">scheduled</span> <span style="color:#19177c">&#39;integer</span>) (<span style="color:#00f">-</span> <span style="color:#19177c">before-time</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-alert--schedule</span> <span style="color:#19177c">label</span> <span style="color:#19177c">time</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> (<span style="color:#00f">cons</span> <span style="color:#19177c">label</span> <span style="color:#19177c">time</span>) <span style="color:#19177c">scheduled-keys</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-alert-cleanup</span> <span style="color:#19177c">scheduled-keys</span>))))
</span></span></code></pre></div><p>Let&rsquo;s wrap it into a minor mode:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/org-alert--timer</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">define-minor-mode</span> <span style="color:#19177c">my/org-alert-mode</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#008000">:global</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">my/org-alert-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-alert--update-today-alerts</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">timerp</span> <span style="color:#19177c">my/org-alert--timer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cancel-timer</span> <span style="color:#19177c">my/org-alert--timer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/org-alert--timer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">run-at-time</span> <span style="color:#666">600</span> <span style="color:#800">t</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-alert--update-today-alerts</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">timerp</span> <span style="color:#19177c">my/org-alert--timer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cancel-timer</span> <span style="color:#19177c">my/org-alert--timer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-alert-cleanup</span>)))
</span></span></code></pre></div><p>I don&rsquo;t have any idea why, but evaluating <code>(my/org-alert-mode)</code> just after <code>org</code> breaks font-lock after I try to open <code>inbox.org</code>. <code>emacs-startup-hook</code>, however, works fine.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">my/emacs-started</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-alert-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;emacs-startup-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-alert-mode</span>)))
</span></span></code></pre></div><h5 id="seqeuential-headers">Seqeuential headers</h5>
<p>I like to add numbers to repeating events, like meetings. E.g.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>* Job meeting 62
</span></span><span style="display:flex;"><span>SCHEDULED: &lt;2022-11-13 16:00&gt;
</span></span><span style="display:flex;"><span>* Job meeting 63
</span></span><span style="display:flex;"><span>SCHEDULED: &lt;2022-11-14 16:00&gt;
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><h6 id="copying-records">Copying records</h6>
<p>Naturally, I want a way to copy such records. Org Mode already has a function called <code>org-clone-subtree-with-time-shift</code>, that does everything I want except for updating the numbers.</p>
<p>Unfortunately, I see no way to advise the original function, so here&rsquo;s my version that makes use of <code>evil-numbers</code>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-clone-subtree-with-time-shift</span> (<span style="color:#19177c">n</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">shift</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#ba2121">&#34;nNumber of clones to produce: &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">wholenump</span> <span style="color:#19177c">n</span>) (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Invalid number of replications %s&#34;</span> <span style="color:#19177c">n</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">org-before-first-heading-p</span>) (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No subtree to clone&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">beg</span> (<span style="color:#008000">save-excursion</span> (<span style="color:#19177c">org-back-to-heading</span> <span style="color:#800">t</span>) (<span style="color:#00f">point</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">end-of-tree</span> (<span style="color:#008000">save-excursion</span> (<span style="color:#19177c">org-end-of-subtree</span> <span style="color:#800">t</span> <span style="color:#800">t</span>) (<span style="color:#00f">point</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shift</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> <span style="color:#19177c">shift</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">and</span> (<span style="color:#19177c">not</span> (<span style="color:#00f">equal</span> <span style="color:#19177c">current-prefix-arg</span> <span style="color:#666">&#39;</span>(<span style="color:#666">4</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> <span style="color:#19177c">beg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">re-search-forward</span> <span style="color:#19177c">org-ts-regexp-both</span> <span style="color:#19177c">end-of-tree</span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">read-from-minibuffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Date shift per clone (e.g. +1w, empty to copy unchanged): &#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span>))) <span style="color:#408080;font-style:italic">;No time shift</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">doshift</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span> (<span style="color:#19177c">org-string-nw-p</span> <span style="color:#19177c">shift</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#00f">string-match</span> <span style="color:#ba2121">&#34;\\`[ \t]*\\([+-]?[0-9]+\\)\\([hdwmy]\\)[ \t]*\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">shift</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Invalid shift specification %s&#34;</span> <span style="color:#19177c">shift</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> <span style="color:#19177c">end-of-tree</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">bolp</span>) (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;\n&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">end</span> (<span style="color:#00f">point</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">template</span> (<span style="color:#00f">buffer-substring</span> <span style="color:#19177c">beg</span> <span style="color:#19177c">end</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shift-n</span> (<span style="color:#008000">and</span> <span style="color:#19177c">doshift</span> (<span style="color:#00f">string-to-number</span> (<span style="color:#19177c">match-string</span> <span style="color:#666">1</span> <span style="color:#19177c">shift</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shift-what</span> (<span style="color:#008000">pcase</span> (<span style="color:#008000">and</span> <span style="color:#19177c">doshift</span> (<span style="color:#19177c">match-string</span> <span style="color:#666">2</span> <span style="color:#19177c">shift</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#666">`</span><span style="color:#800">nil</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;h&#34;</span> <span style="color:#19177c">&#39;hour</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#19177c">&#39;day</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;w&#34;</span> (<span style="color:#008000">setq</span> <span style="color:#19177c">shift-n</span> (<span style="color:#00f">*</span> <span style="color:#666">7</span> <span style="color:#19177c">shift-n</span>)) <span style="color:#19177c">&#39;day</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;m&#34;</span> <span style="color:#19177c">&#39;month</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;y&#34;</span> <span style="color:#19177c">&#39;year</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">_</span> (<span style="color:#d2413a;font-weight:bold">error</span> <span style="color:#ba2121">&#34;Unsupported time unit&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">nmin</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">nmax</span> <span style="color:#19177c">n</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">n-no-remove</span> <span style="color:#666">-1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-id-overriding-file-name</span> (<span style="color:#00f">buffer-file-name</span> (<span style="color:#00f">buffer-base-buffer</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">idprop</span> (<span style="color:#19177c">org-entry-get</span> <span style="color:#19177c">beg</span> <span style="color:#ba2121">&#34;ID&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">and</span> <span style="color:#19177c">doshift</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;&lt;[^&lt;&gt;\n]+ [.+]?\\+[0-9]+[hdwmy][^&lt;&gt;\n]*&gt;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">template</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">delete-region</span> <span style="color:#19177c">beg</span> <span style="color:#19177c">end</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">end</span> <span style="color:#19177c">beg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">nmin</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">nmax</span> (<span style="color:#00f">1+</span> <span style="color:#19177c">nmax</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">n-no-remove</span> <span style="color:#19177c">nmax</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> <span style="color:#19177c">end</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">n</span> <span style="color:#19177c">from</span> <span style="color:#19177c">nmin</span> <span style="color:#19177c">to</span> <span style="color:#19177c">nmax</span> <span style="color:#008000">do</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Prepare clone.</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#19177c">template</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-min</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-show-subtree</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span> <span style="color:#19177c">idprop</span> (<span style="color:#008000">if</span> <span style="color:#19177c">org-clone-delete-id</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-entry-delete</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;ID&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-id-get-create</span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">=</span> <span style="color:#19177c">n</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">while</span> (<span style="color:#00f">re-search-forward</span> <span style="color:#19177c">org-clock-line-re</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">delete-region</span> (<span style="color:#00f">line-beginning-position</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">line-beginning-position</span> <span style="color:#666">2</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-min</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">while</span> (<span style="color:#00f">re-search-forward</span> <span style="color:#19177c">org-drawer-regexp</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-remove-empty-drawer-at</span> (<span style="color:#00f">point</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-min</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">doshift</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">while</span> (<span style="color:#00f">re-search-forward</span> <span style="color:#19177c">org-ts-regexp-both</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-timestamp-change</span> (<span style="color:#00f">*</span> <span style="color:#19177c">n</span> <span style="color:#19177c">shift-n</span>) <span style="color:#19177c">shift-what</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-min</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-numbers/inc-at-pt</span> <span style="color:#19177c">n</span> (<span style="color:#00f">point-min</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">=</span> <span style="color:#19177c">n</span> <span style="color:#19177c">n-no-remove</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-min</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">while</span> (<span style="color:#00f">re-search-forward</span> <span style="color:#19177c">org-ts-regexp</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">match-beginning</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">looking-at</span> <span style="color:#ba2121">&#34;&lt;[^&lt;&gt;\n]+\\( +[.+]?\\+[0-9]+[hdwmy]\\)&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">delete-region</span> (<span style="color:#00f">match-beginning</span> <span style="color:#666">1</span>) (<span style="color:#00f">match-end</span> <span style="color:#666">1</span>)))))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-string</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> <span style="color:#19177c">beg</span>)))
</span></span></code></pre></div><p>My addition to that is the form with <code>evil-numbers/inc-at-pt</code>.</p>
<h6 id="keeping-consistency-among-sequential-records">Keeping consistency among sequential records</h6>
<p>I also like to keep such headers consistent. Here are a few tools to help with that.</p>
<p>First, I need to find and group and such headers. <code>org-ql</code> can help with that:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org--headings-in-outline</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-ql-query</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:select</span> (<span style="color:#008000">lambda</span> () (<span style="color:#00f">propertize</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring-no-properties</span> (<span style="color:#19177c">org-get-heading</span> <span style="color:#800">t</span> <span style="color:#800">t</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;marker</span> (<span style="color:#00f">copy-marker</span> (<span style="color:#00f">point</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:from</span> (<span style="color:#00f">append</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#00f">buffer-file-name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">archive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> (<span style="color:#00f">file-name-directory</span> (<span style="color:#00f">buffer-file-name</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;archive/&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-name-nondirectory</span> (<span style="color:#00f">buffer-file-name</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">archive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> <span style="color:#19177c">archive</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:where</span> <span style="color:#666">`</span>(<span style="color:#008000">and</span> (<span style="color:#19177c">outline-path</span> <span style="color:#666">,@</span>(<span style="color:#19177c">org-get-outline-path</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">level</span> <span style="color:#666">,</span>(<span style="color:#19177c">org-current-level</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org--heading-strip</span> (<span style="color:#19177c">heading</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">heading</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring-no-properties</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp-in-string</span> (<span style="color:#008000">rx</span> (<span style="color:#19177c">|</span> <span style="color:#ba2121">&#34;(&#34;</span> <span style="color:#ba2121">&#34;[&#34;</span>) (<span style="color:#00f">+</span> <span style="color:#19177c">nonl</span>) (<span style="color:#19177c">|</span> <span style="color:#ba2121">&#34;]&#34;</span> <span style="color:#ba2121">&#34;)&#34;</span>)) <span style="color:#ba2121">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp-in-string</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34; &#34;</span> (<span style="color:#00f">+</span> (<span style="color:#008000">or</span> <span style="color:#19177c">digit</span> <span style="color:#ba2121">&#34;.&#34;</span>))) <span style="color:#ba2121">&#34; &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp-in-string</span> (<span style="color:#008000">rx</span> (<span style="color:#00f">+</span> <span style="color:#ba2121">&#34; &#34;</span>)) <span style="color:#ba2121">&#34; &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-trim</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org--headings-group-seq</span> (<span style="color:#19177c">headings</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">headings</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-group-by</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org--heading-strip</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-sort-by</span> <span style="color:#00f">#&#39;car</span> <span style="color:#00f">#&#39;string-lessp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">group</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> (<span style="color:#00f">car</span> <span style="color:#19177c">group</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-sort-by</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">heading</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-match-data</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span> (<span style="color:#00f">string-match</span> (<span style="color:#008000">rx</span> (<span style="color:#19177c">group</span> (<span style="color:#00f">+</span> <span style="color:#19177c">digit</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">heading</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">string-to-number</span> (<span style="color:#19177c">match-string</span> <span style="color:#666">1</span> <span style="color:#19177c">heading</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#666">-1</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;&lt;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">group</span>)))))))
</span></span></code></pre></div><p>Then, display all such headings a buffer:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-headings-seq</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">headings</span> (<span style="color:#19177c">my/org--headings-in-outline</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">headings-seq</span> (<span style="color:#19177c">my/org--headings-group-seq</span> <span style="color:#19177c">headings</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">buffer</span> (<span style="color:#19177c">generate-new-buffer</span> <span style="color:#ba2121">&#34;*Sequential Headings in Outline*&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">outline-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">widget-push-button-prefix</span> <span style="color:#ba2121">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">widget-push-button-suffix</span> <span style="color:#ba2121">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">group</span> <span style="color:#19177c">headings-seq</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;* %s\n&#34;</span> (<span style="color:#00f">car</span> <span style="color:#19177c">group</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">heading</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">group</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">widget-create</span> <span style="color:#19177c">&#39;push-button</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:marker</span> (<span style="color:#00f">get-text-property</span> <span style="color:#666">0</span> <span style="color:#19177c">&#39;marker</span> <span style="color:#19177c">heading</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:notify</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">widget</span> <span style="color:#008000">&amp;rest</span> <span style="color:#19177c">ignore</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">marker</span> (<span style="color:#00f">widget-get</span> <span style="color:#19177c">widget</span> <span style="color:#008000">:marker</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">pop-to-buffer</span> (<span style="color:#00f">marker-buffer</span> <span style="color:#19177c">marker</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> <span style="color:#19177c">marker</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;** &#34;</span> (<span style="color:#00f">substring-no-properties</span> <span style="color:#19177c">heading</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;\n&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">widget-setup</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">buffer-read-only</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-min</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">pop-to-buffer</span> <span style="color:#19177c">buffer</span>)))
</span></span></code></pre></div><p>And insert a similar heading:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-heading-seq-insert</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">headings</span> (<span style="color:#19177c">my/org--headings-in-outline</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">headings-seq</span> (<span style="color:#19177c">my/org--headings-group-seq</span> <span style="color:#19177c">headings</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">heading</span> (<span style="color:#00f">completing-read</span> <span style="color:#ba2121">&#34;Headings: &#34;</span> <span style="color:#19177c">headings-seq</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">last-number</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span> <span style="color:#19177c">headings-seq</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">heading</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">x</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-match-data</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">string-match</span> (<span style="color:#008000">rx</span> (<span style="color:#19177c">group</span> (<span style="color:#00f">+</span> <span style="color:#19177c">digit</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">x</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">string-to-number</span> (<span style="color:#19177c">match-string</span> <span style="color:#666">1</span> <span style="color:#19177c">x</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#666">1</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-max</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">1+</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-insert-heading</span> <span style="color:#666">&#39;</span>(<span style="color:#666">4</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;FUTURE %s %s&#34;</span> <span style="color:#19177c">heading</span> <span style="color:#19177c">last-number</span>))))
</span></span></code></pre></div><h5 id="archiving-records">Archiving records</h5>
<ul>
<li><strong>CREDIT</strong>: thanks <a href="https://emacs.ch/@grinn">Amy</a> for pointing me to the right functionality of <code>org-refile</code>.</li>
</ul>
<p>I have several org files for long-running projects. They are getting hard to manage because there are lots of different tasks, events, etc.</p>
<p>So I want to create &ldquo;archive versions&rdquo; of these files which would have the same structure but store items, say, with a timestamp older than 2 months.</p>
<p>Archive versions are to be stored in the <code>archive</code> subdirectory relative to the current file, e.g., <code>foo.org</code> -&gt; <code>archive/foo.org</code>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-archive--get-file</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get an archive version of the file.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">archive-file</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-name-directory</span> (<span style="color:#00f">buffer-file-name</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;archive/&#34;</span> (<span style="color:#00f">file-name-nondirectory</span> (<span style="color:#00f">buffer-file-name</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">archive-file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">make-empty-file</span> <span style="color:#19177c">archive-file</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">archive-file</span>))
</span></span></code></pre></div><p>In order to maintain structure, we need to make sure that the archive version has all the necessary headers.</p>
<p><code>org-refile</code> (or, to be precise, <code>org-refile-get-location</code>) by itself can create the last level of headers with <code>org-refile-allow-creating-parent-nodes</code>. So I can just invoke the same logic for all missing headers:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-refile--assert-path-exists</span> (<span style="color:#19177c">refile-path</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">cl-assert</span> (<span style="color:#00f">equal</span> <span style="color:#19177c">org-refile-use-outline-path</span> <span style="color:#19177c">&#39;file</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">parts</span> (<span style="color:#19177c">string-split</span> <span style="color:#19177c">refile-path</span> <span style="color:#ba2121">&#34;/&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tbl</span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">x</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> (<span style="color:#00f">concat</span> (<span style="color:#00f">car</span> <span style="color:#19177c">x</span>) <span style="color:#ba2121">&#34;/&#34;</span>) (<span style="color:#00f">cdr</span> <span style="color:#19177c">x</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-refile-target-table</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">i</span> <span style="color:#19177c">from</span> <span style="color:#666">1</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">part</span> <span style="color:#19177c">in</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">parts</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">target</span> <span style="color:#00f">=</span> (<span style="color:#19177c">org-refile--get-location</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-join</span> (<span style="color:#19177c">seq-take</span> <span style="color:#19177c">parts</span> (<span style="color:#00f">1+</span> <span style="color:#19177c">i</span>)) <span style="color:#ba2121">&#34;/&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">tbl</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">unless</span> <span style="color:#19177c">target</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">parent-target</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-refile--get-location</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-join</span> (<span style="color:#19177c">seq-take</span> <span style="color:#19177c">parts</span> <span style="color:#19177c">i</span>) <span style="color:#ba2121">&#34;/&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">tbl</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> (<span style="color:#19177c">org-refile-new-child</span> <span style="color:#19177c">parent-target</span> <span style="color:#19177c">part</span>) <span style="color:#19177c">tbl</span>)))))
</span></span></code></pre></div><p>Now we can make a function to archive one record interactively.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-archive-refile</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">org-refile-targets</span> <span style="color:#666">`</span>((<span style="color:#666">,</span>(<span style="color:#19177c">my/org-archive--get-file</span>) <span style="color:#666">.</span> (<span style="color:#008000">:maxlevel</span> <span style="color:#666">.</span> <span style="color:#666">6</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-refile-target-table</span> (<span style="color:#19177c">org-refile-get-targets</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-refile-history</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-refile-use-outline-path</span> <span style="color:#19177c">&#39;file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-refile-allow-creating-parent-nodes</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-outline-path-complete-in-steps</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">refile-path</span> (<span style="color:#19177c">string-join</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">append</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#00f">file-name-nondirectory</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-file-name</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-get-outline-path</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;/&#34;</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; The path is already known</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-letf</span> (((<span style="color:#00f">symbol-function</span> <span style="color:#19177c">&#39;completing-read</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">_</span>) <span style="color:#19177c">refile-path</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-refile--assert-path-exists</span> <span style="color:#19177c">refile-path</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-refile</span>))))
</span></span></code></pre></div><p>And a function to archive all records older than the given number of days. I&rsquo;ll use <code>org-ql</code> to find these records.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-archive-refile-all</span> (<span style="color:#19177c">days</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> (<span style="color:#19177c">read-number</span> <span style="color:#ba2121">&#34;Days: &#34;</span> <span style="color:#666">60</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">records</span> (<span style="color:#19177c">org-ql-query</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:select</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">element-with-markers</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:from</span> (<span style="color:#00f">current-buffer</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:where</span> <span style="color:#666">`</span>(<span style="color:#008000">and</span> (<span style="color:#19177c">ts</span> <span style="color:#008000">:to</span> <span style="color:#666">,</span>(<span style="color:#00f">-</span> <span style="color:#19177c">days</span>)) (<span style="color:#19177c">done</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">y-or-n-p</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;Archive %d records? &#34;</span> (<span style="color:#00f">length</span> <span style="color:#19177c">records</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">record</span> <span style="color:#19177c">records</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">marker</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:org-marker</span> <span style="color:#19177c">record</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-with-point-at</span> <span style="color:#19177c">marker</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-archive-refile</span>)))))))
</span></span></code></pre></div><h5 id="keybindings-3">Keybindings</h5>
<p>Global keybindings:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;o&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;org-mode&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#19177c">&#39;org-capture</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;a&#34;</span> <span style="color:#19177c">&#39;org-agenda</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-file-open</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;v&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-ql-view</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-ql-search</span>)
</span></span></code></pre></div><p>Local keybindings</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;SPC&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">org-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;i&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-clock-in</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-clock-out</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;O&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-clock-cancel</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-clock-goto</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;p&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-set-property</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;e&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-set-effort</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-priority</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;m&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-meeting-link</span>))
</span></span></code></pre></div><h4 id="org-journal-1">Org Journal</h4>
<p><a href="https://github.com/bastibe/org-journal">org-journal</a> is a package for maintaining a journal in org mode.</p>
<p>This part turned out to be great. I even consulted the journal a few times to check if something actually happened, which makes me uneasy now that I think about it&hellip;</p>
<p>One issue I found is that it&rsquo;s kinda hard to find anything in the journal, and I&rsquo;m not eager to open the journal for a random date anyway. So I&rsquo;ve made a package called <a href="https://github.com/SqrtMinusOne/org-journal-tags">org-journal-tags</a>.</p>
<p>My initial desire was to be able to query the journal for my thoughts on a particular subject or theme, for progress on some project, or for records related to some person&hellip; Which is kinda useful, although not quite as much as I expected it to be. Relatively fast querying of the journal is also nice.</p>
<p>The section I named &ldquo;on this day&rdquo; turned out to be particularly interesting, as it kinda allowed me to connect with past versions of myself.</p>
<p>And it was interesting to find the reinforcement effect of checked dates on the calendar.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-journal</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;oj&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;org-journal&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;j&#34;</span> <span style="color:#19177c">&#39;org-journal-new-entry</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#19177c">&#39;org-journal-open-current-journal-file</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#19177c">&#39;org-journal-tags-status</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">org</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-journal-dir</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/journal&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-journal-file-type</span> <span style="color:#19177c">&#39;weekly</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-journal-file-format</span> <span style="color:#ba2121">&#34;%Y-%m-%d.org&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-journal-date-format</span> <span style="color:#ba2121">&#34;%A, %Y-%m-%d&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-journal-enable-encryption</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-journal-time-format-post-midnight</span> <span style="color:#ba2121">&#34;PM: %R &#34;</span>))
</span></span></code></pre></div><p>So, <a href="https://github.com/SqrtMinusOne/org-journal-tags">org-journal-tags</a> is my package that implements a tagging system for org-journal.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-journal-tags</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;SqrtMinusOne/org-journal-tags&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org-journal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-journal-tags-autosync-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;org-journal-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c t&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-journal-tags-insert-tag</span>))
</span></span></code></pre></div><p>Also, I want to add some extra information to the journal. Here&rsquo;s a functionality to get the current weather from wttr.in:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">request</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:defer</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/weather-last-time</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/weather-value</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/weather-get</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">&gt;</span> (<span style="color:#00f">-</span> (<span style="color:#19177c">time-convert</span> <span style="color:#800">nil</span> <span style="color:#19177c">&#39;integer</span>) <span style="color:#19177c">my/weather-last-time</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">*</span> <span style="color:#666">60</span> <span style="color:#666">5</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">request</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;https://wttr.in/%s&#34;</span> <span style="color:#19177c">my/location</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:params</span> <span style="color:#666">&#39;</span>((<span style="color:#ba2121">&#34;format&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;%l:%20%C%20%t%20%w%20%p&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:sync</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:parser</span> (<span style="color:#008000">lambda</span> () (<span style="color:#19177c">url-unhex-string</span> (<span style="color:#00f">buffer-string</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:timeout</span> <span style="color:#666">10</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:success</span> (<span style="color:#008000">cl-function</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#008000">&amp;key</span> <span style="color:#19177c">data</span> <span style="color:#008000">&amp;allow-other-keys</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/weather-value</span> <span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/weather-last-time</span> (<span style="color:#19177c">time-convert</span> <span style="color:#800">nil</span> <span style="color:#19177c">&#39;integer</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:error</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-function</span> (<span style="color:#008000">lambda</span> (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">args</span> <span style="color:#008000">&amp;key</span> <span style="color:#19177c">error-thrown</span> <span style="color:#008000">&amp;allow-other-keys</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Got error: %S&#34;</span> <span style="color:#19177c">error-thrown</span>)))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/weather-value</span>)
</span></span></code></pre></div><p>Let&rsquo;s also try to log the current mood:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/get-mood</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">crm-separator</span> <span style="color:#ba2121">&#34; &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">crm-local-completion-map</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">map</span> (<span style="color:#00f">make-sparse-keymap</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-keymap-parent</span> <span style="color:#19177c">map</span> <span style="color:#19177c">crm-local-completion-map</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">define-key</span> <span style="color:#19177c">map</span> <span style="color:#ba2121">&#34; &#34;</span> <span style="color:#19177c">&#39;self-insert-command</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">map</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">vertico-sort-function</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapconcat</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;identity</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">completing-read-multiple</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;How do you feel: &#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/mood-list</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34; &#34;</span>)))
</span></span></code></pre></div><p>And here&rsquo;s the function that creates a drawer with such information. At the moment, it&rsquo;s:</p>
<ul>
<li>Emacs version</li>
<li>Hostname</li>
<li>Location</li>
<li>Weather</li>
<li>Current EMMS track</li>
<li>Current mood</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/set-journal-header</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-set-property</span> <span style="color:#ba2121">&#34;Emacs&#34;</span> <span style="color:#19177c">emacs-version</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-set-property</span> <span style="color:#ba2121">&#34;Hostname&#34;</span> (<span style="color:#19177c">my/system-name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-journal-tags-prop-apply-delta</span> <span style="color:#008000">:add</span> (<span style="color:#00f">list</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;host.%s&#34;</span> (<span style="color:#19177c">my/system-name</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">boundp</span> <span style="color:#19177c">&#39;my/location</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-set-property</span> <span style="color:#ba2121">&#34;Location&#34;</span> <span style="color:#19177c">my/location</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let</span> ((<span style="color:#19177c">weather</span> (<span style="color:#19177c">my/weather-get</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-set-property</span> <span style="color:#ba2121">&#34;Weather&#34;</span> <span style="color:#19177c">weather</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">boundp</span> <span style="color:#19177c">&#39;my/loc-tag</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-journal-tags-prop-apply-delta</span> <span style="color:#008000">:add</span> (<span style="color:#00f">list</span> <span style="color:#19177c">my/loc-tag</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">fboundp</span> <span style="color:#19177c">&#39;emms-playlist-current-selected-track</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">track</span> (<span style="color:#19177c">emms-playlist-current-selected-track</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">track</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">album</span> (<span style="color:#00f">cdr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">&#39;info-album</span> <span style="color:#19177c">track</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">artist</span> (<span style="color:#008000">or</span> (<span style="color:#00f">cdr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">&#39;info-albumartist</span> <span style="color:#19177c">track</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">&#39;info-album</span> <span style="color:#19177c">track</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">title</span> (<span style="color:#00f">cdr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">&#39;info-title</span> <span style="color:#19177c">track</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">string</span> <span style="color:#ba2121">&#34;&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">artist</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#00f">string</span> (<span style="color:#00f">concat</span> <span style="color:#00f">string</span> <span style="color:#ba2121">&#34;[&#34;</span> <span style="color:#19177c">artist</span> <span style="color:#ba2121">&#34;] &#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">album</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#00f">string</span> (<span style="color:#00f">concat</span> <span style="color:#00f">string</span> <span style="color:#19177c">album</span> <span style="color:#ba2121">&#34; - &#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">title</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#00f">string</span> (<span style="color:#00f">concat</span> <span style="color:#00f">string</span> <span style="color:#19177c">title</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">&gt;</span> (<span style="color:#00f">length</span> <span style="color:#00f">string</span>) <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-set-property</span> <span style="color:#ba2121">&#34;EMMS_Track&#34;</span> <span style="color:#00f">string</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let</span> (<span style="color:#19177c">mood</span> (<span style="color:#19177c">my/get-mood</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-set-property</span> <span style="color:#ba2121">&#34;Mood&#34;</span> <span style="color:#19177c">mood</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-journal-after-entry-create-hook</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/set-journal-header</span>)
</span></span></code></pre></div><p>Also, a function to decrypt the current file:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-journal-decrypt</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Decrypt the current org journal file.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-journal-tags--ensure-decrypted</span>))
</span></span></code></pre></div><h4 id="bibliography">Bibliography</h4>
<p>I use <a href="https://www.zotero.org/">Zotero</a> to manage my bibliograhy.</p>
<p>There is a Zotero extension called <a href="https://retorque.re/zotero-better-bibtex/">better bibtex</a>, which allows for having one bibtex file that is always syncronized with the library. That comes quite handy for Emacs integration.</p>
<p>Resources:</p>
<ul>
<li><a href="https://blog.tecosaur.com/tmio/2021-07-31-citations.html">Introducing citations!</a></li>
</ul>
<h5 id="citar">citar</h5>
<p><a href="https://github.com/emacs-citar/citar">citar</a> is a package that works with citations.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">citar</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;fB&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">citar-open</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">citar-open</span> <span style="color:#19177c">citar-insert-citation</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-cite-global-bibliography</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;~/30-39 Life/32 org-mode/library.bib&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-cite-insert-processor</span> <span style="color:#19177c">&#39;citar</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-cite-follow-processor</span> <span style="color:#19177c">&#39;citar</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-cite-activate-processor</span> <span style="color:#19177c">&#39;citar</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">citar-bibliography</span> <span style="color:#19177c">org-cite-global-bibliography</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-cite-export-processors</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">latex</span> <span style="color:#19177c">bibtex</span> <span style="color:#ba2121">&#34;numeric&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">citar-library-paths</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;~/30-39 Life/33 Library/33.01 Documents/&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;latex-mode</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">citar-capf-setup</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-mode</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">citar-capf-setup</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">citar-embark</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">citar</span> <span style="color:#19177c">embark</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">citar-embark-mode</span>))
</span></span></code></pre></div><h5 id="org-ref">org-ref</h5>
<p><a href="https://github.com/jkitchin/org-ref">org-ref</a> is a package by John Kitchin that provides support for citations and cross-references in Org Mode.</p>
<p>I&rsquo;ve switched to citar for citations because <code>org-ref</code> only works with Ivy and Helm. Fortunately, <code>org-ref</code> is designed to co-exist with <code>citar</code> and <code>org-cite</code>.</p>
<p>Also, at some point the package loaded Helm on start, so I exclude these files from the recipe.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-ref</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:files</span> (<span style="color:#008000">:defaults</span> <span style="color:#ba2121">&#34;citeproc&#34;</span> (<span style="color:#008000">:exclude</span> <span style="color:#ba2121">&#34;*helm*&#34;</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">org-ref-insert-link-hydra/body</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">org-ref-bibtex-hydra/body</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">bibtex-dialect</span> <span style="color:#19177c">&#39;biblatex</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;bibtex-mode</span> <span style="color:#19177c">&#39;smartparens-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;org-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c l&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-ref-insert-link-hydra/body</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;bibtex-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-RET&#34;</span> <span style="color:#19177c">&#39;org-ref-bibtex-hydra/body</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-ref-insert-cite-function</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#00f">call-interactively</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">citar-insert-citation</span>))))
</span></span></code></pre></div><h4 id="org-roam-1">Org Roam</h4>
<p><a href="https://github.com/org-roam/org-roam">org-roam</a> is a plain-text knowledge database.</p>
<p>Things I tried with Org Roam:</p>
<ul>
<li>Managing projects. Ended up preferring plain Org.</li>
<li>Writing a journal with <code>org-roam-dailies</code>.
Didn&rsquo;t work out as I expected, so I&rsquo;ve made <code>org-journal-tags</code> after I understood better what I want.</li>
</ul>
<p>Regardless, it turned out to be great for managing Zettelkasten, which is the original purpose of the package anyway. I didn&rsquo;t expect to ever get into something like this, but I guess I was wrong.</p>
<p>Some resources that helped me along the way (and still help):</p>
<ul>
<li>Sönke Ahrens&rsquo; book &ldquo;How to take smart notes&rdquo;</li>
<li><a href="https://zettelkasten.de/">https://zettelkasten.de/</a> - a lot of useful stuff here, especially in the &ldquo;Getting Started&rdquo; section.</li>
<li><a href="https://www.youtube.com/watch?v=-TpWahIzueg">System Crafters Live! - Can You Apply Zettelkasten in Emacs?</a></li>
</ul>
<h5 id="basic-package-configuration">Basic package configuration</h5>
<table>
<thead>
<tr>
<th>Guix dependency</th>
<th>Disabled</th>
</tr>
</thead>
<tbody>
<tr>
<td>emacs-emacsql-sqlite3</td>
<td>t</td>
</tr>
<tr>
<td>graphviz</td>
<td></td>
</tr>
</tbody>
</table>
<p>About installing the package on Guix (<strong>CREDIT</strong>: thanks @Ashraz on the SystemCrafters discord)</p>
<blockquote>
<p>So, for all those interested: unfortunately, org-roam (or rather emacsql-sqlite) cannot compile the sqlite.c and emacsql.c due to missing headers (linux/falloc.h) on Guix. You would have to properly set all the include paths on Guix, and also adjust the PATH to have gcc actually find as later on in the compilation process.</p>
<p>Instead, you should remove all Org-Roam related packages from your Emacs installation (via M-x package-delete org-roam RET and M-x package-autoremove RET y RET) and then use the Guix package called emacs-org-roam.</p></blockquote>
<p>References:</p>
<ul>
<li><a href="https://github.com/org-roam/org-roam/wiki/Hitchhiker%27s-Rough-Guide-to-Org-roam-V2">Hitchhiker&rsquo;s Rough Guide to Org roam V2</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">emacsql-sqlite</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:defer</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:type</span> <span style="color:#19177c">built-in</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-roam</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;org-roam/org-roam&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:files</span> (<span style="color:#008000">:defaults</span> <span style="color:#ba2121">&#34;extensions/*.el&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#008000">and</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-directory-p</span> <span style="color:#19177c">org-roam-directory</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">org</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-roam-file-extensions</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;org&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-roam-v2-ack</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-roam-node-display-template</span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;${title:*} &#34;</span> (<span style="color:#00f">propertize</span> <span style="color:#ba2121">&#34;${tags:10}&#34;</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;org-tag</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-setup</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;org-roam-protocol</span>))
</span></span></code></pre></div><h5 id="capture-templates-1">Capture templates</h5>
<p>Capture templates for <code>org-roam-capture</code>. As for now, nothing too complicated here.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">org-roam-capture-templates</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#ba2121">&#34;default&#34;</span> <span style="color:#19177c">plain</span> <span style="color:#ba2121">&#34;%?&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:target</span> (<span style="color:#19177c">file+head</span> <span style="color:#ba2121">&#34;%&lt;%Y%m%d%H%M%S&gt;-${slug}.org&#34;</span> <span style="color:#ba2121">&#34;#+title: ${title}\n&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:unnarrowed</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#ba2121">&#34;fleeting&#34;</span> <span style="color:#19177c">plain</span> <span style="color:#ba2121">&#34;%?&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:target</span> (<span style="color:#19177c">file+head</span> <span style="color:#ba2121">&#34;%&lt;%Y%m%d%H%M%S&gt;-${slug}.org&#34;</span> <span style="color:#ba2121">&#34;#+title: ${title}\n#+filetags: :fleeting:\n&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:unnarrowed</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;e&#34;</span> <span style="color:#ba2121">&#34;encrypted&#34;</span> <span style="color:#19177c">plain</span> <span style="color:#ba2121">&#34;%?&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:target</span> (<span style="color:#19177c">file+head</span> <span style="color:#ba2121">&#34;%&lt;%Y%m%d%H%M%S&gt;-${slug}.org.gpg&#34;</span> <span style="color:#ba2121">&#34;#+title: ${title}\n&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:unnarrowed</span> <span style="color:#800">t</span>)))
</span></span></code></pre></div><h5 id="org-roam-ql">org-roam-ql</h5>
<p><a href="https://github.com/ahmed-shariff/org-roam-ql">org-roam-ql</a> is a package to query <code>org-roam</code> files like <code>org-ql</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-roam-ql</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org-roam</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">visual</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">org-roam-ql-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-roam-ql-buffer-dispatch</span>))
</span></span></code></pre></div><h5 id="finding-nodes">Finding nodes</h5>
<p>Find and insert permanent nodes:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-roam-node-find-permanent</span> (<span style="color:#008000">&amp;optional</span> <span style="color:#19177c">other-window</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#19177c">current-prefix-arg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-find</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">other-window</span>
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">node</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;fleeting&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-tags</span> <span style="color:#19177c">node</span>))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-roam-node-insert-permanent</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-insert</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">node</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-tags</span> <span style="color:#19177c">node</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;fleeting&#34;</span>)))))
</span></span></code></pre></div><p>List unprocessed fleeting notes:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-roam-ql-fleeting</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-ql-search</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">tags</span> <span style="color:#ba2121">&#34;fleeting&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Fleeting notes&#34;</span>))
</span></span></code></pre></div><h5 id="keybindings-4">Keybindings</h5>
<p>A set of keybindings to quickly access things in Org Roam.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org-roam</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;or&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;org-roam&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;i&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-roam-node-insert-permanent</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-roam-node-find-permanent</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;g&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-roam-graph</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-roam-capture</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;b&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-roam-buffer-toggle</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-roam-ql-search</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-roam-ql-fleeting</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;org-roam-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;TAB&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">magit-section-toggle</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">quit-window</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;k&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">magit-section-backward</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;j&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">magit-section-forward</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gr&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">revert-buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;RET&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-roam-buffer-visit-thing</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymap</span> <span style="color:#19177c">&#39;org-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;or&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;t&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-roam-tag-add</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;T&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-roam-tag-remove</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-roam-db-autosync-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;a&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-roam-alias-add</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymap</span> <span style="color:#19177c">&#39;org-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c i&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-roam-node-insert-permanent</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c I&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-roam-node-insert</span>))
</span></span></code></pre></div><h5 id="backlinks-count-display">Backlinks count display</h5>
<p>Occasionally I want to see how many backlinks a particular page has.</p>
<p>This idea came to my mind because I often write a note in the following form:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>According to &lt;This Person&gt;, &lt;some opinion&gt;
</span></span></code></pre></div><p>And I have a note called <code>#Personalities</code> that looks like that:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Philosophers:
</span></span><span style="display:flex;"><span>- &lt;This Person&gt;
</span></span><span style="display:flex;"><span>- &lt;That Person&gt;
</span></span><span style="display:flex;"><span>- &lt;Another Person&gt;
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>So I&rsquo;m curious to see how many notes I have linked to each:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Philosophers:
</span></span><span style="display:flex;"><span>- &lt;This Person&gt; [30]
</span></span><span style="display:flex;"><span>- &lt;That Person&gt; [40]
</span></span><span style="display:flex;"><span>- &lt;Another Person&gt; [20]
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>The obvious way to implement that is via <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Overlays.html">overlays</a>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defface</span> <span style="color:#19177c">my/org-roam-count-overlay-face</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#800">t</span> <span style="color:#008000">:inherit</span> <span style="color:#19177c">tooltip</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Face for Org Roam count overlay.&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-roam--count-overlay-make</span> (<span style="color:#19177c">pos</span> <span style="color:#19177c">count</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">overlay-value</span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34; &#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">propertize</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%d&#34;</span> <span style="color:#19177c">count</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;my/org-roam-count-overlay-face</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34; &#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ov</span> (<span style="color:#00f">make-overlay</span> <span style="color:#19177c">pos</span> <span style="color:#19177c">pos</span> (<span style="color:#00f">current-buffer</span>) <span style="color:#800">nil</span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">overlay-put</span> <span style="color:#19177c">ov</span> <span style="color:#19177c">&#39;roam-backlinks-count</span> <span style="color:#19177c">count</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">overlay-put</span> <span style="color:#19177c">ov</span> <span style="color:#19177c">&#39;priority</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">overlay-put</span> <span style="color:#19177c">ov</span> <span style="color:#19177c">&#39;after-string</span> <span style="color:#19177c">overlay-value</span>)))
</span></span></code></pre></div><p>Also a function to remove them:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-roam--count-overlay-remove-all</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">ov</span> (<span style="color:#00f">overlays-in</span> (<span style="color:#00f">point-min</span>) (<span style="color:#00f">point-max</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">overlay-get</span> <span style="color:#19177c">ov</span> <span style="color:#19177c">&#39;roam-backlinks-count</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">delete-overlay</span> <span style="color:#19177c">ov</span>))))
</span></span></code></pre></div><p>Now we can iterate over all roam links in the buffer, count the number of backlinks via <code>org-roam-db-query</code> and invoke <code>my/org-roam--count-overlay-make</code> if that number is greater than zero:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-roam--count-overlay-make-all</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-roam--count-overlay-remove-all</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-map</span> (<span style="color:#19177c">org-element-parse-buffer</span>) <span style="color:#19177c">&#39;link</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">string-equal</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:type</span> <span style="color:#19177c">elem</span>) <span style="color:#ba2121">&#34;id&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">id</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:path</span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">count</span> (<span style="color:#19177c">caar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-db-query</span>
</span></span><span style="display:flex;"><span> [<span style="color:#008000">:select</span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">count</span> <span style="color:#19177c">source</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:from</span> <span style="color:#19177c">links</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:where</span> (<span style="color:#00f">=</span> <span style="color:#19177c">dest</span> <span style="color:#19177c">$s1</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:and</span> (<span style="color:#00f">=</span> <span style="color:#19177c">type</span> <span style="color:#ba2121">&#34;id&#34;</span>)]
</span></span><span style="display:flex;"><span> <span style="color:#19177c">id</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">&lt;</span> <span style="color:#666">0</span> <span style="color:#19177c">count</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-roam--count-overlay-make</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:end</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">count</span>)))))))
</span></span></code></pre></div><p>And a minor mode to toggle the display in a particular <code>org-roam</code> buffer.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">define-minor-mode</span> <span style="color:#19177c">my/org-roam-count-overlay-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Display backlink count for org-roam links.&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">my/org-roam-count-overlay-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-roam--count-overlay-make-all</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;after-save-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-roam--count-overlay-make-all</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-roam--count-overlay-remove-all</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">remove-hook</span> <span style="color:#19177c">&#39;after-save-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-roam--count-overlay-remove-all</span> <span style="color:#800">t</span>)))
</span></span></code></pre></div><h5 id="extract-all-links-from-page">Extract all links from page</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-roam-extract-links</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">buffer</span> (<span style="color:#19177c">generate-new-buffer</span> <span style="color:#ba2121">&#34;*roam-links*&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">elems</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-map</span> (<span style="color:#19177c">org-element-parse-buffer</span>) <span style="color:#19177c">&#39;link</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">string-equal</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:type</span> <span style="color:#19177c">elem</span>) <span style="color:#ba2121">&#34;id&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#19177c">elem</span> <span style="color:#19177c">elems</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">elem</span> <span style="color:#19177c">in</span> <span style="color:#19177c">elems</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">file-name</span> <span style="color:#00f">=</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-name-nondirectory</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">caar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-db-query</span>
</span></span><span style="display:flex;"><span> [<span style="color:#008000">:select</span> [<span style="color:#19177c">file</span>]
</span></span><span style="display:flex;"><span> <span style="color:#008000">:from</span> <span style="color:#19177c">nodes</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:where</span> (<span style="color:#00f">=</span> <span style="color:#19177c">id</span> <span style="color:#19177c">$s1</span>)]
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:path</span> <span style="color:#19177c">elem</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">insert</span> <span style="color:#19177c">file-name</span> <span style="color:#ba2121">&#34;\n&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">switch-to-buffer</span> <span style="color:#19177c">buffer</span>)))
</span></span></code></pre></div><h5 id="org-roam-ui">Org Roam UI</h5>
<p>A browser frontend to visualize the Roam database as a graph.</p>
<p>Actually, I don&rsquo;t find this quite as useful as structure nodes, because over time my graph grew somewhat convoluted. But it looks impressive.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-roam-ui</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;org-roam/org-roam-ui&#34;</span> <span style="color:#008000">:branch</span> <span style="color:#ba2121">&#34;main&#34;</span> <span style="color:#008000">:files</span> (<span style="color:#ba2121">&#34;*.el&#34;</span> <span style="color:#ba2121">&#34;out&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">org-roam</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; :hook (org-roam . org-roam-ui-mode)</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;oru&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-roam-ui-mode</span>))
</span></span></code></pre></div><h5 id="deft">Deft</h5>
<p><a href="https://github.com/jrblevin/deft">Deft</a> is an Emacs package to quickly find notes. I use it as a full-text search engine for <code>org-roam</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">deft</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">deft</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ord&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">deft</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">deft-directory</span> <span style="color:#19177c">org-roam-directory</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">deft-recursive</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">deft-use-filter-string-for-filename</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;deft-mode-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> () (<span style="color:#19177c">display-line-numbers-mode</span> <span style="color:#666">-1</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;deft-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">motion</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">quit-window</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">deft-refresh</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">deft-filter</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">deft-filter-clear</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;y&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">deft-filter-yank</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;t&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">deft-toggle-incremental-search</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">deft-toggle-sort-method</span>))
</span></span></code></pre></div><p>The default deft view does not look that great because of various Roam metadata. To improve that, we can tweak <code>deft-strip-summary-regexp</code>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">deft-strip-summary-regexp</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> (<span style="color:#666">:</span> <span style="color:#ba2121">&#34;:PROPERTIES:&#34;</span> (<span style="color:#00f">*</span> <span style="color:#19177c">anything</span>) <span style="color:#ba2121">&#34;:END:&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#666">:</span> <span style="color:#ba2121">&#34;#+&#34;</span> (<span style="color:#00f">+</span> <span style="color:#19177c">alnum</span>) <span style="color:#ba2121">&#34;:&#34;</span> (<span style="color:#00f">*</span> <span style="color:#19177c">nonl</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">regexp</span> <span style="color:#ba2121">&#34;[\n\t]&#34;</span>))))
</span></span></code></pre></div><p>And advise <code>deft-parse-summary</code> to filter out Org links:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/deft-parse-summary-around</span> (<span style="color:#19177c">fun</span> <span style="color:#19177c">contents</span> <span style="color:#19177c">title</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">fun</span> (<span style="color:#19177c">org-link-display-format</span> <span style="color:#19177c">contents</span>) <span style="color:#19177c">title</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;deft</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">deft-parse-summary</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/deft-parse-summary-around</span>))
</span></span></code></pre></div><p>Advise <code>deft-parse-title</code> to be able to extract title from the Org property:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/deft-parse-title</span> (<span style="color:#19177c">file</span> <span style="color:#19177c">contents</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#19177c">contents</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-min</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">search-forward-regexp</span> (<span style="color:#008000">rx</span> (<span style="color:#19177c">|</span> <span style="color:#ba2121">&#34;#+title:&#34;</span> <span style="color:#ba2121">&#34;#+TITLE:&#34;</span>)) <span style="color:#800">nil</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-trim</span> (<span style="color:#00f">buffer-substring-no-properties</span> (<span style="color:#00f">point</span>) (<span style="color:#00f">line-end-position</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">file</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/deft-parse-title-around</span> (<span style="color:#19177c">fun</span> <span style="color:#19177c">file</span> <span style="color:#19177c">contents</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">my/deft-parse-title</span> <span style="color:#19177c">file</span> <span style="color:#19177c">contents</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">fun</span> <span style="color:#19177c">file</span> <span style="color:#19177c">contents</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;deft</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">deft-parse-title</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/deft-parse-title-around</span>))
</span></span></code></pre></div><h5 id="notes-display">Notes display</h5>
<p>I decided to borrow a few UX things from <a href="https://obsidian.md/">Obsidian</a>, namely hiding syntax when cursor leaves the line.</p>
<p><a href="https://github.com/awth13/org-appear?tab=readme-ov-file">org-appear</a> and <a href="https://github.com/io12/org-fragtog">org-fragtog</a> do pretty much that.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-roam-node-setup</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">org-hide-emphasis-markers</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-appear-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">display-graphic-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-fragtog-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-latex-preview</span> <span style="color:#666">&#39;</span>(<span style="color:#666">16</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-roam-find-file-hook</span> <span style="color:#19177c">&#39;my/org-roam-node-setup</span>))
</span></span></code></pre></div><h4 id="review-workflow">Review workflow</h4>
<p>Tiago Forte has several few interesting blog posts:</p>
<ul>
<li><a href="https://fortelabs.com/blog/the-weekly-review-is-an-operating-system/">The Weekly Review is an Operating System</a></li>
<li><a href="https://fortelabs.com/blog/the-design-of-a-weekly-review/">The Design of a Weekly Review</a></li>
</ul>
<p>This is probably my third time to implement a weekly review.</p>
<p>I want two general things from the workflow:</p>
<ul>
<li>to perform maintainance operations, such as clearing various inboxes;</li>
<li>to reflect on what I&rsquo;ve done over the past week.</li>
</ul>
<p>For the second point I&rsquo;ll try to collect data from various sources and add the data to my review template.</p>
<h5 id="data-from-git">Data from git</h5>
<p>First, as I have <a href="/configs/console/#autocommit">autocommit</a> set up in my org directory, here is a function to get an alist of changed files in a form <code>(status . path)</code>. The <code>rev</code> parameter can be a commit, tag, etc. but here I&rsquo;m interested in the date form (e.g. <code>@{2021-08-30}</code>).</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/git-diff-status</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#ba2121">&#34;A&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">added</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;C&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">copied</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;D&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">deleted</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;M&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">modified</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;R&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">renamed</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;R100&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">moved</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;T&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">type-changed</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;U&#34;</span> <span style="color:#666">.</span> <span style="color:#19177c">unmerged</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/get-files-status</span> (<span style="color:#19177c">rev</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">files</span> (<span style="color:#19177c">shell-command-to-string</span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;git diff --name-status &#34;</span> <span style="color:#19177c">rev</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">elems</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">file</span> <span style="color:#ba2121">&#34;\t&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span> (<span style="color:#00f">assoc</span> (<span style="color:#00f">car</span> <span style="color:#19177c">elems</span>) <span style="color:#19177c">my/git-diff-status</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">car</span> (<span style="color:#19177c">last</span> <span style="color:#19177c">elems</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">files</span> <span style="color:#ba2121">&#34;\n&#34;</span> <span style="color:#800">t</span>))))
</span></span></code></pre></div><p>I&rsquo;ll use it to get a list of added and changed files in the Org directory since the last review. The date should be in a format <code>YYYY-MM-DD</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-changed-files-since-date</span> (<span style="color:#19177c">date</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">default-directory</span> <span style="color:#19177c">org-directory</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/get-files-status</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;@{%s}&#34;</span> <span style="color:#19177c">date</span>))))
</span></span></code></pre></div><h5 id="data-from-org-roam">Data from org-roam</h5>
<p>I&rsquo;ll use data from git to get the list of what I&rsquo;ve been working on. The directories include <code>org-roam</code> itself and <code>inbox-notes</code>, where my in-process notes live.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-review--org-roam-get-changes</span> (<span style="color:#19177c">date</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">changes</span> (<span style="color:#19177c">my/org-changed-files-since-date</span> <span style="color:#19177c">date</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">nodes</span> (<span style="color:#19177c">org-roam-node-list</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">nodes-by-file</span> (<span style="color:#00f">make-hash-table</span> <span style="color:#008000">:test</span> <span style="color:#00f">#&#39;equal</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">node</span> <span style="color:#19177c">in</span> <span style="color:#19177c">nodes</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">file</span> <span style="color:#00f">=</span> (<span style="color:#19177c">org-roam-node-file</span> <span style="color:#19177c">node</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">puthash</span> <span style="color:#19177c">file</span> <span style="color:#19177c">node</span> <span style="color:#19177c">nodes-by-file</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">changed-nodes</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">changes</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">c</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> (<span style="color:#00f">car</span> <span style="color:#19177c">c</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">gethash</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/&#34;</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">nodes-by-file</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span> <span style="color:#00f">#&#39;cdr</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">changed-inbox</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">changes</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>) (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;inbox-notes&#34;</span>) (<span style="color:#00f">cdr</span> <span style="color:#19177c">file</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">changed-fleeting</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">changed-nodes</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">c</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span> (<span style="color:#19177c">org-roam-node-tags</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;fleeting&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-sort-by</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">c</span>) (<span style="color:#00f">concat</span> (<span style="color:#00f">symbol-name</span> (<span style="color:#00f">car</span> <span style="color:#19177c">c</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-title</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;string-lessp</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">changed-permanent</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">changed-nodes</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">c</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">seq-contains-p</span> (<span style="color:#19177c">org-roam-node-tags</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;fleeting&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-sort-by</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">c</span>) (<span style="color:#00f">concat</span> (<span style="color:#00f">symbol-name</span> (<span style="color:#00f">car</span> <span style="color:#19177c">c</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-title</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;string-lessp</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">changed-inbox</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">changed-fleeting</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">changed-permanent</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-review-org-roam-format</span> (<span style="color:#19177c">date</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">data</span> (<span style="color:#19177c">my/org-review--org-roam-get-changes</span> <span style="color:#19177c">date</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">changed-inbox</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">data</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">changed-fleeting</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">data</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">changed-permanent</span> (<span style="color:#00f">nth</span> <span style="color:#666">2</span> <span style="color:#19177c">data</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Changes in inbox:\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">changed-inbox</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">change</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;- %s :: %s\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">or</span> (<span style="color:#00f">member</span> (<span style="color:#00f">car</span> <span style="color:#19177c">change</span>) <span style="color:#666">&#39;</span>(<span style="color:#19177c">deleted</span> <span style="color:#19177c">moved</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;figured-out&#34;</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">change</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Processed&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> (<span style="color:#00f">capitalize</span> (<span style="color:#00f">symbol-name</span> (<span style="color:#00f">car</span> <span style="color:#19177c">change</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">change</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#00f">#&#39;concat</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\nChanges in fleeting notes:\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">changed-fleeting</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">c</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;- %s :: [[id:%s][%s]]\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">capitalize</span> (<span style="color:#00f">symbol-name</span> (<span style="color:#00f">car</span> <span style="color:#19177c">c</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-id</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-title</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#00f">#&#39;concat</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\nChanges in permanent notes:\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">changed-permanent</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">c</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;- %s :: [[id:%s][%s]]\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">capitalize</span> (<span style="color:#00f">symbol-name</span> (<span style="color:#00f">car</span> <span style="color:#19177c">c</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-id</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-title</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#00f">#&#39;concat</span>)))))
</span></span></code></pre></div><h5 id="general-review-logic">General review logic</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-review-get-last-review-date</span> (<span style="color:#19177c">kind</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">start-of-day</span> (<span style="color:#00f">-</span> (<span style="color:#19177c">time-convert</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">integer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">%</span> (<span style="color:#19177c">time-convert</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">integer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">*</span> <span style="color:#666">24</span> <span style="color:#666">60</span> <span style="color:#666">60</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query-res</span> (<span style="color:#19177c">org-journal-tags-query</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:tag-names</span> (<span style="color:#00f">list</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;review.%s&#34;</span> <span style="color:#19177c">kind</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:start-date</span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">kind</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;weekly</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">-</span> <span style="color:#19177c">start-of-day</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">*</span> <span style="color:#666">21</span> <span style="color:#666">24</span> <span style="color:#666">60</span> <span style="color:#666">60</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;zk</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">-</span> <span style="color:#19177c">start-of-day</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">*</span> <span style="color:#666">45</span> <span style="color:#666">24</span> <span style="color:#666">60</span> <span style="color:#666">60</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">_</span> (<span style="color:#d2413a;font-weight:bold">error</span> <span style="color:#ba2121">&#34;Unsupported kind: %s&#34;</span> <span style="color:#19177c">kind</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:location</span> <span style="color:#19177c">&#39;section</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:order</span> <span style="color:#19177c">&#39;descending</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">query-res</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-journal-tag-reference-date</span> (<span style="color:#00f">car</span> <span style="color:#19177c">query-res</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">kind</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;weekly</span> (<span style="color:#00f">-</span> <span style="color:#19177c">start-of-day</span> (<span style="color:#00f">*</span> <span style="color:#666">7</span> <span style="color:#666">24</span> <span style="color:#666">60</span> <span style="color:#666">60</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;zk</span> (<span style="color:#00f">-</span> <span style="color:#19177c">start-of-day</span> (<span style="color:#00f">*</span> <span style="color:#666">45</span> <span style="color:#666">24</span> <span style="color:#666">60</span> <span style="color:#666">60</span>)))))))
</span></span></code></pre></div><h5 id="weekly-review">Weekly review</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-review-set-weekly-record</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">last-review-date</span> (<span style="color:#19177c">my/org-review-get-last-review-date</span> <span style="color:#19177c">&#39;weekly</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-journal-tags-prop-apply-delta</span> <span style="color:#008000">:add</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;review.weekly&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;Weekly Review&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-max</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;Last review date: &#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format-time-string</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;[%Y-%m-%d]&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seconds-to-time</span> <span style="color:#19177c">last-review-date</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Review checklist (/delete this/):
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- [ ] Clear email inbox
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- [ ] Reconcile ledger
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- [ ] Clear [[file:~/Downloads][downloads]] and [[file:~/00-Scratch][scratch]] folders
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- [ ] Process [[file:~/30-39 Life/35 Photos/35.00 Inbox/][photo inbox]]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- [ ] Process [[file:../inbox.org][inbox]]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- [ ] Create [[file:../recurring.org][recurring tasks]] for next week
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- [ ] Check agenda (-1 / +2 weeks): priorities, deadlines
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- [ ] Check TODOs: priorities, deadlines
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"> - [[org-ql-search:todo%3A?buffers-files=%22org-agenda-files%22&amp;super-groups=%28%28%3Aauto-outline-path-file%20t%29%29&amp;sort=%28priority%20todo%20deadline%29][org-ql-search: All TODOs]]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"> - [[org-ql-search:(and (todo) (not (tags \&#34;nots\&#34;)) (not (ts :from -14)) (not (todo \&#34;MAYBE\&#34;)))?buffers-files=%22org-agenda-files%22&amp;super-groups=%28%28%3Aauto-outline-path-file%20t%29%29&amp;sort=%28priority%20todo%20deadline%29][org-ql-search: Stale tasks]]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"> - [[org-ql-search:todo%3AWAIT?buffers-files=%22org-agenda-files%22&amp;super-groups=%28%28%3Aauto-outline-path-file%20t%29%29&amp;sort=%28priority%20todo%20deadline%29][org-ql-search: WAIT]]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"> - [[org-ql-search:todo%3AMAYBE?buffers-files=%22org-agenda-files%22&amp;super-groups=%28%28%3Aauto-outline-path-file%20t%29%29&amp;sort=%28priority%20todo%20deadline%29][org-ql-search: MAYBE]]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- [ ] Run auto-archiving
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- [ ] Review journal records
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">*** Summary
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">TODO Write something, maybe? &#34;</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-review-weekly</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">org-journal-after-entry-create-hook</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,@</span><span style="color:#19177c">org-journal-after-entry-create-hook</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/org-review-set-weekly-record</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-journal-new-entry</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-fold-show-subtree</span>)))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org-journal</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ojw&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-review-weekly</span>))
</span></span></code></pre></div><h5 id="daily-review">Daily review</h5>
<p>My attempt at a daily review, or an end-of-day routine.</p>
<p>I try to keep it under 10-15 minutes.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/kill-messengers</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">get-buffer</span> <span style="color:#19177c">telega-root-buffer-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-kill</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">call-process-shell-command</span> <span style="color:#ba2121">&#34;pkill -f rocketchat-desktop&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">call-process-shell-command</span> <span style="color:#ba2121">&#34;pkill -f &#39;bwrap --args 36 element&#39;&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">call-process-shell-command</span> <span style="color:#ba2121">&#34;pkill -f element-desktop&#34;</span>))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-review-set-daily-record</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">today</span> (<span style="color:#00f">format-time-string</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;%Y-%m-%d&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">days-to-time</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">-</span> (<span style="color:#19177c">org-today</span>) (<span style="color:#19177c">time-to-days</span> <span style="color:#666">0</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">roam-changes</span> (<span style="color:#19177c">my/org-review--org-roam-get-changes</span> <span style="color:#19177c">today</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-journal-tags-prop-apply-delta</span> <span style="color:#008000">:add</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;review.daily&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;Daily Review&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-max</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Maintenance checklist (/delete this/):
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- [ ] [[elisp:(my/kill-messengers)][Close all messengers]]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- [ ] Process [[file:../inbox.org][inbox]]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- [ ] Check if clocked tasks are properly annotated
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"> - [[elisp:(my/org-ql-clocked-today)][Tasks clocked today]]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"> - [[elisp:(my/org-ql-closed-today)][Tasks closed today]]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- [ ] Check agenda for the current week
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">/Remember, all of the following headers are optional./
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">*** Happened today
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Happened to me:
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- /Anything interesting?/
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Happened to the world:
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- /Anything important?/
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">*** New ideas
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">/Write them down in org-roam with the \&#34;fleeting\&#34; tag; leave links here. Perhaps note what sparked that idea?/
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">roam-changes</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">c</span>) (<span style="color:#00f">eq</span> <span style="color:#19177c">&#39;added</span> (<span style="color:#00f">car</span> <span style="color:#19177c">c</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">c</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;- [[id:%s][%s]]\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-id</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-title</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#00f">#&#39;concat</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">*** Interactions today
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">/Any meaninginful interactions, conflicts or tensions?/
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">*** Emotions today
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">/How did I feel?/
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">&#34;</span>))))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-review-daily</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">org-journal-after-entry-create-hook</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,@</span><span style="color:#19177c">org-journal-after-entry-create-hook</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/org-review-set-daily-record</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-journal-new-entry</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-fold-show-subtree</span>)))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org-journal</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ojd&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-review-daily</span>))
</span></span></code></pre></div><h5 id="zk-review">ZK review</h5>
<p>Mostly incorporating or discarding my fleeting notes here.</p>
<p>This function formats the list of notes to review:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-review-org-roam-format-zk-before</span> (<span style="color:#19177c">date</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">data</span> (<span style="color:#19177c">my/org-review--org-roam-get-changes</span> <span style="color:#19177c">date</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">changed-inbox</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">data</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">changed-fleeting</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">data</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">changed-permanent</span> (<span style="color:#00f">nth</span> <span style="color:#666">2</span> <span style="color:#19177c">data</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">changed-inbox</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Process these changes in inbox:\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">changed-inbox</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">change</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;- [ ] %s :: %s\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">or</span> (<span style="color:#00f">member</span> (<span style="color:#00f">car</span> <span style="color:#19177c">change</span>) <span style="color:#666">&#39;</span>(<span style="color:#19177c">deleted</span> <span style="color:#19177c">moved</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;figured-out&#34;</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">change</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Processed&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> (<span style="color:#00f">capitalize</span> (<span style="color:#00f">symbol-name</span> (<span style="color:#00f">car</span> <span style="color:#19177c">change</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">change</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#00f">#&#39;concat</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\n&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">changed-fleeting</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Process these fleeting notes:\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">changed-fleeting</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">c</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;- [ ] %s :: [[id:%s][%s]]\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">capitalize</span> (<span style="color:#00f">symbol-name</span> (<span style="color:#00f">car</span> <span style="color:#19177c">c</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-id</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-title</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#00f">#&#39;concat</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\n&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">changed-permanent</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Check these changes in permanent notes:\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">changed-permanent</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">c</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;- [ ] %s :: [[id:%s][%s]]\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">capitalize</span> (<span style="color:#00f">symbol-name</span> (<span style="color:#00f">car</span> <span style="color:#19177c">c</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-id</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-node-title</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">c</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#00f">#&#39;concat</span>)))))))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-review-org-roam-finish</span> (<span style="color:#19177c">date</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-roam-db-sync</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-back-to-heading</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;:BEGIN_REVIEW:&#34;</span> (<span style="color:#00f">*</span> <span style="color:#19177c">anything</span>) <span style="color:#ba2121">&#34;:END_REVIEW:&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-trim</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-review-org-roam-format</span> <span style="color:#19177c">date</span>)))))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-review-set-zk-record</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">last-review-date</span> (<span style="color:#19177c">my/org-review-get-last-review-date</span> <span style="color:#19177c">&#39;zk</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-journal-tags-prop-apply-delta</span> <span style="color:#008000">:add</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;review.zk&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;Zettelkasten Review&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-max</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;Last review date: &#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format-time-string</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;[%Y-%m-%d]&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seconds-to-time</span> <span style="color:#19177c">last-review-date</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;\n\n:BEGIN_REVIEW:\n&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Process all the required categories in this block, then execute \&#34;Finish review\&#34;.\n\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-trim</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/org-review-org-roam-format-zk-before</span> <span style="color:#19177c">last-review-date</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\n\n[[elisp:(my/org-review-org-roam-finish \&#34;&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format-time-string</span> <span style="color:#ba2121">&#34;%Y-%m-%d&#34;</span> <span style="color:#19177c">last-review-date</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\&#34;)][Finish review]]&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\n:END_REVIEW:\n&#34;</span>))))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-review-zk</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">org-journal-after-entry-create-hook</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,@</span><span style="color:#19177c">org-journal-after-entry-create-hook</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/org-review-set-zk-record</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-journal-new-entry</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-fold-show-subtree</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org-journal</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ojz&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-review-zk</span>))
</span></span></code></pre></div><h4 id="contacts">Contacts</h4>
<p><code>org-contacts</code> is a package to store contacts in an org file.</p>
<p>It seems the package has been somewhat revived in the recent months. It used things like <code>lexical-let</code> when I first found it.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-contacts</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:type</span> <span style="color:#19177c">git</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;https://repo.or.cz/org-contacts.git&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-contacts-files</span> (<span style="color:#00f">list</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/contacts.org&#34;</span>))))
</span></span></code></pre></div><p>An example contact entry can look like this:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>* Pavel Korytov
</span></span><span style="display:flex;"><span>:PROPERTIES:
</span></span><span style="display:flex;"><span>:TYPE: person
</span></span><span style="display:flex;"><span>:EMAIL: thexcloud@gmail.com
</span></span><span style="display:flex;"><span>:EMAIL+: pvkorytov@etu.ru
</span></span><span style="display:flex;"><span>:BIRTHDAY: [1998-08-14]
</span></span><span style="display:flex;"><span>:END:
</span></span></code></pre></div><h4 id="calendar-view">Calendar view</h4>
<p><a href="https://github.com/kiwanami/emacs-calfw">calfw</a> is a nice package that displays calendars in Emacs.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/calfw-setup-buffer</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-line-numbers-mode</span> <span style="color:#666">-1</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">calfw</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:defer</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;cfw:calendar-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/calfw-setup-buffer</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">calfw-org</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">calfw</span> <span style="color:#19177c">org</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h4 id="org-timeblock">org-timeblock</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-timeblock-conf</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-line-numbers-mode</span> <span style="color:#666">-1</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-timeblock</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;ichernyshovvv/org-timeblock&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">org-timeblock-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ot&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-timeblock</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-timeblock-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/org-timeblock-conf</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">org-timeblock-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">visual</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;j&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-timeblock-forward-block</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;h&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-timeblock-backward-column</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;l&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-timeblock-forward-column</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;k&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-timeblock-backward-block</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-[&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-timeblock-day-earlier</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-]&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-timeblock-day-later</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;H&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-timeblock-day-earlier</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;L&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-timeblock-day-later</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;RET&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-timeblock-goto</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;t&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-timeblock-todo-set</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">quit-window</span>))
</span></span></code></pre></div><h4 id="org-drill">org-drill</h4>
<p>Trying to learn stuff with this.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">org-drill</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">org-drill</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">org</span>))
</span></span></code></pre></div><h3 id="export">Export</h3>
<h4 id="hugo">Hugo</h4>
<p>A package for exporting Org to Hugo. That&rsquo;s how I manage my <a href="https://sqrtminusone.xyz">sqrtminusone.xyz</a>.</p>
<p>References:</p>
<ul>
<li><a href="https://ox-hugo.scripter.co/">ox-hugo homepage</a></li>
<li><a href="https://github.com/SqrtMinusOne/sqrtminusone.github.io">Source code for sqrtminusone.xyz</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ox-hugo</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">ox</span>)
</span></span></code></pre></div><h4 id="jupyter-notebook">Jupyter Notebook</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ox-ipynb</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;jkitchin/ox-ipynb&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">ox</span>)
</span></span></code></pre></div><h4 id="html-export">Html export</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">htmlize</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">ox</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-html-htmlize-output-type</span> <span style="color:#19177c">&#39;css</span>))
</span></span></code></pre></div><h4 id="org-ref-1">org-ref</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org-ref</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-ref-csl-default-locale</span> <span style="color:#ba2121">&#34;ru-RU&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-ref-csl-default-style</span> (<span style="color:#00f">expand-file-name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">user-emacs-directory</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gost-r-7-0-5-2008-numeric.csl&#34;</span>))))
</span></span></code></pre></div><h4 id="latex-1">LaTeX</h4>
<p>Add a custom LaTeX template without default packages. Packages are indented to be imported with function from <a href="#import-dot-sty-1">Import *.sty</a>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/setup-org-latex</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-latex-prefer-user-labels</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-latex-compiler</span> <span style="color:#ba2121">&#34;xelatex&#34;</span>) <span style="color:#408080;font-style:italic">;; Probably not necessary</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-latex-pdf-process</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;latexmk -outdir=%o %f&#34;</span>)) <span style="color:#408080;font-style:italic">;; Use latexmk</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-latex-listings</span> <span style="color:#19177c">&#39;minted</span>) <span style="color:#408080;font-style:italic">;; Use minted to highlight source code</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-latex-minted-options</span> <span style="color:#408080;font-style:italic">;; Some minted options I like</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#ba2121">&#34;breaklines&#34;</span> <span style="color:#ba2121">&#34;true&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;tabsize&#34;</span> <span style="color:#ba2121">&#34;4&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;autogobble&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;linenos&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;numbersep&#34;</span> <span style="color:#ba2121">&#34;0.5cm&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;xleftmargin&#34;</span> <span style="color:#ba2121">&#34;1cm&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;frame&#34;</span> <span style="color:#ba2121">&#34;single&#34;</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Use extarticle without the default packages</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;org-latex-classes</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;org-plain-extarticle&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\\documentclass{extarticle}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">[NO-DEFAULT-PACKAGES]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">[PACKAGES]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">[EXTRA]&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;\\section{%s}&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\section*{%s}&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;\\subsection{%s}&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\subsection*{%s}&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;\\subsubsection{%s}&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\subsubsection*{%s}&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;\\paragraph{%s}&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\paragraph*{%s}&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;\\subparagraph{%s}&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\subparagraph*{%s}&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;org-latex-classes</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;org-plain-extreport&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\\documentclass{extreport}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">[NO-DEFAULT-PACKAGES]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">[PACKAGES]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">[EXTRA]&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;\\chapter{%s}&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\chapter*{%s}&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;\\section{%s}&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\section*{%s}&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;\\subsection{%s}&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\subsection*{%s}&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;\\subsubsection{%s}&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\subsubsection*{%s}&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;\\paragraph{%s}&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\paragraph*{%s}&#34;</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Use beamer without the default packages</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;org-latex-classes</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;org-latex-beamer&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\\documentclass{beamer}
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">[NO-DEFAULT-PACKAGES]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">[PACKAGES]
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">[EXTRA]&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;beamer&#34;</span> <span style="color:#ba2121">&#34;\\documentclass[presentation]{beamer}&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;\\section{%s}&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\section*{%s}&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;\\subsection{%s}&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\subsection*{%s}&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;\\subsubsection{%s}&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;\\subsubsection*{%s}&#34;</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; Make sure to eval the function when org-latex-classes list already exists</span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;ox-latex</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/setup-org-latex</span>))
</span></span></code></pre></div><h5 id="fix-russian-dictionary">Fix Russian dictionary</h5>
<p>No idea why, but somehow the exported file uses english words if there isn&rsquo;t <code>:default</code> key in the dictionary.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;ox</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-export-dictionary</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">item</span> <span style="color:#19177c">in</span> <span style="color:#19177c">org-export-dictionary</span> <span style="color:#19177c">collect</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">car</span> <span style="color:#19177c">item</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">entry</span> <span style="color:#19177c">in</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">item</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#008000">and</span> (<span style="color:#00f">equal</span> (<span style="color:#00f">car</span> <span style="color:#19177c">entry</span>) <span style="color:#ba2121">&#34;ru&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">plist-get</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">entry</span>) <span style="color:#008000">:utf-8</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#00f">list</span> <span style="color:#ba2121">&#34;ru&#34;</span> <span style="color:#008000">:default</span> (<span style="color:#00f">plist-get</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">entry</span>) <span style="color:#008000">:utf-8</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">else</span> <span style="color:#19177c">collect</span> <span style="color:#19177c">entry</span>)))))
</span></span></code></pre></div><h3 id="system-configuration">System configuration</h3>
<p>Functions related to literate configuration.</p>
<h4 id="tables-for-guix-dependencies">Tables for Guix Dependencies</h4>
<p>This section deals with using <a href="https://guix.gnu.org/en/cookbook/en/html_node/Advanced-package-management.html#Advanced-package-management">using profiles in GNU Guix</a>.</p>
<p>A &ldquo;profile&rdquo; in Guix is a way to group package installations. For instance, I have a &ldquo;music&rdquo; profile that has software like <a href="https://www.musicpd.org/">MPD</a>, <a href="https://github.com/ncmpcpp/ncmpcpp">ncmpcpp</a> that I&rsquo;m still occasionally using because of its tag editor, etc. Corresponding to that profile, there&rsquo;s a manifest named <code>music.scm</code> that looks like this:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-scheme" data-lang="scheme"><span style="display:flex;"><span>(<span style="color:#00f">specifications-&gt;manifest</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;flac&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;cuetools&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;shntool&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;mpd-mpc&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;mpd-watcher&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;picard&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;ncmpcpp&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;mpd&#34;</span>))
</span></span></code></pre></div><p>I could generate this file with <code>org-babel</code> as any other, but that is often not so convenient. For example, I have a <a href="https://github.com/polybar/polybar">polybar</a> module that uses <a href="https://github.com/risacher/sunwait">sunwait</a> to show sunset and sunrise times, and ideally, I want to declare <code>sunwait</code> to be in the &ldquo;desktop-polybar&rdquo; profile in the same section that has the polybar module definition and the bash script.</p>
<p>So here&rsquo;s an approach I came up with. The relevant section of the config looks like this:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>*** sun
</span></span><span style="display:flex;"><span>| Category | Guix dependency |
</span></span><span style="display:flex;"><span>|-----------------+-----------------|
</span></span><span style="display:flex;"><span>| desktop-polybar | sunwait |
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Prints out the time of sunrise/sunset. Uses [[https://github.com/risacher/sunwait][sunwait]]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>#+begin_src bash :tangle ./bin/polybar/sun.sh :noweb no-export
</span></span><span style="display:flex;"><span>...script...
</span></span><span style="display:flex;"><span>#+end_src
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>#+begin_src ini :noweb no-export
</span></span><span style="display:flex;"><span>...polybar module definition...
</span></span><span style="display:flex;"><span>#+end_src
</span></span></code></pre></div><p>So <code>sunwait</code> is declared in an Org table with <code>Guix dependency</code> in the header. Such tables are spread through my configuration files.</p>
<p>Thus I made a function that extracts packages from all such tables from the current Org buffer. The rules are as follows:</p>
<ul>
<li>If a column name matches <code>[G|g]uix.*dep</code>, its contents are added to the result.</li>
<li>If <code>CATEGORY</code> is passed, a column with name <code>[C|c]ategory</code> is used to filter results. That way, one Org file can be used to produce multiple manifests.</li>
<li>If <code>CATEGORY</code> is not passed, entries with the non-empty category are filtered out</li>
<li>If there is a <code>[D|d]isabled</code> column, entries that have a non-empty value in this column are filtered out.</li>
</ul>
<p>And here is the implementation:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/extract-guix-dependencies</span> (<span style="color:#008000">&amp;optional</span> <span style="color:#19177c">category</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">dependencies</span> <span style="color:#666">&#39;</span>()))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-table-map-tables</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">table</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">q</span>) (<span style="color:#19177c">not</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">q</span> <span style="color:#19177c">&#39;hline</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-table-to-lisp</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dep-name-index</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-position</span>
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> <span style="color:#00f">#&#39;substring-no-properties</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">table</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:test</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">_</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;[G|g]uix.*dep&#34;</span> <span style="color:#19177c">elem</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">category-name-index</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-position</span>
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> <span style="color:#00f">#&#39;substring-no-properties</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">table</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:test</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">_</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;.*[C|c]ategory.*&#34;</span> <span style="color:#19177c">elem</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">disabled-name-index</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-position</span>
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> <span style="color:#00f">#&#39;substring-no-properties</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">table</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:test</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">_</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;.*[D|d]isabled.*&#34;</span> <span style="color:#19177c">elem</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">dep-name-index</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">elem</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">table</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Category</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Category not set and not present in the table</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">category</span>) (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">category</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> <span style="color:#19177c">category-name-index</span>))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Category is set and present in the table</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">category-name-index</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">category</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> <span style="color:#19177c">category</span> (<span style="color:#00f">nth</span> <span style="color:#19177c">category-name-index</span> <span style="color:#19177c">elem</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Not disabled</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> <span style="color:#19177c">disabled-name-index</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-empty-p</span> (<span style="color:#00f">nth</span> <span style="color:#19177c">disabled-name-index</span> <span style="color:#19177c">elem</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;dependencies</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring-no-properties</span> (<span style="color:#00f">nth</span> <span style="color:#19177c">dep-name-index</span> <span style="color:#19177c">elem</span>)))))))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">dependencies</span>))
</span></span></code></pre></div><p>To make it work in the configuration, it is necessary to format the list so that Scheme could read it:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/format-guix-dependencies</span> (<span style="color:#008000">&amp;optional</span> <span style="color:#19177c">category</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapconcat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">e</span>) (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;\&#34;&#34;</span> <span style="color:#19177c">e</span> <span style="color:#ba2121">&#34;\&#34;&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/extract-guix-dependencies</span> <span style="color:#19177c">category</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\n&#34;</span>))
</span></span></code></pre></div><p>And we need an Org snippet such as this:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: packages
</span></span><span style="display:flex;"><span>#+begin_src emacs-lisp :tangle no :var category=&#34;&#34;
</span></span><span style="display:flex;"><span>(my/format-guix-dependencies category)
</span></span><span style="display:flex;"><span>#+end_src
</span></span></code></pre></div><p>Now, creating a manifest, for example, for the <code>desktop-polybar</code> profile is as simple as:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src scheme :tangle ~/.config/guix/manifests/desktop-polybar.scm :noweb no-export
</span></span><span style="display:flex;"><span>(specifications-&gt;manifest
</span></span><span style="display:flex;"><span> &#39;(
</span></span><span style="display:flex;"><span> &lt;&lt;packages(&#34;desktop-polybar&#34;)&gt;&gt;))
</span></span><span style="display:flex;"><span>#+end_src
</span></span></code></pre></div><p>There&rsquo;s a newline symbol between &ldquo;(&rdquo; and <code>&lt;&lt;packages(&quot;desktop-polybar&quot;)&gt;&gt;</code> 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.</p>
<p>One reason this is so is to support languages where indentation is a part of the syntax, for instance, Python:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">class</span> <span style="color:#00f;font-weight:bold">TestClass</span>:
</span></span><span style="display:flex;"><span> <span style="color:#666">&lt;&lt;</span>class<span style="color:#666">-</span>contents<span style="color:#666">&gt;&gt;</span>
</span></span></code></pre></div><p>So every line of <code>&lt;&lt;class-contents&gt;&gt;</code> will be indented appropriately. In our case though, it is a minor inconvenience to be aware of.</p>
<h4 id="noweb-evaluations">Noweb evaluations</h4>
<p>One note is that by default running these commands will require the user to confirm evaluation of each code block. To avoid that, I set <code>org-confirm-babel-evaluate</code> to <code>nil</code>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/org-config-files</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;expand-file-name</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;~/Emacs.org&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;~/Desktop.org&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;~/Console.org&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;~/Guix.org&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;~/Mail.org&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;org-mode-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">member</span> (<span style="color:#00f">buffer-file-name</span>) <span style="color:#19177c">my/org-config-files</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">org-confirm-babel-evaluate</span> <span style="color:#800">nil</span>))))
</span></span></code></pre></div><h4 id="yadm-hook">yadm hook</h4>
<p>A script to run tangle from CLI.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">require</span> <span style="color:#19177c">&#39;org</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">org-babel-do-load-languages</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;org-babel-load-languages</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">emacs-lisp</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shell</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; Do not ask to confirm evaluations</span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">org-confirm-babel-evaluate</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#19177c">&lt;&lt;guix-tables&gt;&gt;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; A few dummy modes to avoid being prompted for comment systax</span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">define-derived-mode</span> <span style="color:#19177c">fish-mode</span> <span style="color:#19177c">prog-mode</span> <span style="color:#ba2121">&#34;Fish&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">comment-start</span> <span style="color:#ba2121">&#34;# &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">comment-start-skip</span> <span style="color:#ba2121">&#34;#+[\t ]*&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">define-derived-mode</span> <span style="color:#19177c">yaml-mode</span> <span style="color:#19177c">text-mode</span> <span style="color:#ba2121">&#34;YAML&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">comment-start</span> <span style="color:#ba2121">&#34;# &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">comment-start-skip</span> <span style="color:#ba2121">&#34;#+ *&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#00f">mapcar</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">org-babel-tangle-file</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;/home/pavel/Emacs.org&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;/home/pavel/Desktop.org&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;/home/pavel/Console.org&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;/home/pavel/Guix.org&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;/home/pavel/Mail.org&#34;</span>))
</span></span></code></pre></div><p>To launch from CLI, run:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>emacs -Q --batch -l run-tangle.el
</span></span></code></pre></div><p>I have added this line to yadm&rsquo;s <code>post_alt</code> hook, so to run tangle after <code>yadm alt</code></p>
<h4 id="regenerate-desktop-config">Regenerate desktop config</h4>
<p>Somewhat similar to the previous one&hellip; Occasinally I want to re-tangle all desktop configuration files, for instance to apply a new theme.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/regenerate-desktop</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-tangle-file</span> <span style="color:#ba2121">&#34;/home/pavel/Desktop.org&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-tangle-file</span> <span style="color:#ba2121">&#34;/home/pavel/Console.org&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">call-process</span> <span style="color:#ba2121">&#34;xrdb&#34;</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;-load&#34;</span> <span style="color:#ba2121">&#34;/home/pavel/.Xresources&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">call-process</span> <span style="color:#ba2121">&#34;~/bin/polybar.sh&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">call-process</span> <span style="color:#ba2121">&#34;pkill&#34;</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;dunst&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">call-process</span> <span style="color:#ba2121">&#34;herd&#34;</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;restart&#34;</span> <span style="color:#ba2121">&#34;xsettingsd&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">fboundp</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/exwm-set-alpha</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">my/light-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/exwm-set-alpha</span> <span style="color:#666">100</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/exwm-set-alpha</span> <span style="color:#666">90</span>))))
</span></span></code></pre></div><h2 id="applications">Applications</h2>
<h3 id="dired">Dired</h3>
<p>Dired is the built-in Emacs file manager. It&rsquo;s so good that it&rsquo;s strange that, to my knowledge, no one tried to replicate it outside of Emacs.</p>
<p>I currently use it as my primary file manager.</p>
<h4 id="basic-config-and-keybindings">Basic config &amp; keybindings</h4>
<p>My config mostly follows ranger&rsquo;s and vifm&rsquo;s keybindings which I&rsquo;m used to.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">dired</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:ensure</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:custom</span> ((<span style="color:#19177c">dired-listing-switches</span> <span style="color:#ba2121">&#34;-alh --group-directories-first&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">dired</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">dired-dwim-target</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">wdired-allow-to-change-permissions</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">wdired-create-parent-directories</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">dired-recursive-copies</span> <span style="color:#19177c">&#39;always</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">dired-recursive-deletes</span> <span style="color:#19177c">&#39;always</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">dired-kill-when-opening-new-dired-buffer</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;dired-mode-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">truncate-lines</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">visual-line-mode</span> <span style="color:#800">nil</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">my/is-termux</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;dired-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-hide-details-mode</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;dired-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;h&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-up-directory</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;l&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-find-file</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;=&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-narrow</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;-&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/dired-create-empty-file-subtree</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;~&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">eshell</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-r&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">wdired-change-to-wdired-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;left&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-up-directory</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;right&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-find-file</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-&lt;return&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/dired-open-xdg</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-home</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Open dired at $HOME&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">&#34;~&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;ad&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;aD&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/dired-bookmark-open</span>)
</span></span></code></pre></div><h4 id="addons-1">Addons</h4>
<p>I used to use <a href="https://www.emacswiki.org/emacs/DiredPlus">dired+</a>, which provides a lot of extensions for dired functionality, but it also creates some new problems, so I opt out of it. Fortunately, the one feature I want from this package - adding more colors to dired buffers - is available as a separate package.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">diredfl</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">dired</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">diredfl-global-mode</span> <span style="color:#666">1</span>))
</span></span></code></pre></div><p><a href="https://github.com/Fuco1/dired-hacks#dired-subtree">dired-subtree</a> is a package that enables managing Dired buffers in a tree-like manner. By default <code>evil-collection</code> maps <code>dired-subtree-toggle</code> to <code>TAB</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">dired-subtree</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">dired</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-create-empty-file-subtree</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">default-directory</span> (<span style="color:#19177c">dired-current-directory</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired-create-empty-file</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">read-file-name</span> <span style="color:#ba2121">&#34;Create empty file: &#34;</span>))))
</span></span></code></pre></div><p><a href="https://github.com/jojojames/dired-sidebar">dired-sidebar</a> enables opening Dired in sidebar. For me, with dired-subtree this makes dired a better option than Treemacs.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-sidebar-toggle</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">current-prefix-arg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired-sidebar-toggle-sidebar</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">dired-sidebar-follow-file-at-point-on-toggle-open</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">current-prefix-arg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">current-prefix-arg</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired-sidebar-toggle-sidebar</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">dired-sidebar</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">dired</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">dired-sidebar-toggle-sidebar</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">dired-sidebar-follow-file-at-point-on-toggle-open</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">override</span> <span style="color:#19177c">global</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-n&#34;</span> <span style="color:#666">`</span>(<span style="color:#19177c">my/dired-sidebar-toggle</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:wk</span> <span style="color:#ba2121">&#34;dired-sidebar&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">dired-sidebar-width</span> <span style="color:#666">45</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-sidebar-setup</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">toggle-truncate-lines</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-line-numbers-mode</span> <span style="color:#666">-1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">dired-subtree-use-backgrounds</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">window-size-fixed</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;dired-sidebar-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">emacs</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;l&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-sidebar-find-file</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;h&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-sidebar-up-directory</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;=&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-narrow</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;dired-sidebar-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/dired-sidebar-setup</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-create-empty-file</span> <span style="color:#008000">:after</span> <span style="color:#19177c">&#39;dired-sidebar-refresh-buffer</span>))
</span></span></code></pre></div><p><a href="https://github.com/vifon/dired-recent.el">dired-recent.el</a> adds history to dired.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">dired-recent</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">dired</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired-recent-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;dired-recent-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-x C-d&#34;</span> <span style="color:#800">nil</span>))
</span></span></code></pre></div><p>Display icons for files.</p>
<table>
<thead>
<tr>
<th>Note</th>
<th>Type</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>ACHTUNG</strong></td>
<td>This plugin is slow as hell with TRAMP or in <code>gnu/store</code></td>
</tr>
</tbody>
</table>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">all-the-icons-dired</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">dired</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">display-graphic-p</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> (<span style="color:#19177c">dired-mode</span> <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;/gnu/store&#34;</span> <span style="color:#19177c">default-directory</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">all-the-icons-dired-mode</span>)))))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">nerd-icons-dired</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">dired</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> (<span style="color:#19177c">dired-mode</span> <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">file-remote-p</span> <span style="color:#19177c">default-directory</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;/gnu/store&#34;</span> <span style="color:#19177c">default-directory</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">nerd-icons-dired-mode</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-create-empty-file</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">nerd-icons-dired--refresh-advice</span>))
</span></span></code></pre></div><p>Provides stuff like <code>dired-open-xdg</code></p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">dired-open</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">dired</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">dired-open-xdg</span>))
</span></span></code></pre></div><p><a href="https://elpa.gnu.org/packages/dired-du.html">dired-du</a> is a package that shows directory sizes</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">dired-du</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">dired-du-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">dired-du-size-format</span> <span style="color:#800">t</span>))
</span></span></code></pre></div><p>vifm-like filter</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">dired-narrow</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">dired-narrow</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;dired-narrow-map</span>
</span></span><span style="display:flex;"><span> [<span style="color:#19177c">escape</span>] <span style="color:#19177c">&#39;keyboard-quit</span>))
</span></span></code></pre></div><p>Display git info, such as the last commit for file and stuff. It&rsquo;s pretty useful but also slows down Dired a bit, hence I don&rsquo;t turn it out by default.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">dired-git-info</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">dired</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymap</span> <span style="color:#19177c">&#39;dired-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">emacs</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;)&#34;</span> <span style="color:#19177c">&#39;dired-git-info-mode</span>))
</span></span></code></pre></div><p><a href="https://github.com/SqrtMinusOne/avy-dired">avy-dired</a> is my experimentation with Avy &amp; Dired. It&rsquo;s somewhat unstable.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">avy-dired</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;SqrtMinusOne/avy-dired&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">dired</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;aa&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">avy-dired-goto-line</span>))
</span></span></code></pre></div><p><a href="https://github.com/stsquad/dired-rsync">dired-rsync</a> allows using <code>rsync</code> instead of the default synchronous copy operation. The only trouble is that it doesn&rsquo;t replace <code>dired-do-copy</code> completely, so&hellip;</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-rsync--refresh</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">window</span> <span style="color:#19177c">being</span> <span style="color:#19177c">the</span> <span style="color:#19177c">windows</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#008000">with-current-buffer</span> (<span style="color:#00f">window-buffer</span> <span style="color:#19177c">window</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">derived-mode-p</span> <span style="color:#19177c">&#39;dired-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">revert-buffer</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">dired-rsync</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">dired</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;global-mode-string</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:eval</span> <span style="color:#19177c">dired-rsync-modeline-status</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;dired-rsync-success-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/dired-rsync--refresh</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">dired-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-rsync</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gC&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-rsync-transient</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gd&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-do-copy</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">dired-rsync-transient</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">dired</span>))
</span></span></code></pre></div><h4 id="subdirectories">Subdirectories</h4>
<p>Subdirectories are one of the interesting features of Dired. It allows displaying multiple folders on the same window.</p>
<p>I add my own keybindings and some extra functionality.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-open-this-subdir</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired</span> (<span style="color:#19177c">dired-current-directory</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-kill-all-subdirs</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">dir</span> <span style="color:#19177c">dired-directory</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">kill-buffer</span> (<span style="color:#00f">current-buffer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired</span> <span style="color:#19177c">dir</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;dired</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;dired-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;ss&#34;</span> <span style="color:#19177c">&#39;dired-maybe-insert-subdir</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;sl&#34;</span> <span style="color:#19177c">&#39;dired-maybe-insert-subdir</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;sq&#34;</span> <span style="color:#19177c">&#39;dired-kill-subdir</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;sk&#34;</span> <span style="color:#19177c">&#39;dired-prev-subdir</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;sj&#34;</span> <span style="color:#19177c">&#39;dired-next-subdir</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;sS&#34;</span> <span style="color:#19177c">&#39;my/dired-open-this-subdir</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;sQ&#34;</span> <span style="color:#19177c">&#39;my/dired-kill-all-subdirs</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">kbd</span> <span style="color:#ba2121">&#34;TAB&#34;</span>) <span style="color:#19177c">&#39;dired-hide-subdir</span>))
</span></span></code></pre></div><h4 id="other-functions">Other functions</h4>
<p>Goto project root.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-goto-project-root</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired--find-possibly-alternative-file</span> (<span style="color:#19177c">projectile-project-root</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;dired</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;dired-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;H&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/dired-goto-project-root</span>))
</span></span></code></pre></div><p>Open a file with <code>xdg-open</code>. I used <code>dired-open</code> for this before, but I&rsquo;ve had to abandon the package because it switched from <code>start-process</code> to <code>call-process</code>, which blocks my EXWM.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-open-xdg</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Try to run </span><span style="color:#19177c">`xdg-open&#39;</span><span style="color:#ba2121"> to open the file under point.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">executable-find</span> <span style="color:#ba2121">&#34;xdg-open&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">file</span> (<span style="color:#008000">ignore-errors</span> (<span style="color:#19177c">dired-get-file-for-visit</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">start-process</span> <span style="color:#ba2121">&#34;dired-open&#34;</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;xdg-open&#34;</span> (<span style="color:#19177c">file-truename</span> <span style="color:#19177c">file</span>)))))
</span></span></code></pre></div><p>Run a command on the marked files. Unlike <code>dired-do-async-shell-command</code>, this uses <code>start-process</code> instead of <code>shell-command</code>, which prevents the output buffer from popping up.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-do-async-shell-command</span> (<span style="color:#19177c">command</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">arg</span> <span style="color:#19177c">file-list</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">files</span> (<span style="color:#19177c">dired-get-marked-files</span> <span style="color:#800">t</span> <span style="color:#19177c">current-prefix-arg</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Want to give feedback whether this file or marked files are used:</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired-read-shell-command</span> <span style="color:#ba2121">&#34;&amp; on %s: &#34;</span> <span style="color:#19177c">current-prefix-arg</span> <span style="color:#19177c">files</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">current-prefix-arg</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">files</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">start-process-shell-command</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;*Dired Command*&#34;</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired-shell-stuff-it</span> <span style="color:#19177c">command</span> <span style="color:#19177c">file-list</span> <span style="color:#19177c">arg</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;dired</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#00f">insert</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">dired-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&amp;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/dired-do-async-shell-command</span>))
</span></span></code></pre></div><h4 id="bookmarks">Bookmarks</h4>
<p>A simple bookmark list for Dired, mainly to use with TRAMP. I may look into a proper bookmarking system later.</p>
<p>Bookmarks are listed in the <a href=".emacs.d/private.el">private.el</a> file, which has an expression like this:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>(setq my/dired-bookmarks
</span></span><span style="display:flex;"><span> &#39;((&#34;HOME&#34; . &#34;~&#34;)
</span></span><span style="display:flex;"><span> (&#34;sudo&#34; . &#34;/sudo::/&#34;)))
</span></span></code></pre></div><p>The file itself is encrypted with yadm.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-bookmark-open</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">bookmarks</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">el</span>) (<span style="color:#00f">cons</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%-30s %s&#34;</span> (<span style="color:#00f">car</span> <span style="color:#19177c">el</span>) (<span style="color:#00f">cdr</span> <span style="color:#19177c">el</span>)) (<span style="color:#00f">cdr</span> <span style="color:#19177c">el</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/dired-bookmarks</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">assoc</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">completing-read</span> <span style="color:#ba2121">&#34;Dired: &#34;</span> <span style="color:#19177c">bookmarks</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;^&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">bookmarks</span>)))))
</span></span></code></pre></div><h4 id="integrations">Integrations</h4>
<p>A few functions to send files from Dired to various places.</p>
<p>First, a function to get the target buffer.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/get-good-buffer</span> (<span style="color:#19177c">buffer-major-mode</span> <span style="color:#19177c">prompt</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">buf</span> <span style="color:#19177c">being</span> <span style="color:#19177c">the</span> <span style="color:#19177c">buffers</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#00f">eq</span> (<span style="color:#00f">buffer-local-value</span> <span style="color:#19177c">&#39;major-mode</span> <span style="color:#19177c">buf</span>) <span style="color:#19177c">buffer-major-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> <span style="color:#19177c">buf</span> <span style="color:#19177c">into</span> <span style="color:#19177c">all-buffers</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#008000">and</span> (<span style="color:#00f">eq</span> (<span style="color:#00f">buffer-local-value</span> <span style="color:#19177c">&#39;major-mode</span> <span style="color:#19177c">buf</span>) <span style="color:#19177c">buffer-major-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">get-buffer-window</span> <span style="color:#19177c">buf</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> <span style="color:#19177c">buf</span> <span style="color:#19177c">into</span> <span style="color:#19177c">visible-buffers</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">finally</span> <span style="color:#008000">return</span> (<span style="color:#008000">if</span> (<span style="color:#00f">=</span> (<span style="color:#00f">length</span> <span style="color:#19177c">visible-buffers</span>) <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">car</span> <span style="color:#19177c">visible-buffers</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">=</span> (<span style="color:#00f">length</span> <span style="color:#19177c">all-buffers</span>) <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">car</span> <span style="color:#19177c">all-buffers</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let</span> ((<span style="color:#19177c">buffers-by-name</span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">b</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> (<span style="color:#00f">buffer-name</span> <span style="color:#19177c">b</span>) <span style="color:#19177c">b</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">all-buffers</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">assoc</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">completing-read</span> <span style="color:#19177c">prompt</span> <span style="color:#19177c">buffers-by-name</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">buffers-by-name</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No buffer found!&#34;</span>)))
</span></span></code></pre></div><p>Attach file to telega.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-attach-to-telega</span> (<span style="color:#19177c">files</span> <span style="color:#19177c">telega-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#19177c">dired-get-marked-files</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-nondirectory-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/get-good-buffer</span> <span style="color:#19177c">&#39;telega-chat-mode</span> <span style="color:#ba2121">&#34;Telega buffer: &#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">files</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No (non-directory) files selected&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">telega-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">file</span> <span style="color:#19177c">files</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-chatbuf-attach-file</span> <span style="color:#19177c">file</span>))))
</span></span></code></pre></div><p>Save a telega file to a dired buffer.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/telega-save-to-dired</span> (<span style="color:#19177c">msg</span> <span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#19177c">telega-msg-for-interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">prefix-numeric-value</span> <span style="color:#19177c">current-prefix-arg</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">arg</span> <span style="color:#666">4</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">telega-msg-save-dir</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> (<span style="color:#19177c">my/get-good-buffer</span> <span style="color:#19177c">&#39;dired-mode</span> <span style="color:#ba2121">&#34;Dired buffer: &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired-current-directory</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-msg-save</span> <span style="color:#19177c">msg</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">default-directory</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">&#34;~&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">telega-msg-save-dir</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-msg-save</span> <span style="color:#19177c">msg</span>)))
</span></span></code></pre></div><p>Attach files to notmuch.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-attach-to-notmuch</span> (<span style="color:#19177c">files</span> <span style="color:#19177c">notmuch-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#19177c">dired-get-marked-files</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-nondirectory-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/get-good-buffer</span> <span style="color:#19177c">&#39;notmuch-message-mode</span> <span style="color:#ba2121">&#34;Notmuch message buffer: &#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">files</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No (non-directory) files selected&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">notmuch-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-max</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">file</span> <span style="color:#19177c">files</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">type</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">mm-default-file-type</span> <span style="color:#19177c">file</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;application/octet-stream&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mml-attach-file</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">file</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">type</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mml-minibuffer-read-description</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mml-minibuffer-read-disposition</span> <span style="color:#19177c">type</span> <span style="color:#800">nil</span> <span style="color:#19177c">file</span>))))))
</span></span></code></pre></div><p>Save a notmuch file to a dired buffer.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/notmuch-save-to-dired</span> (<span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#00f">prefix-numeric-value</span> <span style="color:#19177c">current-prefix-arg</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">arg</span> <span style="color:#666">4</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">default-directory</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> (<span style="color:#19177c">my/get-good-buffer</span> <span style="color:#19177c">&#39;dired-mode</span> <span style="color:#ba2121">&#34;Dired buffer: &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired-current-directory</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">notmuch-show-save-part</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">notmuch-show-save-part</span>)))
</span></span></code></pre></div><p>Attach files to ement.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-attach-to-ement</span> (<span style="color:#19177c">files</span> <span style="color:#19177c">ement-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#19177c">dired-get-marked-files</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-nondirectory-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/get-good-buffer</span> <span style="color:#19177c">&#39;ement-room-mode</span> <span style="color:#ba2121">&#34;Ement room buffer: &#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">files</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No (non-directory) files selected&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">ement-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ement-with-room-and-session</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">file</span> <span style="color:#19177c">files</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ement-room-send-file</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">file</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">read-from-minibuffer</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;Message body for %s: &#34;</span> <span style="color:#19177c">file</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">ement-room</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">ement-session</span>)))))
</span></span></code></pre></div><p>Attach files to mastodon.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/dired-attach-to-mastodon</span> (<span style="color:#19177c">files</span> <span style="color:#19177c">mastodon-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#19177c">dired-get-marked-files</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-nondirectory-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">buf</span> <span style="color:#19177c">being</span> <span style="color:#19177c">the</span> <span style="color:#19177c">buffers</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#00f">eq</span> (<span style="color:#00f">buffer-local-value</span> <span style="color:#19177c">&#39;mastodon-toot-mode</span> <span style="color:#19177c">buf</span>) <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">return</span> <span style="color:#19177c">buf</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No buffer found!&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">files</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No (non-directory) files selected&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">mastodon-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">file</span> <span style="color:#19177c">files</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mastodon-toot-attach-media</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">file</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">read-from-minibuffer</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;Description for %s: &#34;</span> <span style="color:#19177c">file</span>))))))
</span></span></code></pre></div><p>And the keybindings:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;dired</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;dired-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;a&#34;</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;at&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/dired-attach-to-telega</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;am&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/dired-attach-to-notmuch</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;ai&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/dired-attach-to-ement</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;an&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/dired-attach-to-mastodon</span>))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;telega</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;telega-msg-button-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;S&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/telega-save-to-dired</span>))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;notmuch</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;notmuch-show-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#19177c">&#39;normal</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;. s&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/notmuch-save-to-dired</span>))
</span></span></code></pre></div><h3 id="tramp">TRAMP</h3>
<p>TRAMP is a package that provides remote editing capacities. It is particularly useful for remote server management.</p>
<h4 id="general-settings-4">General settings</h4>
<p>Some settings I copy-pasted from somewhere:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">remote-file-name-inhibit-cache</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">vc-ignore-dir-regexp</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;\\(%s\\)\\|\\(%s\\)&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">vc-ignore-dir-regexp</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">tramp-file-name-regexp</span>))
</span></span></code></pre></div><p>Also, a hack to make TRAMP find <code>ls</code> on Guix:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;tramp</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">tramp-remote-path</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">append</span> <span style="color:#19177c">tramp-remote-path</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">tramp-own-remote-path</span>))))
</span></span></code></pre></div><p>Set the default shell to <code>bin/bash</code> for TRAMP or on a remote server.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">when</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">explicit-shell-file-name</span> <span style="color:#ba2121">&#34;/bin/bash&#34;</span>))
</span></span></code></pre></div><h4 id="package-optimizations">Package optimizations</h4>
<p>Unfortunately, many Emacs packages don&rsquo;t exactly moderate their rate of filesystem operations, and on TRAMP over network each operation adds additional overhead, so&hellip; it can get pretty slow. To debug these issues, set the following variable to 6:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">tramp-verbose</span> <span style="color:#666">0</span>)
</span></span></code></pre></div><p>I used to launch a separate Emacs instance for TRAMP to disable these packages with an environment variable, but my <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Advising-Functions.html">advice</a>-fu got better since then.</p>
<p>So, to determine if the buffer is in TRAMP:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/tramp-p</span> (<span style="color:#008000">&amp;optional</span> <span style="color:#19177c">buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">file-remote-p</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-local-value</span> <span style="color:#19177c">&#39;default-directory</span> (<span style="color:#008000">or</span> <span style="color:#19177c">buffer</span> (<span style="color:#00f">current-buffer</span>)))))
</span></span></code></pre></div><p>And advice to disable a function for TRAMP-related buffers:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/tramp-void-if-tramp</span> (<span style="color:#19177c">fun</span> <span style="color:#008000">&amp;rest</span> <span style="color:#19177c">args</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">my/tramp-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#19177c">fun</span> <span style="color:#19177c">args</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/tramp-void-if-file-is-tramp</span> (<span style="color:#19177c">fun</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">dir</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">file-remote-p</span> (<span style="color:#008000">or</span> <span style="color:#19177c">dir</span> <span style="color:#19177c">default-directory</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">fun</span> <span style="color:#19177c">dir</span>)))
</span></span></code></pre></div><p><code>editorconfig</code>. This lovely package looks for <code>.editorconfig</code> in the file tree.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/editorconfig--advice-find-file-noselect-around</span> (<span style="color:#19177c">f</span> <span style="color:#19177c">f1</span> <span style="color:#19177c">filename</span> <span style="color:#008000">&amp;rest</span> <span style="color:#19177c">args</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">file-remote-p</span> <span style="color:#19177c">filename</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#19177c">f1</span> <span style="color:#19177c">filename</span> <span style="color:#19177c">args</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#19177c">f</span> <span style="color:#19177c">f1</span> <span style="color:#19177c">filename</span> <span style="color:#19177c">args</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;editorconfig</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">editorconfig-apply</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/tramp-void-if-tramp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">editorconfig--disabled-for-filename</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/tramp-void-if-file-is-tramp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">editorconfig--advice-find-file-noselect</span> <span style="color:#008000">:around</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/editorconfig--advice-find-file-noselect-around</span>))
</span></span></code></pre></div><p><code>all-the-icons-dired</code> runs <code>test</code> on every file in the directory.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;all-the-icons-dired</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">all-the-icons-dired-mode</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/tramp-void-if-tramp</span>))
</span></span></code></pre></div><p><code>projectile</code> looks for <code>.git</code>, <code>.svn</code>, etc. to find the project root. Maybe I&rsquo;ll make a more economic implementation if I need one.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;projectile</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">projectile-project-root</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/tramp-void-if-file-is-tramp</span>))
</span></span></code></pre></div><p><code>lsp</code> does a whole lot of stuff. It probably can be used with TRAMP on faster connections, but not in my case.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;lsp-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">lsp</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/tramp-void-if-tramp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">lsp-deferred</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/tramp-void-if-tramp</span>))
</span></span></code></pre></div><p><code>git-gutter</code> runs <code>git</code> a lot of times.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;git-gutter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">git-gutter--turn-on</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/tramp-void-if-tramp</span>))
</span></span></code></pre></div><p><code>dired-git-info</code> is runs <code>git</code> a lot of times.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;dired-git-info</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired-git-info-mode</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/tramp-void-if-tramp</span>))
</span></span></code></pre></div><p><code>pipenv</code>. Don&rsquo;t remember what was the deal with this one.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;pipenv</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">pipenv-mode</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/tramp-void-if-tramp</span>))
</span></span></code></pre></div><p><code>eshell</code> works pretty well, but <code>company-mode</code> gets pretty slow.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/shell-maybe-configure-for-tramp</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">my/tramp-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">company-idle-delay</span> <span style="color:#800">nil</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;eshell-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/shell-maybe-configure-for-tramp</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;shell-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/shell-maybe-configure-for-tramp</span>)
</span></span></code></pre></div><h3 id="shells-terminals">Shells / Terminals</h3>
<h4 id="vterm">vterm</h4>
<p><a href="https://github.com/akermu/emacs-libvterm">vterm</a> is a terminal emulator for Emacs.</p>
<p>References:</p>
<ul>
<li><a href="https://github.com/akermu/emacs-libvterm">emacs-libvterm repo</a></li>
</ul>
<h5 id="configuration-1">Configuration</h5>
<p>On Guix it makes more sense to use the Guix package to avoid building the vterm module, but obviously not an option on termux, hence this:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">when</span> <span style="color:#19177c">my/is-termux</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">straight-use-package</span> <span style="color:#19177c">&#39;vterm</span>))
</span></span></code></pre></div><p>The actual config:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/vterm-setup</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-line-numbers-mode</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">term-prompt-regexp</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bol</span> (<span style="color:#19177c">|</span> <span style="color:#ba2121">&#34;&gt;&#34;</span> <span style="color:#ba2121">&#34;✕&#34;</span>) <span style="color:#ba2121">&#34; &#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">vterm</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">vterm</span> <span style="color:#19177c">vterm-other-window</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">vterm-kill-buffer-on-exit</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">vterm-environment</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;IS_VTERM=1&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;vterm-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/vterm-setup</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (advice-add &#39;evil-collection-vterm-insert</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; :before (lambda (&amp;rest args)</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (ignore-errors</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (apply #&#39;vterm-reset-cursor-point args))))</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;vterm-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-q&#34;</span> <span style="color:#19177c">&#39;vterm-send-escape</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-h&#34;</span> <span style="color:#19177c">&#39;evil-window-left</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-l&#34;</span> <span style="color:#19177c">&#39;evil-window-right</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-k&#34;</span> <span style="color:#19177c">&#39;evil-window-up</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-j&#34;</span> <span style="color:#19177c">&#39;evil-window-down</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-&lt;right&gt;&#34;</span> <span style="color:#19177c">&#39;evil-window-right</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-&lt;left&gt;&#34;</span> <span style="color:#19177c">&#39;evil-window-left</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-&lt;up&gt;&#34;</span> <span style="color:#19177c">&#39;evil-window-up</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-&lt;down&gt;&#34;</span> <span style="color:#19177c">&#39;evil-window-down</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-&lt;left&gt;&#34;</span> <span style="color:#19177c">&#39;vterm-send-left</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-&lt;right&gt;&#34;</span> <span style="color:#19177c">&#39;vterm-send-right</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-&lt;up&gt;&#34;</span> <span style="color:#19177c">&#39;vterm-send-up</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-&lt;down&gt;&#34;</span> <span style="color:#19177c">&#39;vterm-send-down</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;vterm-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#00f">insert</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;home&gt;&#34;</span> <span style="color:#19177c">&#39;vterm-beginning-of-line</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;end&gt;&#34;</span> <span style="color:#19177c">&#39;vterm-end-of-line</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;vterm-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#00f">insert</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-r&#34;</span> <span style="color:#19177c">&#39;vterm-send-C-r</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-k&#34;</span> <span style="color:#19177c">&#39;vterm-send-C-k</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-j&#34;</span> <span style="color:#19177c">&#39;vterm-send-C-j</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-l&#34;</span> <span style="color:#19177c">&#39;vterm-send-right</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-h&#34;</span> <span style="color:#19177c">&#39;vterm-send-left</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-k&#34;</span> <span style="color:#19177c">&#39;vterm-send-up</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-j&#34;</span> <span style="color:#19177c">&#39;vterm-send-down</span>))
</span></span></code></pre></div><h5 id="subterminal">Subterminal</h5>
<p>Open a terminal in the lower third of the frame with the <code>`</code> key.</p>
<p>I guess that&rsquo;s the first Emacs function I wrote!</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;display-buffer-alist</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,</span><span style="color:#ba2121">&#34;vterm-subterminal.*&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-buffer-reuse-window</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">display-buffer-in-side-window</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">side</span> <span style="color:#666">.</span> <span style="color:#19177c">bottom</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">reusable-frames</span> <span style="color:#666">.</span> <span style="color:#19177c">visible</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">window-height</span> <span style="color:#666">.</span> <span style="color:#666">0.33</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/toggle-vterm-subteminal</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Toogle subteminal.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">vterm-window</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-find</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">window</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">string-match</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;vterm-subterminal.*&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-name</span> (<span style="color:#00f">window-buffer</span> <span style="color:#19177c">window</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">window-list</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">vterm-window</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">eq</span> (<span style="color:#00f">get-buffer-window</span> (<span style="color:#00f">current-buffer</span>)) <span style="color:#19177c">vterm-window</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">kill-buffer</span> (<span style="color:#00f">current-buffer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">select-window</span> <span style="color:#19177c">vterm-window</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">vterm-other-window</span> <span style="color:#ba2121">&#34;vterm-subterminal&#34;</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (unless my/slow-ssh</span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (general-nmap &#34;`&#34; &#39;my/toggle-vterm-subteminal)</span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (general-nmap &#34;~&#34; &#39;vterm))</span>
</span></span></code></pre></div><h5 id="dired-integration">Dired integration</h5>
<p>A function to get pwd for vterm. Couldn&rsquo;t find a built-in function for some reason, but this seems work fine:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/vterm-get-pwd</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">vterm--process</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">file-truename</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;/proc/%d/cwd&#34;</span> (<span style="color:#00f">process-id</span> <span style="color:#19177c">vterm--process</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">default-directory</span>))
</span></span></code></pre></div><p>Now we can open dired for vterm pwd:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/vterm-dired-other-window</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Open dired in vterm pwd in other window&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired-other-window</span> (<span style="color:#19177c">my/vterm-get-pwd</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/vterm-dired-replace</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Replace vterm with dired&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">pwd</span> (<span style="color:#19177c">my/vterm-get-pwd</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">kill-process</span> <span style="color:#19177c">vterm--process</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dired</span> <span style="color:#19177c">pwd</span>)))
</span></span></code></pre></div><p>The second function is particularly handy because that way I can alternate between vterm and dired.</p>
<p>Keybindings:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;vterm</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;vterm-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gd&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/vterm-dired-other-window</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gD&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/vterm-dired-replace</span>))
</span></span></code></pre></div><h5 id="with-editor-integration">With-editor integration</h5>
<p>A package used by Magit to use the current Emacs instance as the <code>$EDITOR</code>.</p>
<p>That is, with the help of <a href="/configs/console/#functions">this function</a>, I can just write <code>e &lt;filename&gt;</code>, edit the file, and then return to the same vterm buffer. No more running vim inside Emacs.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">with-editor</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">vterm</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;vterm-mode-hook</span> <span style="color:#19177c">&#39;with-editor-export-editor</span>))
</span></span></code></pre></div><h4 id="eshell">eshell</h4>
<p><a href="https://www.gnu.org/software/emacs/manual/html_mono/eshell.html">eshell</a> is a shell implemented in Emacs Lisp.</p>
<p>I&rsquo;ll try to use it as my primary shell for a few reasons. First, I just want to have a &ldquo;normal&rdquo; (&hellip;evil&hellip;) editing experience for shell prompts. My current shell setup is fish with vi bindings, which doesn&rsquo;t work well with vterm because the shell just accepts the keystrokes from the terminal, completely oblivious to the current Emacs state. So, I need to do stuff like entering insert state in Emacs, then entering normal state in the shell while keeping Emacs in insert state. That&rsquo;s just too much pain sometimes.</p>
<p>This setup also frequently messes with fish autosuggestions.</p>
<p>Second, I do want to be able to run <code>dired</code> or <code>find-file</code> from the terminal. I&rsquo;ve sort of implemented that in the <a href="#vterm-1">vterm</a> section, but an Emacs-integrated shell is obviously more convenient for that.</p>
<p>TODO:</p>
<ul>
<li>Configure it for TRAMP (<code>company-idle-delay</code> to a large value, what else?)</li>
</ul>
<h5 id="initial-configuration">Initial configuration</h5>
<p>Some initial configuration.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/configure-eshell</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;eshell-pre-command-hook</span> <span style="color:#19177c">&#39;eshell-save-some-history</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;eshell-output-filter-functions</span> <span style="color:#19177c">&#39;eshell-truncate-buffer</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#00f">insert</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;eshell-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;home&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">eshell-bol</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;eshell-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#00f">insert</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;tab&gt;&#34;</span> <span style="color:#19177c">&#39;my/eshell-complete</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-k&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">eshell-previous-matching-input-from-input</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-j&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">eshell-next-matching-input-from-input</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;eshell-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-h&#34;</span> <span style="color:#19177c">&#39;evil-window-left</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-l&#34;</span> <span style="color:#19177c">&#39;evil-window-right</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-k&#34;</span> <span style="color:#19177c">&#39;evil-window-up</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-j&#34;</span> <span style="color:#19177c">&#39;evil-window-down</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; XXX Did they forget to set it to nil?</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-first-time-p</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">eshell</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:type</span> <span style="color:#19177c">built-in</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">evil-collection</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">eshell</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-history-size</span> <span style="color:#666">10000</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-hist-ignoredups</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-buffer-maximum-lines</span> <span style="color:#666">10000</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; XXX 90 to override `evil-collection&#39;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;eshell-first-time-mode-hook</span> <span style="color:#19177c">&#39;my/configure-eshell</span> <span style="color:#666">90</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-command-aliases-list</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#ba2121">&#34;exit&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#ba2121">&#34;clear&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ll&#34;</span> <span style="color:#ba2121">&#34;ls -la&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;e&#34;</span> <span style="color:#ba2121">&#34;find-file&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-banner-message</span> <span style="color:#ba2121">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (setq eshell-visual-commands</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; `(,@eshell-visual-commands &#34;jless&#34;))</span>
</span></span><span style="display:flex;"><span> )
</span></span></code></pre></div><h5 id="ui-2">UI</h5>
<p>I&rsquo;ll try reusing the <a href="https://starship.rs/">Starship</a> prompt.</p>
<p>The executable can print out the text of the prompt, but somehow it refuses when there&rsquo;s <code>TERM=dumb</code> in the environment. I also advise Eshell to record the execution time for the <code>--cmd-duration</code> flag.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar-local</span> <span style="color:#19177c">my/eshell-last-command-start-time</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/get-starship-prompt</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">cmd</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;TERM=xterm starship prompt --status=%d --cmd-duration=%d --logical-path=%s&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">eshell-last-command-status</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">my/eshell-last-command-start-time</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">delta</span> (<span style="color:#00f">float-time</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">time-subtract</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">current-time</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/eshell-last-command-start-time</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/eshell-last-command-start-time</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">round</span> (<span style="color:#00f">*</span> <span style="color:#19177c">delta</span> <span style="color:#666">1000</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shell-quote-argument</span> <span style="color:#19177c">default-directory</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">call-process</span> <span style="color:#ba2121">&#34;bash&#34;</span> <span style="color:#800">nil</span> <span style="color:#800">t</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;-c&#34;</span> <span style="color:#19177c">cmd</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">my/is-termux</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">inhibit-message</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-string</span> <span style="color:#ba2121">&#34;\\[&#34;</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#800">nil</span> (<span style="color:#00f">point-min</span>) (<span style="color:#00f">point-max</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-string</span> <span style="color:#ba2121">&#34;\\]&#34;</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#800">nil</span> (<span style="color:#00f">point-min</span>) (<span style="color:#00f">point-max</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-first</span> <span style="color:#ba2121">&#34;\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> (<span style="color:#19177c">string-trim</span> (<span style="color:#00f">buffer-string</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ansi-color-apply</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/eshell-set-start-time</span> (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">_args</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">my/eshell-last-command-start-time</span> (<span style="color:#00f">current-time</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;eshell</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">eshell-send-input</span> <span style="color:#008000">:before</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/eshell-set-start-time</span>))
</span></span></code></pre></div><p>Now this can go in <code>eshell-prompt-function</code> with two more options. First, <code>eshell-highlight-prompt</code> has to be set to nil because it screws up faces applied by <code>ansi-color.el</code>.</p>
<p>Second, <code>eshell-prompt-regexp</code> has to align with the <code>starship</code> configuration. The relevant part of mine looks like this:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[character]
</span></span><span style="display:flex;"><span>success_symbol = <span style="color:#ba2121">&#34;[&gt; ](bold green)&#34;</span>
</span></span><span style="display:flex;"><span>error_symbol = <span style="color:#ba2121">&#34;[✕ ](bold red)&#34;</span>
</span></span></code></pre></div><p>So my regex matches with either of these two prompts. IIRC the default value is different from mine.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;eshell</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-prompt-regexp</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bol</span> (<span style="color:#19177c">|</span> <span style="color:#ba2121">&#34;&gt;&#34;</span> <span style="color:#ba2121">&#34;✕&#34;</span>) <span style="color:#ba2121">&#34; &#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-prompt-function</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/get-starship-prompt</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-highlight-prompt</span> <span style="color:#800">nil</span>))
</span></span></code></pre></div><p><a href="https://github.com/zwild/eshell-prompt-extras/">eshell-prompt-extras</a> is an alternative to the above that doesn&rsquo;t depend on <code>starship</code>. I&rsquo;ll keep it here for now because I expect I won&rsquo;t be able to use starship everywhere.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my/use-colors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">epe-pipeline-delimiter-face</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;green</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">epe-pipeline-host-face</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;blue</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">epe-pipeline-time-face</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;yellow</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">epe-pipeline-user-face</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;red</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">eshell-prompt-extras</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">eshell</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-prompt-function</span> <span style="color:#19177c">&#39;epe-theme-pipeline</span>))
</span></span></code></pre></div><p><a href="https://github.com/akreisher/eshell-syntax-highlighting/">eshell-syntax-highlighting</a> highlights things like correct/incorrect commands (like fish).</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">eshell-syntax-highlighting</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">eshell</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">eshell-syntax-highlighting-global-mode</span>))
</span></span></code></pre></div><p><a href="https://github.com/ryuslash/eshell-fringe-status/">eshell-fringe-status</a> shows the status of the last command in fringe. I&rsquo;ve disabled it because I configured starship to use status from eshell.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">eshell-fringe-status</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">eshell</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;eshell-mode-hook</span> <span style="color:#19177c">&#39;eshell-fringe-status-mode</span>))
</span></span></code></pre></div><h5 id="fish-completions">Fish completions</h5>
<p><a href="https://github.com/LemonBreezes/emacs-fish-completion/">emacs-fish-completion</a> uses <code>fish</code> to autocomplete prompts when the built-in completion fails. This way, it can autocomplete <code>docker</code>, <code>yarn</code>, etc., which is pretty cool.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">fish-completion</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">eshell</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">executable-find</span> <span style="color:#ba2121">&#34;fish&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">global-fish-completion-mode</span>))
</span></span></code></pre></div><h5 id="fish-like-autosuggestions">Fish-like autosuggestions</h5>
<p>I&rsquo;m used to these fancy autosuggestions provided by <code>fish</code>.</p>
<p>There are two packages that do something like that:</p>
<ul>
<li><a href="https://github.com/dieggsy/esh-autosuggest">esh-autosuggest</a>. It just uses <a href="https://github.com/company-mode/company-mode">company-mode</a> to display suggestions, which prevents using <code>company-mode</code> for anything else.</li>
<li><a href="https://elpa.gnu.org/packages/capf-autosuggest.html">capf-autosuggest</a>. It mostly does what I want, but it doesn&rsquo;t verify its suggestion, e.g. it can suggest <code>cd</code> to a non-existing directory. I tried advising this functionality, but then the package became too slow because it fetches all candidates on each keystroke.</li>
</ul>
<p>So, I&rsquo;ve spent a ridiculous amount of time implementing this probably unnecessary feature, and I&rsquo;m still not sure if I should keep it&hellip;</p>
<p>But anyway, here&rsquo;s my overlay-based solution inspired by <a href="https://github.com/copilot-emacs/copilot.el">copilot.el</a>. First, we need to get the current input string:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/eshell-get-input</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">beginning-of-line</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">looking-at-p</span> <span style="color:#19177c">eshell-prompt-regexp</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring-no-properties</span> (<span style="color:#19177c">eshell-get-old-input</span>)))))
</span></span></code></pre></div><p>In order to verify suggestions (for instance, to check whether the suggested directory exists), it&rsquo;s necessary to &ldquo;unquote&rdquo; strings because history stores them in the quoted form.</p>
<p>There&rsquo;s a built-in function called <code>shell-unquote-argument</code>, but it requires the current buffer to have a process for a seemingly Windows-related reason&hellip; So below is a copy of this function without that part.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/shell-unquote-argument-without-process</span> (<span style="color:#00f">string</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-match-data</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">idx</span> <span style="color:#666">0</span>) <span style="color:#19177c">next</span> <span style="color:#19177c">inside</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">quote-chars</span> (<span style="color:#008000">rx</span> (<span style="color:#19177c">|</span> <span style="color:#ba2121">&#34;&#39;&#34;</span> <span style="color:#ba2121">&#34;`&#34;</span> <span style="color:#ba2121">&#34;\&#34;&#34;</span> <span style="color:#ba2121">&#34;\\&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">while</span> (<span style="color:#008000">and</span> (<span style="color:#00f">&lt;</span> <span style="color:#19177c">idx</span> (<span style="color:#00f">length</span> <span style="color:#00f">string</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">next</span> (<span style="color:#00f">string-match</span> <span style="color:#19177c">quote-chars</span> <span style="color:#00f">string</span> <span style="color:#19177c">next</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span> ((<span style="color:#00f">=</span> (<span style="color:#00f">aref</span> <span style="color:#00f">string</span> <span style="color:#19177c">next</span>) <span style="color:#ba2121">?\\</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#00f">string</span> (<span style="color:#00f">replace-match</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">string</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">next</span> (<span style="color:#00f">1+</span> <span style="color:#19177c">next</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">and</span> <span style="color:#19177c">inside</span> (<span style="color:#00f">=</span> (<span style="color:#00f">aref</span> <span style="color:#00f">string</span> <span style="color:#19177c">next</span>) <span style="color:#19177c">inside</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#00f">string</span> (<span style="color:#00f">replace-match</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">string</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">inside</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">inside</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">next</span> (<span style="color:#00f">1+</span> <span style="color:#19177c">next</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">inside</span> (<span style="color:#00f">aref</span> <span style="color:#00f">string</span> <span style="color:#19177c">next</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#00f">string</span> (<span style="color:#00f">replace-match</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">string</span>)))))
</span></span><span style="display:flex;"><span> <span style="color:#00f">string</span>)))
</span></span></code></pre></div><p>Now, verify one suggestion against the current input. At the moment, outside of checking the prefix, it does the following:</p>
<ul>
<li>If the suggestion is <code>cd</code> to directory, check if this directory exists</li>
<li>If it&rsquo;s <code>git something</code>, check if we&rsquo;re in a git repo</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/eshell-history-is-good-suggestion</span> (<span style="color:#19177c">input</span> <span style="color:#19177c">suggestion</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span> (<span style="color:#19177c">string-prefix-p</span> <span style="color:#19177c">input</span> <span style="color:#19177c">suggestion</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">string-prefix-p</span> <span style="color:#ba2121">&#34;cd &#34;</span> <span style="color:#19177c">input</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">suggested-dir</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/shell-unquote-argument-without-process</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span> <span style="color:#19177c">suggestion</span> <span style="color:#666">3</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">string-prefix-p</span> <span style="color:#ba2121">&#34;/&#34;</span> <span style="color:#19177c">suggested-dir</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-prefix-p</span> <span style="color:#ba2121">&#34;~&#34;</span> <span style="color:#19177c">suggested-dir</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-directory-p</span> <span style="color:#19177c">suggested-dir</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-directory-p</span> (<span style="color:#00f">concat</span> (<span style="color:#19177c">eshell/pwd</span>) <span style="color:#ba2121">&#34;/&#34;</span> <span style="color:#19177c">suggested-dir</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">string-prefix-p</span> <span style="color:#ba2121">&#34;git&#34;</span> <span style="color:#19177c">suggestion</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; How is this faster than &#39;magit-toplevel&#39;?</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">vc-git-root</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">t</span>)))
</span></span></code></pre></div><p>And propose one suggestion for the current <code>input</code>, because I don&rsquo;t need more. It users two sources:</p>
<ul>
<li><code>eshell-history-ring</code></li>
<li><code>pcomplete</code>, which is integrated with <code>eshell</code> out-of-the-box. It was soo painful to figure out&hellip; But it works.</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/eshell-history-suggest-one</span> (<span style="color:#19177c">input</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">seq-empty-p</span> <span style="color:#19177c">input</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let</span> (<span style="color:#19177c">s</span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">elem</span> <span style="color:#19177c">in</span> (<span style="color:#19177c">ring-elements</span> <span style="color:#19177c">eshell-history-ring</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">proc-elem</span> <span style="color:#00f">=</span> (<span style="color:#19177c">string-trim</span> (<span style="color:#00f">substring-no-properties</span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">when</span> (<span style="color:#19177c">my/eshell-history-is-good-suggestion</span> <span style="color:#19177c">input</span> <span style="color:#19177c">proc-elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">return</span> <span style="color:#19177c">proc-elem</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span> <span style="color:#19177c">s</span> (<span style="color:#00f">length</span> <span style="color:#19177c">input</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">ignore-errors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let*</span> ((<span style="color:#19177c">pcomplete-stub</span> <span style="color:#19177c">input</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">completions</span> (<span style="color:#19177c">pcomplete-completions</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">one-completion</span> (<span style="color:#00f">car</span> (<span style="color:#00f">all-completions</span> <span style="color:#19177c">pcomplete-stub</span> <span style="color:#19177c">completions</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">bound</span> (<span style="color:#00f">car</span> (<span style="color:#19177c">completion-boundaries</span> <span style="color:#19177c">pcomplete-stub</span> <span style="color:#19177c">completions</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">zerop</span> <span style="color:#19177c">bound</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">one-completion</span> (<span style="color:#00f">concat</span> (<span style="color:#00f">substring</span> <span style="color:#19177c">pcomplete-stub</span> <span style="color:#666">0</span> <span style="color:#19177c">bound</span>) <span style="color:#19177c">one-completion</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (message &#34;%s %s&#34; pcomplete-stub one-completion)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">comint-quote-filename</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span> <span style="color:#19177c">one-completion</span> (<span style="color:#00f">min</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">length</span> <span style="color:#19177c">pcomplete-stub</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">length</span> <span style="color:#19177c">one-completion</span>)))))))))
</span></span></code></pre></div><p>As I said, I want to use an overlay to display the suggestion. I tried to store the current overlay in a buffer-local variable, but somehow it was getting lost at times&hellip; And there aren&rsquo;t many overlays anyway, so this doesn&rsquo;t seem to slow down Emacs that much.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/eshell-overlay-get</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-find</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">ov</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">overlay-get</span> <span style="color:#19177c">ov</span> <span style="color:#19177c">&#39;my/eshell-completion-overlay</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">overlays-in</span> (<span style="color:#00f">point-min</span>) (<span style="color:#00f">point-max</span>))))
</span></span></code></pre></div><p>Thanks <a href="https://emacs.stackexchange.com/questions/15078/inserting-before-an-after-string-overlay">this answer on StackExchange</a> for pointing out the <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Special-Properties.html#index-cursor-_0028text-property_0029">cursor</a> text property.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/eshell-overlay-update</span> (<span style="color:#19177c">pos</span> <span style="color:#19177c">value</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">overlay-value</span> (<span style="color:#00f">propertize</span> <span style="color:#19177c">value</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;shadow</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;cursor</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">overlay</span> (<span style="color:#19177c">my/eshell-overlay-get</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">overlay</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">move-overlay</span> <span style="color:#19177c">overlay</span> <span style="color:#19177c">pos</span> <span style="color:#19177c">pos</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">overlay</span> (<span style="color:#00f">make-overlay</span> <span style="color:#19177c">pos</span> <span style="color:#19177c">pos</span> (<span style="color:#00f">current-buffer</span>) <span style="color:#800">nil</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">overlay-put</span> <span style="color:#19177c">overlay</span> <span style="color:#19177c">&#39;my/eshell-completion-overlay</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">overlay-put</span> <span style="color:#19177c">overlay</span> <span style="color:#19177c">&#39;after-string</span> <span style="color:#19177c">overlay-value</span>)))
</span></span></code></pre></div><p>The function to remove the overlay:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/eshell-overlay-remove</span> (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">_</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">ov</span> (<span style="color:#00f">overlays-in</span> (<span style="color:#00f">point-min</span>) (<span style="color:#00f">point-max</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">overlay-get</span> <span style="color:#19177c">ov</span> <span style="color:#19177c">&#39;my/eshell-completion-overlay</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">delete-overlay</span> <span style="color:#19177c">ov</span>))))
</span></span></code></pre></div><p>Putting that all together.</p>
<p>This also hides the overlay if <code>company</code> completion is active because <code>company</code> sometimes creates its own overlays that intersect with mine&hellip; I don&rsquo;t yet understand when it happens because sometimes <code>company</code> just creates the completion dialog with no overlay, and I couldn&rsquo;t find a way to check if the overlay is created or not.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/eshell-overlay-suggest</span> (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">_args</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">if-let*</span> ((<span style="color:#19177c">input</span> (<span style="color:#19177c">my/eshell-get-input</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">suggestion</span> (<span style="color:#19177c">my/eshell-history-suggest-one</span> <span style="color:#19177c">input</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">_</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">company-prefix</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/eshell-overlay-update</span> (<span style="color:#00f">line-end-position</span>) <span style="color:#19177c">suggestion</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/eshell-overlay-remove</span>)))
</span></span></code></pre></div><p>The function can be added in <code>after-change-functions</code>, which is executed on every text modification. This shouldn&rsquo;t slow eshell down because <code>eshell-send-input</code> sets <code>inhibit-modification-hooks</code> to t.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">define-minor-mode</span> <span style="color:#19177c">my/eshell-overlay-suggest-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Fish-like suggestions for eshell.&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">my/eshell-overlay-suggest-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;after-change-functions</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/eshell-overlay-suggest</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;company-completion-started-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/eshell-overlay-suggest</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;company-after-completion-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/eshell-overlay-suggest</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">remove-hook</span> <span style="color:#19177c">&#39;after-change-functions</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/eshell-overlay-suggest</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;company-completion-started-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/eshell-overlay-suggest</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;company-after-completion-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/eshell-overlay-suggest</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/eshell-overlay-remove</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (add-hook &#39;eshell-mode-hook #&#39;my/eshell-overlay-suggest-mode)</span>
</span></span></code></pre></div><p>Finally, a function that inserts the overlay in buffer if it&rsquo;s available and calls <code>company-complete</code> if it&rsquo;s not. I&rsquo;ve bound it to <code>&lt;tab&gt;</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/eshell-complete</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">and</span> (<span style="color:#00f">=</span> (<span style="color:#00f">point</span>) (<span style="color:#00f">line-end-position</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">if-let</span> ((<span style="color:#19177c">overlay</span> (<span style="color:#19177c">my/eshell-overlay-get</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">delete-overlay</span> <span style="color:#19177c">overlay</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">overlay-get</span> <span style="color:#19177c">overlay</span> <span style="color:#19177c">&#39;after-string</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">company-complete</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">company-complete</span>)))
</span></span></code></pre></div><h5 id="atuin-integration">Atuin integration</h5>
<p><a href="https://github.com/SqrtMinusOne/eshell-atuin">eshell-atuin</a> is my package that integrates eshell with <a href="https://github.com/atuinsh/atuin">atuin</a>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">eshell-atuin</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;SqrtMinusOne/eshell-atuin&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">eshell</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">eshell-atuin-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-atuin-search-fields</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">time</span> <span style="color:#19177c">duration</span> <span style="color:#19177c">command</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">eshell-atuin-history-format</span> <span style="color:#ba2121">&#34;%-160c %t + %d&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#00f">insert</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;eshell-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-r&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">eshell-atuin-history</span>))
</span></span></code></pre></div><h5 id="dedicated-buffer">Dedicated buffer</h5>
<p>Make a dedicated buffer for eshell in the bottom of the screen.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;display-buffer-alist</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;eshell-dedicated.*&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-buffer-reuse-window</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">display-buffer-in-side-window</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">side</span> <span style="color:#666">.</span> <span style="color:#19177c">bottom</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">reusable-frames</span> <span style="color:#666">.</span> <span style="color:#19177c">visible</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">window-height</span> <span style="color:#666">.</span> <span style="color:#666">0.33</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/eshell-dedicated</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; XXX the byte-compiler freaks out if eshell is required within the</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; `let*&#39; block because it binds `dedicated-buffer&#39;... dynamically?</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; How?</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;eshell</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">eshell-buffer-name</span> <span style="color:#ba2121">&#34;eshell-dedicated&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dedicated-buffer</span> (<span style="color:#00f">get-buffer</span> <span style="color:#19177c">eshell-buffer-name</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">dedicated-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">eshell</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">window</span> (<span style="color:#00f">get-buffer-window</span> <span style="color:#19177c">dedicated-buffer</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">eq</span> (<span style="color:#00f">selected-window</span>) <span style="color:#19177c">window</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">kill-buffer-and-window</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">select-window</span> <span style="color:#19177c">window</span>))))))
</span></span></code></pre></div><h5 id="custom-commands">Custom commands</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">eshell/prt</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">if-let</span> ((<span style="color:#19177c">root</span> (<span style="color:#19177c">projectile-project-root</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">eshell/cd</span> <span style="color:#19177c">root</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Not in a project&#34;</span>)))
</span></span></code></pre></div><h5 id="global-keybindings">Global keybindings</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;`&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/eshell-dedicated</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;~&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">eshell</span>)
</span></span></code></pre></div><h4 id="eat">eat</h4>
<p><a href="https://codeberg.org/akib/emacs-eat">eat</a> is a terminal emulator written in Emacs Lisp.</p>
<p>It&rsquo;s slower than <code>vterm</code>, but it seems to be the second best option because of <code>line-mode</code>, which sends the input line-by-line allowing it to edit like in <code>eshell</code>. However, this obviously disables syntax higlighting and autosuggestions, which <code>eshell</code> with my configuration has.</p>
<p>Still, I&rsquo;ll probably switch to <code>eat</code> if <code>eshell</code> doesn&rsquo;t work for me.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">eat</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:files</span> (<span style="color:#ba2121">&#34;*.el&#34;</span> (<span style="color:#ba2121">&#34;term&#34;</span> <span style="color:#ba2121">&#34;term/*.el&#34;</span>) <span style="color:#ba2121">&#34;*.texi&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;*.ti&#34;</span> (<span style="color:#ba2121">&#34;terminfo/e&#34;</span> <span style="color:#ba2121">&#34;terminfo/e/*&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;terminfo/65&#34;</span> <span style="color:#ba2121">&#34;terminfo/65/*&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;integration&#34;</span> <span style="color:#ba2121">&#34;integration/*&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:exclude</span> <span style="color:#ba2121">&#34;.dir-locals.el&#34;</span> <span style="color:#ba2121">&#34;*-tests.el&#34;</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">eat</span> <span style="color:#19177c">eat-shell-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">eat-shell</span> <span style="color:#ba2121">&#34;/bin/bash&#34;</span>))
</span></span></code></pre></div><p>Yeah, and <code>eat</code> has integration with eshell too.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;eshell-load-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">eat-eshell-mode</span>)
</span></span></code></pre></div><h4 id="shell-1">shell</h4>
<p>Interactive subshell (<code>M-x shell</code>) is a way to run commands with input and output through an Emacs buffer.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/setup-shell</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">comint-use-prompt-regexp</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">comint-prompt-read-only</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;shell-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/setup-shell</span>)
</span></span></code></pre></div><h3 id="managing-dotfiles">Managing dotfiles</h3>
<p>A bunch of functions for managing dotfiles with yadm.</p>
<h4 id="open-emacs-config">Open Emacs config</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; &#34;C-c c&#34; (my/command-in-persp &#34;Emacs.org&#34; &#34;conf&#34; 1 (find-file &#34;~/Emacs.org&#34;))</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c c&#34;</span> <span style="color:#666">`</span>(<span style="color:#666">,</span>(<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">find-file</span> <span style="color:#ba2121">&#34;~/Emacs.org&#34;</span>)) <span style="color:#008000">:wk</span> <span style="color:#ba2121">&#34;Emacs.org&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;c&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;configuration&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; &#34;c&#34; (my/command-in-persp &#34;Emacs.org&#34; &#34;conf&#34; 1 (find-file &#34;~/Emacs.org&#34;))</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#666">`</span>(<span style="color:#666">,</span>(<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">find-file</span> <span style="color:#ba2121">&#34;~/Emacs.org&#34;</span>)) <span style="color:#008000">:wk</span> <span style="color:#ba2121">&#34;Emacs.org&#34;</span>))
</span></span></code></pre></div><h4 id="open-magit-for-yadm">Open Magit for yadm</h4>
<p>Idea:</p>
<ul>
<li><a href="https://www.reddit.com/r/emacs/comments/gjukb3/yadm_magit/">https://www.reddit.com/r/emacs/comments/gjukb3/yadm_magit/</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;tramp</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;tramp-methods</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#ba2121">&#34;yadm&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tramp-login-program</span> <span style="color:#ba2121">&#34;yadm&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tramp-login-args</span> ((<span style="color:#ba2121">&#34;enter&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tramp-login-env</span> ((<span style="color:#ba2121">&#34;SHELL&#34;</span>) <span style="color:#ba2121">&#34;/bin/sh&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tramp-remote-shell</span> <span style="color:#ba2121">&#34;/bin/sh&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tramp-remote-shell-args</span> (<span style="color:#ba2121">&#34;-c&#34;</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/yadm-magit</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">magit-status</span> <span style="color:#ba2121">&#34;/yadm::&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;cm&#34;</span> <span style="color:#19177c">&#39;my/yadm-magit</span>)
</span></span></code></pre></div><h4 id="open-a-dotfile">Open a dotfile</h4>
<p>Open a file managed by yadm.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/open-yadm-file</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Open a file managed by yadm&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">find-file</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-name-as-directory</span> (<span style="color:#19177c">getenv</span> <span style="color:#ba2121">&#34;HOME&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">completing-read</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;yadm files: &#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">split-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shell-command-to-string</span> <span style="color:#ba2121">&#34;yadm ls-files $HOME --full-name&#34;</span>) <span style="color:#ba2121">&#34;\n&#34;</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c f&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">my/open-yadm-file</span> <span style="color:#008000">:wk</span> <span style="color:#ba2121">&#34;yadm file&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;cf&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">my/open-yadm-file</span> <span style="color:#008000">:wk</span> <span style="color:#ba2121">&#34;yadm file&#34;</span>))
</span></span></code></pre></div><h3 id="elfeed">Elfeed</h3>
<p><a href="https://github.com/skeeto/elfeed">elfeed</a> is one of the most popular Emacs packages, and it&rsquo;s also one in which I ended up investing a lot of effort.</p>
<p>There&rsquo;s a lot of stuff in this section, so it&rsquo;s here and not in &ldquo;Internet and Multimedia&rdquo;.</p>
<h4 id="general-settings-5">General settings</h4>
<p>The advice there sets <code>shr-use-fonts</code> to nil while rendering HTML, so the <code>elfeed-show</code> buffer will use monospace font.</p>
<p>Using my own fork until the modifications are merged into master.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">elfeed</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;SqrtMinusOne/elfeed&#34;</span> <span style="color:#008000">:host</span> <span style="color:#19177c">github</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/is-termux</span> <span style="color:#19177c">my/remote-server</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">elfeed</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ae&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">elfeed-summary</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/persp-add-rule</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">elfeed-summary-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">&#34;elfeed&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">elfeed-search-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">&#34;elfeed&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">elfeed-show-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">&#34;elfeed&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">shr-max-image-proportion</span> <span style="color:#666">0.5</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">elfeed-db-directory</span> <span style="color:#ba2121">&#34;~/.elfeed&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">elfeed-enclosure-default-dir</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">&#34;~/Downloads&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (advice-add #&#39;elfeed-insert-html</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; :around</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (lambda (fun &amp;rest r)</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (let ((shr-use-fonts nil))</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (apply fun r))))</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;elfeed-search-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/elfeed-search-filter-source</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">elfeed-search-clear-filter</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gl&#34;</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">elfeed-search-set-filter</span> <span style="color:#ba2121">&#34;+later&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;elfeed-show-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;ge&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/elfeed-show-visit-eww</span>))
</span></span></code></pre></div><p><a href="https://github.com/remyhonig/elfeed-org">elfeed-org</a> allows configuring Elfeed feeds with an Org file.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">elfeed-org</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">elfeed</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">rmh-elfeed-org-files</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;~/.emacs.d/private.org&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-org</span>))
</span></span></code></pre></div><h4 id="some-additions">Some additions</h4>
<p>Filter elfeed search buffer by the feed under the cursor.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/elfeed-search-filter-source</span> (<span style="color:#19177c">entry</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Filter elfeed search buffer by the feed under cursor.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> (<span style="color:#19177c">elfeed-search-selected</span> <span style="color:#008000">:ignore-region</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">elfeed-entry-p</span> <span style="color:#19177c">entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-search-set-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;@6-months-ago &#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;+unread &#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;=&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp-in-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;?&#34;</span> (<span style="color:#00f">*</span> <span style="color:#19177c">not-newline</span>) <span style="color:#19177c">eos</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-feed-url</span> (<span style="color:#19177c">elfeed-entry-feed</span> <span style="color:#19177c">entry</span>)))))))
</span></span></code></pre></div><p>Open a URL with eww.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/elfeed-show-visit-eww</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Visit the current entry in eww&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">link</span> (<span style="color:#19177c">elfeed-entry-link</span> <span style="color:#19177c">elfeed-show-entry</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">link</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">eww</span> <span style="color:#19177c">link</span>))))
</span></span></code></pre></div><h4 id="custom-faces">Custom faces</h4>
<p>Setting up custom faces for certain tags to make the feed look a bit nicer.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defface</span> <span style="color:#19177c">elfeed-videos-entry</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Face for the elfeed entries with tag \&#34;videos\&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defface</span> <span style="color:#19177c">elfeed-twitter-entry</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Face for the elfeed entries with tah \&#34;twitter\&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defface</span> <span style="color:#19177c">elfeed-emacs-entry</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Face for the elfeed entries with tah \&#34;emacs\&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defface</span> <span style="color:#19177c">elfeed-music-entry</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Face for the elfeed entries with tah \&#34;music\&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defface</span> <span style="color:#19177c">elfeed-podcasts-entry</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Face for the elfeed entries with tag \&#34;podcasts\&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defface</span> <span style="color:#19177c">elfeed-blogs-entry</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Face for the elfeed entries with tag \&#34;blogs\&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defface</span> <span style="color:#19177c">elfeed-govt-entry</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Face for the elfeed entries with tag \&#34;blogs\&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my/use-colors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-search-tag-face</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;yellow</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-videos-entry</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;red</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-twitter-entry</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;blue</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-emacs-entry</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;magenta</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-music-entry</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;green</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-podcasts-entry</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;yellow</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-blogs-entry</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;orange</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-govt-entry</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;dark-cyan</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;elfeed</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">elfeed-search-face-alist</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">podcasts</span> <span style="color:#19177c">elfeed-podcasts-entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">music</span> <span style="color:#19177c">elfeed-music-entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">gov</span> <span style="color:#19177c">elfeed-govt-entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">twitter</span> <span style="color:#19177c">elfeed-twitter-entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">videos</span> <span style="color:#19177c">elfeed-videos-entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">emacs</span> <span style="color:#19177c">elfeed-emacs-entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">blogs</span> <span style="color:#19177c">elfeed-blogs-entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">unread</span> <span style="color:#19177c">elfeed-search-unread-title-face</span>))))
</span></span></code></pre></div><h4 id="elfeed-summary">elfeed-summary</h4>
<p><a href="https://github.com/SqrtMinusOne/elfeed-summary">elfeed-summary</a> is my package that provides a feed summary interface for elfeed.</p>
<p>The default interface of elfeed is just a list of all entries, so it gets hard to navigate when there are a lot of sources with varying frequencies of posts. This is my attempt to address this issue.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">elfeed-summary</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">elfeed-summary</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">elfeed-summary-filter-by-title</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">elfeed-summary-skip-sync-tag</span> <span style="color:#19177c">&#39;skip</span>))
</span></span></code></pre></div><h4 id="elfeed-sync">elfeed-sync</h4>
<p><a href="https://github.com/SqrtMinusOne/elfeed-sync">elfeed-sync</a> is my package to sync elfeed with <a href="https://tt-rss.org/">tt-rss</a>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">elfeed-sync</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;SqrtMinusOne/elfeed-sync&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">elfeed</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-sync-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">elfeed-sync-tt-rss-instance</span> <span style="color:#ba2121">&#34;https://sqrtminusone.xyz/tt-rss&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">elfeed-sync-tt-rss-login</span> <span style="color:#ba2121">&#34;sqrtminusone&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">elfeed-sync-tt-rss-password</span> (<span style="color:#19177c">my/password-store-get</span> <span style="color:#ba2121">&#34;Selfhosted/tt-rss&#34;</span>)))
</span></span></code></pre></div><h4 id="youtube-podcasts-and-emms">YouTube, podcasts &amp; EMMS</h4>
<p>Previously this block was opening MPV with <code>start-process</code>, but now I&rsquo;ve managed to hook up MPV with EMMS. So there is the EMMS+elfeed &ldquo;integration&rdquo;.</p>
<p>There are multiple kinds of entries that I want to be opened by EMMS. First, a function that returns a YouTube URL:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/get-youtube-url</span> (<span style="color:#19177c">entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">watch-id</span> (<span style="color:#19177c">cadr</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">assoc</span> <span style="color:#ba2121">&#34;watch?v&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url-parse-query-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url-filename</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url-generic-parse-url</span> (<span style="color:#19177c">elfeed-entry-link</span> <span style="color:#19177c">entry</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#666">1</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">watch-id</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;https://www.youtube.com/watch?v=&#34;</span> <span style="color:#19177c">watch-id</span>))))
</span></span></code></pre></div><p>Second, a function that returns a URL to an enclosure. This is generally how podcasts are distributed.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/get-enclosures-url</span> (<span style="color:#19177c">entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">caar</span> (<span style="color:#19177c">elfeed-entry-enclosures</span> <span style="color:#19177c">entry</span>)))
</span></span></code></pre></div><p>And a package called <a href="https://github.com/karthink/elfeed-tube">elfeed-tube</a> to fetch some additional data from YouTUbe.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">elfeed-tube</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">elfeed</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">elfeed-tube-auto-fetch-p</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-tube-setup</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#19177c">&#39;normal</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">elfeed-search-mode-map</span> <span style="color:#19177c">elfeed-show-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gf&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">elfeed-tube-fetch</span>))
</span></span></code></pre></div><p>Now, a function to add a YouTube link with metadata from elfeed to EMMS.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;emms</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">define-emms-source</span> <span style="color:#19177c">elfeed</span> (<span style="color:#19177c">entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">url</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">my/get-enclosures-url</span> <span style="color:#19177c">entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/get-youtube-url</span> <span style="color:#19177c">entry</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">url</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">error</span> <span style="color:#ba2121">&#34;URL not found&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">track</span> (<span style="color:#19177c">emms-track</span> <span style="color:#19177c">&#39;url</span> <span style="color:#19177c">url</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">emms-track-set</span> <span style="color:#19177c">track</span> <span style="color:#19177c">&#39;info-title</span> (<span style="color:#19177c">elfeed-entry-title</span> <span style="color:#19177c">entry</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">emms-playlist-insert-track</span> <span style="color:#19177c">track</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/elfeed-add-emms</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">emms-add-elfeed</span> <span style="color:#19177c">elfeed-show-entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-tag</span> <span style="color:#19177c">elfeed-show-entry</span> <span style="color:#19177c">&#39;watched</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-show-refresh</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;elfeed</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;elfeed-show-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gm&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/elfeed-add-emms</span>))
</span></span></code></pre></div><h4 id="rdrview">rdrview</h4>
<p><a href="https://github.com/eafer/rdrview">rdrview</a> is a command-line tool to strip webpages from clutter, extracting only parts related to the actual content. It&rsquo;s a standalone port of the corresponding feature of Firefox, called <a href="https://support.mozilla.org/en-US/kb/firefox-reader-view-clutter-free-web-pages">Reader View</a>.</p>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>rdrview</td>
</tr>
</tbody>
</table>
<p>It seems like the tool <a href="https://repology.org/project/rdrview/versions">isn&rsquo;t available</a> in a whole lot of package repositories, but it&rsquo;s pretty easy to compile. I&rsquo;ve put together a <a href="https://github.com/SqrtMinusOne/channel-q/blob/master/rdrview.scm">Guix definition</a>, which <em>one day</em> I&rsquo;ll submit to the upstream.</p>
<h5 id="integrating-rdrview-with-emacs">Integrating rdrview with Emacs</h5>
<p>Let&rsquo;s start by integrating <code>rdrview</code> with Emacs. In the general case, we want to fetch both metadata and the actual content from the page.</p>
<p>However, the interface of <code>rdrview</code> is a bit awkward in this part, so we have the following options:</p>
<ul>
<li>call <code>rdrview</code> two times: with <code>-M</code> flag to fetch the metadata, and without the flag to fetch the HTML;</li>
<li>call <code>rdrview</code> with <code>-T</code> flag to append the metadata to the resulting HTML.</li>
</ul>
<p>I&rsquo;ve decided to go with the second option. Here is a function that calls rdrview with the required flags:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/rdrview-get</span> (<span style="color:#19177c">url</span> <span style="color:#19177c">callback</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get the rdrview representation of URL.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Call CALLBACK with the output.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">buffer</span> (<span style="color:#19177c">generate-new-buffer</span> <span style="color:#ba2121">&#34;rdrview&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">proc</span> (<span style="color:#00f">start-process</span> <span style="color:#ba2121">&#34;rdrview&#34;</span> <span style="color:#19177c">buffer</span> <span style="color:#ba2121">&#34;rdrview&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">url</span> <span style="color:#ba2121">&#34;-T&#34;</span> <span style="color:#ba2121">&#34;title,sitename,body&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;-H&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-process-sentinel</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">proc</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">process</span> <span style="color:#19177c">_msg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">status</span> (<span style="color:#00f">process-status</span> <span style="color:#19177c">process</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">code</span> (<span style="color:#00f">process-exit-status</span> <span style="color:#19177c">process</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span> ((<span style="color:#008000">and</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">status</span> <span style="color:#19177c">&#39;exit</span>) (<span style="color:#00f">=</span> <span style="color:#19177c">code</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">callback</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> (<span style="color:#00f">process-buffer</span> <span style="color:#19177c">process</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-string</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">kill-buffer</span> (<span style="color:#00f">process-buffer</span> <span style="color:#19177c">process</span>))) )
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">or</span> (<span style="color:#008000">and</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">status</span> <span style="color:#19177c">&#39;exit</span>) (<span style="color:#00f">&gt;</span> <span style="color:#19177c">code</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">eq</span> <span style="color:#19177c">status</span> <span style="color:#19177c">&#39;signal</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">err</span> (<span style="color:#008000">with-current-buffer</span> (<span style="color:#00f">process-buffer</span> <span style="color:#19177c">process</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-string</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">kill-buffer</span> (<span style="color:#00f">process-buffer</span> <span style="color:#19177c">process</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Error in rdrview: %s&#34;</span> <span style="color:#19177c">err</span>)))))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">proc</span>))
</span></span></code></pre></div><p>The function calls <code>callback</code> with the output of <code>rdrview</code>. This usually doesn&rsquo;t take long, but it&rsquo;s still nice to avoid freezing Emacs that way.</p>
<p>Now we have to parse the output. The <code>-T</code> flag puts the title in the <code>&lt;h1&gt;</code> tag, the site name site in the <code>&lt;h2&gt;</code> tag, and the content in a <code>&lt;div&gt;</code>. What&rsquo;s more, headers of the content are often shifted, e.g. the top-level header may well end up being and <code>&lt;h2&gt;</code> or <code>&lt;h3&gt;</code>, which does not look great in LaTeX.</p>
<p>With that said, here&rsquo;s a function that does the required changes:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/rdrview-parse</span> (<span style="color:#19177c">dom-string</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">dom</span> (<span style="color:#008000">with-temp-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#19177c">dom-string</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">libxml-parse-html-region</span> (<span style="color:#00f">point-min</span>) (<span style="color:#00f">point-max</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> (<span style="color:#19177c">title</span> <span style="color:#19177c">sitename</span> <span style="color:#19177c">content</span> (<span style="color:#19177c">i</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">child</span> (<span style="color:#19177c">dom-children</span> (<span style="color:#00f">car</span> (<span style="color:#19177c">dom-by-id</span> <span style="color:#19177c">dom</span> <span style="color:#ba2121">&#34;readability-page-1&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">listp</span> <span style="color:#19177c">child</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">eq</span> (<span style="color:#00f">car</span> <span style="color:#19177c">child</span>) <span style="color:#19177c">&#39;h1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">title</span> (<span style="color:#19177c">dom-text</span> <span style="color:#19177c">child</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">eq</span> (<span style="color:#00f">car</span> <span style="color:#19177c">child</span>) <span style="color:#19177c">&#39;h2</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">sitename</span> (<span style="color:#19177c">dom-text</span> <span style="color:#19177c">child</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">eq</span> (<span style="color:#00f">car</span> <span style="color:#19177c">child</span>) <span style="color:#19177c">&#39;div</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">content</span> <span style="color:#19177c">child</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">while</span> (<span style="color:#008000">and</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">dom-by-tag</span> <span style="color:#19177c">content</span> <span style="color:#19177c">&#39;h1</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dom-search</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">content</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">el</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">listp</span> <span style="color:#19177c">el</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> (<span style="color:#00f">car</span> <span style="color:#19177c">el</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;h2</span> (<span style="color:#008000">setf</span> (<span style="color:#00f">car</span> <span style="color:#19177c">el</span>) <span style="color:#19177c">&#39;h1</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;h3</span> (<span style="color:#008000">setf</span> (<span style="color:#00f">car</span> <span style="color:#19177c">el</span>) <span style="color:#19177c">&#39;h2</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;h4</span> (<span style="color:#008000">setf</span> (<span style="color:#00f">car</span> <span style="color:#19177c">el</span>) <span style="color:#19177c">&#39;h3</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;h5</span> (<span style="color:#008000">setf</span> (<span style="color:#00f">car</span> <span style="color:#19177c">el</span>) <span style="color:#19177c">&#39;h4</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">&#39;h6</span> (<span style="color:#008000">setf</span> (<span style="color:#00f">car</span> <span style="color:#19177c">el</span>) <span style="color:#19177c">&#39;h5</span>))))))))
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#19177c">title</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">title</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">sitename</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">sitename</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">content</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#008000">with-temp-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dom-print</span> <span style="color:#19177c">content</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-string</span>)))))))
</span></span></code></pre></div><h5 id="using-rdrview-from-elfeed">Using rdrview from elfeed</h5>
<p>Because I didn&rsquo;t find a smart way to advise the desired behavior into elfeed, here&rsquo;s a modification of the <code>elfeed-show-refresh--mail-style</code> function with two changes:</p>
<ul>
<li>it uses <code>rdrview</code> to fetch the HTML;</li>
<li>it saves the resulting HTML into a buffer-local variable (we&rsquo;ll need that later).</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar-local</span> <span style="color:#19177c">my/elfeed-show-rdrview-html</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/rdrview-elfeed-show</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">elfeed-show-entry</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No elfeed entry in this buffer!&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/rdrview-get</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-entry-link</span> <span style="color:#19177c">elfeed-show-entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">result</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">data</span> (<span style="color:#19177c">my/rdrview-parse</span> <span style="color:#19177c">result</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">inhibit-read-only</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">title</span> (<span style="color:#19177c">elfeed-entry-title</span> <span style="color:#19177c">elfeed-show-entry</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">date</span> (<span style="color:#19177c">seconds-to-time</span> (<span style="color:#19177c">elfeed-entry-date</span> <span style="color:#19177c">elfeed-show-entry</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">authors</span> (<span style="color:#19177c">elfeed-meta</span> <span style="color:#19177c">elfeed-show-entry</span> <span style="color:#008000">:authors</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">link</span> (<span style="color:#19177c">elfeed-entry-link</span> <span style="color:#19177c">elfeed-show-entry</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tags</span> (<span style="color:#19177c">elfeed-entry-tags</span> <span style="color:#19177c">elfeed-show-entry</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tagsstr</span> (<span style="color:#00f">mapconcat</span> <span style="color:#00f">#&#39;symbol-name</span> <span style="color:#19177c">tags</span> <span style="color:#ba2121">&#34;, &#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">nicedate</span> (<span style="color:#00f">format-time-string</span> <span style="color:#ba2121">&#34;%a, %e %b %Y %T %Z&#34;</span> <span style="color:#19177c">date</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">content</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;content</span> <span style="color:#19177c">data</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">feed</span> (<span style="color:#19177c">elfeed-entry-feed</span> <span style="color:#19177c">elfeed-show-entry</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">feed-title</span> (<span style="color:#19177c">elfeed-feed-title</span> <span style="color:#19177c">feed</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">base</span> (<span style="color:#008000">and</span> <span style="color:#19177c">feed</span> (<span style="color:#19177c">elfeed-compute-base</span> (<span style="color:#19177c">elfeed-feed-url</span> <span style="color:#19177c">feed</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">erase-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">format</span> (<span style="color:#00f">propertize</span> <span style="color:#ba2121">&#34;Title: %s\n&#34;</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;message-header-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">propertize</span> <span style="color:#19177c">title</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;message-header-subject</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">elfeed-show-entry-author</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">author</span> <span style="color:#19177c">authors</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">formatted</span> (<span style="color:#19177c">elfeed--show-format-author</span> <span style="color:#19177c">author</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> (<span style="color:#00f">propertize</span> <span style="color:#ba2121">&#34;Author: %s\n&#34;</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;message-header-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">propertize</span> <span style="color:#19177c">formatted</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;message-header-to</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">format</span> (<span style="color:#00f">propertize</span> <span style="color:#ba2121">&#34;Date: %s\n&#34;</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;message-header-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">propertize</span> <span style="color:#19177c">nicedate</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;message-header-other</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">format</span> (<span style="color:#00f">propertize</span> <span style="color:#ba2121">&#34;Feed: %s\n&#34;</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;message-header-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">propertize</span> <span style="color:#19177c">feed-title</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;message-header-other</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">tags</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">format</span> (<span style="color:#00f">propertize</span> <span style="color:#ba2121">&#34;Tags: %s\n&#34;</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;message-header-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">propertize</span> <span style="color:#19177c">tagsstr</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;message-header-other</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">propertize</span> <span style="color:#ba2121">&#34;Link: &#34;</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;message-header-name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-insert-link</span> <span style="color:#19177c">link</span> <span style="color:#19177c">link</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;\n&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">enclosure</span> <span style="color:#19177c">in</span> (<span style="color:#19177c">elfeed-entry-enclosures</span> <span style="color:#19177c">elfeed-show-entry</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">insert</span> (<span style="color:#00f">propertize</span> <span style="color:#ba2121">&#34;Enclosure: &#34;</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;message-header-name</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#19177c">elfeed-insert-link</span> (<span style="color:#00f">car</span> <span style="color:#19177c">enclosure</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;\n&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;\n&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">content</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-insert-html</span> <span style="color:#19177c">content</span> <span style="color:#19177c">base</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">propertize</span> <span style="color:#ba2121">&#34;(empty)\n&#34;</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;italic</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">my/elfeed-show-rdrview-html</span> <span style="color:#19177c">content</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-min</span>))))))
</span></span></code></pre></div><p>That way, calling <code>M-x my/rdrview-elfeed-show</code> replaces the original content with one from <code>rdrview</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;elfeed</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;elfeed-show-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gp&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/rdrview-elfeed-show</span>))
</span></span></code></pre></div><h5 id="how-well-does-it-work">How well does it work?</h5>
<p>Rather ironically, it works well with sites that already ship with proper RSS, like <a href="https://protesilaos.com/">Protesilaos Stavrou&rsquo;s</a> or <a href="https://karthinks.com/software/simple-folding-with-hideshow/">Karthik Chikmagalur&rsquo;s</a> blogs or <a href="https://www.theatlantic.com/world/">The Atlantic</a> magazine.</p>
<p>Of my other subscriptions, it does a pretty good job with <a href="https://www.theverge.com/">The Verge</a>, which by default sends entries truncated by the words &ldquo;Read the full article&rdquo;. For <a href="https://arstechnica.com/">Ars Technica</a>, it works only if the story is not large enough, otherwise the site returns its HTML-based pagination interface.</p>
<p>For paywalled sites such as <a href="https://www.nytimes.com/">New York Times</a> or <a href="https://www.economist.com/">The Economist</a>, this usually doesn&rsquo;t work (by the way, what&rsquo;s the problem with providing individual RSS feeds for subscribers?). If you need this kind of thing, I&rsquo;d suggest using the <a href="https://github.com/RSS-Bridge/rss-bridge">RSS-Bridge</a> project. And if something is not available, contributing business logic there definitely makes more sense than implementing workarounds in Emacs Lisp.</p>
<h4 id="latex-and-pandoc">LaTeX and pandoc</h4>
<p>However, I also find that I&rsquo;m not really a fan of reading articles from Emacs. Somehow what works for program code doesn&rsquo;t work that well for natural text. When I have to, I usually switch the Emacs theme to a light one.</p>
<p>But the best solution I&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.</p>
<h5 id="template">Template</h5>
<p>So first, we need a LaTeX template. Pandoc already ships with one, but I don&rsquo;t like it too much, so I&rsquo;ve put up a template from my LaTeX styles, targeting my preferred XeLaTeX engine.</p>
<p>The code for the template is available <a href=".emacs.d/rdrview.tex">dotfiles repo</a>. If you use LaTeX, you&rsquo;ll probably be better off using your own setup. Be sure to define the following variables:</p>
<ul>
<li><code>main-lang</code> and <code>other-lang</code> for polyglossia (or remove them if you have only one language)</li>
<li><code>title</code></li>
<li><code>subtitle</code></li>
<li><code>author</code></li>
<li><code>date</code></li>
</ul>
<h5 id="invoking-pandoc">Invoking pandoc</h5>
<p>Now that we have the template, let&rsquo;s save it somewhere and store the path to a variable:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/rdrview-template</span> (<span style="color:#00f">expand-file-name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">user-emacs-directory</span> <span style="color:#ba2121">&#34;rdrview.tex&#34;</span>)))
</span></span></code></pre></div><p>And let&rsquo;s invoke pandoc. We need to pass the following flags:</p>
<ul>
<li><code>--pdf-engine=xelatex</code>, of course</li>
<li><code>--template &lt;path-to-template&gt;</code>;</li>
<li><code>-o &lt;path-to-pdf&gt;</code>;</li>
<li><code>--variable key=value</code>.</li>
</ul>
<p>In fact, pandoc is a pretty awesome tool in the sense that it allows for feeding custom variables to rich-language templates.</p>
<p>So, the rendering function is as follows:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">cl-defun</span> <span style="color:#19177c">my/rdrview-render</span> (<span style="color:#19177c">content</span> <span style="color:#19177c">type</span> <span style="color:#19177c">variables</span> <span style="color:#19177c">callback</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">&amp;key</span> <span style="color:#19177c">file-name</span> <span style="color:#19177c">overwrite</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Render CONTENT with pandoc.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">TYPE is a file extension as supported by pandoc, for instance,
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">html or txt. VARIABLES is an alist that is fed into the
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">template. After the rendering is complete successfully, CALLBACK
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">is called with the resulting PDF.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">FILE-NAME is a path to the resulting PDF. If nil it&#39;s generated
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">randomly.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">If a file with the given FILE-NAME already exists, the function will
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">invoke CALLBACK straight away without doing the rendering, unless
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">OVERWRITE is non-nil.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">file-name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">file-name</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;/tmp/%d.pdf&#34;</span> (<span style="color:#00f">random</span> <span style="color:#666">100000000</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> (<span style="color:#19177c">params</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">temp-file-name</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;/tmp/%d.%s&#34;</span> (<span style="color:#00f">random</span> <span style="color:#666">100000000</span>) <span style="color:#19177c">type</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> (<span style="color:#19177c">key</span> <span style="color:#666">.</span> <span style="color:#19177c">value</span>) <span style="color:#19177c">in</span> <span style="color:#19177c">variables</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">when</span> <span style="color:#19177c">value</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#ba2121">&#34;--variable&#34;</span> <span style="color:#19177c">params</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%s=%s&#34;</span> <span style="color:#19177c">key</span> <span style="color:#19177c">value</span>) <span style="color:#19177c">params</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">params</span> (<span style="color:#00f">nreverse</span> <span style="color:#19177c">params</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">and</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">file-name</span>) (<span style="color:#19177c">not</span> <span style="color:#19177c">overwrite</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">callback</span> <span style="color:#19177c">file-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-file</span> <span style="color:#19177c">temp-file-name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#19177c">content</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">proc</span> (<span style="color:#00f">apply</span> <span style="color:#00f">#&#39;start-process</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;pandoc&#34;</span> (<span style="color:#00f">get-buffer-create</span> <span style="color:#ba2121">&#34;*Pandoc*&#34;</span>) <span style="color:#ba2121">&#34;pandoc&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">temp-file-name</span> <span style="color:#ba2121">&#34;-o&#34;</span> <span style="color:#19177c">file-name</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;--pdf-engine=xelatex&#34;</span> <span style="color:#ba2121">&#34;--template&#34;</span> <span style="color:#19177c">my/rdrview-template</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">params</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-process-sentinel</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">proc</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">process</span> <span style="color:#19177c">_msg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">status</span> (<span style="color:#00f">process-status</span> <span style="color:#19177c">process</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">code</span> (<span style="color:#00f">process-exit-status</span> <span style="color:#19177c">process</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span> ((<span style="color:#008000">and</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">status</span> <span style="color:#19177c">&#39;exit</span>) (<span style="color:#00f">=</span> <span style="color:#19177c">code</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Done!&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">callback</span> <span style="color:#19177c">file-name</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">or</span> (<span style="color:#008000">and</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">status</span> <span style="color:#19177c">&#39;exit</span>) (<span style="color:#00f">&gt;</span> <span style="color:#19177c">code</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">eq</span> <span style="color:#19177c">status</span> <span style="color:#19177c">&#39;signal</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Error in pandoc. Check the *Pandoc* buffer&#34;</span>))))))))))
</span></span></code></pre></div><h5 id="opening-elfeed-entries">Opening elfeed entries</h5>
<p>Now we have everything required to open elfeed entries.</p>
<p>Also, in my case elfeed entries come in two languages, so I have to set <code>main-lang</code> and <code>other-lang</code> variables accordingly. Here&rsquo;s the main function:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/elfeed-pdf-dir</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">&#34;~/.elfeed/pdf/&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/elfeed-open-pdf</span> (<span style="color:#19177c">entry</span> <span style="color:#19177c">overwrite</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Open the current elfeed ENTRY with a pdf viewer.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">If OVERWRITE is non-nil, do the rendering even if the resulting
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">PDF already exists.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> <span style="color:#19177c">elfeed-show-entry</span> <span style="color:#19177c">current-prefix-arg</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">authors</span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">m</span>) (<span style="color:#00f">plist-get</span> <span style="color:#19177c">m</span> <span style="color:#008000">:name</span>)) (<span style="color:#19177c">elfeed-meta</span> <span style="color:#19177c">entry</span> <span style="color:#008000">:authors</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">feed-title</span> (<span style="color:#19177c">elfeed-feed-title</span> (<span style="color:#19177c">elfeed-entry-feed</span> <span style="color:#19177c">entry</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tags</span> (<span style="color:#00f">mapconcat</span> <span style="color:#00f">#&#39;symbol-name</span> (<span style="color:#19177c">elfeed-entry-tags</span> <span style="color:#19177c">entry</span>) <span style="color:#ba2121">&#34;, &#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">date</span> (<span style="color:#00f">format-time-string</span> <span style="color:#ba2121">&#34;%a, %e %b %Y&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seconds-to-time</span> (<span style="color:#19177c">elfeed-entry-date</span> <span style="color:#19177c">entry</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">content</span> (<span style="color:#19177c">elfeed-deref</span> (<span style="color:#19177c">elfeed-entry-content</span> <span style="color:#19177c">entry</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">file-name</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">my/elfeed-pdf-dir</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-ref-id</span> (<span style="color:#19177c">elfeed-entry-content</span> <span style="color:#19177c">entry</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;.pdf&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">main-language</span> <span style="color:#ba2121">&#34;english&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">other-language</span> <span style="color:#ba2121">&#34;russian&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">content</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No content!&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">subtitle</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">seq-empty-p</span> <span style="color:#19177c">authors</span>) <span style="color:#19177c">feed-title</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">and</span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">seq-empty-p</span> (<span style="color:#00f">car</span> <span style="color:#19177c">authors</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> (<span style="color:#00f">regexp-quote</span> (<span style="color:#00f">car</span> <span style="color:#19177c">authors</span>)) <span style="color:#19177c">feed-title</span>)) <span style="color:#19177c">feed-title</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> (<span style="color:#00f">concat</span> (<span style="color:#19177c">string-join</span> <span style="color:#19177c">authors</span> <span style="color:#ba2121">&#34;, &#34;</span>) <span style="color:#ba2121">&#34;\\\\&#34;</span> <span style="color:#19177c">feed-title</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">member</span> <span style="color:#19177c">&#39;ru</span> (<span style="color:#19177c">elfeed-entry-tags</span> <span style="color:#19177c">entry</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">main-language</span> <span style="color:#ba2121">&#34;russian&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">other-language</span> <span style="color:#ba2121">&#34;english&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/rdrview-render</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">bound-and-true-p</span> <span style="color:#19177c">my/elfeed-show-rdrview-html</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/elfeed-show-rdrview-html</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">content</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-entry-content-type</span> <span style="color:#19177c">entry</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#19177c">title</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#19177c">elfeed-entry-title</span> <span style="color:#19177c">entry</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">subtitle</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">subtitle</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">date</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">date</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">tags</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">tags</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">main-lang</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">main-language</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">other-lang</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">other-language</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">start-process</span> <span style="color:#ba2121">&#34;xdg-open&#34;</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;xdg-open&#34;</span> <span style="color:#19177c">file-name</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:file-name</span> <span style="color:#19177c">file-name</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:overwrite</span> <span style="color:#19177c">current-prefix-arg</span>)))
</span></span></code></pre></div><p>If the <code>my/elfeed-show-rdrview-html</code> variable is bound and true, then the content in this buffer was retrieved via <code>rdrview</code>, so we&rsquo;ll use that instead of the output of <code>elfeed-deref</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;elfeed</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">elfeed-show-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gv&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/elfeed-open-pdf</span>))
</span></span></code></pre></div><p>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.</p>
<h5 id="opening-arbitrary-sites">Opening arbitrary sites</h5>
<p>As you may have noticed, we also can display arbitrary web pages with this setup, so let&rsquo;s go ahead and implement that:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/get-languages</span> (<span style="color:#19177c">url</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">main-lang</span> <span style="color:#ba2121">&#34;english&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">other-lang</span> <span style="color:#ba2121">&#34;russian&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;.ru&#34;</span>) <span style="color:#19177c">url</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">main-lang</span> <span style="color:#ba2121">&#34;russian&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">other-lang</span> <span style="color:#ba2121">&#34;english&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> <span style="color:#19177c">main-lang</span> <span style="color:#19177c">other-lang</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/rdrview-open</span> (<span style="color:#19177c">url</span> <span style="color:#19177c">overwrite</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">url</span> (<span style="color:#00f">read-from-minibuffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;URL: &#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">bound-and-true-p</span> <span style="color:#19177c">elfeed-show-entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-entry-link</span> <span style="color:#19177c">elfeed-show-entry</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">url</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;URL is empty&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> <span style="color:#19177c">url</span> <span style="color:#19177c">current-prefix-arg</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/rdrview-get</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">url</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">res</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">data</span> (<span style="color:#19177c">my/rdrview-parse</span> <span style="color:#19177c">res</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">langs</span> (<span style="color:#19177c">my/get-languages</span> <span style="color:#19177c">url</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/rdrview-render</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;content</span> <span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;html</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#19177c">title</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;title</span> <span style="color:#19177c">data</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">subtitle</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;sitename</span> <span style="color:#19177c">data</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">main-lang</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">langs</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">other-lang</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">langs</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">start-process</span> <span style="color:#ba2121">&#34;xdg-open&#34;</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;xdg-open&#34;</span> <span style="color:#19177c">file-name</span>)))))))
</span></span></code></pre></div><p>Unfortunately, this part doesn&rsquo;t work that well, so we can&rsquo;t just uninstall Firefox or Chromium and browse the web from a PDF viewer.</p>
<p>The most common problem I&rsquo;ve encountered is incorrectly formed pictures, such as <code>.png</code> files without the boundary info. I&rsquo;m sure you&rsquo;ve also come across this if you ever tried to insert a lot of Internet pictures into a LaTeX document.</p>
<p>However, sans the pictures issue, for certain sites like Wikipedia this is usable.</p>
<h4 id="youtube-transcripts">YouTube transcripts</h4>
<h5 id="getting-subtitles">Getting subtitles</h5>
<p>Finally, let&rsquo;s get to transcripts.</p>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>python-youtube-transcript-api</td>
</tr>
</tbody>
</table>
<p>In principle, the YouTube API allows for downloading subtitles, but I&rsquo;ve found <a href="https://github.com/jdepoix/youtube-transcript-api">this awesome Python script</a> which does the same. You can install it from <code>pip</code>, or here&rsquo;s mine <a href="https://github.com/SqrtMinusOne/channel-q/blob/master/youtube-transcript-api.scm">Guix definition</a> once again.</p>
<p>Much like the previous cases, we need to invoke the program and save the output. The <a href="https://en.wikipedia.org/wiki/WebVTT">WebVTT</a> format will work well enough for our purposes. Here comes the function:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">cl-defun</span> <span style="color:#19177c">my/youtube-subtitles-get</span> (<span style="color:#19177c">video-id</span> <span style="color:#19177c">callback</span> <span style="color:#008000">&amp;key</span> <span style="color:#19177c">file-name</span> <span style="color:#19177c">overwrite</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get subtitles for VIDEO-ID in WebVTT format.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Call CALLBACK when done.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">FILE-NAME is a path to the resulting WebVTT file. If nil it&#39;s
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">generated randomly.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">If a file with the given FILE-NAME already exists, the function will
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">invoke CALLBACK straight away without doing the rendering, unless
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">OVERWRITE is non-nil.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> (<span style="color:#00f">read-string</span> <span style="color:#ba2121">&#34;Video ID: &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">find-file</span> <span style="color:#19177c">file-name</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:file-name</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:overwrite</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">file-name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">file-name</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;/tmp/%d.vtt&#34;</span> (<span style="color:#00f">random</span> <span style="color:#666">100000000</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">and</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">file-name</span>) (<span style="color:#19177c">not</span> <span style="color:#19177c">overwrite</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">callback</span> <span style="color:#19177c">file-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">buffer</span> (<span style="color:#19177c">generate-new-buffer</span> <span style="color:#ba2121">&#34;youtube-transcripts&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">proc</span> (<span style="color:#00f">start-process</span> <span style="color:#ba2121">&#34;youtube_transcript_api&#34;</span> <span style="color:#19177c">buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;youtube_transcript_api&#34;</span> <span style="color:#19177c">video-id</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;--languages&#34;</span> <span style="color:#ba2121">&#34;en&#34;</span> <span style="color:#ba2121">&#34;ru&#34;</span> <span style="color:#ba2121">&#34;de&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;--format&#34;</span> <span style="color:#ba2121">&#34;webvtt&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-process-sentinel</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">proc</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">process</span> <span style="color:#19177c">_msg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">status</span> (<span style="color:#00f">process-status</span> <span style="color:#19177c">process</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">code</span> (<span style="color:#00f">process-exit-status</span> <span style="color:#19177c">process</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span> ((<span style="color:#008000">and</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">status</span> <span style="color:#19177c">&#39;exit</span>) (<span style="color:#00f">=</span> <span style="color:#19177c">code</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> (<span style="color:#00f">process-buffer</span> <span style="color:#19177c">process</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#00f">buffer-file-name</span> <span style="color:#19177c">file-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">save-buffer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">kill-buffer</span> (<span style="color:#00f">process-buffer</span> <span style="color:#19177c">process</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">callback</span> <span style="color:#19177c">file-name</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">or</span> (<span style="color:#008000">and</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">status</span> <span style="color:#19177c">&#39;exit</span>) (<span style="color:#00f">&gt;</span> <span style="color:#19177c">code</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">eq</span> <span style="color:#19177c">status</span> <span style="color:#19177c">&#39;signal</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">err</span> (<span style="color:#008000">with-current-buffer</span> (<span style="color:#00f">process-buffer</span> <span style="color:#19177c">process</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-string</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">kill-buffer</span> (<span style="color:#00f">process-buffer</span> <span style="color:#19177c">process</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Error in youtube_transcript_api: %s&#34;</span> <span style="color:#19177c">err</span>)))))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">proc</span>)))
</span></span></code></pre></div><h5 id="elfeed-and-subed">elfeed and subed</h5>
<p>Now that we have a standalone function, let&rsquo;s invoke it with the current <code>elfeed-show-entry</code>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/elfeed-srt-dir</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">&#34;~/.elfeed/srt/&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/elfeed-youtube-subtitles</span> (<span style="color:#19177c">entry</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get subtitles for the current elfeed ENTRY.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Works only in the entry is a YouTube video.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">If ARG is non-nil, re-fetch the subtitles regardless of whether
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">they were fetched before.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> <span style="color:#19177c">elfeed-show-entry</span> <span style="color:#19177c">current-prefix-arg</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">video-id</span> (<span style="color:#19177c">cadr</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">assoc</span> <span style="color:#ba2121">&#34;watch?v&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url-parse-query-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url-filename</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url-generic-parse-url</span> (<span style="color:#19177c">elfeed-entry-link</span> <span style="color:#19177c">entry</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#666">1</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">video-id</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Can&#39;t get video ID from the entry&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/youtube-subtitles-get</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">video-id</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> (<span style="color:#19177c">find-file-other-window</span> <span style="color:#19177c">file-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">elfeed-show-entry</span> <span style="color:#19177c">entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">goto-char</span> (<span style="color:#00f">point-min</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:file-name</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">my/elfeed-srt-dir</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-ref-id</span> (<span style="color:#19177c">elfeed-entry-content</span> <span style="color:#19177c">entry</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;.vtt&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:overwrite</span> <span style="color:#19177c">arg</span>)))
</span></span></code></pre></div><p>That opens up a <code>.vtt</code> buffer with the subtitles for the current video, which means now we can use the functionality of Sacha Chua&rsquo;s awesome package called <a href="https://github.com/sachac/subed">subed</a>.</p>
<p>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 <code>setq-local</code> in the previous function.</p>
<p>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 <code>emms-player-mpv-parameters</code> variable, the method of setting which I&rsquo;ve discussed above. The function is as follows:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/subed-elfeed</span> (<span style="color:#19177c">entry</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Open the video file from elfeed ENTRY in MPV.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">This has to be launched from inside the subtitles buffer, opened
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">by the </span><span style="color:#19177c">`my/elfeed-youtube-subtitles&#39;</span><span style="color:#ba2121"> function.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> <span style="color:#19177c">elfeed-show-entry</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">entry</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No entry!&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">derived-mode-p</span> <span style="color:#19177c">&#39;subed-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Not subed mode!&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">subed-mpv-arguments</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-uniq</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">append</span> <span style="color:#19177c">subed-mpv-arguments</span> <span style="color:#19177c">emms-player-mpv-parameters</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">subed-mpv-video-file</span> (<span style="color:#19177c">elfeed-entry-link</span> <span style="color:#19177c">entry</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">subed-mpv--play</span> <span style="color:#19177c">subed-mpv-video-file</span>))
</span></span></code></pre></div><p>Keep in mind that this function has to be launched inside the buffer opened by the <code>my/elfeed-youtube-subtitles</code> function.</p>
<h3 id="internet-and-multimedia">Internet &amp; Multimedia</h3>
<h4 id="notmuch">Notmuch</h4>
<p>My notmuch config now resides in <a href="/configs/mail/">Mail.org</a>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">unless</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">mail-file</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">&#34;mail.el&#34;</span> <span style="color:#19177c">user-emacs-directory</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">mail-file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">load-file</span> <span style="color:#19177c">mail-file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Can&#39;t load mail.el&#34;</span>))))
</span></span></code></pre></div><h4 id="gnus">Gnus</h4>
<p><a href="https://www.gnu.org/software/emacs/manual/html_node/gnus/index.html">Gnus</a> is an Emacs newsreader.</p>
<p>I&rsquo;ll try to use it for NTTP for now. Will see if I can do more with it.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">gnus</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;au&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">gnus</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">gnus</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/persp-add-rule</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">gnus-summary-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">&#34;gnus&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; gnus-article-edit-mode 0 &#34;gnus&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">gnus-browse-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">&#34;gnus&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">gnus-server-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">&#34;gnus&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">gnus-article-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">&#34;gnus&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">gnus-group-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">&#34;gnus&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">gnus-category-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">&#34;gnus&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">gnus-directory</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">user-emacs-directory</span> <span style="color:#ba2121">&#34;gnus&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">file-directory-p</span> <span style="color:#19177c">gnus-directory</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">make-directory</span> <span style="color:#19177c">gnus-directory</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-dribble-directory</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">gnus-directory</span> <span style="color:#ba2121">&#34;/dribble&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-init-file</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">gnus-directory</span> <span style="color:#ba2121">&#34;/gnus.el&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-startup-file</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">gnus-directory</span> <span style="color:#ba2121">&#34;/newsrc&#34;</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Sources</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-select-method</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">nntp</span> <span style="color:#ba2121">&#34;news.gwene.org&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Dribble</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-always-read-dribble-file</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Agent</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-agent-article-alist-save-format</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-agent-cache</span> <span style="color:#800">t</span>))
</span></span></code></pre></div><h5 id="groups">Groups</h5>
<p>Toggle current topic.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/gnus-topic-toggle-topic</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#19177c">gnus-topic-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">gnus-group-topic-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">topic</span> (<span style="color:#19177c">gnus-topic-find-topology</span> (<span style="color:#19177c">gnus-current-topic</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">eq</span> (<span style="color:#19177c">cadadr</span> <span style="color:#19177c">topic</span>) <span style="color:#19177c">&#39;visible</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">gnus-topic-goto-topic</span> (<span style="color:#19177c">gnus-current-topic</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">gnus-topic-remove-topic</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">gnus-topic-remove-topic</span> <span style="color:#800">t</span> <span style="color:#800">nil</span>)))))
</span></span></code></pre></div><p>Custom keybindings.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;gnus-group</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Group</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;gnus-group-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">gnus-topic-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">gnus-group-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;a&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">gnus-group-toggle-subscription-at-point</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">gnus-topic-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;TAB&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/gnus-topic-toggle-topic</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">gnus-topic-catchup-articles</span>))
</span></span></code></pre></div><h5 id="summary">Summary</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;gnus-summary</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-summary-line-format</span> <span style="color:#ba2121">&#34;%U%R%z%I%(%[%4L: %-23,23f%]%) %s\n&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-sum-thread-tree-false-root</span> <span style="color:#ba2121">&#34;&gt; &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-sum-thread-tree-indent</span> <span style="color:#ba2121">&#34; &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-sum-thread-tree-single-indent</span> <span style="color:#ba2121">&#34; &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-sum-thread-tree-leaf-with-other</span> <span style="color:#ba2121">&#34;+-&gt; &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-sum-thread-tree-root</span> <span style="color:#ba2121">&#34;&gt; &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-sum-thread-tree-single-leaf</span> <span style="color:#ba2121">&#34;\\-&gt; &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gnus-sum-thread-tree-vertical</span> <span style="color:#ba2121">&#34;| &#34;</span>))
</span></span></code></pre></div><h4 id="emms">EMMS</h4>
<p>EMMS is the Emacs Multi-Media System. I use it to control MPD &amp; MPV.</p>
<p>References:</p>
<ul>
<li><a href="https://www.gnu.org/software/emms/manual/">EMMS Manual</a></li>
<li><a href="https://www.youtube.com/watch?v=xTVN8UDScqk">Uncle Dave&rsquo;s video</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">emms</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/remote-server</span> <span style="color:#19177c">my/is-termux</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">emms-smart-browse</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">emms-browser</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">emms-add-url</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">emms-add-file</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">emms-add-find</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;as&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;emms&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;s&#34;</span> (<span style="color:#19177c">my/command-in-persp</span> <span style="color:#ba2121">&#34;EMMS&#34;</span> <span style="color:#ba2121">&#34;EMMS&#34;</span> <span style="color:#666">0</span> (<span style="color:#19177c">emms-smart-browse</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;b&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">emms-browser</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;p&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">emms-pause</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">emms-stop</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; &#34;h&#34; #&#39;emms-previous</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; &#34;l&#34; #&#39;emms-next</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;u&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">emms-player-mpd-connect</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;ww&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">emms-lyrics</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;wb&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">emms-lyrics-toggle-display-on-minibuffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;wm&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">emms-lyrics-toggle-display-on-modeline</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;k&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">emms-volume-raise</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;j&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">emms-volume-lower</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/persp-add-rule</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">emms-browser-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">&#34;EMMS&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">emms-playlist-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">&#34;EMMS&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">emms-mode-line-icon-enabled-p</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;emms-setup</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;emms-player-mpd</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;emms-player-mpv</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">emms-all</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; MPD setup</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&lt;&lt;emms-mpd-setup&gt;&gt;</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; MPV setup</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&lt;&lt;emms-mpv-setup&gt;&gt;</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; evil-lion and evil-commentary shadow some gX bindings</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (add-hook &#39;emms-browser-mode-hook</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (lambda ()</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (evil-lion-mode -1)</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (evil-commentary-mode -1)</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; ))</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; &lt;I&#39;ve just read the line below as &#34;I hate everything&#34;&gt;</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; I have everything I need in polybar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">emms-mode-line-mode</span> <span style="color:#666">-1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">emms-playing-time-display-mode</span> <span style="color:#666">-1</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&lt;&lt;emms-fixes&gt;&gt;</span>)
</span></span></code></pre></div><h5 id="mpd">MPD</h5>
<p><a href="https://www.musicpd.org/">mpd</a> is a server for playing music. It has a couple of first-class clients, including curses-based <a href="https://github.com/ncmpcpp/ncmpcpp">ncmpcpp</a>, but of course, I want to use Emacs.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">emms-source-file-default-directory</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">&#34;~/Music/&#34;</span>))
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;emms-info-functions</span> <span style="color:#19177c">&#39;emms-info-mpd</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;emms-player-list</span> <span style="color:#19177c">&#39;emms-player-mpd</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">emms-player-mpd-server-name</span> <span style="color:#ba2121">&#34;localhost&#34;</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">emms-player-mpd-server-port</span> <span style="color:#ba2121">&#34;6600&#34;</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">emms-player-mpd-music-directory</span> <span style="color:#ba2121">&#34;~/Music&#34;</span>)
</span></span></code></pre></div><p>Connect on setup. For some reason, it stops the mpd playback whenever it connects, but it is not a big issue.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">emms-player-mpd-connect</span>)
</span></span></code></pre></div><p>Clear MPD playlist on clearing EMMS playlist. IDK if this is fine for MPD library playlist, I don&rsquo;t use them anyhow.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;emms-playlist-cleared-hook</span> <span style="color:#19177c">&#39;emms-player-mpd-clear</span>)
</span></span></code></pre></div><p>Set a custom regex for MPD. EMMS sets up the default one from MPD&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 I want to use MPV as well, I override the regex.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">emms-player-set</span> <span style="color:#19177c">emms-player-mpd</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;regex</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span> (<span style="color:#008000">or</span> (<span style="color:#666">:</span> <span style="color:#ba2121">&#34;https://&#34;</span> (<span style="color:#00f">*</span> <span style="color:#19177c">nonl</span>) (<span style="color:#008000">or</span> <span style="color:#ba2121">&#34;acast.com&#34;</span>) (<span style="color:#00f">*</span> <span style="color:#19177c">nonl</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">+</span> (<span style="color:#ba2121">? </span>(<span style="color:#008000">or</span> <span style="color:#ba2121">&#34;https://&#34;</span> <span style="color:#ba2121">&#34;http://&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">*</span> <span style="color:#19177c">nonl</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">regexp</span> (<span style="color:#00f">eval</span> (<span style="color:#19177c">emms-player-simple-regexp</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;m3u&#34;</span> <span style="color:#ba2121">&#34;ogg&#34;</span> <span style="color:#ba2121">&#34;flac&#34;</span> <span style="color:#ba2121">&#34;mp3&#34;</span> <span style="color:#ba2121">&#34;wav&#34;</span> <span style="color:#ba2121">&#34;mod&#34;</span> <span style="color:#ba2121">&#34;au&#34;</span> <span style="color:#ba2121">&#34;aiff&#34;</span> <span style="color:#ba2121">&#34;m4a&#34;</span>)))))))
</span></span></code></pre></div><p>After all this is done, run <code>M-x emms-cache-set-from-mpd-all</code> to set cache from MPD. If everything is correct, EMMS browser will be populated with MPD database.</p>
<h5 id="mpv">MPV</h5>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>mpv</td>
</tr>
<tr>
<td>yt-dlp</td>
</tr>
</tbody>
</table>
<p><a href="https://mpv.io/">mpv</a> is a decent media player, which has found a place in this configuration because it integrates with <del>youtube-dl</del> yt-dlp.</p>
<p>It looks like YouTube has started to throttle youtube-dl, and yt-dlp has a workaround for that particular case. Just don&rsquo;t forget to add the following like to the mpv config:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-ini" data-lang="ini"><span style="display:flex;"><span><span style="color:#7d9029">script-opts</span><span style="color:#666">=</span><span style="color:#ba2121">ytdl_hook-ytdl_path=yt-dlp</span>
</span></span></code></pre></div><p>It seems a bit strange to keep the MPV config in this file, but I don&rsquo;t use the program outside Emacs.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;emms-player-list</span> <span style="color:#19177c">&#39;emms-player-mpv</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><p>Also a custom regex. My demands for MPV include running <code>yt-dlp</code>, so there is a regex that matches youtube.com or some of the video formats.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">emms-player-set</span> <span style="color:#19177c">emms-player-mpv</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;regex</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span> (<span style="color:#008000">or</span> (<span style="color:#666">:</span> <span style="color:#ba2121">&#34;https://&#34;</span> (<span style="color:#00f">*</span> <span style="color:#19177c">nonl</span>) <span style="color:#ba2121">&#34;youtube.com&#34;</span> (<span style="color:#00f">*</span> <span style="color:#19177c">nonl</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">+</span> (<span style="color:#ba2121">? </span>(<span style="color:#008000">or</span> <span style="color:#ba2121">&#34;https://&#34;</span> <span style="color:#ba2121">&#34;http://&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">*</span> <span style="color:#19177c">nonl</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">regexp</span> (<span style="color:#00f">eval</span> (<span style="color:#19177c">emms-player-simple-regexp</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;mp4&#34;</span> <span style="color:#ba2121">&#34;mov&#34;</span> <span style="color:#ba2121">&#34;wmv&#34;</span> <span style="color:#ba2121">&#34;webm&#34;</span> <span style="color:#ba2121">&#34;flv&#34;</span> <span style="color:#ba2121">&#34;avi&#34;</span> <span style="color:#ba2121">&#34;mkv&#34;</span>)))))))
</span></span></code></pre></div><p>By default, MPV plays the video in the best possible quality, which may be pretty high, even too high with limited bandwidth. So here is the logic to choose the quality.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/youtube-dl-quality-list</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;bestvideo[height&lt;=720]+bestaudio/best[height&lt;=720]&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;bestvideo[height&lt;=480]+bestaudio/best[height&lt;=480]&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;bestvideo[height&lt;=1080]+bestaudio/best[height&lt;=1080]&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/default-emms-player-mpv-parameters</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;--quiet&#34;</span> <span style="color:#ba2121">&#34;--really-quiet&#34;</span> <span style="color:#ba2121">&#34;--no-audio-display&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/set-emms-mpd-youtube-quality</span> (<span style="color:#19177c">quality</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#ba2121">&#34;P&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">quality</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">quality</span> (<span style="color:#00f">completing-read</span> <span style="color:#ba2121">&#34;Quality: &#34;</span> <span style="color:#19177c">my/youtube-dl-quality-list</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">emms-player-mpv-parameters</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,@</span><span style="color:#19177c">my/default-emms-player-mpv-parameters</span> <span style="color:#666">,</span>(<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;--ytdl-format=%s&#34;</span> <span style="color:#19177c">quality</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my/set-emms-mpd-youtube-quality</span> (<span style="color:#00f">car</span> <span style="color:#19177c">my/youtube-dl-quality-list</span>))
</span></span></code></pre></div><p>Now <code>emms-add-url</code> 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.</p>
<h5 id="cache-cleanup">Cache cleanup</h5>
<p>All the added URLs reside in the EMMS cache after being played. I don&rsquo;t want them to stay there for a long time, so here is a handy function to clean it.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/emms-cleanup-urls</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">keys-to-delete</span> <span style="color:#666">&#39;</span>()))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">maphash</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">key</span> <span style="color:#19177c">value</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">eq</span> (<span style="color:#00f">cdr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">&#39;type</span> <span style="color:#19177c">value</span>)) <span style="color:#19177c">&#39;url</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;keys-to-delete</span> <span style="color:#19177c">key</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">emms-cache-db</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">key</span> <span style="color:#19177c">keys-to-delete</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">remhash</span> <span style="color:#19177c">key</span> <span style="color:#19177c">emms-cache-db</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">emms-cache-dirty</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;asc&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/emms-cleanup-urls</span>)
</span></span></code></pre></div><h5 id="fetching-lyrics">Fetching lyrics</h5>
<p>My package for fetching EMMS lyrics and album covers.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">lyrics-fetcher</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">emms</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;ast&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">lyrics-fetcher-show-lyrics</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;asT&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">lyrics-fetcher-show-lyrics-query</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lyrics-fetcher-genius-access-token</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/password-store-get</span> <span style="color:#ba2121">&#34;My_Online/APIs/genius.com&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">emacs</span> <span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;emms-browser-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gr&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">emms-browse-by-artist</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gl&#34;</span> <span style="color:#19177c">&#39;lyrics-fetcher-emms-browser-show-at-point</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gC&#34;</span> <span style="color:#19177c">&#39;lyrics-fetcher-emms-browser-fetch-covers-at-point</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;go&#34;</span> <span style="color:#19177c">&#39;lyrics-fetcher-emms-browser-open-large-cover-at-point</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">emms-lyrics-mode-line</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:override</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/emms-lyrics-mode-line-override</span>))
</span></span></code></pre></div><p>Also advice to change the location of the lyrics in the mode line.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/emms-lyrics-mode-line-override</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;global-mode-string</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:eval</span> <span style="color:#19177c">emms-lyrics-mode-line-string</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/emms-lyrics-restore-mode-line-override</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Restore the mode line.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">global-mode-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">remove</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:eval</span> <span style="color:#19177c">emms-lyrics-mode-line-string</span>) <span style="color:#19177c">global-mode-string</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">force-mode-line-update</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;emms-lyrics</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">emms-lyrics-mode-line</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:override</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/emms-lyrics-mode-line-override</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">emms-lyrics-restore-mode-line</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:override</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/emms-lyrics-restore-mode-line-override</span>))
</span></span></code></pre></div><h5 id="some-keybindings">Some keybindings</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;emms-browser</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;emms-browser-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#19177c">&#39;quit-window</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;emms</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;emms-playlist-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#19177c">&#39;quit-window</span>))
</span></span></code></pre></div><h5 id="setting-volume">Setting volume</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/set-volume</span> (<span style="color:#19177c">value</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">start-process</span> <span style="color:#ba2121">&#34;ponymix&#34;</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;ponymix&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">&lt;</span> <span style="color:#666">0</span> <span style="color:#19177c">value</span>) <span style="color:#ba2121">&#34;increase&#34;</span> <span style="color:#ba2121">&#34;decrease&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">number-to-string</span> (<span style="color:#00f">abs</span> <span style="color:#19177c">value</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;--max-volume&#34;</span> <span style="color:#ba2121">&#34;150&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">emms-volume-change-function</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/set-volume</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">emms-volume-change-amount</span> <span style="color:#666">5</span>)
</span></span></code></pre></div><h5 id="emms-and-mpd-fixes">EMMS &amp; mpd Fixes</h5>
<p><del>Some fixes until I submit a patch.</del> I&rsquo;ve submitted a patch for with these fixes, so I&rsquo;ll remove this section eventually.</p>
<p>For some reason EMMS doesn&rsquo;t fetch <code>albumartist</code> from MPD. Overriding this function fixes that.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">emms-info-mpd-process</span> (<span style="color:#19177c">track</span> <span style="color:#19177c">info</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">data</span> <span style="color:#19177c">info</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">name</span> (<span style="color:#00f">car</span> <span style="color:#19177c">data</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">value</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">data</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">name</span> (<span style="color:#008000">cond</span> ((<span style="color:#19177c">string=</span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;artist&#34;</span>) <span style="color:#19177c">&#39;info-artist</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string=</span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;albumartist&#34;</span>) <span style="color:#19177c">&#39;info-albumartist</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string=</span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;composer&#34;</span>) <span style="color:#19177c">&#39;info-composer</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string=</span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;performer&#34;</span>) <span style="color:#19177c">&#39;info-performer</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string=</span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;title&#34;</span>) <span style="color:#19177c">&#39;info-title</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string=</span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;album&#34;</span>) <span style="color:#19177c">&#39;info-album</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string=</span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;track&#34;</span>) <span style="color:#19177c">&#39;info-tracknumber</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string=</span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;disc&#34;</span>) <span style="color:#19177c">&#39;info-discnumber</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string=</span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;date&#34;</span>) <span style="color:#19177c">&#39;info-year</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string=</span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;genre&#34;</span>) <span style="color:#19177c">&#39;info-genre</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string=</span> <span style="color:#19177c">name</span> <span style="color:#ba2121">&#34;time&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">value</span> (<span style="color:#00f">string-to-number</span> <span style="color:#19177c">value</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;info-playing-time</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> <span style="color:#800">nil</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">emms-track-set</span> <span style="color:#19177c">track</span> <span style="color:#19177c">name</span> <span style="color:#19177c">value</span>)))))
</span></span></code></pre></div><p>Also, <code>emms-player-mpd-get-alists</code> has an interesting bug. This function parses the response to <code>listallinfo</code>, which looks something like this:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>tag1: value1
</span></span><span style="display:flex;"><span>tag2: value2
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span>tag1: value1&#39;
</span></span><span style="display:flex;"><span>tag2: value2&#39;
</span></span></code></pre></div><p>This structure has to be converted to list of alists, which looks like:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>((&#34;tag1&#34; . &#34;value1&#34;
</span></span><span style="display:flex;"><span> &#34;tag2&#34; . &#34;value2&#34;)
</span></span><span style="display:flex;"><span> (&#34;tag1&#34; . &#34;value1&#39;&#34;
</span></span><span style="display:flex;"><span> (&#34;tag2&#34; . &#34;value2&#39;&#34;)))
</span></span></code></pre></div><p>The original implementation creates a new alist whenever it encounters a tag it has already put in the current alist. Which doesn&rsquo;t work too well if some tags don&rsquo;t repeat, if the order is messed up, etc.</p>
<p>Fortunately, according to the <a href="https://mpd.readthedocs.io/en/latest/protocol.html#command-lsinfo">protocol specification</a>, each new record has to start with <code>file</code>, <code>directory</code> or <code>playlist</code>. I&rsquo;ve overridden the function with that in mind and it fixed the import, at least for my case.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">emms-player-mpd-get-alists</span> (<span style="color:#19177c">info</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Turn the given parsed INFO from MusicPD into an list of alists.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The list will be in reverse order.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">and</span> <span style="color:#19177c">info</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">null</span> (<span style="color:#00f">car</span> <span style="color:#19177c">info</span>)) <span style="color:#408080;font-style:italic">; no error has occurred</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">info</span>)) <span style="color:#408080;font-style:italic">; data exists</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">alists</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">cell</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">line</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">info</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">setq</span> <span style="color:#19177c">cell</span> (<span style="color:#19177c">emms-player-mpd-parse-line</span> <span style="color:#19177c">line</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">member</span> (<span style="color:#00f">car</span> <span style="color:#19177c">cell</span>) <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;file&#34;</span> <span style="color:#ba2121">&#34;directory&#34;</span> <span style="color:#ba2121">&#34;playlist&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">alists</span> (<span style="color:#00f">cons</span> <span style="color:#19177c">alist</span> <span style="color:#19177c">alists</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">alist</span> (<span style="color:#00f">list</span> <span style="color:#19177c">cell</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">alist</span> (<span style="color:#00f">cons</span> <span style="color:#19177c">cell</span> <span style="color:#19177c">alist</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">alist</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">alists</span> (<span style="color:#00f">cons</span> <span style="color:#19177c">alist</span> <span style="color:#19177c">alists</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">alists</span>)))
</span></span></code></pre></div><h4 id="eww">EWW</h4>
<p>Emacs built-in web browser. <del>I wonder if anyone actually uses it.</del></p>
<p>I use it occasionally to open links in elfeed.</p>
<p>Toggle using fonts in buffer:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/toggle-shr-use-fonts</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Toggle the shr-use-fonts variable in buffer&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">shr-use-fonts</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">shr-use-fonts</span>)))
</span></span></code></pre></div><p>Setting the default font.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defface</span> <span style="color:#19177c">my/shr-face</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#800">t</span> <span style="color:#008000">:inherit</span> <span style="color:#19177c">variable-pitch</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Default face for shr rendering.&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my/use-colors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/shr-face</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;blue</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/shr-insert-around</span> (<span style="color:#19177c">fun</span> <span style="color:#008000">&amp;rest</span> <span style="color:#19177c">args</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">shr-current-font</span> (<span style="color:#008000">or</span> <span style="color:#19177c">shr-current-font</span> <span style="color:#19177c">&#39;my/shr-face</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#19177c">fun</span> <span style="color:#19177c">args</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/shr-urlify-around</span> (<span style="color:#19177c">fun</span> <span style="color:#19177c">start</span> <span style="color:#19177c">url</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">title</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">fun</span> <span style="color:#19177c">start</span> <span style="color:#19177c">url</span> <span style="color:#19177c">title</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">faces</span> (<span style="color:#00f">get-text-property</span> <span style="color:#19177c">start</span> <span style="color:#19177c">&#39;face</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">put-text-property</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">start</span> (<span style="color:#00f">point</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;face</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">face</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">face</span> <span style="color:#19177c">&#39;my/shr-face</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;link</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">face</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">sequencep</span> <span style="color:#19177c">faces</span>) <span style="color:#19177c">faces</span> (<span style="color:#00f">list</span> <span style="color:#19177c">faces</span>))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;shr</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">shr-insert</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/shr-insert-around</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">shr-urlify</span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/shr-urlify-around</span>))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;aw&#34;</span> <span style="color:#19177c">&#39;eww</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my/persp-add-rule</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">eww-mode</span> <span style="color:#666">2</span> <span style="color:#ba2121">&#34;browser&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;eww</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">eww-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">emacs</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ace-link-eww</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;+&#34;</span> <span style="color:#19177c">&#39;text-scale-increase</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;-&#34;</span> <span style="color:#19177c">&#39;text-scale-decrease</span>))
</span></span></code></pre></div><h4 id="erc">ERC</h4>
<p>ERC is a built-it Emacs IRC client.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">erc</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">erc</span> <span style="color:#19177c">erc-tls</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:type</span> <span style="color:#19177c">built-in</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">erc-log-channels-directory</span> <span style="color:#ba2121">&#34;~/.erc/logs&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">erc-save-buffer-on-part</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;erc-modules</span> <span style="color:#19177c">&#39;autojoin</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;erc-modules</span> <span style="color:#19177c">&#39;notifications</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;erc-modules</span> <span style="color:#19177c">&#39;log</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">erc-update-modules</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">erc-autojoin-channels-alist</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#666">,</span>(<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;libera.chat&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;#systemcrafters&#34;</span> <span style="color:#ba2121">&#34;#systemcrafters-emacs&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">erc-kill-buffer-on-part</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">erc-track-shorten-start</span> <span style="color:#666">8</span>))
</span></span></code></pre></div><p>Exclude everything but actual messages from notifications.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">erc-track-exclude-types</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;NICK&#34;</span> <span style="color:#ba2121">&#34;JOIN&#34;</span> <span style="color:#ba2121">&#34;LEAVE&#34;</span> <span style="color:#ba2121">&#34;QUIT&#34;</span> <span style="color:#ba2121">&#34;PART&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;301&#34;</span> <span style="color:#408080;font-style:italic">; away notice</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;305&#34;</span> <span style="color:#408080;font-style:italic">; return from awayness</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;306&#34;</span> <span style="color:#408080;font-style:italic">; set awayness</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;324&#34;</span> <span style="color:#408080;font-style:italic">; modes</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;329&#34;</span> <span style="color:#408080;font-style:italic">; channel creation date</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;332&#34;</span> <span style="color:#408080;font-style:italic">; topic notice</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;333&#34;</span> <span style="color:#408080;font-style:italic">; who set the topic</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;353&#34;</span> <span style="color:#408080;font-style:italic">; Names notice</span>
</span></span><span style="display:flex;"><span> ))
</span></span></code></pre></div><p>A plugin to highlight IRC nicknames:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">erc-hl-nicks</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:hook</span> (<span style="color:#19177c">erc-mode</span> <span style="color:#666">.</span> <span style="color:#19177c">erc-hl-nicks-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">erc</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><p>ZNC support. Seems to provide a few nice features for ZNC.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">znc</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">znc-erc</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (my-leader-def &#34;ai&#34; #&#39;znc-erc)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/persp-add-rule</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">erc-mode</span> <span style="color:#666">3</span> <span style="color:#ba2121">&#34;ERC&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">znc-servers</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#ba2121">&#34;sqrtminusone.xyz&#34;</span> <span style="color:#666">6697</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">libera</span> <span style="color:#ba2121">&#34;sqrtminusone&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#19177c">my/password-store-get</span> <span style="color:#ba2121">&#34;Selfhosted/ZNC&#34;</span>)))))))
</span></span></code></pre></div><p>Send <code>/detach</code> to all servers. Kinda strange that there&rsquo;s no such function already</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/erc-detach-all</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">buf</span> <span style="color:#19177c">being</span> <span style="color:#19177c">the</span> <span style="color:#19177c">buffers</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#00f">eq</span> (<span style="color:#00f">buffer-local-value</span> <span style="color:#19177c">&#39;major-mode</span> <span style="color:#19177c">buf</span>) <span style="color:#19177c">&#39;erc-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buf</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">erc-server-process-alive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">tgt</span> (<span style="color:#19177c">erc-default-target</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">erc-server-send</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;DETACH %s&#34;</span> <span style="color:#19177c">tgt</span>) <span style="color:#800">nil</span> <span style="color:#19177c">tgt</span>))))))
</span></span></code></pre></div><h4 id="mastodon">Mastodon</h4>
<p>Mastodon is a decentralized social media network. I use an instance called <a href="https://emacs.ch/">emacs.ch</a>.</p>
<h5 id="package-configuration">Package configuration</h5>
<p><a href="https://codeberg.org/martianh/mastodon.el">mastodon.el</a> is an Emacs client for Mastodon.</p>
<p>The default UI is rather rough, but Nicolas Rougier&rsquo;s <a href="https://github.com/rougier/mastodon-alt">mastodon-alt</a> package makes things a bit more how I would like to see them.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">mastodon</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">my/mastodon</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;an&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/mastodon</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">mastodon-instance-url</span> <span style="color:#ba2121">&#34;https://mastodon.bsd.cafe&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">mastodon-active-user</span> <span style="color:#ba2121">&#34;sqrtminusone&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/persp-add-rule</span> <span style="color:#19177c">mastodon-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">&#34;mastodon&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Hide spoilers by default</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (setq-default mastodon-toot--content-warning nil)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">mastodon-media--avatar-height</span> <span style="color:#666">40</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">mastodon-tl--timeline-posts-count</span> <span style="color:#ba2121">&#34;40&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">mastodon-tl--show-avatars</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">mastodon-tl--horiz-bar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">make-string</span> <span style="color:#19177c">shr-max-width</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">char-displayable-p</span> <span style="color:#ba2121">?―</span>) <span style="color:#ba2121">?―</span> <span style="color:#ba2121">?-</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; The default emojis take two characters for me</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">item</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> (<span style="color:#00f">car</span> <span style="color:#19177c">item</span>) <span style="color:#19177c">mastodon-tl--symbols</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">item</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">reply</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;R&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">boost</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;B&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">favourite</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;F&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">bookmark</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;K&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">media</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;[media]&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">verified</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;V&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">locked</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;[locked]&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">private</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;[followers]&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">direct</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;[direct]&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">edited</span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;[edited]&#34;</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">mastodon-alt</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;rougier/mastodon-alt&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">mastodon</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mastodon-alt-tl-activate</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">transient</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:defer</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><p>Compatibility with termux.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">unless</span> (<span style="color:#19177c">display-graphic-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defun</span> <span style="color:#19177c">image-transforms-p</span> () <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">image-types</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">svg</span> <span style="color:#19177c">png</span> <span style="color:#19177c">gif</span> <span style="color:#19177c">tiff</span> <span style="color:#19177c">jpeg</span> <span style="color:#19177c">xpm</span> <span style="color:#19177c">xbm</span> <span style="color:#19177c">pbm</span>)))
</span></span></code></pre></div><h5 id="ui-and-keymaps">UI and keymaps</h5>
<p><code>display-line-numbers-mode</code> screws the UI for some reason.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/mastodon-configure</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-line-numbers-mode</span> <span style="color:#666">-1</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;mastodon-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/mastodon-configure</span>)
</span></span></code></pre></div><p>Kill processes. Useful when the package stops working due to unstable connection.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/mastodon-reset</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">process</span> <span style="color:#19177c">in</span> (<span style="color:#00f">process-list</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">&#34;emacs.ch&#34;</span> (<span style="color:#00f">process-name</span> <span style="color:#19177c">process</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">delete-process</span> <span style="color:#19177c">process</span>)))
</span></span></code></pre></div><p>The package also doesn&rsquo;t have evil bindings. I implement a few basic bindings here:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;mastodon</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">motion</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">mastodon-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;J&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">mastodon-tl-goto-next-item</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;K&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">mastodon-tl-goto-prev-item</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-j&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">mastodon-tl-next-tab-item</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-k&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">mastodon-tl-prev-tab-item</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;tab&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">mastodon-tl-next-tab-item</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;backtab&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">mastodon-tl-previous-tab-item</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/mastodon-toot</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#19177c">&#39;mastodon-tl-update</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">mastodon-tl-toggle-spoiler-text-in-toot</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">kill-current-buffer</span>))
</span></span></code></pre></div><h5 id="modeline-segment">Modeline segment</h5>
<p>This is my attempt to make a modeline indicator for new mastodon notifications.</p>
<p>Edit <span class="timestamp-wrapper"><span class="timestamp">[2023-07-28 Fri]</span></span>: I&rsquo;ll probably remove that, don&rsquo;t feel like it&rsquo;s actually useful.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/mastodon-mode-string</span> <span style="color:#ba2121">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/mastodon-mode-line-unread-ids</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/mastodon-mode-line-saved-ids</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/mastodon-mode-line-timer</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/mastodon-mode-line-file</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">no-littering-var-directory</span> <span style="color:#ba2121">&#34;mastodon/notif-ids&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/mastodon-mode-line-load-meta</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">my/mastodon-mode-line-file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">ignore-errors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert-file-contents</span> <span style="color:#19177c">my/mastodon-mode-line-file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/mastodon-mode-line-saved-ids</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">read</span> (<span style="color:#00f">current-buffer</span>)))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/mastodon-mode-line-persist-meta</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mkdir</span> (<span style="color:#00f">file-name-directory</span> <span style="color:#19177c">my/mastodon-mode-line-file</span>) <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">coding-system-for-write</span> <span style="color:#19177c">&#39;utf-8</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">ignore-errors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-file</span> <span style="color:#19177c">my/mastodon-mode-line-file</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">standard-output</span> (<span style="color:#00f">current-buffer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">print-level</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">print-length</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">print-circle</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">princ</span> <span style="color:#ba2121">&#34;;;; Mastodon Saved Notifications\n\n&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">prin1</span> <span style="color:#19177c">my/mastodon-mode-line-saved-ids</span>))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/mastodon-mode-line-update</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">my/mastodon-mode-line-unread-ids</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/mastodon-mode-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;[&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">propertize</span> (<span style="color:#00f">number-to-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">length</span> <span style="color:#19177c">my/mastodon-mode-line-unread-ids</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;success</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;]&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/mastodon-mode-string</span> <span style="color:#ba2121">&#34;&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/mastodon-mode-line-update-fetch</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mastodon-http--get-json-async</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mastodon-http--api</span> <span style="color:#ba2121">&#34;notifications&#34;</span>) <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">fetched-ids</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">datum</span> <span style="color:#19177c">in</span> <span style="color:#19177c">data</span> <span style="color:#19177c">collect</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;id</span> <span style="color:#19177c">datum</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/mastodon-mode-line-unread-ids</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-difference</span> <span style="color:#19177c">fetched-ids</span> <span style="color:#19177c">my/mastodon-mode-line-saved-ids</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/mastodon-mode-line-saved-ids</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-intersection</span> <span style="color:#19177c">my/mastodon-mode-line-saved-ids</span> <span style="color:#19177c">fetched-ids</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/mastodon-mode-line-update</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/mastodon-notifications--timeline-before</span> (<span style="color:#19177c">toots</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">all-ids</span> (<span style="color:#19177c">seq-uniq</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">append</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/mastodon-mode-line-saved-ids</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">datum</span> <span style="color:#19177c">in</span> <span style="color:#19177c">toots</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;id</span> <span style="color:#19177c">datum</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/mastodon-mode-line-unread-ids</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-difference</span> <span style="color:#19177c">my/mastodon-mode-line-unread-ids</span> <span style="color:#19177c">all-ids</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/mastodon-mode-line-saved-ids</span> <span style="color:#19177c">all-ids</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/mastodon-mode-line-update</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;mastodon</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">define-minor-mode</span> <span style="color:#19177c">my/mastodon-mode-line</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Display mastodon notification count in mode line.&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:require</span> <span style="color:#19177c">&#39;mastodon</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:global</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:group</span> <span style="color:#19177c">&#39;mastodon</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">timerp</span> <span style="color:#19177c">my/mastodon-mode-line-timer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cancel-timer</span> <span style="color:#19177c">my/mastodon-mode-line-timer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">my/mastodon-mode-line</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;mode-line-misc-info</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:eval</span> <span style="color:#19177c">my/mastodon-mode-string</span>) <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/mastodon-mode-line-load-meta</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/mastodon-mode-line-timer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">run-with-timer</span> <span style="color:#666">0</span> <span style="color:#666">150</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/mastodon-mode-line-update-fetch</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">mastodon-notifications--timeline</span> <span style="color:#008000">:before</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/mastodon-notifications--timeline-before</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;kill-emacs-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/mastodon-mode-line-persist-meta</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">mode-line-misc-info</span> (<span style="color:#00f">delete</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:eval</span> <span style="color:#19177c">my/mastodon-mode-string</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">mode-line-misc-info</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-remove</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">mastodon-notifications--timeline</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/mastodon-notifications--timeline-before</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">remove-hook</span> <span style="color:#19177c">&#39;kill-emacs-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/mastodon-mode-line-persist-meta</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/mastodon-mode-line-persist-meta</span>)))))
</span></span></code></pre></div><h5 id="timeline-transient">Timeline Transient</h5>
<p>The default <code>mastodon-tl--get-home-timeline</code> allows only to hide replies, and not boosted posts.</p>
<p>So here&rsquo;s a custom update function:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/mastodon-get-update-funciton</span> (<span style="color:#19177c">hide-replies</span> <span style="color:#19177c">hide-boosts</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">toots</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">is-profile</span> (<span style="color:#00f">eq</span> (<span style="color:#19177c">mastodon-tl--get-buffer-type</span>) <span style="color:#19177c">&#39;profile-statuses</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">hide-replies</span> (<span style="color:#008000">and</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">is-profile</span>) <span style="color:#19177c">hide-replies</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">hide-boosts</span> (<span style="color:#008000">and</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">is-profile</span>) <span style="color:#19177c">hide-boosts</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">toots</span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">toot</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">hide-replies</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">mastodon-tl--is-reply</span> <span style="color:#19177c">toot</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">hide-boosts</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;reblog</span> <span style="color:#19177c">toot</span>)))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">toots</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">start-pos</span> (<span style="color:#00f">point</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapc</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">mastodon-tl--toot</span> <span style="color:#19177c">toots</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">mastodon-tl--display-media-p</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-excursion</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mastodon-media--inline-images</span> <span style="color:#19177c">start-pos</span> (<span style="color:#00f">point</span>)))))))
</span></span></code></pre></div><p>In order to use it, the function has to be passed to <code>mastodon-tl--init</code>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/mastodon-tl--get-home</span> (<span style="color:#19177c">hide-replies</span> <span style="color:#19177c">hide-boosts</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mastodon-tl--init</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;home&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;timelines/home&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/mastodon-get-update-funciton</span> <span style="color:#19177c">hide-replies</span> <span style="color:#19177c">hide-boosts</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#ba2121">&#34;limit&#34;</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">mastodon-tl--timeline-posts-count</span>))
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span>))
</span></span></code></pre></div><p>And a transient to use it.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;mastodon</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;transient</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">transient-define-prefix</span> <span style="color:#19177c">my/mastodon-tl</span> ()
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Home timeline params&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;-r&#34;</span> <span style="color:#ba2121">&#34;--hide-replies&#34;</span> <span style="color:#ba2121">&#34;--hide-replies&#34;</span> <span style="color:#008000">:init-value</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">obj</span>) (<span style="color:#008000">oset</span> <span style="color:#19177c">obj</span> <span style="color:#19177c">value</span> <span style="color:#ba2121">&#34;--hide-replies&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;-b&#34;</span> <span style="color:#ba2121">&#34;--hide-boosts&#34;</span> <span style="color:#ba2121">&#34;--hide-boosts&#34;</span> <span style="color:#008000">:init-value</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">obj</span>) (<span style="color:#008000">oset</span> <span style="color:#19177c">obj</span> <span style="color:#19177c">value</span> <span style="color:#ba2121">&#34;--hide-boosts&#34;</span>)))]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Timelines&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;t&#34;</span> <span style="color:#ba2121">&#34;Home&#34;</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">args</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> (<span style="color:#19177c">transient-args</span> <span style="color:#19177c">transient-current-command</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/mastodon-tl--get-home</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span> <span style="color:#19177c">args</span> <span style="color:#ba2121">&#34;--hide-replies&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span> <span style="color:#19177c">args</span> <span style="color:#ba2121">&#34;--hide-boosts&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;l&#34;</span> <span style="color:#ba2121">&#34;Local&#34;</span> <span style="color:#19177c">mastodon-tl-get-local-timeline</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#ba2121">&#34;Federated&#34;</span> <span style="color:#19177c">mastodon-tl-get-federated-timeline</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;g&#34;</span> <span style="color:#ba2121">&#34;One tag&#34;</span> <span style="color:#19177c">mastodon-tl-get-tag-timeline</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;a&#34;</span> <span style="color:#ba2121">&#34;Followed tags&#34;</span> <span style="color:#19177c">mastodon-tl-followed-tags-timeline</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#ba2121">&#34;Some followed tags&#34;</span> <span style="color:#19177c">mastodon-tl-some-followed-tags-timeline</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Misc&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#ba2121">&#34;Quit&#34;</span> <span style="color:#19177c">transient-quit-one</span>)]))
</span></span></code></pre></div><h5 id="main-transient">Main Transient</h5>
<p>Also, there are so many commands that it&rsquo;s hard to remember all of them. So I define two transient prefixes.</p>
<p>The first dispatches &ldquo;general&rdquo; actions:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;mastodon</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;transient</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">transient-define-prefix</span> <span style="color:#19177c">my/mastodon</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Mastodon.&#34;</span>
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Various views&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;m&#34;</span> <span style="color:#ba2121">&#34;Mastodon&#34;</span> <span style="color:#19177c">mastodon</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;t&#34;</span> <span style="color:#ba2121">&#34;Timelines&#34;</span> <span style="color:#19177c">my/mastodon-tl</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;n&#34;</span> <span style="color:#ba2121">&#34;Notifications&#34;</span> <span style="color:#19177c">mastodon-notifications-get</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#ba2121">&#34;Search query&#34;</span> <span style="color:#19177c">mastodon-search-query</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Tags&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;aa&#34;</span> <span style="color:#ba2121">&#34;Followed tags&#34;</span> <span style="color:#19177c">mastodon-tl-list-followed-tags</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;af&#34;</span> <span style="color:#ba2121">&#34;Follow tag&#34;</span> <span style="color:#19177c">mastodon-tl-follow-tag</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;aF&#34;</span> <span style="color:#ba2121">&#34;Unfollow tag&#34;</span> <span style="color:#19177c">mastodon-tl-unfollow-tag</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Own profile&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#ba2121">&#34;Toot&#34;</span> <span style="color:#19177c">mastodon-toot</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#ba2121">&#34;My profile&#34;</span> <span style="color:#19177c">mastodon-profile-my-profile</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;u&#34;</span> <span style="color:#ba2121">&#34;Update profile note&#34;</span> <span style="color:#19177c">mastodon-profile-update-user-profile-note</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#ba2121">&#34;Favourites&#34;</span> <span style="color:#19177c">mastodon-profile-view-favourites</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;b&#34;</span> <span style="color:#ba2121">&#34;Bookmarks&#34;</span> <span style="color:#19177c">mastodon-profile-view-bookmarks</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Minor views&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;F&#34;</span> <span style="color:#ba2121">&#34;Follow requests&#34;</span> <span style="color:#19177c">mastodon-views-view-follow-requests</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;S&#34;</span> <span style="color:#ba2121">&#34;Scheduled toots&#34;</span> <span style="color:#19177c">mastodon-views-view-scheduled-toots</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;I&#34;</span> <span style="color:#ba2121">&#34;Filters&#34;</span> <span style="color:#19177c">mastodon-views-view-filters</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;G&#34;</span> <span style="color:#ba2121">&#34;Follow suggestions&#34;</span> <span style="color:#19177c">mastodon-views-view-follow-suggestions</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;L&#34;</span> <span style="color:#ba2121">&#34;Lists&#34;</span> <span style="color:#19177c">mastodon-views-view-lists</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Misc&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;/&#34;</span> <span style="color:#ba2121">&#34;Switch to buffer&#34;</span> <span style="color:#19177c">mastodon-switch-to-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;Q&#34;</span> <span style="color:#ba2121">&#34;Kill all buffers&#34;</span> <span style="color:#19177c">mastodon-kill-all-buffers</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#ba2121">&#34;Quit&#34;</span> <span style="color:#19177c">transient-quit-one</span>)]))
</span></span></code></pre></div><h5 id="toot-transient">Toot Transient</h5>
<p>And the second one dispatches actions related to particular toot / profile.</p>
<p>Also, some actions don&rsquo;t have any confirmations, so here&rsquo;s a macro that wraps a function with <code>y-or-n-p</code>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defmacro</span> <span style="color:#19177c">my/def-confirmer</span> (<span style="color:#19177c">func</span> <span style="color:#19177c">text</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#008000">defun</span> <span style="color:#666">,</span>(<span style="color:#00f">intern</span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;my/&#34;</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">func</span>) <span style="color:#ba2121">&#34;-confirm&#34;</span>)) ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">y-or-n-p</span> <span style="color:#666">,</span><span style="color:#19177c">text</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">call-interactively</span> <span style="color:#00f">#&#39;</span><span style="color:#666">,</span><span style="color:#19177c">func</span>))))
</span></span></code></pre></div><p>A function to open the toot in browser:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/mastodon-toot--browse</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Copy URL of toot at point.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">If the toot is a fave/boost notification, copy the URLof the
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">base toot.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">toot</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">mastodon-tl--property</span> <span style="color:#19177c">&#39;base-toot</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mastodon-tl--property</span> <span style="color:#19177c">&#39;toot-json</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url</span> (<span style="color:#008000">if</span> (<span style="color:#19177c">mastodon-tl--field</span> <span style="color:#19177c">&#39;reblog</span> <span style="color:#19177c">toot</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;url</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;reblog</span> <span style="color:#19177c">toot</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;url</span> <span style="color:#19177c">toot</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">browse-url</span> <span style="color:#19177c">url</span>)))
</span></span></code></pre></div><p>And the prefix itself:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;mastodon</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/def-confirmer</span> <span style="color:#19177c">mastodon-toot-toggle-boost</span> <span style="color:#ba2121">&#34;Toggle boost for this post? &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/def-confirmer</span> <span style="color:#19177c">mastodon-toot-toggle-favourite</span> <span style="color:#ba2121">&#34;Toggle favourite this post? &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/def-confirmer</span> <span style="color:#19177c">mastodon-toot-toggle-bookmark</span> <span style="color:#ba2121">&#34;Toggle bookmark this post? &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/def-confirmer</span> <span style="color:#19177c">mastodon-tl-follow-user</span> <span style="color:#ba2121">&#34;Follow this user? &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/def-confirmer</span> <span style="color:#19177c">mastodon-tl-unfollow-user</span> <span style="color:#ba2121">&#34;Unfollow this user? &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/def-confirmer</span> <span style="color:#19177c">mastodon-tl-block-user</span> <span style="color:#ba2121">&#34;Block this user? &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/def-confirmer</span> <span style="color:#19177c">mastodon-tl-unblock-user</span> <span style="color:#ba2121">&#34;Unblock this user? &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/def-confirmer</span> <span style="color:#19177c">mastodon-tl-mute-user</span> <span style="color:#ba2121">&#34;Mute this user? &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/def-confirmer</span> <span style="color:#19177c">mastodon-tl-unmute-user</span> <span style="color:#ba2121">&#34;Unmute this user? &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/def-confirmer</span> <span style="color:#19177c">mastodon-tl-unmute-user</span> <span style="color:#ba2121">&#34;Unmute this user? &#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">transient-define-prefix</span> <span style="color:#19177c">my/mastodon-toot</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Mastodon toot actions.&#34;</span>
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;View&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#ba2121">&#34;Thread&#34;</span> <span style="color:#19177c">mastodon-tl-thread</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;w&#34;</span> <span style="color:#ba2121">&#34;Browser&#34;</span> <span style="color:#19177c">my/mastodon-toot--browse</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;le&#34;</span> <span style="color:#ba2121">&#34;List edits&#34;</span> <span style="color:#19177c">mastodon-toot-view-toot-edits</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;lf&#34;</span> <span style="color:#ba2121">&#34;List favouriters&#34;</span> <span style="color:#19177c">mastodon-toot-list-favouriters</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;lb&#34;</span> <span style="color:#ba2121">&#34;List boosters&#34;</span> <span style="color:#19177c">mastodon-toot-list-boosters</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Toot Actions&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#ba2121">&#34;Reply&#34;</span> <span style="color:#19177c">mastodon-toot-reply</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;v&#34;</span> <span style="color:#ba2121">&#34;Vote&#34;</span> <span style="color:#19177c">mastodon-tl-poll-vote</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;b&#34;</span> <span style="color:#ba2121">&#34;Boost&#34;</span> <span style="color:#19177c">my/mastodon-toot--toggle-boost-confirm</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#ba2121">&#34;Favourite&#34;</span> <span style="color:#19177c">my/mastodon-toot--toggle-favourite-confirm</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;k&#34;</span> <span style="color:#ba2121">&#34;Bookmark&#34;</span> <span style="color:#19177c">my/mastodon-toot--toggle-bookmark-confirm</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;My Toot Actions&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;md&#34;</span> <span style="color:#ba2121">&#34;Delete&#34;</span> <span style="color:#19177c">mastodon-toot-delete-toot</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;mD&#34;</span> <span style="color:#ba2121">&#34;Delete and redraft&#34;</span> <span style="color:#19177c">mastodon-toot-delete-and-redraft-toot</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;mp&#34;</span> <span style="color:#ba2121">&#34;Pin&#34;</span> <span style="color:#19177c">mastodon-toot-pin-toot-toggle</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;me&#34;</span> <span style="color:#ba2121">&#34;Edit&#34;</span> <span style="color:#19177c">mastodon-toot-edit-toot-at-point</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Profile Actions&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;pp&#34;</span> <span style="color:#ba2121">&#34;Profile&#34;</span> <span style="color:#19177c">mastodon-profile-show-user</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;pf&#34;</span> <span style="color:#ba2121">&#34;List followers&#34;</span> <span style="color:#19177c">mastodon-profile-open-followers</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;pF&#34;</span> <span style="color:#ba2121">&#34;List following&#34;</span> <span style="color:#19177c">mastodon-profile-open-following</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ps&#34;</span> <span style="color:#ba2121">&#34;List statues (no reblogs)&#34;</span> <span style="color:#19177c">mastodon-profile-open-statuses-no-reblogs</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;User Actions&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;uf&#34;</span> <span style="color:#ba2121">&#34;Follow user&#34;</span> <span style="color:#19177c">my/mastodon-tl-follow-user-confirm</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;uF&#34;</span> <span style="color:#ba2121">&#34;Unfollow user&#34;</span> <span style="color:#19177c">my/mastodon-tl-unfollow-user-confirm</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ub&#34;</span> <span style="color:#ba2121">&#34;Block user&#34;</span> <span style="color:#19177c">my/mastodon-tl-block-user-confirm</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;uB&#34;</span> <span style="color:#ba2121">&#34;Unblock user&#34;</span> <span style="color:#19177c">my/mastodon-tl-unblock-user-confirm</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;um&#34;</span> <span style="color:#ba2121">&#34;Mute user&#34;</span> <span style="color:#19177c">my/mastodon-tl-mute-user-confirm</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;uB&#34;</span> <span style="color:#ba2121">&#34;Unmute user&#34;</span> <span style="color:#19177c">my/mastodon-tl-unmute-user-confirm</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Misc&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#ba2121">&#34;Quit&#34;</span> <span style="color:#19177c">transient-quit-one</span>)]))
</span></span></code></pre></div><h4 id="wallabag">wallabag</h4>
<p><a href="https://github.com/wallabag/wallabag">wallabag</a> is a self-hosted &ldquo;read it later&rdquo; app.</p>
<p>This might be the best online reading advice I&rsquo;ve heard:</p>
<blockquote>
<p>I have a different approach: waiting periods. Every time I come across something I may want to read/watch, Im totally allowed to. No limits! The only requirement is I have to save it to Pocket, and then choose to consume it at a later time.</p></blockquote>
<p>Source: <a href="https://fortelabs.com/blog/the-secret-power-of-read-it-later-apps/">Tiago Forte - The Secret Power of Read It Later Apps</a></p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">wallabag</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;chenyanming/wallabag.el&#34;</span> <span style="color:#008000">:files</span> (<span style="color:#008000">:defaults</span> <span style="color:#ba2121">&#34;default.css&#34;</span> <span style="color:#ba2121">&#34;emojis.alist&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;aE&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">wallabag</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">wallabag</span> <span style="color:#19177c">wallabag-add-entry</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">wallabag-host</span> <span style="color:#ba2121">&#34;https://wallabag.sqrtminusone.xyz&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">wallabag-username</span> <span style="color:#ba2121">&#34;sqrtminusone&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">wallabag-password</span> (<span style="color:#19177c">my/password-store-get</span> <span style="color:#ba2121">&#34;Selfhosted/wallabag&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">wallabag-clientid</span> (<span style="color:#19177c">password-store-get-field</span> <span style="color:#ba2121">&#34;Selfhosted/wallabag&#34;</span> <span style="color:#ba2121">&#34;client_id&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">wallabag-secret</span> (<span style="color:#19177c">password-store-get-field</span> <span style="color:#ba2121">&#34;Selfhosted/wallabag&#34;</span> <span style="color:#ba2121">&#34;client_secret&#34;</span>)))
</span></span></code></pre></div><h4 id="ement-dot-el">ement.el</h4>
<p><a href="https://github.com/alphapapa/ement.el">ement.el</a> is a Matrix client for Emacs. This package turned out to be somewhat complicated to setup.</p>
<h5 id="general-config">General config</h5>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">plz</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;alphapapa/plz.el&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:defer</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ement</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ement-connect</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:user-id</span> <span style="color:#ba2121">&#34;@sqrtminusone:matrix.org&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:password</span> (<span style="color:#19177c">my/password-store-get</span> <span style="color:#ba2121">&#34;My_Online/Accounts/matrix&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ement</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;alphapapa/ement.el&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">ement-connect</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ax&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/ement</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ement-room-list-auto-update</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ement-room-mark-rooms-read</span> <span style="color:#19177c">&#39;send</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/persp-add-rule</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">ement-room-mode</span> <span style="color:#666">3</span> <span style="color:#ba2121">&#34;ement&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">ement-describe-room-mode</span> <span style="color:#666">3</span> <span style="color:#ba2121">&#34;ement&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">ement-room-occur-mode</span> <span style="color:#666">3</span> <span style="color:#ba2121">&#34;ement&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">ement-room-list-mode</span> <span style="color:#666">3</span> <span style="color:#ba2121">&#34;ement&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Room UI</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ement-room-message-format-spec</span> <span style="color:#ba2121">&#34;%S&gt; %W%B%r%R[%t]&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ement-room-left-margin-width</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ement-room-right-margin-width</span> <span style="color:#666">10</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ement-room-sender-in-left-margin</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ement-room-sender-headers</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ement-room-sender-in-headers</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ement-room-wrap-prefix</span> <span style="color:#ba2121">&#34;-&gt; &#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Changing some default faces</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-face-attribute</span> <span style="color:#19177c">&#39;ement-room-reactions</span> <span style="color:#800">nil</span> <span style="color:#008000">:height</span> <span style="color:#19177c">&#39;unspecified</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-face-attribute</span> <span style="color:#19177c">&#39;ement-room-reactions-key</span> <span style="color:#800">nil</span> <span style="color:#008000">:height</span> <span style="color:#19177c">&#39;unspecified</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-face-attribute</span> <span style="color:#19177c">&#39;ement-room-timestamp</span> <span style="color:#800">nil</span> <span style="color:#008000">:inherit</span> <span style="color:#19177c">&#39;font-lock-function-name-face</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-face-attribute</span> <span style="color:#19177c">&#39;ement-room-membership</span> <span style="color:#800">nil</span> <span style="color:#008000">:height</span> <span style="color:#666">0.9</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:inherit</span> <span style="color:#19177c">&#39;font-lock-warning-face</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-face-attribute</span> <span style="color:#19177c">&#39;ement-room-wrap-prefix</span> <span style="color:#800">nil</span> <span style="color:#008000">:inherit</span> <span style="color:#19177c">&#39;unspecified</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-face-attribute</span> <span style="color:#19177c">&#39;ement-room-timestamp-header</span> <span style="color:#800">nil</span> <span style="color:#008000">:height</span> <span style="color:#19177c">&#39;unspecified</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">set-face-attribute</span> <span style="color:#19177c">&#39;ement-room-wrap-prefix</span> <span style="color:#800">nil</span> <span style="color:#008000">:inherit</span> <span style="color:#19177c">&#39;unspecified</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Notify only on mentions</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ement-notify-notification-predicates</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">ement-notify--event-mentions-session-user-p</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">ement-notify--event-mentions-room-p</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">ement-notify--room-unread-p</span>))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Fix the anti-synergy with major mode re-activation in `ement-room-list-revert&#39;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-list-revert</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:around</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/perspective-assign-ignore-advice</span>))
</span></span></code></pre></div><h5 id="keybindings-5">Keybindings</h5>
<p>Some custom keymaps for room lists:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;ement-room-list</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">visual</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">ement-room-list-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;tab&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">magit-section-toggle</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-j&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">magit-section-forward</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-k&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">magit-section-backward</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">quit-window</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gr&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">revert-buffer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;RET&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-list-RET</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;ement-tabulated-room-list</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">visual</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">ement-tabulated-room-list-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">quit-window</span>))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ement-room-send-reaction</span> (<span style="color:#19177c">key</span> <span style="color:#19177c">position</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">completing-read</span> <span style="color:#ba2121">&#34;Add reaction: &#34;</span> (<span style="color:#00f">append</span> <span style="color:#19177c">telega-emoji-reaction-list</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;👋&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">point</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ement-room-send-reaction</span> <span style="color:#19177c">key</span> <span style="color:#19177c">position</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ement-room-compose-quit</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">string-empty-p</span> (<span style="color:#00f">buffer-string</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">y-or-n-p</span> <span style="color:#ba2121">&#34;Quit compose? &#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">quit-window</span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ement-room-compose-setup</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ement-room-compose-org</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">company-backends</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">telega-company-emoji</span> <span style="color:#19177c">company-capf</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">visual</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;local</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/ement-room-compose-quit</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c C-k&#34;</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">quit-window</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-c C-c&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-compose-send</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;ement-room-compose-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/ement-room-compose-setup</span>)
</span></span></code></pre></div><p>Also a keymap for room mode:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;ement</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">visual</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">ement-room-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">quit-window</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;?&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-transient</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-u&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-scroll-down-command</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-d&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-scroll-up-mark-read</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-write-reply</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;a&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-send-message</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;i&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-send-message</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;e&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-edit-message</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-&lt;RET&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-compose-message</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;RET&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-send-message</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;K&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-goto-prev</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;J&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-goto-next</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gr&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-sync</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;g?&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-describe-room</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;R?&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-describe-room</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Rm&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-list-members</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Rn&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-set-notification-state</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Rt&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-set-topic</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;!&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/ement-room-send-reaction</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;m?&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-view-event</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Zf&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-send-file</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;ui&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-invite-user</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span> <span style="color:#19177c">visual</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">ement-describe-room-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">quit-window</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">motion</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">ement-room-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-u&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-scroll-down-command</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-d&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-scroll-up-mark-read</span>))
</span></span></code></pre></div><h5 id="various-functions">Various functions</h5>
<p>Scroll to the previous mention.</p>
<blockquote>
<p>alphapapa 🐃​&gt; And, yes, that is a currently unsolved problem. As I said, in the future we can try using a different API endpoint to access those notifications similarly to Element. In the meantime, you can load old messages (e.g. &ldquo;C-u 1000 M-v&rdquo; to load 1000 old ones at a time), until you find it, maybe using &ldquo;C-s sqrtm&rdquo; to search for messages mentioning you.</p>
<p>Or you can load up Element for a moment to see what the mention was, if that&rsquo;s easier.</p></blockquote>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ement-about-me-p</span> (<span style="color:#19177c">event</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">me</span> (<span style="color:#19177c">ement-user-id</span> (<span style="color:#19177c">ement-session-user</span> <span style="color:#19177c">ement-session</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">equal</span> (<span style="color:#19177c">ement-user-id</span> (<span style="color:#19177c">ement-event-sender</span> <span style="color:#19177c">event</span>)) <span style="color:#19177c">me</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let</span> ((<span style="color:#19177c">formatted-body</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;formatted_body</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ement-event-content</span> <span style="color:#19177c">event</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> <span style="color:#19177c">me</span> <span style="color:#19177c">formatted-body</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ement-scroll-to-previous-about-me</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">scrolled</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">&lt;</span> (<span style="color:#19177c">line-number-at-pos</span>) <span style="color:#666">20</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">forward-line</span> <span style="color:#666">20</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">ement-room-retro-loading</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">run-with-timer</span> <span style="color:#666">0.5</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/ement-scroll-to-previous-about-me</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">while</span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">event</span> (<span style="color:#19177c">ewoc-data</span> (<span style="color:#19177c">ewoc-locate</span> <span style="color:#19177c">ement-ewoc</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> <span style="color:#19177c">ement-room-retro-loading</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">ement-event-p</span> <span style="color:#19177c">event</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">my/ement-about-me-p</span> <span style="color:#19177c">event</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">condition-case</span> <span style="color:#19177c">_err</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">scroll-down</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">beginning-of-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">call-interactively</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ement-room-retro</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">run-with-timer</span> <span style="color:#666">0.5</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/ement-scroll-to-previous-about-me</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-incf</span> <span style="color:#19177c">scrolled</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Scrolled %s&#34;</span> <span style="color:#19177c">scrolled</span>)))))
</span></span></code></pre></div><h4 id="telega">Telega</h4>
<p><a href="https://github.com/zevlg/telega.el/">telega.el</a> is a Telegam client for Emacs.</p>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>emacs-telega-sever</td>
</tr>
<tr>
<td>font-gnu-unifont</td>
</tr>
<tr>
<td>font-gnu-freefont</td>
</tr>
</tbody>
</table>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">telega</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; :straight (:type built-in)</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; For now emacs-telega-server is compatible with the latest telega.el</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/remote-server</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">telega</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;a l&#34;</span> (<span style="color:#19177c">my/command-in-persp</span> <span style="color:#ba2121">&#34;telega&#34;</span> <span style="color:#ba2121">&#34;telega&#34;</span> <span style="color:#666">3</span> (<span style="color:#19177c">telega</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/use-colors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-button-active</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;base0</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;cyan</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-webpage-chat-link</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;base0</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;fg</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-entity-type-spoiler</span> <span style="color:#008000">:background</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;base8</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#ba2121">&#34;~/.guix-extra-profiles/emacs/emacs/bin/telega-server&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">telega-server-command</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">expand-file-name</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;~/.guix-extra-profiles/emacs/emacs/bin/telega-server&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">telega-emoji-use-images</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">telega-chat-fill-column</span> <span style="color:#666">80</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">telega-completing-read-function</span> <span style="color:#00f">#&#39;completing-read</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">telega-sticker-size</span> <span style="color:#666">&#39;</span>(<span style="color:#666">12</span> <span style="color:#666">.</span> <span style="color:#666">24</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;savehist-additional-variables</span> <span style="color:#19177c">&#39;telega-msg-add-reaction</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">remove-hook</span> <span style="color:#19177c">&#39;telega-chat-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">telega-chat-auto-fill-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">telega-root-mode-map</span> <span style="color:#19177c">telega-chat-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gp&#34;</span> <span style="color:#19177c">telega-prefix-map</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">telega-msg-button-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;SPC&gt;&#34;</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">telega-chat-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-&lt;return&gt;&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">newline</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/persp-add-rule</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">telega-root-mode</span> <span style="color:#666">3</span> <span style="color:#ba2121">&#34;telega&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">telega-chat-mode</span> <span style="color:#666">3</span> <span style="color:#ba2121">&#34;telega&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">telega-image-mode</span> <span style="color:#666">3</span> <span style="color:#ba2121">&#34;telega&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">telega-webpage-mode</span> <span style="color:#666">3</span> <span style="color:#ba2121">&#34;telega&#34;</span>))
</span></span></code></pre></div><p>Building <code>telega-server</code> can create problems. On Guix I can use the Guix package definition, on termux just build manually.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/telega-server-build</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">telega-server-libs-prefix</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">executable-find</span> <span style="color:#ba2121">&#34;guix&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-trim</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shell-command-to-string</span> <span style="color:#ba2121">&#34;guix build tdlib&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">&#34;~/bin/td/build/res/usr/local&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-server-build</span> <span style="color:#ba2121">&#34;CC=gcc&#34;</span>))
</span></span></code></pre></div><p>Setting up the modeline. The default mode string doesn&rsquo;t look great with my other modeline modules, so I override that.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;telega-load-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">telega-mode-line-mode</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">telega-mode-line-string-format</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;[&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:eval</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-mode-line-online-status</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:eval</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">telega-use-tracking-for</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-mode-line-tracking</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:eval</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-mode-line-unread-unmuted</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:eval</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-mode-line-mentions</span> <span style="color:#19177c">&#39;messages</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;]&#34;</span>))
</span></span></code></pre></div><p>Configuring company backends for the chat buffer, as recommended in the manual:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/telega-chat-setup</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set</span> (<span style="color:#00f">make-local-variable</span> <span style="color:#19177c">&#39;company-backends</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">append</span> (<span style="color:#00f">list</span> <span style="color:#19177c">&#39;telega-company-emoji</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;telega-company-username</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;telega-company-hashtag</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;telega-company-markdown-precode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">telega-chat-bot-p</span> <span style="color:#19177c">telega-chatbuf--chat</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">telega-company-botcmd</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">company-mode</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">setopt</span> <span style="color:#19177c">visual-fill-column-width</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">+</span> <span style="color:#19177c">telega-chat-fill-column</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">display-graphic-p</span>) <span style="color:#666">5</span> <span style="color:#666">6</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">split-width-threshold</span> <span style="color:#666">1</span>))
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;telega-chat-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/telega-chat-setup</span>)
</span></span></code></pre></div><p>And custom online status. By default it marks you online when the Emacs frame is active, but I use EXWM, so I change that to when <code>telega.el</code> buffer is active. Otherwise, I&rsquo;m online all the time.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/telega-online-status</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">derived-mode-p</span> <span style="color:#19177c">&#39;telega-root-mode</span> <span style="color:#19177c">&#39;telega-chat-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;telega-image-mode</span> <span style="color:#19177c">&#39;telega-webpage-mode</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">telega-online-status-function</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/telega-online-status</span>)
</span></span></code></pre></div><p>Switch to topic in forum chats.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/telega-switch-to-topic</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">topics-data</span> (<span style="color:#00f">gethash</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">plist-get</span> <span style="color:#19177c">telega-chatbuf--chat</span> <span style="color:#008000">:id</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">telega--chat-topics</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">topics-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">topic</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">name</span> (<span style="color:#00f">plist-get</span> (<span style="color:#00f">plist-get</span> <span style="color:#19177c">topic</span> <span style="color:#008000">:info</span>) <span style="color:#008000">:name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">unread-count</span> (<span style="color:#00f">plist-get</span> <span style="color:#19177c">topic</span> <span style="color:#008000">:unread_count</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">name-string</span> (<span style="color:#008000">with-temp-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-ins--topic-title</span> <span style="color:#19177c">topic</span> <span style="color:#19177c">&#39;with-icon</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-string</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">zerop</span> <span style="color:#19177c">unread-count</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">name-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%-40s (%s)&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">name-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">propertize</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%d&#34;</span> <span style="color:#19177c">unread-count</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;telega-unread-unmuted-modeline</span>)))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">topics-data</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">topics-collection</span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">datum</span> <span style="color:#19177c">in</span> <span style="color:#19177c">topics-data</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#00f">string</span> <span style="color:#19177c">in</span> <span style="color:#19177c">topics-string</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#00f">cons</span> <span style="color:#00f">string</span> <span style="color:#19177c">datum</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">topic</span> (<span style="color:#00f">completing-read</span> <span style="color:#ba2121">&#34;Topic: &#34;</span> <span style="color:#19177c">topics-collection</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">telega-chat--goto-thread</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">telega-chatbuf--chat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">plist-get</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">plist-get</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">topic</span> <span style="color:#19177c">topics-collection</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;equal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:info</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:message_thread_id</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;telega</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;telega-chat-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;T&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/telega-switch-to-topic</span>))
</span></span></code></pre></div><h4 id="google-translate">Google Translate</h4>
<p>Emacs interface to Google Translate.</p>
<p>Can&rsquo;t make it load lazily for some strange reason.</p>
<p>References:</p>
<ul>
<li><a href="https://github.com/atykhonov/google-translate">google-translate repo</a></li>
<li><a href="https://github.com/atykhonov/google-translate/issues/137#issuecomment-728278849">issue with ttk error fix</a></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">google-translate</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:functions</span> (<span style="color:#19177c">my-google-translate-at-point</span> <span style="color:#19177c">google-translate--search-tkk</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">google-translate-at-point</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">google-translate-at-point-reverse</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">google-translate-query-translate</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">google-translate-query-translate-reverse</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">google-translate-smooth-translate</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:custom</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">google-translate-backend-method</span> <span style="color:#19177c">&#39;curl</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;facemenu</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defun</span> <span style="color:#19177c">google-translate--search-tkk</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Search TKK.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> <span style="color:#666">430675</span> <span style="color:#666">2721866130</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defun</span> <span style="color:#19177c">my-google-translate-at-point</span>()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;reverse translate if prefix&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">current-prefix-arg</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">google-translate-at-point</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">google-translate-at-point-reverse</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">google-translate-translation-directions-alist</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#ba2121">&#34;en&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;ru&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ru&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;en&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;de&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;en&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;en&#34;</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;de&#34;</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;at&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">&#34;google translate&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;p&#34;</span> <span style="color:#19177c">&#39;google-translate-at-point</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;P&#34;</span> <span style="color:#19177c">&#39;google-translate-at-point-reverse</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#19177c">&#39;google-translate-query-translate</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Q&#34;</span> <span style="color:#19177c">&#39;google-translate-query-translate-reverse</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;t&#34;</span> <span style="color:#19177c">&#39;google-translate-smooth-translate</span>)
</span></span></code></pre></div><h4 id="biome">biome</h4>
<p><a href="https://github.com/SqrtMinusOne/biome">biome</a> is my <a href="https://open-meteo.com/">open-meteo</a> client.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">biome</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">biome</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ab&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">biome</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">my/is-termux</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">biome-query-tab-key</span> <span style="color:#ba2121">&#34;&lt;TAB&gt;&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">biome-api-try-parse-error-as-response</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;biome-query-coords</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;Saint-Petersburg, Russia&#34;</span> <span style="color:#666">59.942651</span> <span style="color:#666">30.229930</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;biome-query-coords</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;Tyumen, Russia&#34;</span> <span style="color:#666">57.15222</span> <span style="color:#666">65.52722</span>)))
</span></span></code></pre></div><h3 id="reading-documentation">Reading documentation</h3>
<h4 id="tldr">tldr</h4>
<p><a href="https://tldr.sh/">tldr</a> is a collaborative project providing cheatsheets for various console commands. For some reason, the built-in download in the package is broken, so I use my own function.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">tldr</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">tldr</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">tldr-source-zip-url</span> <span style="color:#ba2121">&#34;https://github.com/tldr-pages/tldr/archive/refs/heads/main.zip&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defun</span> <span style="color:#19177c">tldr-update-docs</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shell-command-to-string</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;curl -L %s --output %s&#34;</span> <span style="color:#19177c">tldr-source-zip-url</span> <span style="color:#19177c">tldr-saved-zip-path</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#ba2121">&#34;/tmp/tldr&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">delete-directory</span> <span style="color:#ba2121">&#34;/tmp/tldr&#34;</span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shell-command-to-string</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;unzip -d /tmp/tldr/ %s&#34;</span> <span style="color:#19177c">tldr-saved-zip-path</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">tldr-directory-path</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">delete-directory</span> <span style="color:#19177c">tldr-directory-path</span> <span style="color:#19177c">&#39;recursive</span> <span style="color:#19177c">&#39;no-trash</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shell-command-to-string</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;mv %s %s&#34;</span> <span style="color:#ba2121">&#34;/tmp/tldr/tldr-main&#34;</span> <span style="color:#19177c">tldr-directory-path</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;hT&#34;</span> <span style="color:#19177c">&#39;tldr</span>)
</span></span></code></pre></div><h4 id="man-and-info">man &amp; info</h4>
<p>Of course, Emacs can also display man and info pages.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">Man-width-max</span> <span style="color:#666">180</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;hM&#34;</span> <span style="color:#19177c">&#39;woman</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">woman-fill-column</span> <span style="color:#666">90</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;Info-mode-map</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">kbd</span> <span style="color:#ba2121">&#34;RET&#34;</span>) <span style="color:#00f">#&#39;</span><span style="color:#19177c">Info-follow-nearest-node</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;H&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">Info-history-back</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;L&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">Info-history-forward</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;n&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">Info-search-next</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;b&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">Info-search-backward</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">ace-link-info</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/man-fix-width</span> (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">_</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">Man-width</span> (<span style="color:#00f">-</span> (<span style="color:#19177c">window-width</span>) <span style="color:#666">4</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">advice-add</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">Man-update-manpage</span> <span style="color:#008000">:before</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/man-fix-width</span>)
</span></span></code></pre></div><h4 id="devdocs-dot-io">devdocs.io</h4>
<p>There is a package called <code>devdocs</code> that does more or less the same, but I like <code>devdocs-browser</code> more because it uses <code>eww</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">devdocs-browser</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">devdocs-browser-open</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">devdocs-browser-open-in</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">devdocs-browser-install-doc</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">devdocs-browser-uninstall-doc</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">devdocs-browser-download-offline-data</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">devdocs-browser-remove-offline-data</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">devdocs-browser-upgrade-all-docs</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">devdocs-browser-update-docs</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;hd&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:wk</span> <span style="color:#ba2121">&#34;devdocs&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">devdocs-browser-open</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">devdocs-browser-open-in</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;i&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">devdocs-browser-install-doc</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;n&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">devdocs-browser-uninstall-doc</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;o&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">devdocs-browser-download-offline-data</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;O&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">devdocs-browser-remove-offline-data</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;u&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">devdocs-browser-upgrade-all-docs</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;r&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">devdocs-browser-update-docs</span>))
</span></span></code></pre></div><h4 id="stackexchange">StackExchange</h4>
<p><a href="https://github.com/vermiculus/sx.el">sx.el</a> is a StackExchange client for Emacs.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">sx</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">sx-search</span> <span style="color:#19177c">sx-tab-frontpage</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">sx-question-mode-map</span> <span style="color:#19177c">sx-question-list-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;go&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-visit-externally</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">quit-window</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;s*&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-tab-starred</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;sU&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-tab-unanswered-my-tags</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;sa&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-ask</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;sf&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-tab-featured</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;sh&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-tab-frontpage</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;si&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-inbox</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;sm&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-tab-meta-or-main</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;sn&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-tab-newest</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;su&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-tab-unanswered</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;sv&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-tab-topvoted</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;sw&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-tab-week</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;u&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-upvote</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;d&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-downvote</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;j&#34;</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;k&#34;</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">sx-question-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gr&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-question-mode-refresh</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;J&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-question-mode-next-section</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;K&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-question-mode-previous-section</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;a&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-answer</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;e&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-edit</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;D&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-delete</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;c&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-comment</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">sx-question-list-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;RET&#34;</span> <span style="color:#19177c">&#39;sx-display</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;j&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-question-list-next</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;k&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-question-list-previous</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;S&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-search</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;m&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-question-list-mark-read</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;O&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-question-list-order-by</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;t&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-tab-switch</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;hs&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-search</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;hS&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">sx-tab-frontpage</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/use-colors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">sx-question-mode-accepted</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">my/color-value</span> <span style="color:#19177c">&#39;green</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:weight</span> <span style="color:#19177c">&#39;bold</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">sx-question-mode-content</span> <span style="color:#008000">:background</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;sx-question-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">doom-modeline-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;sx-question-list-mode-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">doom-modeline-mode</span>))
</span></span></code></pre></div><h3 id="not-an-ai">Not-an-AI</h3>
<p>Workflows, which are sometimes referred to as &ldquo;AI&rdquo;, go in here.</p>
<p>I&rsquo;m technically writing a PhD on a related topic, so I&rsquo;m a bit more receptive towards the whole thing than most of the community. But I&rsquo;m still not calling it AI.</p>
<h4 id="llms">LLMs</h4>
<p>I don&rsquo;t have access to any proprietary APIs, but LLaMA 3.1 8b with <a href="https://ollama.com/">ollama</a> works for some purposes.</p>
<h5 id="gptel">gptel</h5>
<p><a href="https://github.com/karthink/gptel">gtpel</a> is a package that provides an interface to chat with LLMs.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">gptel</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/is-termux</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;ai&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:wk</span> <span style="color:#ba2121">&#34;AI&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;i&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">gptel</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">gptel</span> <span style="color:#19177c">gptel-send</span> <span style="color:#19177c">gptel-menu</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gptel-mode</span> <span style="color:#ba2121">&#34;llama3:latest&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gptel-track-media</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gptel-backend</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">gptel-make-ollama</span> <span style="color:#ba2121">&#34;Ollama&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:host</span> <span style="color:#ba2121">&#34;localhost:11434&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:stream</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:models</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;llama3.1:8b&#34;</span> <span style="color:#ba2121">&#34;deepseek-r1:32b&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;qwen2.5:32b&#34;</span> <span style="color:#ba2121">&#34;qwen2.5-coder:32b&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;eva-qwen2.5-q4_k_l-32b:latest&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;t-pro-1.0-q4_k_m:latest&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;qwq:32b&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">gemma3:32b</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:capabilities</span> (<span style="color:#19177c">media</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mime-types</span> (<span style="color:#ba2121">&#34;image/jpeg&#34;</span> <span style="color:#ba2121">&#34;image/png&#34;</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">gptel-make-openai</span> <span style="color:#ba2121">&#34;OpenRouter&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:host</span> <span style="color:#ba2121">&#34;openrouter.ai/api&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:key</span> (<span style="color:#008000">lambda</span> () (<span style="color:#19177c">my/password-store-get-field</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;My_Online/Accounts/openrouter&#34;</span> <span style="color:#ba2121">&#34;api-key&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:stream</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:models</span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;anthropic/claude-3.5-haiku&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gptel--known-backends</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">cell</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#00f">equal</span> (<span style="color:#00f">car</span> <span style="color:#19177c">cell</span>) <span style="color:#ba2121">&#34;ChatGPT&#34;</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">gptel--known-backends</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">gptel-response-prefix-alist</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#19177c">markdown-mode</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;[Response] &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-mode</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;*** Response: &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">text-mode</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;[Response]&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">gptel-mode-map</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#00f">insert</span> <span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;C-&lt;return&gt;&#34;</span> <span style="color:#19177c">&#39;gptel-send</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-o&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">gptel-menu</span>))
</span></span></code></pre></div><h5 id="ellama">ellama</h5>
<p><a href="https://github.com/s-kostyaev/ellama">ellama</a> provides commands that feed things from Emacs buffers into LLMs with various prompts.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ellama</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ellama-language</span> <span style="color:#ba2121">&#34;English&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:defer</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;llm-ollama</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; I&#39;ve looked for this option for 1.5 hours</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ellama-long-lines-length</span> <span style="color:#666">100000</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ellama-provider</span> (<span style="color:#19177c">make-llm-ollama</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:chat-model</span> <span style="color:#ba2121">&#34;qwen2.5:32b&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:embedding-model</span> <span style="color:#ba2121">&#34;qwen2.5:32b&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ellama-coding-provider</span> (<span style="color:#19177c">make-llm-ollama</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:chat-model</span> <span style="color:#ba2121">&#34;qwen2.5-coder:32b&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:embedding-model</span> <span style="color:#ba2121">&#34;qwen2.5-coder:32b&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ellama-providers</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#ba2121">&#34;llama3.1:8b&#34;</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#19177c">make-llm-ollama</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:chat-model</span> <span style="color:#ba2121">&#34;llama3.1:latest&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:embedding-model</span> <span style="color:#ba2121">&#34;llama3.1:latest&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;phi4:latest&#34;</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#19177c">make-llm-ollama</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:chat-model</span> <span style="color:#ba2121">&#34;phi4:latest&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:embedding-model</span> <span style="color:#ba2121">&#34;phi4:latest&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;qwen2.5:32b&#34;</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#19177c">make-llm-ollama</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:chat-model</span> <span style="color:#ba2121">&#34;qwen2.5:32b&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:embedding-model</span> <span style="color:#ba2121">&#34;qwen2.5:32b&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;qwen2.5-coder:32b&#34;</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#19177c">make-llm-ollama</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:chat-model</span> <span style="color:#ba2121">&#34;qwen2.5-coder:32b&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:embedding-model</span> <span style="color:#ba2121">&#34;qwen2.5-coder:32b&#34;</span>)))))
</span></span></code></pre></div><p>The keybindings are a bit crazy to use even with <code>which-key</code>, so here goes transient.el.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;ellama</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">transient-define-prefix</span> <span style="color:#19177c">my/ellama-transient</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Ellama actions.&#34;</span>
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;General&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;a&#34;</span> <span style="color:#ba2121">&#34;Chat&#34;</span> <span style="color:#19177c">ellama-chat</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Code&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ca&#34;</span> <span style="color:#ba2121">&#34;Add&#34;</span> <span style="color:#19177c">ellama-code-add</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;cc&#34;</span> <span style="color:#ba2121">&#34;Complete&#34;</span> <span style="color:#19177c">ellama-code-complete</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ce&#34;</span> <span style="color:#ba2121">&#34;Edit&#34;</span> <span style="color:#19177c">ellama-code-edit</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;cr&#34;</span> <span style="color:#ba2121">&#34;Review&#34;</span> <span style="color:#19177c">ellama-code-review</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ci&#34;</span> <span style="color:#ba2121">&#34;Improve&#34;</span> <span style="color:#19177c">ellama-code-improve</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Natural Language&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;np&#34;</span> <span style="color:#ba2121">&#34;Proof-read&#34;</span> <span style="color:#19177c">my/ellama-proof-read</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Formatting&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ff&#34;</span> <span style="color:#ba2121">&#34;Format&#34;</span> <span style="color:#19177c">ellama-make-format</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;fm&#34;</span> <span style="color:#ba2121">&#34;List&#34;</span> <span style="color:#19177c">ellama-make-list</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ft&#34;</span> <span style="color:#ba2121">&#34;Table&#34;</span> <span style="color:#19177c">ellama-make-table</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Explain &amp; Summarize&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;es&#34;</span> <span style="color:#ba2121">&#34;Summarize&#34;</span> <span style="color:#19177c">ellama-summarize</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ea&#34;</span> <span style="color:#ba2121">&#34;Ask about&#34;</span> <span style="color:#19177c">ellama-ask-about</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;es&#34;</span> <span style="color:#ba2121">&#34;Send to chat&#34;</span> <span style="color:#19177c">ellama-ask-selection</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ew&#34;</span> <span style="color:#ba2121">&#34;Word definition&#34;</span> <span style="color:#19177c">ellama-define-word</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Context&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;xb&#34;</span> <span style="color:#ba2121">&#34;Add buffer&#34;</span> <span style="color:#19177c">ellama-context-add-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;xf&#34;</span> <span style="color:#ba2121">&#34;Add file&#34;</span> <span style="color:#19177c">ellama-context-add-file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;xi&#34;</span> <span style="color:#ba2121">&#34;Add info&#34;</span> <span style="color:#19177c">ellama-context-add-info-node</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;xs&#34;</span> <span style="color:#ba2121">&#34;Add selection&#34;</span> <span style="color:#19177c">ellama-context-add-selection</span>)]
</span></span><span style="display:flex;"><span> [<span style="color:#ba2121">&#34;Settings &amp; Sessions&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:class</span> <span style="color:#19177c">transient-row</span>
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;sp&#34;</span> <span style="color:#ba2121">&#34;Provider&#34;</span> <span style="color:#19177c">ellama-provider-select</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;ss&#34;</span> <span style="color:#ba2121">&#34;Session&#34;</span> <span style="color:#19177c">ellama-session-switch</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;sr&#34;</span> <span style="color:#ba2121">&#34;Rename ression&#34;</span> <span style="color:#19177c">ellama-session-rename</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">&#34;sd&#34;</span> <span style="color:#ba2121">&#34;Delete session&#34;</span> <span style="color:#19177c">ellama-session-remove</span>)]))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ellama</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;ellama</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">call-interactively</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/ellama-transient</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;aie&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/ellama</span>)
</span></span></code></pre></div><h5 id="change-natural-language-text-and-diff-against-the-results">Change natural-language text &amp; diff against the results</h5>
<p>One pattern I often want is to change the given text and compare it to the old version.</p>
<p>LLMs aren&rsquo;t perfectly good at saying what changes they have done, so the pattern here is to query the model and show the changed text together with the diff.</p>
<p>So first, I need to diff two strings.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/diff-strings</span> (<span style="color:#19177c">str1</span> <span style="color:#19177c">str2</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">file1</span> (<span style="color:#19177c">make-temp-file</span> <span style="color:#ba2121">&#34;diff1&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">file2</span> (<span style="color:#19177c">make-temp-file</span> <span style="color:#ba2121">&#34;diff2&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unwind-protect</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-file</span> <span style="color:#19177c">file1</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#19177c">str1</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-file</span> <span style="color:#19177c">file2</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#19177c">str2</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">diff-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">diff-no-select</span> <span style="color:#19177c">file1</span> <span style="color:#19177c">file2</span> (<span style="color:#19177c">diff-switches</span>) <span style="color:#800">t</span> (<span style="color:#00f">current-buffer</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">font-lock-fontify-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-string</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">delete-file</span> <span style="color:#19177c">file1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">delete-file</span> <span style="color:#19177c">file2</span>))))
</span></span></code></pre></div><p>And the function to do the prompting iself. Llama tends to output in Markdown, so I use a function from Ellama to convert the output back to Org-mode, if necessary.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ellama-proof-read--display</span> (<span style="color:#19177c">text</span> <span style="color:#19177c">is-org-mode</span> <span style="color:#19177c">prompt</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">llm-chat-async</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">ellama-provider</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">llm-make-chat-prompt</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#19177c">prompt</span> <span style="color:#19177c">text</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">response</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">parts</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">response</span> <span style="color:#ba2121">&#34;-FIXED TEXT ENDS-&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">changed-text</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">parts</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">comments</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">parts</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">buffer</span> (<span style="color:#19177c">generate-new-buffer</span> <span style="color:#ba2121">&#34;*ellama-diff*&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">is-org-mode</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">changed-text</span> (<span style="color:#19177c">ellama--translate-markdown-to-org-filter</span> <span style="color:#19177c">changed-text</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">text-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">propertize</span> <span style="color:#ba2121">&#34;Changed text:\n&#34;</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;transient-heading</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-trim</span> <span style="color:#19177c">changed-text</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\n\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">propertize</span> <span style="color:#ba2121">&#34;Comments:\n&#34;</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;transient-heading</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-trim</span> <span style="color:#19177c">comments</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\n\n&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">propertize</span> <span style="color:#ba2121">&#34;Diff:\n&#34;</span> <span style="color:#19177c">&#39;face</span> <span style="color:#19177c">&#39;transient-heading</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/diff-strings</span> <span style="color:#19177c">text</span> <span style="color:#19177c">changed-text</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">display-buffer</span> <span style="color:#19177c">buffer</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">err</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Error: %s&#34;</span> <span style="color:#19177c">err</span>))))
</span></span></code></pre></div><p>As for prompts, I like the following prompt to proof-read text. It&rsquo;s pretty conservative, but good for fixing typos, missing commas, articles, etc.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/ellama-proof-read-prompt</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Proof-read the following text. Follow these rules:
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- Fix all grammar errors
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- Keep the original style and punctuation, including linebreaks.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- Use British spelling
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- Do not replace &#39; with , and do not touch other such symbols
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Output the following and nothing else:
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- The fixed text
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- The string -FIXED TEXT ENDS-
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- List of found errors
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- List of style suggestions
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">%s&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ellama--text</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">region-active-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-substring-no-properties</span> (<span style="color:#00f">region-beginning</span>) (<span style="color:#00f">region-end</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-substring-no-properties</span> (<span style="color:#00f">point-min</span>) (<span style="color:#00f">point-max</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/ellama-proof-read</span> (<span style="color:#19177c">text</span> <span style="color:#19177c">is-org-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> (<span style="color:#19177c">my/ellama--text</span>) (<span style="color:#19177c">derived-mode-p</span> <span style="color:#19177c">&#39;org-mode</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;ellama</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/ellama-proof-read--display</span> <span style="color:#19177c">text</span> <span style="color:#19177c">is-org-mode</span> <span style="color:#19177c">my/ellama-proof-read-prompt</span>))
</span></span></code></pre></div><h4 id="podcast-transcripts">Podcast transcripts</h4>
<p>In my experience, finding something in a podcast can be particularly troublesome. For instance, at times, I want to refer to a specific line in the podcast to make an <a href="https://github.com/org-roam/org-roam">org-roam</a> node, and I need to check if I got that part right. And I have no reasonable way to get there because audio files, in themselves, don&rsquo;t allow for <a href="https://en.wikipedia.org/wiki/Random_access">random access</a>, i.e. there are no &ldquo;landmarks&rdquo; that point to a particular portion of the file. At least if nothing like a transcript is available.</p>
<p>For obvious reasons, podcasts rarely ship with transcripts. So in this <del>post</del> section I&rsquo;ll be using a speech recognition engine to make up for that. The general idea is to obtain the podcast information from <a href="https://github.com/skeeto/elfeed">elfeed</a>, process it with <a href="https://github.com/openai/whisper">OpenAI Whisper</a> and feed it to <a href="https://github.com/sachac/subed">subed</a> to control the playback in <a href="https://mpv.io/">MPV</a>.</p>
<p>Edit <span class="timestamp-wrapper"><span class="timestamp">&lt;2022-10-08 Sat&gt;</span></span>: Changed <a href="https://github.com/alphacep/vosk-api">vosk-api</a> to OpenAI Whisper.</p>
<p>Edit <span class="timestamp-wrapper"><span class="timestamp">&lt;2024-11-10 Sun&gt;</span></span>: Moved from elfeed to Not-an-AI, reworked to use <a href="https://github.com/Vaibhavs10/insanely-fast-whisper">insanely-fast-whisper</a>.</p>
<h5 id="whisper">Whisper</h5>
<p><a href="https://github.com/openai/whisper">OpenAI Whisper</a> is an amazing speech recognition toolkit.</p>
<p>I previously used <a href="https://github.com/ggerganov/whisper.cpp">whisper.cpp</a> by Georgi Gerganov, but have switched to <a href="https://github.com/Vaibhavs10/insanely-fast-whisper">insanely-fast-whisper</a> since it&rsquo;s easier to run on GPU, it doesn&rsquo;t require converting everything to WAV, and it includes speaker diarization capabilities.</p>
<p>One disadvantage is that it doesn&rsquo;t produce human-readable output by default, so I make my own.</p>
<table>
<thead>
<tr>
<th>Guix dependency</th>
<th>Disabled</th>
</tr>
</thead>
<tbody>
<tr>
<td>whisper-cpp</td>
<td>t</td>
</tr>
</tbody>
</table>
<h5 id="running-it-from-emacs">Running it from Emacs</h5>
<p>First, some functions to process the output. These take a JSON formed by <code>insanely-fast-whisper</code> and create a set of files:</p>
<ul>
<li>a TXT file with the full text;</li>
<li>a VTT file;</li>
<li>if speaker info is available:
<ul>
<li>a TXT file with speaker tags;</li>
<li>a VTT file with speaker tags.</li>
</ul>
</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/whisper--format-vtt-seconds</span> (<span style="color:#19177c">seconds</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">numberp</span> <span style="color:#19177c">seconds</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">hours</span> (<span style="color:#00f">/</span> (<span style="color:#00f">floor</span> <span style="color:#19177c">seconds</span>) (<span style="color:#00f">*</span> <span style="color:#666">60</span> <span style="color:#666">60</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">minutes</span> (<span style="color:#00f">/</span> (<span style="color:#00f">-</span> (<span style="color:#00f">floor</span> <span style="color:#19177c">seconds</span>) (<span style="color:#00f">*</span> <span style="color:#19177c">hours</span> <span style="color:#666">60</span> <span style="color:#666">60</span>)) <span style="color:#666">60</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">sec</span> (<span style="color:#00f">%</span> (<span style="color:#00f">floor</span> <span style="color:#19177c">seconds</span>) <span style="color:#666">60</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ms</span> (<span style="color:#00f">floor</span> (<span style="color:#00f">*</span> <span style="color:#666">1000</span> (<span style="color:#00f">-</span> <span style="color:#19177c">seconds</span> (<span style="color:#00f">floor</span> <span style="color:#19177c">seconds</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%.2d:%.2d:%.2d.%.3d&#34;</span> <span style="color:#19177c">hours</span> <span style="color:#19177c">minutes</span> <span style="color:#19177c">sec</span> <span style="color:#19177c">ms</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/whisper--save-chucks-vtt</span> (<span style="color:#19177c">path</span> <span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-file</span> <span style="color:#19177c">path</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;WEBVTT\n\n&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">chunk</span> <span style="color:#19177c">across</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;chunks</span> <span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">start</span> <span style="color:#00f">=</span> (<span style="color:#19177c">my/whisper--format-vtt-seconds</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">aref</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;timestamp</span> <span style="color:#19177c">chunk</span>) <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">end</span> <span style="color:#00f">=</span> (<span style="color:#19177c">my/whisper--format-vtt-seconds</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">aref</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;timestamp</span> <span style="color:#19177c">chunk</span>) <span style="color:#666">1</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">insert</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%s --&gt; %s&#34;</span> <span style="color:#19177c">start</span> <span style="color:#19177c">end</span>) <span style="color:#ba2121">&#34;\n&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">insert</span> (<span style="color:#19177c">string-trim</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;text</span> <span style="color:#19177c">chunk</span>)) <span style="color:#ba2121">&#34;\n\n&#34;</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/whisper--save-speakers-vtt</span> (<span style="color:#19177c">path</span> <span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-file</span> <span style="color:#19177c">path</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;WEBVTT\n\n&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">chunk</span> <span style="color:#19177c">across</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;speakers</span> <span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">start</span> <span style="color:#00f">=</span> (<span style="color:#19177c">my/whisper--format-vtt-seconds</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">aref</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;timestamp</span> <span style="color:#19177c">chunk</span>) <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">end</span> <span style="color:#00f">=</span> (<span style="color:#19177c">my/whisper--format-vtt-seconds</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">aref</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;timestamp</span> <span style="color:#19177c">chunk</span>) <span style="color:#666">1</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">insert</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%s --&gt; %s&#34;</span> <span style="color:#19177c">start</span> <span style="color:#19177c">end</span>) <span style="color:#ba2121">&#34;\n&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">insert</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;&lt;v %s&gt;&#34;</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;speaker</span> <span style="color:#19177c">chunk</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-trim</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;text</span> <span style="color:#19177c">chunk</span>)) <span style="color:#ba2121">&#34;\n\n&#34;</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/whisper--save-speakers-txt</span> (<span style="color:#19177c">path</span> <span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-file</span> <span style="color:#19177c">path</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">with</span> <span style="color:#19177c">prev-speaker</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">chunk</span> <span style="color:#19177c">across</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;speakers</span> <span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">speaker</span> <span style="color:#00f">=</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;speaker</span> <span style="color:#19177c">chunk</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#19177c">not</span> (<span style="color:#00f">equal</span> <span style="color:#19177c">speaker</span> <span style="color:#19177c">prev-speaker</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">prev-speaker</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">fill-region</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">line-beginning-position</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">line-end-position</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;\n\n&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;[%s]&#34;</span> <span style="color:#19177c">speaker</span>) <span style="color:#ba2121">&#34;\n&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">prev-speaker</span> <span style="color:#19177c">speaker</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">insert</span> (<span style="color:#19177c">string-trim</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;text</span> <span style="color:#19177c">chunk</span>)) <span style="color:#ba2121">&#34; &#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">fill-region</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">line-beginning-position</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">line-end-position</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/whisper--process-output</span> (<span style="color:#19177c">transcript-path</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">data</span> (<span style="color:#19177c">json-read-file</span> <span style="color:#19177c">transcript-path</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;text</span> <span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-file</span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">file-name-sans-extension</span> <span style="color:#19177c">transcript-path</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;.txt&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#19177c">string-trim</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;text</span> <span style="color:#19177c">data</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">do-auto-fill</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">seq-empty-p</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;speakers</span> <span style="color:#19177c">data</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/whisper--save-speakers-vtt</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> (<span style="color:#19177c">file-name-sans-extension</span> <span style="color:#19177c">transcript-path</span>) <span style="color:#ba2121">&#34;-spk.vtt&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">data</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/whisper--save-speakers-txt</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> (<span style="color:#19177c">file-name-sans-extension</span> <span style="color:#19177c">transcript-path</span>) <span style="color:#ba2121">&#34;-spk.txt&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">data</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/whisper--save-chucks-vtt</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> (<span style="color:#19177c">file-name-sans-extension</span> <span style="color:#19177c">transcript-path</span>) <span style="color:#ba2121">&#34;.vtt&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">data</span>)))
</span></span></code></pre></div><p>Then run the program itself with <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Asynchronous-Processes.html">asyncronous processes</a>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/whisper-path</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;/home/pavel/micromamba/envs/insanely-fast-whisper/bin/insanely-fast-whisper&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/invoke-whisper</span> (<span style="color:#19177c">input</span> <span style="color:#19177c">output-dir</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">language</span> <span style="color:#19177c">num-speakers</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">read-file-name</span> <span style="color:#ba2121">&#34;Input file:&#34;</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">read-directory-name</span> <span style="color:#ba2121">&#34;Output-directory: &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">lang</span> (<span style="color:#00f">read-string</span> <span style="color:#ba2121">&#34;Language (optional): &#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">lang</span>) <span style="color:#800">nil</span> <span style="color:#19177c">lang</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">num</span> (<span style="color:#19177c">read-number</span> <span style="color:#ba2121">&#34;Number of speakers (optional): &#34;</span> <span style="color:#666">0</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">&gt;</span> <span style="color:#19177c">num</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">number-to-string</span> <span style="color:#19177c">num</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">transcript-path</span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">expand-file-name</span> (<span style="color:#00f">file-name-as-directory</span> <span style="color:#19177c">output-dir</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">file-name-base</span> <span style="color:#19177c">input</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;.json&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">args</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#ba2121">&#34;--file-name&#34;</span> <span style="color:#666">,</span>(<span style="color:#00f">expand-file-name</span> <span style="color:#19177c">input</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;--transcript-path&#34;</span> <span style="color:#666">,</span><span style="color:#19177c">transcript-path</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;--hf-token&#34;</span> <span style="color:#666">,</span>(<span style="color:#19177c">my/password-store-get-field</span> <span style="color:#ba2121">&#34;My_Online/Accounts/huggingface.co&#34;</span> <span style="color:#ba2121">&#34;token&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">,@</span>(<span style="color:#008000">when</span> <span style="color:#19177c">language</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#ba2121">&#34;--language&#34;</span> <span style="color:#666">,</span><span style="color:#19177c">language</span>))
</span></span><span style="display:flex;"><span> <span style="color:#666">,@</span>(<span style="color:#008000">when</span> <span style="color:#19177c">num-speakers</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#ba2121">&#34;--num-speakers&#34;</span> <span style="color:#666">,</span><span style="color:#19177c">num-speakers</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">buffer</span> (<span style="color:#19177c">generate-new-buffer</span> <span style="color:#ba2121">&#34;*whisper*&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">proc</span> (<span style="color:#00f">apply</span> <span style="color:#00f">#&#39;start-process</span> <span style="color:#ba2121">&#34;whisper&#34;</span> <span style="color:#19177c">buffer</span> <span style="color:#19177c">my/whisper-path</span> <span style="color:#19177c">args</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-process-sentinel</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">proc</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">process</span> <span style="color:#19177c">_msg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">status</span> (<span style="color:#00f">process-status</span> <span style="color:#19177c">process</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">code</span> (<span style="color:#00f">process-exit-status</span> <span style="color:#19177c">process</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span> ((<span style="color:#008000">and</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">status</span> <span style="color:#19177c">&#39;exit</span>) (<span style="color:#00f">=</span> <span style="color:#19177c">code</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/whisper--process-output</span> <span style="color:#19177c">transcript-path</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">notifications-notify</span> <span style="color:#008000">:body</span> <span style="color:#ba2121">&#34;Audio conversion completed&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:title</span> <span style="color:#ba2121">&#34;Whisper&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">kill-buffer</span> (<span style="color:#00f">process-buffer</span> <span style="color:#19177c">process</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">or</span> (<span style="color:#008000">and</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">status</span> <span style="color:#19177c">&#39;exit</span>) (<span style="color:#00f">&gt;</span> <span style="color:#19177c">code</span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">eq</span> <span style="color:#19177c">status</span> <span style="color:#19177c">&#39;signal</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">err</span> (<span style="color:#008000">with-current-buffer</span> (<span style="color:#00f">process-buffer</span> <span style="color:#19177c">process</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-string</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Error in Whisper: %s&#34;</span> <span style="color:#19177c">err</span>)))))))))
</span></span></code></pre></div><p>If run interactively, the defined function prompts for paths to both files.</p>
<p>The process sentinel sends a <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Desktop-Notifications.html">desktop notification</a> because it&rsquo;s a bit more noticeable than <code>message</code>, and the process is expected to take some time.</p>
<h5 id="integrating-with-elfeed">Integrating with elfeed</h5>
<p>To actually run the function from the section above, we need to download the file in question.</p>
<p>The <code>whisper</code> executable, given the file <code>&lt;file&gt;.&lt;extension&gt;</code>, creates files named <code>&lt;file&gt;.vtt</code>, <code>&lt;file&gt;.srt</code>, <code>&lt;file&gt;.txt</code>. So first we need to save the file under the correct name.</p>
<p>I use a library called <a href="https://github.com/tkf/emacs-request">request.el</a> to download files elsewhere, so I&rsquo;ll re-use it here. You can just as well invoke <code>curl</code> or <code>wget</code> via a asynchronous process.</p>
<p>This function downloads the file to a non-temporary folder, which is <code>~/.elfeed/podcast-files/</code> if you didn&rsquo;t move the elfeed database. That is so because a permanently downloaded file works better for the next section.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;elfeed</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defvar</span> <span style="color:#19177c">my/elfeed-whisper-podcast-files-directory</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">elfeed-db-directory</span> <span style="color:#ba2121">&#34;/podcast-files/&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/elfeed-whisper-get-transcript-new</span> (<span style="color:#19177c">entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> <span style="color:#19177c">elfeed-show-entry</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">url</span> (<span style="color:#19177c">caar</span> (<span style="color:#19177c">elfeed-entry-enclosures</span> <span style="color:#19177c">entry</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">file-name</span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-ref-id</span> (<span style="color:#19177c">elfeed-entry-content</span> <span style="color:#19177c">entry</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">file-name-extension</span> <span style="color:#19177c">url</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">file-path</span> (<span style="color:#00f">expand-file-name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/elfeed-whisper-podcast-files-directory</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">file-name</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Download started&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">my/elfeed-whisper-podcast-files-directory</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mkdir</span> <span style="color:#19177c">my/elfeed-whisper-podcast-files-directory</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">request</span> <span style="color:#19177c">url</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:type</span> <span style="color:#ba2121">&#34;GET&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:encoding</span> <span style="color:#19177c">&#39;binary</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:complete</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-function</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#008000">&amp;key</span> <span style="color:#19177c">data</span> <span style="color:#008000">&amp;allow-other-keys</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">coding-system-for-write</span> <span style="color:#19177c">&#39;binary</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">write-region-annotate-functions</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">write-region-post-annotation-function</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">write-region</span> <span style="color:#19177c">data</span> <span style="color:#800">nil</span> <span style="color:#19177c">file-path</span> <span style="color:#800">nil</span> <span style="color:#008000">:silent</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Conversion started&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/invoke-whisper</span> <span style="color:#19177c">file-path</span> <span style="color:#19177c">my/elfeed-srt-dir</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:error</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-function</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#008000">&amp;key</span> <span style="color:#19177c">error-thrown</span> <span style="color:#008000">&amp;allow-other-keys</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Error!: %S&#34;</span> <span style="color:#19177c">error-thrown</span>))))))
</span></span></code></pre></div><p>I also experimented with a bunch of options to write binary data in Emacs, of which the way with <code>write-region</code> (as implemented in <a href="https://github.com/rejeep/f.el">f.el</a>) seems to be the fastest. <a href="https://emacs.stackexchange.com/questions/59449/how-do-i-save-raw-bytes-into-a-file">This thread on StackExchange</a> 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 <code>seq-doseq</code> takes at least a few seconds.</p>
<p>As <code>my/invoke-whisper</code> creates multiple files, here&rsquo;s a function to select related files:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/elfeed-show-related-files</span> (<span style="color:#19177c">entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> <span style="color:#19177c">elfeed-show-entry</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">files</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>) (<span style="color:#00f">cons</span> (<span style="color:#19177c">file-name-extension</span> <span style="color:#19177c">file</span>) <span style="color:#19177c">file</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> (<span style="color:#19177c">literal</span> (<span style="color:#19177c">elfeed-ref-id</span> (<span style="color:#19177c">elfeed-entry-content</span> <span style="color:#19177c">entry</span>))) <span style="color:#ba2121">&#34;.&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">file</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-files</span> <span style="color:#19177c">my/elfeed-srt-dir</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">find-file-other-window</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/elfeed-srt-dir</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">completing-read</span> <span style="color:#ba2121">&#34;File: &#34;</span> <span style="color:#19177c">files</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">files</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;equal</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">elfeed-show-entry</span> <span style="color:#19177c">entry</span>))))
</span></span></code></pre></div><p>Finally, we need a function to show the transcript if it exists or invoke <code>my/elfeed-whisper-get-transcript-new</code> if it doesn&rsquo;t. And this is the function that we&rsquo;ll call from an <code>elfeed-entry</code> buffer.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/elfeed-whisper-get-transcript</span> (<span style="color:#19177c">entry</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Retrieve transcript for the enclosure of the current elfeed ENTRY.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> <span style="color:#19177c">elfeed-show-entry</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">enclosure</span> (<span style="color:#19177c">caar</span> (<span style="color:#19177c">elfeed-entry-enclosures</span> <span style="color:#19177c">entry</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">enclosure</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No enclosure found!&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">srt-path</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">my/elfeed-srt-dir</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-ref-id</span> (<span style="color:#19177c">elfeed-entry-content</span> <span style="color:#19177c">entry</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;.srt&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">srt-path</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">buffer</span> (<span style="color:#19177c">find-file-other-window</span> <span style="color:#19177c">srt-path</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">elfeed-show-entry</span> <span style="color:#19177c">entry</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/elfeed-whisper-get-transcript-new</span> <span style="color:#19177c">entry</span>)))))
</span></span></code></pre></div><h5 id="integrating-with-subed">Integrating with subed</h5>
<p>Now that we&rsquo;ve produced a <code>.srt</code> file, we can use a package called <a href="https://github.com/sachac/subed">subed</a> to control the playback, as I have done in the YouTube section.</p>
<p>By the way, this wasn&rsquo;t the most straightforward thing to figure out, because the MPV window doesn&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.</p>
<p>With that in mind, here&rsquo;s a function to launch MPV from the buffer generated by <code>my/elfeed-whisper-get-transcript</code>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/elfeed-whisper-subed</span> (<span style="color:#19177c">entry</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Run MPV for the current Whisper-generated subtitles file.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">ENTRY is an instance of </span><span style="color:#19177c">`elfeed-entry&#39;</span><span style="color:#ba2121">.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> <span style="color:#19177c">elfeed-show-entry</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">entry</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No entry!&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">derived-mode-p</span> <span style="color:#19177c">&#39;subed-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Not subed mode!&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">subed-mpv-video-file</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">expand-file-name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">my/elfeed-whisper-podcast-files-directory</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/get-file-name-from-url</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">caar</span> (<span style="color:#19177c">elfeed-entry-enclosures</span> <span style="color:#19177c">entry</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">subed-mpv--play</span> <span style="color:#19177c">subed-mpv-video-file</span>))
</span></span></code></pre></div><p>After running <code>M-x my/elfeed-whisper-subed</code>, run <code>M-x subed-toggle-loop-over-current-subtitle</code> (<code>C-c C-l</code>), because somehow it&rsquo;s turned on by default, and <code>M-x subed-toggle-pause-while-typing</code> (<code>C-c C-p</code>), because sometimes this made my instance of MPV lag.</p>
<p>After that, <code>M-x subed-mpv-toggle-pause</code> should start the playback, which you can control by moving the cursor in the buffer.</p>
<p>You can also run <code>M-x subed-toggle-sync-point-to-player</code> (<code>C-c .</code>) to toggle syncing the point in the buffer to the currently played subtitle (this automatically gets disabled when you switch buffers).</p>
<p>Running <code>M-x subed-toggle-sync-player-to-point</code> (<code>C-c ,</code>) 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&rsquo;t available.</p>
<h5 id="running-it-for-internet-files">Running it for Internet Files</h5>
<p>And since lately I don&rsquo;t listen to podcasts via elfeed that much, I also want a function that runs whisper on random Internet files.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/whisper-url</span> (<span style="color:#19177c">url</span> <span style="color:#19177c">file-name</span> <span style="color:#19177c">output-dir</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">language</span> <span style="color:#19177c">num-speakers</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#00f">read-from-minibuffer</span> <span style="color:#ba2121">&#34;URL: &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">read-from-minibuffer</span> <span style="color:#ba2121">&#34;File name: &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">read-directory-name</span> <span style="color:#ba2121">&#34;Output directory: &#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">lang</span> (<span style="color:#00f">read-string</span> <span style="color:#ba2121">&#34;Language (optional): &#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">lang</span>) <span style="color:#800">nil</span> <span style="color:#19177c">lang</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">num</span> (<span style="color:#19177c">read-number</span> <span style="color:#ba2121">&#34;Number of speakers (optional): &#34;</span> <span style="color:#666">0</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">&gt;</span> <span style="color:#19177c">num</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">number-to-string</span> <span style="color:#19177c">num</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">file-path</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">output-dir</span> <span style="color:#19177c">file-name</span> <span style="color:#ba2121">&#34;.&#34;</span> (<span style="color:#19177c">file-name-extension</span> <span style="color:#19177c">url</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Download started&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">request</span> <span style="color:#19177c">url</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:type</span> <span style="color:#ba2121">&#34;GET&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:encoding</span> <span style="color:#19177c">&#39;binary</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:complete</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-function</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#008000">&amp;key</span> <span style="color:#19177c">data</span> <span style="color:#008000">&amp;allow-other-keys</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">coding-system-for-write</span> <span style="color:#19177c">&#39;binary</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">write-region-annotate-functions</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">write-region-post-annotation-function</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">write-region</span> <span style="color:#19177c">data</span> <span style="color:#800">nil</span> <span style="color:#19177c">file-path</span> <span style="color:#800">nil</span> <span style="color:#008000">:silent</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Conversion started&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/invoke-whisper</span> <span style="color:#19177c">file-path</span> <span style="color:#19177c">output-dir</span> <span style="color:#19177c">language</span> <span style="color:#19177c">num-speakers</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:error</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-function</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#008000">&amp;key</span> <span style="color:#19177c">error-thrown</span> <span style="color:#008000">&amp;allow-other-keys</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Error!: %S&#34;</span> <span style="color:#19177c">error-thrown</span>))))))
</span></span></code></pre></div><h5 id="some-observations">Some observations</h5>
<p>So, the functions above work for my purposes.</p>
<p>Vosk API works much faster than Whisper. The smallest Vosk model requires ~10 times less than the playback time, and even the <code>tiny.en</code> Whisper model on my PC requires maybe 1.2x playback time.</p>
<p>However, the quality of the output for Whisper is just so much better so I consider it to be worth the wait. Even with the <code>tiny</code> model, the transcript is almost perfect, provided that the audio is of reasonable quality.</p>
<h3 id="declarative-filesystem-management">Declarative filesystem management</h3>
<p>My filesystem is, shall we say, not the most orderly place.</p>
<center>
<iframe src="https://emacs.ch/@sqrtminusone/110514686718545191/embed" class="mastodon-embed" style="max-width: 100%; border: 0" width="500" allowfullscreen="allowfullscreen"></iframe><script src="https://emacs.ch/embed.js" async="async"></script>
</center>
<p>It&rsquo;s been somewhat messy, and messy in different ways across my three machines. For instance, my laptop had work projects in <code>~/Code/Job</code>, my work machine had just <code>~/Code</code>, and so forth.</p>
<p>Strangely, I couldn&rsquo;t find and existing solution to that problem. Surely, I can&rsquo;t be the only one facing that issue, can I?</p>
<p>Fortunately, I&rsquo;m well-acquainted with (make-yourself-a) Swiss Army Knife of computing called <a href="https://www.gnu.org/software/emacs/">Emacs</a>, so&hellip; below is my attempt to make something of it. And another addition to the already substantial list of my Emacs uses.</p>
<h4 id="idea">Idea</h4>
<p>So, I decided to try declarative filesystem management.</p>
<p>At the core is my work-in-progress adaptation of <a href="https://johnnydecimal.com/">Johnny.Decimal</a>. Essentially, it suggests prefixing your folders with numbers like <code>12.34</code>, where:</p>
<ul>
<li>the first digit is the &ldquo;<a href="https://johnnydecimal.com/10-19-concepts/11-core/11.02-areas-and-categories/">category</a>&rdquo;;</li>
<li>the second digit is the &ldquo;<a href="https://johnnydecimal.com/10-19-concepts/11-core/11.02-areas-and-categories/">area</a>&rdquo;;</li>
<li>the last two digits are the <a href="https://johnnydecimal.com/10-19-concepts/11-core/11.03-ids/">ID</a>.</li>
</ul>
<p>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.</p>
<p>So, what I want is to:</p>
<ul>
<li>define a Jonny.Decimal-esque file tree in a single <a href="https://orgmode.org/">Org</a> file;</li>
<li>have different nodes of that file tree active on different machines, e.g. I don&rsquo;t want <a href="https://github.com/SqrtMinusOne?tab=repositories&amp;q=&amp;type=&amp;language=emacs+lisp&amp;sort=">my Emacs stuff</a> on my work machine;</li>
<li>use different tools to sync different nodes (currently <a href="https://git-scm.com/">git</a>, <a href="https://mega.nz/">MEGA</a>, and &ldquo;nothing&rdquo;).</li>
</ul>
<h5 id="folder-structure">Folder structure</h5>
<p>As I said, I tried (and still trying) to adapt the proposed scheme to better suit my needs. Here&rsquo;s a subset of my current tree:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>10-19 Code
</span></span><span style="display:flex;"><span> 10 [REDACTED]
</span></span><span style="display:flex;"><span> 10.02 Digital Schedule ; project root
</span></span><span style="display:flex;"><span> 10.03 Digital Trajectories ; project root
</span></span><span style="display:flex;"><span> 12 My Emacs Packages
</span></span><span style="display:flex;"><span> 12.01 lyrics-fetcher.el ; managed by git
</span></span><span style="display:flex;"><span> 12.02 pomm.el ; managed by git
</span></span><span style="display:flex;"><span> 15 Other Projects
</span></span><span style="display:flex;"><span> 15.04 ZMU_2022 ; I&#39;m done with this and don&#39;t need it on any machine
</span></span><span style="display:flex;"><span>20-29 Education
</span></span><span style="display:flex;"><span> 24 Publications ; the entrire area is managed by MEGA
</span></span><span style="display:flex;"><span> 24.Y20.01 [bibtex code]
</span></span><span style="display:flex;"><span> 24.Y20.02 [bibtex code]
</span></span><span style="display:flex;"><span> 26 Students
</span></span><span style="display:flex;"><span> 26.Y22.01 [student name]
</span></span><span style="display:flex;"><span>30-39 Life
</span></span><span style="display:flex;"><span> 32 org-mode
</span></span><span style="display:flex;"><span> 33 Library
</span></span></code></pre></div><p>The root of the tree is my <code>$HOME</code>. The entry at the third (or second) level can be either an entity itself (such as a git repository), or a &ldquo;project root&rdquo;.</p>
<p>In several places, I use year references (<code>Y20</code>) instead of the plain <code>AC.ID</code>. 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 (<code>SEM10</code>) for my undergraduate studies.</p>
<p>The project structure is more or less standard. Johnny.Decimal <a href="https://johnnydecimal.com/10-19-concepts/13-multiple-projects/13.01-introduction/">proposes</a> using <code>PRO.AC.ID</code> to manage multiple projects, but this doesn&rsquo;t seem to fit quite as well in my case. So I came up with the following:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>10.03 Digital Trajectories ; project root
</span></span><span style="display:flex;"><span> 10.03.A Artifacts ; managed by MEGA
</span></span><span style="display:flex;"><span> 10.03.A.04 library queries (Jan 23)
</span></span><span style="display:flex;"><span> 10.03.D Documents ; managed by MEGA
</span></span><span style="display:flex;"><span> 10.03.D.01 Initial design
</span></span><span style="display:flex;"><span> 10.03.R Repos
</span></span><span style="display:flex;"><span> 10.03.R.00 digital-trajectories-deploy ; managed by MEGA
</span></span><span style="display:flex;"><span> 10.03.R.01 digital-trajectories-backend ; managed by git
</span></span><span style="display:flex;"><span> 10.03.U Dumps ; managed by nothing, no need to sync this
</span></span></code></pre></div><p>I also use year references on the third level for courses I happen to teach across multiple academic years.</p>
<p>Perhaps this is too verbose (<code>10.03.R.01</code>), but it works for now.</p>
<h5 id="tools-choice">Tools choice</h5>
<p>As I mentioned earlier, my current options to manage a particular node are:</p>
<ul>
<li><a href="https://git-scm.com/">git</a>;</li>
<li><a href="https://mega.nz/">MEGA</a> - for files that don&rsquo;t fit into git, such as DOCX documents, photos, etc.;</li>
<li>&ldquo;nothing&rdquo; - for something that I don&rsquo;t need to sync across machines, e.g. database dumps.</li>
</ul>
<p>Another tool I considered was <a href="https://github.com/restic/restic">restic</a>. It&rsquo;s an interesting backup &amp; sync solution with built-in encryption, snapshots, etc.</p>
<p>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&rsquo;t be able to use the MEGA file-sharing features, which I occasionally want for document or photo folders. Hence, for now, I&rsquo;m more interested in synchronizing the file tree in MEGA with <a href="https://github.com/meganz/MEGAcmd">MEGAcmd</a> (and also clean up the mess up there).</p>
<p>Another interesting tool is <a href="https://rclone.org/">rclone</a>, 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&rsquo;t want.</p>
<h4 id="implementation">Implementation</h4>
<h5 id="dependencies">Dependencies</h5>
<p>We&rsquo;ll a package called <a href="https://github.com/daniel-ness/ini.el">ini.el</a> to parse INI files.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ini</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> <span style="color:#ba2121">&#34;\\.ini\\&#39;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;daniel-ness/ini.el&#34;</span>))
</span></span></code></pre></div><p>The rest is built into Emacs.</p>
<h4 id="org-tree">Org tree</h4>
<h5 id="tree-definitions">Tree definitions</h5>
<p>The root is my <code>$HOME</code> directory.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/index-root</span> (<span style="color:#00f">concat</span> (<span style="color:#19177c">getenv</span> <span style="color:#ba2121">&#34;HOME&#34;</span>) <span style="color:#ba2121">&#34;/&#34;</span>))
</span></span></code></pre></div><p>The org tree is located in my <code>org-mode</code> folder in a file called <code>index.org</code>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">&#39;org</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defvar</span> <span style="color:#19177c">my/index-file</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/misc/index.org&#34;</span>)))
</span></span></code></pre></div><p>Each &ldquo;area&rdquo; is an Org header with the <code>folder</code> tag; the Org hierarchy forms the file tree. A header can have the following properties:</p>
<ul>
<li><code>machine</code> - a list of hostnames for which the node is active (or <code>nil</code>)</li>
<li><code>kind</code> - <code>mega</code>, <code>git</code>, or <code>dummy</code></li>
<li><code>remote</code> - remote URL for <code>git</code></li>
<li><code>symlink</code> - in case the folder has to be symlinked somewhere else</li>
</ul>
<p>E.g. a part of the tree above:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-org" data-lang="org"><span style="display:flex;"><span><span style="color:#000080;font-weight:bold">*</span><span style="font-weight:bold"> 10-19 Code </span><span style="font-style:italic"> :folder:</span>
</span></span><span style="display:flex;"><span><span style="color:#800080;font-weight:bold">**</span> 10 [REDACTED]
</span></span><span style="display:flex;"><span><span style="color:#800080;font-weight:bold">***</span> 10.03 Digital Trajectories
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">:PROPERTIES:
</span></span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"></span><span style="color:#408080;font-style:italic">:machine: indigo eminence
</span></span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">:project: t
</span></span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"></span><span style="color:#408080;font-style:italic">:END:</span>
</span></span><span style="display:flex;"><span><span style="color:#800080;font-weight:bold">****</span> 10.03.A Artifacts
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">:PROPERTIES:
</span></span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"></span><span style="color:#408080;font-style:italic">:kind: mega
</span></span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"></span><span style="color:#408080;font-style:italic">:END:</span>
</span></span><span style="display:flex;"><span><span style="color:#800080;font-weight:bold">****</span> 10.03.D Documents
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">:PROPERTIES:
</span></span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"></span><span style="color:#408080;font-style:italic">:kind: mega
</span></span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"></span><span style="color:#408080;font-style:italic">:END:</span>
</span></span><span style="display:flex;"><span><span style="color:#800080;font-weight:bold">****</span> 10.03.R Repos
</span></span><span style="display:flex;"><span><span style="color:#800080;font-weight:bold">*****</span> 10.03.R.00 digital-trajectories-deploy
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">:PROPERTIES:
</span></span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"></span><span style="color:#408080;font-style:italic">:kind: mega
</span></span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"></span><span style="color:#408080;font-style:italic">:END:</span>
</span></span><span style="display:flex;"><span><span style="color:#800080;font-weight:bold">*****</span> 10.03.R.01 digital-trajectories-backend
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">:PROPERTIES:
</span></span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"></span><span style="color:#408080;font-style:italic">:kind: git
</span></span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">:remote: [REACTED]
</span></span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"></span><span style="color:#408080;font-style:italic">:END:</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#800080;font-weight:bold">****</span> 10.03.U Dumps
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">:PROPERTIES:
</span></span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"></span><span style="color:#408080;font-style:italic">:kind: dummy
</span></span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"></span><span style="color:#408080;font-style:italic">:END:</span>
</span></span></code></pre></div><h5 id="parse-tree">Parse tree</h5>
<p>So, let&rsquo;s parse the Org tree. This is done by recursively traversing the tree returned by <code>org-element-parse-buffer</code>.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--tree-get-recursive</span> (<span style="color:#19177c">heading</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">path</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Read the index tree recursively from HEADING.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">HEADING is an org-element of type </span><span style="color:#19177c">`headline&#39;</span><span style="color:#ba2121">.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">If PATH is provided, it is the path to the current node. If not
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">provided, it is assumed to be the root of the index.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The return value is an alist; see </span><span style="color:#19177c">`my/index--tree-get&#39;</span><span style="color:#ba2121"> for details.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">eq</span> (<span style="color:#19177c">org-element-type</span> <span style="color:#19177c">heading</span>) <span style="color:#19177c">&#39;headline</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> (<span style="color:#19177c">val</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">new-path</span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> <span style="color:#19177c">path</span> <span style="color:#19177c">my/index-root</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:raw-value</span> <span style="color:#19177c">heading</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;/&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let*</span> ((<span style="color:#19177c">children</span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-contents</span> <span style="color:#19177c">heading</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">e</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--tree-get-recursive</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">e</span> <span style="color:#19177c">new-path</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span> <span style="color:#00f">#&#39;identity</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">val</span>) <span style="color:#19177c">children</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let</span> ((<span style="color:#19177c">machine</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:MACHINE</span> <span style="color:#19177c">heading</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:machine</span> <span style="color:#19177c">val</span>) (<span style="color:#19177c">split-string</span> <span style="color:#19177c">machine</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let</span> ((<span style="color:#19177c">symlink</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:SYMLINK</span> <span style="color:#19177c">heading</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:symlink</span> <span style="color:#19177c">val</span>) <span style="color:#19177c">symlink</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:PROJECT</span> <span style="color:#19177c">heading</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:project</span> <span style="color:#19177c">val</span>) <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let*</span> ((<span style="color:#19177c">kind-str</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:KIND</span> <span style="color:#19177c">heading</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">kind</span> (<span style="color:#00f">intern</span> <span style="color:#19177c">kind-str</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:kind</span> <span style="color:#19177c">val</span>) <span style="color:#19177c">kind</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">equal</span> <span style="color:#19177c">kind</span> <span style="color:#19177c">&#39;git</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">remote</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:REMOTE</span> <span style="color:#19177c">heading</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">remote</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No remote for %s&#34;</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:name</span> <span style="color:#19177c">val</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:remote</span> <span style="color:#19177c">val</span>) <span style="color:#19177c">remote</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:name</span> <span style="color:#19177c">val</span>) (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:raw-value</span> <span style="color:#19177c">heading</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:path</span> <span style="color:#19177c">val</span>) <span style="color:#19177c">new-path</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">val</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--tree-get</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Read the index tree from the current org buffer.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The return value is a list of alists, each representing a
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">folder/node. Alists can have the following keys:
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- `:name&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- `:path&#39;
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- `:children&#39; - child nodes
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- `:machine&#39; - list of machines on which the node is active
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- `:symlink&#39; - a symlink to create
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- `:kind&#39; - one of \&#34;git\&#34;, \&#34;mega\&#34;, or \&#34;dummy\&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- `:remote&#39; - the remote to use for git nodes&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">tree</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-element-map</span> (<span style="color:#19177c">org-element-parse-buffer</span>) <span style="color:#19177c">&#39;headline</span> <span style="color:#00f">#&#39;identity</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">el</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">=</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:level</span> <span style="color:#19177c">el</span>) <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> <span style="color:#00f">#&#39;substring-no-properties</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:tags</span> <span style="color:#19177c">el</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;folder&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/index--tree-get-recursive</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">tree</span>))
</span></span></code></pre></div><h5 id="verify-tree">Verify tree</h5>
<p>I also want to make sure that I didn&rsquo;t mess up the numbers, i.e., didn&rsquo;t place <code>10.02</code> under <code>11</code>, and so on.</p>
<p>To do that, we first need to extract the number from the name:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--extact-number</span> (<span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Extract the number from the index NAME.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">NAME is a string. The number is the first sequence of digits, e.g.:
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- 10-19
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- 10.01
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- 10.01.Y22.01&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">save-match-data</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">string-match</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> (<span style="color:#00f">+</span> (<span style="color:#19177c">|</span> <span style="color:#19177c">num</span> <span style="color:#19177c">alpha</span> <span style="color:#ba2121">&#34;.&#34;</span> <span style="color:#ba2121">&#34;-&#34;</span>))) <span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">match-string</span> <span style="color:#666">0</span> <span style="color:#19177c">name</span>)))
</span></span></code></pre></div><p>Then, we can recursively verify the numbers:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/tree--verfify-recursive</span> (<span style="color:#19177c">elem</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">current</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Verify that ELEM is a valid tree element.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">CURRENT is the current number or name of the parent element.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">name</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:name</span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">number</span> (<span style="color:#19177c">my/index--extact-number</span> <span style="color:#19177c">name</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">number</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Can&#39;t find number: %s&#34;</span> <span style="color:#19177c">name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">and</span> (<span style="color:#00f">listp</span> <span style="color:#19177c">current</span>) (<span style="color:#19177c">not</span> (<span style="color:#00f">null</span> <span style="color:#19177c">current</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">seq-some</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">cand</span>) (<span style="color:#19177c">string-prefix-p</span> <span style="color:#19177c">cand</span> <span style="color:#19177c">name</span>)) <span style="color:#19177c">current</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Name: %s doesn&#39;t match: %s&#34;</span> <span style="color:#19177c">name</span> <span style="color:#19177c">current</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">stringp</span> <span style="color:#19177c">current</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">string-prefix-p</span> <span style="color:#19177c">current</span> <span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Name: %s doesn&#39;t match: %s&#34;</span> <span style="color:#19177c">name</span> <span style="color:#19177c">current</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">recur-value</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> (<span style="color:#00f">+</span> <span style="color:#19177c">num</span>) <span style="color:#ba2121">&#34;-&#34;</span> (<span style="color:#00f">+</span> <span style="color:#19177c">num</span>)) <span style="color:#19177c">number</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">borders</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">number</span> <span style="color:#ba2121">&#34;-&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">start</span> (<span style="color:#00f">string-to-number</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">borders</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">end</span> (<span style="color:#00f">string-to-number</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">borders</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">i</span> <span style="color:#19177c">from</span> <span style="color:#19177c">start</span> <span style="color:#19177c">to</span> (<span style="color:#00f">1-</span> <span style="color:#19177c">end</span>) <span style="color:#19177c">collect</span> (<span style="color:#00f">number-to-string</span> <span style="color:#19177c">i</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">number</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">e</span>) (<span style="color:#19177c">my/tree--verfify-recursive</span> <span style="color:#19177c">e</span> <span style="color:#19177c">recur-value</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">elem</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--tree-verify</span> (<span style="color:#19177c">tree</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Verify that TREE is a valid tree.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Return t if it is valid, otherwise raise an error.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">See </span><span style="color:#19177c">`my/index--tree-get&#39;</span><span style="color:#ba2121"> for the format of TREE.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/tree--verfify-recursive</span> <span style="color:#19177c">tree</span>))
</span></span></code></pre></div><h5 id="narrow-tree">Narrow tree</h5>
<p>Finally, we need to narrow the tree to only leave nodes that are active for the current machine.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--tree-narrow-recursive</span> (<span style="color:#19177c">elem</span> <span style="color:#19177c">machine</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Remove all children of ELEM that are not active on MACHINE.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">when-let</span> ((<span style="color:#19177c">elem-machines</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:machine</span> <span style="color:#19177c">elem</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">seq-some</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">elem-machine</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">string-equal</span> <span style="color:#19177c">elem-machine</span> <span style="color:#19177c">machine</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">elem-machines</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;identity</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">e</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--tree-narrow-recursive</span> <span style="color:#19177c">e</span> <span style="color:#19177c">machine</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">elem</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--tree-narrow</span> (<span style="color:#19177c">tree</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Remove all elements of TREE that are not active on machine.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;identity</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">elem</span>) (<span style="color:#19177c">my/index--tree-narrow-recursive</span> <span style="color:#19177c">elem</span> (<span style="color:#19177c">my/system-name</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">copy-tree</span> <span style="color:#19177c">tree</span>))))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>my/index--tree-narrow
</span></span></code></pre></div><h4 id="commands">Commands</h4>
<p>Next, apply the tree to the filesystem.</p>
<p>I&rsquo;ve decided to implement this by generating a bash script and executing it with <code>bash +x</code>. This way, I can check the required changes in advance and avert potential data loss if something unexpected happens.</p>
<p>One command for the script will be a list like:</p>
<ul>
<li><code>(&lt;command&gt; &lt;category&gt; &lt;priority&gt;)</code></li>
</ul>
<h5 id="filesystem">Filesystem</h5>
<p>First, we need to create non-existing folders and remove folders that aren&rsquo;t supposed to exist.</p>
<p>To do that, we need to find all such folders:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/index-keep-files</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;.dtrash&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--filesystem-tree-mapping</span> (<span style="color:#19177c">full-tree</span> <span style="color:#19177c">tree</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">active-paths</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Return a \&#34;sync state\&#34; between the filesystem and the tree.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">FULL-TREE and TREE are forms as defined by </span><span style="color:#19177c">`my/index--tree-get&#39;</span><span style="color:#ba2121">. TREE
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">is the narrowed FULL-TREE (returned by </span><span style="color:#19177c">`my/index--tree-narrow&#39;</span><span style="color:#ba2121">).
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">ACTIVE-PATHS is a list of paths that are currently active. If not
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">provided, it is computed from TREE.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The return value is a list of alists with the following keys:
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- path - the path of the folder
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- exists - whether the folder exists on the filesystem
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- has-to-exist - whether the folder exists in the tree
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- extra - if the folder exists in the filesystem but not in the tree.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- children - a list of alists with the same keys for the children of
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"> the folder.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">active-paths</span> (<span style="color:#008000">or</span> <span style="color:#19177c">active-paths</span> (<span style="color:#19177c">my/index--tree-get-paths</span> <span style="color:#19177c">tree</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">elem</span> <span style="color:#19177c">in</span> <span style="color:#19177c">full-tree</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">path</span> <span style="color:#00f">=</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:path</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">extra-folders</span> <span style="color:#00f">=</span> (<span style="color:#008000">when</span> (<span style="color:#008000">and</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-directory-p</span> <span style="color:#19177c">path</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-difference</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">d</span>) (<span style="color:#008000">if</span> (<span style="color:#00f">file-directory-p</span> <span style="color:#19177c">d</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">d</span> <span style="color:#ba2121">&#34;/&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">d</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-files</span> <span style="color:#19177c">path</span> <span style="color:#800">t</span> (<span style="color:#008000">rx</span> (<span style="color:#19177c">not</span> <span style="color:#ba2121">&#34;.&#34;</span>) <span style="color:#19177c">eos</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">child</span> <span style="color:#19177c">in</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:path</span> <span style="color:#19177c">child</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">folder-exists</span> <span style="color:#00f">=</span> (<span style="color:#00f">file-directory-p</span> <span style="color:#19177c">path</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">folder-has-to-exist</span> <span style="color:#00f">=</span> (<span style="color:#19177c">seq-contains-p</span> <span style="color:#19177c">active-paths</span> <span style="color:#19177c">path</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> <span style="color:#666">`</span>((<span style="color:#19177c">path</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">path</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">exists</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">folder-exists</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">has-to-exist</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">folder-has-to-exist</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">children</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#00f">append</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">f</span> <span style="color:#19177c">in</span> <span style="color:#19177c">extra-folders</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#19177c">path</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">f</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">exists</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">has-to-exist</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#00f">member</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-name-nondirectory</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-file-name</span> <span style="color:#19177c">f</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/index-keep-files</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">extra</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--filesystem-tree-mapping</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">elem</span>) <span style="color:#19177c">tree</span> <span style="color:#19177c">active-paths</span>)))))))
</span></span></code></pre></div><p>And generate commands from the results of the above:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--filesystem-commands</span> (<span style="color:#19177c">mapping</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get commands to sync filesystem with the tree.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">MAPPING is a form generated by </span><span style="color:#19177c">`my/index--filesystem-tree-mapping&#39;</span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">that describes the \&#34;sync state\&#34; between the filesystem and the
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">tree.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The return value is a list of commands as defined by
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"></span><span style="color:#19177c">`my/index--commands-display&#39;</span><span style="color:#ba2121">.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">elem</span> <span style="color:#19177c">in</span> <span style="color:#19177c">mapping</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">path</span> <span style="color:#00f">=</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;path</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">exists</span> <span style="color:#00f">=</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;exists</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">has-to-exist</span> <span style="color:#00f">=</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;has-to-exist</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">extra</span> <span style="color:#00f">=</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;extra</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">when</span> (<span style="color:#008000">and</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">exists</span>) <span style="color:#19177c">has-to-exist</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#00f">list</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;mkdir \&#34;%s\&#34;&#34;</span> <span style="color:#19177c">path</span>) <span style="color:#ba2121">&#34;Make directories&#34;</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">when</span> (<span style="color:#008000">and</span> <span style="color:#19177c">exists</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">has-to-exist</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#00f">list</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;rm -rf \&#34;%s\&#34;&#34;</span> <span style="color:#19177c">path</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">extra</span> <span style="color:#ba2121">&#34;Remove extra files&#34;</span> <span style="color:#ba2121">&#34;Remove directories&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">extra</span> <span style="color:#666">20</span> <span style="color:#666">10</span>))
</span></span><span style="display:flex;"><span> <span style="color:#00f">append</span> (<span style="color:#19177c">my/index--filesystem-commands</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;children</span> <span style="color:#19177c">elem</span>))))
</span></span></code></pre></div><h5 id="mega">MEGA</h5>
<p>As I said above, MEGA provides <a href="https://github.com/meganz/MEGAcmd">MEGAcmd</a>, which is a convenient way to access MEGA via CLI.</p>
<p>To initialize the session, run</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mega-login &lt;login&gt; &lt;password&gt;
</span></span></code></pre></div><p>Then you&rsquo;ll be able to run the rest of <code>mega-*</code> commands.</p>
<p>The command I want to run, <code>mega-sync</code>, prints the results in a table-like way. So let&rsquo;s parse that.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/parse-table-str</span> (<span style="color:#00f">string</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Convert a table-like STRING into alist.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The input format is as follows:
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">HEADER1 HEADER2 HEADER3
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">value1 value2 3
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">value4 value5 6
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Which creates the following output:
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\(((HEADER1. \&#34;value1\&#34;) (HEADER2 . \&#34;value2\&#34;) (HEADER3 . \&#34;3\&#34;))
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"> ((HEADER1. \&#34;value4\&#34;) (HEADER2 . \&#34;value5\&#34;) (HEADER3 . \&#34;6\&#34;)))
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The functions also skips lines in [square brackets] and ones that
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">start with more than 3 spaces.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let*</span> ((<span style="color:#19177c">lines</span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">s</span>) (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">s</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;[&#34;</span> (<span style="color:#00f">*</span> <span style="color:#19177c">nonl</span>) <span style="color:#ba2121">&#34;]&#34;</span>) <span style="color:#19177c">s</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> (<span style="color:#00f">&gt;=</span> <span style="color:#666">3</span> <span style="color:#ba2121">&#34; &#34;</span>)) <span style="color:#19177c">s</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">split-string</span> <span style="color:#00f">string</span> <span style="color:#ba2121">&#34;\n&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">first-line</span> (<span style="color:#00f">car</span> <span style="color:#19177c">lines</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">headers</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">first-line</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">header-indices</span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">header</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-search</span> <span style="color:#19177c">header</span> <span style="color:#19177c">first-line</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">headers</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">line</span> <span style="color:#19177c">in</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">lines</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">header</span> <span style="color:#19177c">in</span> <span style="color:#19177c">headers</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">start</span> <span style="color:#19177c">in</span> <span style="color:#19177c">header-indices</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">end</span> <span style="color:#19177c">in</span> (<span style="color:#00f">append</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">header-indices</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#00f">length</span> <span style="color:#19177c">line</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#00f">cons</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">intern</span> <span style="color:#19177c">header</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-trim</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span> <span style="color:#19177c">line</span> <span style="color:#19177c">start</span> <span style="color:#19177c">end</span>)))))))
</span></span></code></pre></div><p>Now we can invoke <code>mega-sync</code> to get the current sync status. <code>--path-display-size=10000</code> disables truncation of long paths.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--mega-data-from-sync</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get the current MEGA sync status.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The return value is a list of alists with the following keys:
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- path - path to file or directory
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- enabled - whether the file or directory is enabled for sync&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">mega-result</span> (<span style="color:#19177c">my/parse-table-str</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shell-command-to-string</span> <span style="color:#ba2121">&#34;mega-sync --path-display-size=10000&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">value</span> <span style="color:#19177c">in</span> <span style="color:#19177c">mega-result</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">localpath</span> <span style="color:#00f">=</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;LOCALPATH</span> <span style="color:#19177c">value</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> <span style="color:#666">`</span>((<span style="color:#19177c">path</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#008000">if</span> (<span style="color:#00f">file-directory-p</span> <span style="color:#19177c">localpath</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#19177c">localpath</span> <span style="color:#ba2121">&#34;/&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">localpath</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">enabled</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#19177c">seq-contains-p</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;Pending&#34;</span> <span style="color:#ba2121">&#34;Loading&#34;</span> <span style="color:#ba2121">&#34;Running&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;RUN_STATE</span> <span style="color:#19177c">value</span>)))))))
</span></span></code></pre></div><p>And get the same data from the tree.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--tree-get-paths</span> (<span style="color:#19177c">tree</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">kind</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get paths from TREE.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">TREE is a form a defined by </span><span style="color:#19177c">`my/index--tree-get&#39;</span><span style="color:#ba2121">. KIND is either a
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">filter by the kind attribute or nil, in which case all paths are
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">returned.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The return value is a list of strings.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">elem</span> <span style="color:#19177c">in</span> <span style="color:#19177c">tree</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">when</span> (<span style="color:#008000">or</span> (<span style="color:#00f">null</span> <span style="color:#19177c">kind</span>) (<span style="color:#00f">eq</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:kind</span> <span style="color:#19177c">elem</span>) <span style="color:#19177c">kind</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:path</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#00f">append</span> (<span style="color:#19177c">my/index--tree-get-paths</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">elem</span>) <span style="color:#19177c">kind</span>)))
</span></span></code></pre></div><p>With that information, we can generate commands to synchronize the required and actual sync paths.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--mega-local-path</span> (<span style="color:#19177c">path</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get path in the MEGA cloud by the local path PATH.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-replace</span> <span style="color:#19177c">my/index-root</span> <span style="color:#ba2121">&#34;/&#34;</span> <span style="color:#19177c">path</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--mega-commands</span> (<span style="color:#19177c">full-tree</span> <span style="color:#19177c">tree</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get commands to sync the mega-sync state with TREE.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">FULL-TREE and TREE are forms as defined by </span><span style="color:#19177c">`my/index--tree-get&#39;</span><span style="color:#ba2121">. TREE
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">is the narrowed FULL-TREE (returned by </span><span style="color:#19177c">`my/index--tree-narrow&#39;</span><span style="color:#ba2121">).
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The return value is a list of commands as defined by
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"></span><span style="color:#19177c">`my/index--commands-display&#39;</span><span style="color:#ba2121">.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">paths-all</span> (<span style="color:#19177c">my/index--tree-get-paths</span> <span style="color:#19177c">full-tree</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mega-paths-to-enable</span> (<span style="color:#19177c">my/index--tree-get-paths</span> <span style="color:#19177c">tree</span> <span style="color:#19177c">&#39;mega</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mega-info</span> (<span style="color:#19177c">my/index--mega-data-from-sync</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mega-paths-enabled</span> (<span style="color:#19177c">seq-map</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">e</span>) (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;path</span> <span style="color:#19177c">e</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">e</span>) (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;enabled</span> <span style="color:#19177c">e</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">mega-info</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mega-paths-disabled</span> (<span style="color:#19177c">seq-map</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">e</span>) (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;path</span> <span style="color:#19177c">e</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">e</span>) (<span style="color:#19177c">not</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;enabled</span> <span style="color:#19177c">e</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">mega-info</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">append</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">path</span> <span style="color:#19177c">in</span> (<span style="color:#19177c">seq-difference</span> <span style="color:#19177c">mega-paths-to-enable</span> <span style="color:#19177c">mega-paths-enabled</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#19177c">seq-contains-p</span> <span style="color:#19177c">mega-paths-disabled</span> <span style="color:#19177c">path</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#00f">list</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;mega-sync -r \&#34;%s\&#34;&#34;</span> <span style="color:#19177c">path</span>) <span style="color:#ba2121">&#34;Mega enable sync&#34;</span> <span style="color:#666">5</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">else</span> <span style="color:#00f">append</span> (<span style="color:#00f">list</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;mega-mkdir -p \&#34;%s\&#34;&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--mega-local-path</span> <span style="color:#19177c">path</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Mega mkdirs&#34;</span> <span style="color:#666">4</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;mega-sync \&#34;%s\&#34; \&#34;%s\&#34;&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">path</span> (<span style="color:#19177c">my/index--mega-local-path</span> <span style="color:#19177c">path</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Mega add sync&#34;</span> <span style="color:#666">5</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">path</span> <span style="color:#19177c">in</span> (<span style="color:#19177c">seq-difference</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-intersection</span> <span style="color:#19177c">mega-paths-enabled</span> <span style="color:#19177c">paths-all</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">mega-paths-to-enable</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#00f">list</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;mega-sync -d \&#34;%s\&#34;&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span> <span style="color:#19177c">path</span> <span style="color:#666">0</span> (<span style="color:#00f">1-</span> (<span style="color:#00f">length</span> <span style="color:#19177c">path</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Mega remove sync&#34;</span> <span style="color:#666">4</span>)))))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>my/index--mega-commands
</span></span></code></pre></div><h5 id="git-repos">Git repos</h5>
<p>To sync git, we just need to clone the required git repos. Removing the repos is handled by the folder sync commands.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--git-commands</span> (<span style="color:#19177c">tree</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get commands to clone the yet uncloned git repos in TREE.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">TREE is a form a defined by </span><span style="color:#19177c">`my/index--tree-get&#39;</span><span style="color:#ba2121">. This is supposed to
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">be the tree narrowed to the current machine (</span><span style="color:#19177c">`my/index--tree-narrow&#39;</span><span style="color:#ba2121">).
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The return value is a list of commands as defined by
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"></span><span style="color:#19177c">`my/index--commands-display&#39;</span><span style="color:#ba2121">.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">elem</span> <span style="color:#19177c">in</span> <span style="color:#19177c">tree</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">path</span> <span style="color:#00f">=</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:path</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">when</span> (<span style="color:#008000">and</span> (<span style="color:#00f">eq</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:kind</span> <span style="color:#19177c">elem</span>) <span style="color:#19177c">&#39;git</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">not</span> (<span style="color:#00f">file-directory-p</span> <span style="color:#19177c">path</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">directory-empty-p</span> <span style="color:#19177c">path</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#00f">list</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;git clone \&#34;%s\&#34; \&#34;%s\&#34;&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:remote</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">path</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Init git repos&#34;</span> <span style="color:#666">2</span>)
</span></span><span style="display:flex;"><span> <span style="color:#00f">append</span> (<span style="color:#19177c">my/index--git-commands</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">elem</span>))))
</span></span></code></pre></div><h5 id="wakatime-1">Wakatime</h5>
<p>So, that&rsquo;s it for synchronization. A few other things are needed here.</p>
<p>I use <a href="https://wakatime.com/">WakaTime</a> to track my coding activity, and I don&rsquo;t like the alphanumeric prefixes in my coding stats. Fortunately, <code>wakatime-cli</code> provides an option called <a href="https://github.com/wakatime/wakatime-cli/blob/develop/USAGE.md#project-map-section">projectmap</a> to rename projects, so we just have to generate its contents.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--bare-project-name</span> (<span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Remove the alphanumeric prefix from NAME.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">E.g. 10.03.R.01 Project Name -&gt; Project Name.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp-in-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> (<span style="color:#00f">+</span> (<span style="color:#19177c">|</span> <span style="color:#19177c">num</span> <span style="color:#19177c">alpha</span> <span style="color:#ba2121">&#34;.&#34;</span> <span style="color:#ba2121">&#34;-&#34;</span>)) <span style="color:#19177c">space</span>) <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#19177c">name</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--wakatime-escape</span> (<span style="color:#00f">string</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Escape STRING for use in a WakaTime config file.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp-in-string</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;&#39;&#34;</span>) <span style="color:#ba2121">&#34;\\\\&#39;&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp-in-string</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;(&#34;</span>) <span style="color:#ba2121">&#34;\\\\(&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">replace-regexp-in-string</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;)&#34;</span>) <span style="color:#ba2121">&#34;\\\\)&#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--wakatime-get-map-tree</span> (<span style="color:#19177c">tree</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get a list of (folder-name . bare-project-name) pairs from TREE.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">TREE is a form as defined by </span><span style="color:#19177c">`my/index--tree-get&#39;</span><span style="color:#ba2121">.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">\&#34;bare-project-name\&#34; is project name without the alphanumeric
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">prefix.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">elem</span> <span style="color:#19177c">in</span> <span style="color:#19177c">tree</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">name</span> <span style="color:#00f">=</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:name</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#00f">eq</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:kind</span> <span style="color:#19177c">elem</span>) <span style="color:#19177c">&#39;git</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#00f">cons</span> (<span style="color:#19177c">my/index--wakatime-escape</span> <span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--wakatime-escape</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--bare-project-name</span> <span style="color:#19177c">name</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#008000">and</span> (<span style="color:#00f">eq</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:kind</span> <span style="color:#19177c">elem</span>) <span style="color:#19177c">&#39;git</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:symlink</span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#00f">cons</span> (<span style="color:#19177c">my/index--wakatime-escape</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; lmao</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; /a/b/c/ -&gt; c</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; /a/b/c -&gt; b</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-name-nondirectory</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-file-name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-name-directory</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:symlink</span> <span style="color:#19177c">elem</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--wakatime-escape</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--bare-project-name</span> <span style="color:#19177c">name</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#00f">append</span> (<span style="color:#19177c">my/index--wakatime-get-map-tree</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">elem</span>))))
</span></span></code></pre></div><p>And insert that in <code>wakatime.cfg</code> if necessary.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--wakatime-commands</span> (<span style="color:#19177c">tree</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get commands to update WakaTime config from TREE.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">TREE is a form a defined by </span><span style="color:#19177c">`my/index--tree-get&#39;</span><span style="color:#ba2121">. The return value is
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">a list of commands as defined by </span><span style="color:#19177c">`my/index--commands-display&#39;</span><span style="color:#ba2121">.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;ini</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">map-tree</span> (<span style="color:#19177c">my/index--wakatime-get-map-tree</span> <span style="color:#19177c">tree</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">map-tree-encoding</span> (<span style="color:#19177c">ini-encode</span> <span style="color:#666">`</span>((<span style="color:#ba2121">&#34;projectmap&#34;</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">map-tree</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">map-tree-saved</span> (<span style="color:#008000">with-temp-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert-file-contents</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">&#34;~/.wakatime.cfg&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> (<span style="color:#00f">regexp-quote</span> <span style="color:#19177c">map-tree-encoding</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-string</span>)))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">map-tree-saved</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">insert-command</span> (<span style="color:#00f">list</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;echo \&#34;\n\n%s\&#34; &gt;&gt; ~/.wakatime.cfg&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">map-tree-encoding</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Update WakaTime config&#34;</span> <span style="color:#666">9</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#00f">list</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;sed -i -z &#39;s/\\[projectmap\\]\\n[^[]*//g&#39; ~/.wakatime.cfg&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Update WakaTime config&#34;</span> <span style="color:#666">9</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">insert-command</span>)))))
</span></span></code></pre></div><h5 id="symlinks">Symlinks</h5>
<p>The last part here is creating symbolic links.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index-get-symlink-commands</span> (<span style="color:#19177c">tree</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get commands to create symlinks from TREE.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">TREE is a form a defined by </span><span style="color:#19177c">`my/index--tree-get&#39;</span><span style="color:#ba2121">. The return value is
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">a list of commands as defined by </span><span style="color:#19177c">`my/index--commands-display&#39;</span><span style="color:#ba2121">.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">elem</span> <span style="color:#19177c">in</span> <span style="color:#19177c">tree</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">path</span> <span style="color:#00f">=</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:path</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">symlink</span> <span style="color:#00f">=</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:symlink</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">when</span> (<span style="color:#008000">and</span> <span style="color:#19177c">symlink</span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;/&#34;</span> <span style="color:#19177c">eos</span>) <span style="color:#19177c">symlink</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Wrong symlink: %s (should be a directory)&#34;</span> <span style="color:#19177c">symlink</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">when</span> (<span style="color:#008000">and</span> <span style="color:#19177c">path</span> <span style="color:#19177c">symlink</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">symlink</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-exists-p</span> (<span style="color:#00f">substring</span> <span style="color:#19177c">symlink</span> <span style="color:#666">0</span> <span style="color:#666">-1</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#00f">file-symlink-p</span> (<span style="color:#00f">substring</span> <span style="color:#19177c">symlink</span> <span style="color:#666">0</span> <span style="color:#666">-1</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#00f">list</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;rm -rf %s&#34;</span> (<span style="color:#00f">substring</span> <span style="color:#19177c">symlink</span> <span style="color:#666">0</span> <span style="color:#666">-1</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Remove files to make symlinks&#34;</span> <span style="color:#666">6</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">when</span> (<span style="color:#008000">and</span> <span style="color:#19177c">path</span> <span style="color:#19177c">symlink</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#00f">file-symlink-p</span> (<span style="color:#00f">substring</span> <span style="color:#19177c">symlink</span> <span style="color:#666">0</span> <span style="color:#666">-1</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#00f">list</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;ln -s &#39;%s&#39; &#39;%s&#39;&#34;</span> <span style="color:#19177c">path</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span> <span style="color:#19177c">symlink</span> <span style="color:#666">0</span> <span style="color:#666">-1</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Make symlinks&#34;</span> <span style="color:#666">7</span>)
</span></span><span style="display:flex;"><span> <span style="color:#00f">append</span> (<span style="color:#19177c">my/index-get-symlink-commands</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">elem</span>))))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>my/index-get-symlink-commands
</span></span></code></pre></div><h5 id="run-all-commands">Run all commands</h5>
<p>And put that all together.</p>
<p>First, as I want to check what&rsquo;s going to be executed, let&rsquo;s make a function to display commands in a separate buffer.</p>
<p>The mode definition is as follows:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/index-commands-mode-map</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">keymap</span> (<span style="color:#00f">make-sparse-keymap</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">define-key</span> <span style="color:#19177c">keymap</span> (<span style="color:#19177c">kbd</span> <span style="color:#ba2121">&#34;C-c C-c&#34;</span>) <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/index-commands-exec</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">define-key</span> <span style="color:#19177c">keymap</span> (<span style="color:#19177c">kbd</span> <span style="color:#ba2121">&#34;q&#34;</span>) <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/quit-window-and-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">fboundp</span> <span style="color:#19177c">&#39;evil-define-key*</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-define-key*</span> <span style="color:#19177c">&#39;normal</span> <span style="color:#19177c">keymap</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;q&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/quit-window-and-buffer</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">keymap</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Keymap for </span><span style="color:#19177c">`biome-api-error-mode&#39;</span><span style="color:#ba2121">.&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">define-derived-mode</span> <span style="color:#19177c">my/index-commands-mode</span> <span style="color:#19177c">sh-mode</span> <span style="color:#ba2121">&#34;Index Commands&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;A mode to display index commands.&#34;</span>)
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar-local</span> <span style="color:#19177c">my/index-commands</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Commands to be executed by </span><span style="color:#19177c">`my/index-commands-exec&#39;</span><span style="color:#ba2121">&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--commands-display</span> (<span style="color:#19177c">commands</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Display COMMANDS in a buffer.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">COMMANDS is a list of commands as defined by </span><span style="color:#19177c">`my/index--commands-display&#39;</span><span style="color:#ba2121">.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">commands</span>
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;No commands to display&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">buffer</span> (<span style="color:#00f">get-buffer-create</span> <span style="color:#ba2121">&#34;*index commands*&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">groups</span> (<span style="color:#19177c">seq-sort-by</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">g</span>) (<span style="color:#00f">nth</span> <span style="color:#666">2</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">g</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;&lt;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-group-by</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">c</span>) (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">c</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">commands</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-current-buffer</span> <span style="color:#19177c">buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index-commands-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">inhibit-read-only</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">commands-sequence</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">erase-buffer</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">my/index-commands</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">g</span> <span style="color:#19177c">in</span> <span style="color:#19177c">groups</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">group-name</span> <span style="color:#00f">=</span> (<span style="color:#00f">car</span> <span style="color:#19177c">g</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">elems</span> <span style="color:#00f">=</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">g</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">&#34;# &#34;</span> <span style="color:#19177c">group-name</span> <span style="color:#ba2121">&#34;\n&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">elem</span> <span style="color:#19177c">in</span> <span style="color:#19177c">elems</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#008000">push</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">elem</span>) <span style="color:#19177c">my/index-commands</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">insert</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">elem</span>) <span style="color:#ba2121">&#34;\n&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">buffer-read-only</span> <span style="color:#800">t</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">switch-to-buffer</span> <span style="color:#19177c">buffer</span>)))
</span></span></code></pre></div><p>In order to execute these commands, <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Compilation.html">compile</a> with <code>bash -x</code> on a temporary file is quite sufficient.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index-commands-exec</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">major-mode</span> <span style="color:#19177c">&#39;my/index-commands-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Not shell mode&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">filename</span> (<span style="color:#19177c">make-temp-file</span> <span style="color:#ba2121">&#34;index-commands-&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">write-region</span> (<span style="color:#00f">point-min</span>) (<span style="color:#00f">point-max</span>) <span style="color:#19177c">filename</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">compile</span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;bash -x &#34;</span> <span style="color:#19177c">filename</span>))))
</span></span></code></pre></div><p>I&rsquo;ll also try to save some time by caching the resulting index tree. <code>file-has-changed-p</code> is pretty helpful in that.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/index--tree</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;The last version of the index tree.&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--tree-retrive</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Retrive the last version of the index tree.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">This function returns the last saved version of the index tree if it
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">is still valid. Otherwise, it re-parses the index file.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/index--tree</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span> ((<span style="color:#00f">string-equal</span> (<span style="color:#00f">buffer-file-name</span>) <span style="color:#19177c">my/index-file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--tree-get</span>))
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">or</span> (<span style="color:#00f">null</span> <span style="color:#19177c">my/index--tree</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">file-has-changed-p</span> <span style="color:#19177c">my/index-file</span> <span style="color:#19177c">&#39;index</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert-file-contents</span> <span style="color:#19177c">my/index-file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#00f">buffer-file-name</span> <span style="color:#19177c">my/index-file</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--tree-get</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> <span style="color:#19177c">my/index--tree</span>))))
</span></span></code></pre></div><p>With that, we can make the main entrypoint.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index-commands-sync</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Sync the filesystem with the index.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">full-tree</span> (<span style="color:#19177c">my/index--tree-retrive</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--tree-verify</span> <span style="color:#19177c">full-tree</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">tree</span> (<span style="color:#19177c">my/index--tree-narrow</span> <span style="color:#19177c">full-tree</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mega-commands</span> (<span style="color:#19177c">my/index--mega-commands</span> <span style="color:#19177c">full-tree</span> <span style="color:#19177c">tree</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mapping</span> (<span style="color:#19177c">my/index--filesystem-tree-mapping</span> <span style="color:#19177c">full-tree</span> <span style="color:#19177c">tree</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">folder-commands</span> (<span style="color:#19177c">my/index--filesystem-commands</span> <span style="color:#19177c">mapping</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">git-commands</span> (<span style="color:#19177c">my/index--git-commands</span> <span style="color:#19177c">tree</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">waka-commands</span> (<span style="color:#19177c">my/index--wakatime-commands</span> <span style="color:#19177c">tree</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">symlink-commands</span> (<span style="color:#19177c">my/index-get-symlink-commands</span> <span style="color:#19177c">tree</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--commands-display</span> (<span style="color:#00f">append</span> <span style="color:#19177c">mega-commands</span> <span style="color:#19177c">folder-commands</span> <span style="color:#19177c">git-commands</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">waka-commands</span> <span style="color:#19177c">symlink-commands</span>)))))
</span></span></code></pre></div><h4 id="navigation-1">Navigation</h4>
<p>The last piece is the navigation interface.</p>
<p>Of course, plain dired does the job fine, thanks to the relatively low-depth filesystem structure. But I still want a navigation interface like <code>M-x projectile-switch-project</code>.</p>
<h5 id="navigation-data">Navigation data</h5>
<p>There are two slight problems with that.</p>
<p>First, the index tree does not always have the full info. For instance, I have the <code>10.03.A Artifacts</code> folder, which I sync with MEGA and which has child folders like <code>10.03.A.01 smth</code> and so on. Names of the latter are not stored anywhere because I don&rsquo;t see the point, which means we have to extract that from the filesystem.</p>
<p>Second, as it turns out, there have to be two levels for navigation, which are delimited by the <code>project</code> property. I&rsquo;m not sure if that the optimal way to implement Jonny.Decimal, but it works for me.</p>
<p>So, a function to tackle the first problem:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--nav-extend</span> (<span style="color:#19177c">name</span> <span style="color:#19177c">path</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Find all index-related files in PATH.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">NAME is the name of the root index entry, e.g. \&#34;10.01
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Something\&#34;. If PATH containts folders like \&#34;10.01.01
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Something\&#34;, \&#34;10.01.02 ...\&#34;, they will be returned.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The return value is a form as defined by </span><span style="color:#19177c">`my/index--nav-get&#39;</span><span style="color:#ba2121">.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">file-directory-p</span> <span style="color:#19177c">path</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">number</span> (<span style="color:#19177c">my/index--extact-number</span> <span style="color:#19177c">name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">files</span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>) (<span style="color:#00f">cons</span> <span style="color:#19177c">f</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">path</span> <span style="color:#19177c">f</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>) (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-prefix-p</span> <span style="color:#ba2121">&#34;.&#34;</span> <span style="color:#19177c">f</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-files</span> <span style="color:#19177c">path</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">matching-files</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>) (<span style="color:#008000">and</span> (<span style="color:#00f">file-directory-p</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">f</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-prefix-p</span> <span style="color:#19177c">number</span> (<span style="color:#00f">car</span> <span style="color:#19177c">f</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">files</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">and</span> (<span style="color:#19177c">length&gt;</span> <span style="color:#19177c">matching-files</span> <span style="color:#666">0</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">length&lt;</span> <span style="color:#19177c">matching-files</span> (<span style="color:#00f">length</span> <span style="color:#19177c">files</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Extraneuous files in %s&#34;</span> <span style="color:#19177c">path</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> (<span style="color:#19177c">name-1</span> <span style="color:#666">.</span> <span style="color:#19177c">path-1</span>) <span style="color:#19177c">in</span> <span style="color:#19177c">matching-files</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">append</span> (<span style="color:#19177c">if-let</span> ((<span style="color:#19177c">child-files</span> (<span style="color:#19177c">my/index--nav-extend</span> <span style="color:#19177c">name-1</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">path-1</span> <span style="color:#ba2121">&#34;/&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">child-datum</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#19177c">name-1</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:names</span> <span style="color:#19177c">child-datum</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">child-datum</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">child-files</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(((<span style="color:#008000">:names</span> <span style="color:#666">.</span> (<span style="color:#666">,</span><span style="color:#19177c">name-1</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:path</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#00f">concat</span> <span style="color:#19177c">path-1</span> <span style="color:#ba2121">&#34;/&#34;</span>)))))))))
</span></span></code></pre></div><p>And one to get the navigation data structure.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--nav-get</span> (<span style="color:#19177c">tree</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">names</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get the navigation structure from TREE.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">TREE is a form as defined by </span><span style="color:#19177c">`my/index--tree-get&#39;</span><span style="color:#ba2121">. NAMES is a
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">list of names of the parent entries, e.g. (\&#34;10.01 Something\&#34;), used
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">for recursive calls.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The result is a list of alists with the following keys:
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- `:names` - list of names, e.g.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"> (\&#34;10.01 Something\&#34; \&#34;10.01.01 Something\&#34;)
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- `:path` - path to the folder, e.g.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"> \&#34;/path/10 stuff/10.01 Something/10.01.01 Something/\&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- `:child-navs` - list of child navigation structures (optional)&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-sort-by</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">item</span>) (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:path</span> <span style="color:#19177c">item</span>))
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;string-lessp</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-reduce</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">acc</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">name</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:name</span> <span style="color:#19177c">elem</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">path</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:path</span> <span style="color:#19177c">elem</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span> ((<span style="color:#19177c">alist-get</span> <span style="color:#008000">:project</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">current-nav</span> <span style="color:#666">`</span>((<span style="color:#008000">:names</span> <span style="color:#666">.</span> (<span style="color:#666">,@</span><span style="color:#19177c">names</span> <span style="color:#666">,</span><span style="color:#19177c">name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:path</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">path</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let</span> (<span style="color:#19177c">child-navs</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--nav-get</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">elem</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:child-navs</span> <span style="color:#19177c">current-nav</span>) <span style="color:#19177c">child-navs</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#19177c">current-nav</span> <span style="color:#19177c">acc</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let</span> (<span style="color:#19177c">child-navs</span> (<span style="color:#19177c">my/index--nav-get</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:children</span> <span style="color:#19177c">elem</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,@</span><span style="color:#19177c">names</span> <span style="color:#666">,</span><span style="color:#19177c">name</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">child-nav</span> <span style="color:#19177c">in</span> <span style="color:#19177c">child-navs</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#008000">push</span> <span style="color:#19177c">child-nav</span> <span style="color:#19177c">acc</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> (<span style="color:#19177c">if-let</span> ((<span style="color:#19177c">extended-nav</span> (<span style="color:#19177c">my/index--nav-extend</span> <span style="color:#19177c">name</span> <span style="color:#19177c">path</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">child-nav</span> <span style="color:#19177c">in</span> <span style="color:#19177c">extended-nav</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:names</span> <span style="color:#19177c">child-nav</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">append</span> <span style="color:#19177c">names</span> (<span style="color:#00f">list</span> <span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:names</span> <span style="color:#19177c">child-nav</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#008000">push</span> <span style="color:#19177c">child-nav</span> <span style="color:#19177c">acc</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#666">`</span>((<span style="color:#008000">:names</span> <span style="color:#666">.</span> (<span style="color:#666">,@</span><span style="color:#19177c">names</span> <span style="color:#666">,</span><span style="color:#19177c">name</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:path</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">path</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">acc</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">acc</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">tree</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:initial-value</span> <span style="color:#800">nil</span>)))
</span></span></code></pre></div><p>It also makes sense to cache results of the above.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">my/index--nav</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Navigation stucture for the index.&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--nav-retrive</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Retrive the navigation structure from the index file.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The return value is a form as defined by </span><span style="color:#19177c">`my/index--nav-get&#39;</span><span style="color:#ba2121">.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">or</span> (<span style="color:#00f">null</span> <span style="color:#19177c">my/index--nav</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">file-has-changed-p</span> <span style="color:#19177c">my/index-file</span> <span style="color:#19177c">&#39;nav</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">tree</span> (<span style="color:#19177c">my/index--tree-retrive</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/index--nav</span> (<span style="color:#19177c">my/index--nav-get</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--tree-narrow</span> <span style="color:#19177c">tree</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/index--nav</span>))
</span></span></code></pre></div><h5 id="emacs-interface">Emacs interface</h5>
<p>As for Emacs interface, <code>completing-read</code> is sufficient, except that I don&rsquo;t want <a href="https://github.com/radian-software/prescient.el">prescient.el</a> to interfere with the default ordering of elements.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--nav-prompt</span> (<span style="color:#19177c">nav</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Prompt the user for the navigation item to select.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">NAV is a structure as defined by </span><span style="color:#19177c">`my/index--nav-get&#39;</span><span style="color:#ba2121">.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">collection</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">item</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons</span> (<span style="color:#00f">car</span> (<span style="color:#19177c">last</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:names</span> <span style="color:#19177c">item</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:path</span> <span style="color:#19177c">item</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">nav</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">vertico-sort-function</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cdr</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">assoc</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">completing-read</span> <span style="color:#ba2121">&#34;Index: &#34;</span> <span style="color:#19177c">collection</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collection</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index--nav-find-path</span> (<span style="color:#19177c">nav</span> <span style="color:#19177c">path</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Find the navigation item in NAV with the given PATH.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">NAV is a structure as defined by </span><span style="color:#19177c">`my/index--nav-get&#39;</span><span style="color:#ba2121">.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-find</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">item</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-prefix-p</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:path</span> <span style="color:#19177c">item</span>) <span style="color:#19177c">path</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">nav</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index-nav</span> (<span style="color:#19177c">arg</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">func</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Navigate the filesystem index.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">If ARG is nil, navigate all levels sequentially from the top one.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">If ARG is &#39;(4), select another directory from the same level.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">FUNC is the function to call with the selected path. It defaults
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">to </span><span style="color:#19177c">`dired&#39;</span><span style="color:#ba2121"> if used interactively.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> <span style="color:#19177c">current-prefix-arg</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">dired</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">nav</span> (<span style="color:#19177c">my/index--nav-retrive</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">current-nav</span> (<span style="color:#19177c">my/index--nav-find-path</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">nav</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#19177c">default-directory</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">current-child-navs</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:child-navs</span> <span style="color:#19177c">current-nav</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span> ((<span style="color:#00f">null</span> <span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">selected</span> (<span style="color:#19177c">my/index--nav-find-path</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">nav</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index--nav-prompt</span> <span style="color:#19177c">nav</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">if-let</span> (<span style="color:#19177c">child-navs</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:child-navs</span> <span style="color:#19177c">selected</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">func</span> (<span style="color:#19177c">my/index--nav-prompt</span> <span style="color:#19177c">child-navs</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">func</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:path</span> <span style="color:#19177c">selected</span>)))))
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">and</span> (<span style="color:#00f">equal</span> <span style="color:#19177c">arg</span> <span style="color:#666">&#39;</span>(<span style="color:#666">4</span>)) <span style="color:#19177c">current-child-navs</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">func</span> (<span style="color:#19177c">my/index--nav-prompt</span> <span style="color:#19177c">current-child-navs</span>)))
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">and</span> (<span style="color:#00f">equal</span> <span style="color:#19177c">arg</span> <span style="color:#666">&#39;</span>(<span style="color:#666">4</span>)) (<span style="color:#00f">null</span> <span style="color:#19177c">current-child-navs</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">func</span> (<span style="color:#19177c">my/index--nav-prompt</span> <span style="color:#19177c">nav</span>))))))
</span></span></code></pre></div><p>Finally, something that I can bind to a key.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index-nav-with-select-file</span> (<span style="color:#19177c">arg</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> <span style="color:#19177c">current-prefix-arg</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/index-nav</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">arg</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">dir</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">default-directory</span> <span style="color:#19177c">dir</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">projectile-find-file</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index-open-file</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">find-file</span> <span style="color:#19177c">my/index-file</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">&#34;i&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span> <span style="color:#666">&#39;</span>(<span style="color:#008000">:wk</span> <span style="color:#ba2121">&#34;index&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;i&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/index-nav</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;s&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/index-commands-sync</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;p&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/index-nav-with-select-file</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;f&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/index-open-file</span>)
</span></span></code></pre></div><h4 id="export-tree">Export tree</h4>
<p>I also need the tree to use in my <code>sqrt-data</code>, so let&rsquo;s export this to JSON.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/index-export</span> (<span style="color:#19177c">file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> (<span style="color:#19177c">read-file-name</span> <span style="color:#ba2121">&#34;File: &#34;</span> <span style="color:#ba2121">&#34;~/logs-sync/data/index.json&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">full-tree</span> (<span style="color:#19177c">my/index--tree-retrive</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">file-exists-p</span> (<span style="color:#00f">file-name-directory</span> <span style="color:#19177c">file</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">make-directory</span> (<span style="color:#00f">file-name-directory</span> <span style="color:#19177c">file</span>) <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-file</span> <span style="color:#19177c">file</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#19177c">json-encode</span> <span style="color:#19177c">full-tree</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">json-pretty-print-buffer</span>))))
</span></span></code></pre></div><h3 id="utilities">Utilities</h3>
<h4 id="pass">pass</h4>
<p>I use <a href="https://www.passwordstore.org/">pass</a> as my password manager. Expectedly, there is an Emacs frontend for it.</p>
<p>This package is pretty good to manage the password database. I use <a href="https://github.com/SqrtMinusOne/password-store-ivy">password-store-ivy</a> (another package of mine) to actually type passwords. <a href="https://github.com/carnager/rofi-pass">rofi-pass</a> is another good option.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">pass</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">pass</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ak&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">pass</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">pass-show-keybindings</span> <span style="color:#800">nil</span>))
</span></span></code></pre></div><p>Also I use <code>password-store-get</code> in a few places in my config, and by default it returns <code>nil</code> if I make an error in the password, which inconvinient if I want to run the command in <code>setq</code>. So:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/password-store-get</span> (<span style="color:#19177c">entry</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">if-let</span> ((<span style="color:#19177c">res</span> (<span style="color:#19177c">password-store-get</span> <span style="color:#19177c">entry</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">res</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/password-store-get</span> <span style="color:#19177c">entry</span>)))
</span></span></code></pre></div><h4 id="docker-1">Docker</h4>
<p>A package to manage docker containers from Emacs.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">docker</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/remote-server</span> <span style="color:#19177c">my/is-termux</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">docker</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ao&#34;</span> <span style="color:#19177c">&#39;docker</span>))
</span></span></code></pre></div><h4 id="screenshot-dot-el">screenshot.el</h4>
<p>Tecosaur&rsquo;s plugin to make beautiful code screenshots.</p>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>imagemagick</td>
</tr>
</tbody>
</table>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">screenshot</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;tecosaur/screenshot&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:host</span> <span style="color:#19177c">github</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:build</span> (<span style="color:#008000">:not</span> <span style="color:#19177c">compile</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">display-graphic-p</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">screenshot</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;S&#34;</span> <span style="color:#19177c">&#39;screenshot</span>))
</span></span></code></pre></div><h4 id="proced">proced</h4>
<p>proced is an Emacs built-it process viewer, like top.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ah&#34;</span> <span style="color:#19177c">&#39;proced</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">proced-auto-update-interval</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;proced-mode-hook</span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">visual-line-mode</span> <span style="color:#666">-1</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">truncate-lines</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">proced-toggle-auto-update</span> <span style="color:#666">1</span>)))
</span></span></code></pre></div><h4 id="guix">Guix</h4>
<p>An Emacs package to help managing GNU Guix.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">guix</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/remote-server</span> <span style="color:#19177c">my/is-termux</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">guix</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ag&#34;</span> <span style="color:#19177c">&#39;guix</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defun</span> <span style="color:#19177c">geiser-company--setup</span> (<span style="color:#008000">&amp;rest</span> <span style="color:#19177c">args</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;A dummy function.&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">defvar</span> <span style="color:#19177c">geiser-repl-company-p</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;A dummy variable.&#34;</span>))
</span></span></code></pre></div><h4 id="atomic-chrome">Atomic Chrome</h4>
<p><a href="https://github.com/alpha22jp/atomic-chrome">Atomic Chrome</a> is an extension that allows to edit browser text fields in Emacs. Despite its name, it also works for Firefox with <a href="https://ghosttext.fregante.com/welcome/">GhostText</a>, which is what I use.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">atomic-chrome</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span> <span style="color:#19177c">my/remote-server</span> <span style="color:#19177c">my/is-termux</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">atomic-chrome-start-server</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h4 id="pinentry">Pinentry</h4>
<p>Emacs-based pinentry works great on Termux.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">pinentry</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> <span style="color:#19177c">my/is-termux</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">setenv</span> <span style="color:#ba2121">&#34;GPG_AGENT_INFO&#34;</span> <span style="color:#800">nil</span>) <span style="color:#408080;font-style:italic">;; use emacs pinentry</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">auth-source-debug</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">epg-gpg-program</span> <span style="color:#ba2121">&#34;gpg&#34;</span>) <span style="color:#408080;font-style:italic">;; not necessary</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">&#39;epa-file</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">epa-file-enable</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">epa-pinentry-mode</span> <span style="color:#19177c">&#39;loopback</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">epg-pinentry-mode</span> <span style="color:#19177c">&#39;loopback</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">pinentry-start</span>))
</span></span></code></pre></div><h3 id="productivity">Productivity</h3>
<h4 id="pomm">pomm</h4>
<p>My package for doing Pomodoro timer.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">pomm</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; :straight (:local-repo &#34;~/Code/Emacs/pomm&#34; :files (:defaults &#34;resources&#34;))</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">pomm</span> <span style="color:#19177c">pomm-third-time</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:init</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my-leader-def</span> <span style="color:#ba2121">&#34;ap&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">pomm</span>)
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (my-leader-def &#34;ap&#34; #&#39;pomm-third-time)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">alert-default-style</span> <span style="color:#19177c">&#39;libnotify</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">pomm-audio-enabled</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">pomm-audio-player-executable</span> (<span style="color:#19177c">executable-find</span> <span style="color:#ba2121">&#34;mpv&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">pomm-mode-line-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;pomm-on-status-changed-hook</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">pomm--sync-org-clock</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;pomm-third-time-on-status-changed-hook</span>
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">pomm-third-time--sync-org-clock</span>))
</span></span></code></pre></div><h4 id="hledger">hledger</h4>
<p>is a plain-text double-entry accounting software. I use it for managing my personal finances, and thus far it&rsquo;s great.</p>
<table>
<thead>
<tr>
<th>Guix dependency</th>
</tr>
</thead>
<tbody>
<tr>
<td>hledger</td>
</tr>
</tbody>
</table>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">hledger-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:mode</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;.journal&#34;</span> <span style="color:#19177c">eos</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">hledger-jfile</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">org-directory</span> <span style="color:#ba2121">&#34;/ledger/ledger.journal&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">&#39;hledger-mode-hook</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#00f">make-local-variable</span> <span style="color:#19177c">&#39;company-backends</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;company-backends</span> <span style="color:#19177c">&#39;hledger-company</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">flycheck-hledger</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">hledger-mode</span>))
</span></span></code></pre></div><p>Here are some usage notes.</p>
<p>The fastest way to enter new entiries to the journal is by running <code>hledger add</code></p>
<p>Then, run <code>hledger bs</code> to check whether the balance sheet matches the ground truth (e.g. the bank UI).</p>
<p>If it doesn&rsquo;t the simplest way to check for the differences is by running <code>hledger register &lt;item&gt;</code>.</p>
<p>Here are some interesting commands to run:</p>
<ul>
<li><code>hledger incomestatement &lt;query&gt;</code>, where <code>&lt;query&gt;</code> is the account prefix. e.g. <code>expenses</code> or <code>revenues</code>.
<ul>
<li>add <code>--pivot=payee</code> to get grouping by transaction descriptions</li>
<li>add <code>-B</code> to cast currencies</li>
</ul>
</li>
</ul>
<h4 id="calendar">Calendar</h4>
<p>Emacs&rsquo; built-in calendar. Can even calculate sunrise and sunset times.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">calendar-date-style</span> <span style="color:#19177c">&#39;iso</span>) <span style="color:#408080;font-style:italic">;; YYYY/mm/dd</span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">calendar-week-start-day</span> <span style="color:#666">1</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">calendar-time-display-form</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">24-hours</span> <span style="color:#ba2121">&#34;:&#34;</span> <span style="color:#19177c">minutes</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">calendar-latitude</span> <span style="color:#666">59.9375</span>)
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">calendar-longitude</span> <span style="color:#666">30.308611</span>)
</span></span></code></pre></div><h3 id="calc">Calc</h3>
<p><a href="https://github.com/kickingvegas/Casual">casual</a> is a transient interface for the built-in calc.el</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">casual</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;kickingvegas/Casual&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">calc</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">general-define-key</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">normal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:keymaps</span> <span style="color:#19177c">&#39;calc-mode-map</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;M-o&#34;</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">casual-main-menu</span>))
</span></span></code></pre></div><h3 id="chess">Chess</h3>
<h4 id="chess-dot-el">chess.el</h4>
<p>chess.el is a package by John Wiegley.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">chess</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">chess-pgn-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
</span></span></code></pre></div><h4 id="render-pgn">Render PGN</h4>
<p>A Python script to convert a PGN string to SVG:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">chess</span>
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">chess.svg</span>
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">chess.pgn</span>
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">cairosvg</span>
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">io</span>
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">sys</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>line <span style="color:#666">=</span> sys<span style="color:#666">.</span>argv[<span style="color:#666">1</span>]
</span></span><span style="display:flex;"><span>out_file <span style="color:#666">=</span> sys<span style="color:#666">.</span>argv[<span style="color:#666">2</span>]
</span></span><span style="display:flex;"><span>is_fen <span style="color:#666">=</span> <span style="color:#008000;font-weight:bold">False</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">if</span> <span style="color:#008000">len</span>(sys<span style="color:#666">.</span>argv) <span style="color:#666">&gt;</span> <span style="color:#666">3</span> <span style="color:#a2f;font-weight:bold">and</span> sys<span style="color:#666">.</span>argv[<span style="color:#666">3</span>] <span style="color:#666">==</span> <span style="color:#ba2121">&#39;true&#39;</span>:
</span></span><span style="display:flex;"><span> is_fen <span style="color:#666">=</span> <span style="color:#008000;font-weight:bold">True</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">def</span> <span style="color:#00f">parse_pgn</span>(line):
</span></span><span style="display:flex;"><span> game <span style="color:#666">=</span> chess<span style="color:#666">.</span>pgn<span style="color:#666">.</span>read_game(io<span style="color:#666">.</span>StringIO(line))
</span></span><span style="display:flex;"><span> game <span style="color:#666">=</span> game<span style="color:#666">.</span>end()
</span></span><span style="display:flex;"><span> board <span style="color:#666">=</span> game<span style="color:#666">.</span>board()
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">return</span> board
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">def</span> <span style="color:#00f">parse_fen</span>(line):
</span></span><span style="display:flex;"><span> board <span style="color:#666">=</span> chess<span style="color:#666">.</span>Board(line)
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">return</span> board
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">if</span> is_fen:
</span></span><span style="display:flex;"><span> board <span style="color:#666">=</span> parse_fen(line)
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">else</span>:
</span></span><span style="display:flex;"><span> board <span style="color:#666">=</span> parse_pgn(line)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>svg <span style="color:#666">=</span> chess<span style="color:#666">.</span>svg<span style="color:#666">.</span>board(board<span style="color:#666">=</span>board)
</span></span><span style="display:flex;"><span>png <span style="color:#666">=</span> cairosvg<span style="color:#666">.</span>svg2png(
</span></span><span style="display:flex;"><span> bytestring<span style="color:#666">=</span>svg, write_to<span style="color:#666">=</span>out_file, output_width<span style="color:#666">=</span><span style="color:#666">400</span>, output_height<span style="color:#666">=</span><span style="color:#666">400</span>
</span></span><span style="display:flex;"><span>)
</span></span></code></pre></div><p><code>python-chess</code> is installed in the <code>dev</code> profile because <code>python3</code> is also there.</p>
<p>An <code>org-babel</code> block:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/chess-python</span> <span style="color:#ba2121">&#34;/home/pavel/.guix-extra-profiles/dev/dev/bin/python3&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">org-babel-execute:pgn</span> (<span style="color:#19177c">body</span> <span style="color:#19177c">params</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">out-file</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:file</span> <span style="color:#19177c">params</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-temp-file</span> <span style="color:#ba2121">&#34;pgn-&#34;</span> <span style="color:#ba2121">&#34;.png&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-eval</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%s %s &#39;%s&#39; &#39;%s&#39;&#34;</span> <span style="color:#19177c">my/chess-python</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;~/bin/python-scripts/render_pgn.py&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">body</span> <span style="color:#19177c">out-file</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">org-babel-default-header-args:pgn</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#008000">:results</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;file&#34;</span>) (<span style="color:#008000">:exports</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;results&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Default arguments for evaluating a pgn source block.&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">org-babel-execute:fen</span> (<span style="color:#19177c">body</span> <span style="color:#19177c">params</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">out-file</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:file</span> <span style="color:#19177c">params</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-temp-file</span> <span style="color:#ba2121">&#34;fen-&#34;</span> <span style="color:#ba2121">&#34;.png&#34;</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-babel-eval</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;%s %s &#39;%s&#39; &#39;%s&#39; true&#34;</span> <span style="color:#19177c">my/chess-python</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;~/bin/python-scripts/render_pgn.py&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">body</span> <span style="color:#19177c">out-file</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defvar</span> <span style="color:#19177c">org-babel-default-header-args:fen</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>((<span style="color:#008000">:results</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;file&#34;</span>) (<span style="color:#008000">:exports</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;results&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Default arguments for evaluating a pgn source block.&#34;</span>)
</span></span></code></pre></div><h3 id="fun">Fun</h3>
<h4 id="discord-integration">Discord integration</h4>
<p>Integration with Discord. Shows which file is being edited in Emacs.</p>
<p>In order for this to work in Guix, a service is necessary - <a href="/configs/desktop/#discord-rich-presence">Discord rich presence</a>.</p>
<p>Some functions to override the displayed message:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/elcord-mask-buffer-name</span> (<span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> (<span style="color:#ba2121">? </span><span style="color:#ba2121">&#34;CAPTURE-&#34;</span>) (<span style="color:#00f">=</span> <span style="color:#666">14</span> <span style="color:#19177c">num</span>) <span style="color:#ba2121">&#34;-&#34;</span> (<span style="color:#00f">*</span> <span style="color:#19177c">not-newline</span>) <span style="color:#ba2121">&#34;.org&#34;</span> <span style="color:#19177c">eos</span>) <span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;ORG-ROAM&gt;&#34;</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">&#34;german&#34;</span> (<span style="color:#00f">*</span> <span style="color:#19177c">not-newline</span>) <span style="color:#ba2121">&#34;.org&#34;</span> <span style="color:#19177c">eos</span>) <span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;LEARNING&gt;&#34;</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> (<span style="color:#00f">+</span> <span style="color:#19177c">num</span>) <span style="color:#ba2121">&#34;-&#34;</span> (<span style="color:#00f">+</span> <span style="color:#19177c">num</span>) <span style="color:#ba2121">&#34;-&#34;</span> (<span style="color:#00f">+</span> <span style="color:#19177c">num</span>) <span style="color:#ba2121">&#34;.org&#34;</span> <span style="color:#19177c">eos</span>) <span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;ORG-JOURNAL&gt;&#34;</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;EXWM&#34;</span>) <span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;EXWM&gt;&#34;</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">&#34;*Org-Habit&#34;</span>) <span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;ORG&gt;&#34;</span>)
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">with-current-buffer</span> (<span style="color:#00f">get-buffer</span> <span style="color:#19177c">name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">derived-mode-p</span> <span style="color:#19177c">&#39;telega-root-mode</span> <span style="color:#19177c">&#39;telega-chat-mode</span>))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;&lt;TELEGA&gt;&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> <span style="color:#19177c">name</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/elcord-buffer-details-format-functions</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">&#34;Editing %s&#34;</span> (<span style="color:#19177c">my/elcord-mask-buffer-name</span> (<span style="color:#00f">buffer-name</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/elcord-update-presence-mask-advice</span> (<span style="color:#19177c">r</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">list</span> (<span style="color:#19177c">my/elcord-mask-buffer-name</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">r</span>)) (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">r</span>)))
</span></span></code></pre></div><p>Create a symlink for flatpak:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/elcord-symlink</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shell-command-to-string</span> <span style="color:#ba2121">&#34;bash -c &#39;ln -sf {app/com.discordapp.Discord,$XDG_RUNTIME_DIR}/discord-ipc-0 &amp;&#39;&#34;</span>))
</span></span></code></pre></div><p>And the package configuration:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">elcord</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:if</span> (<span style="color:#008000">and</span> (<span style="color:#008000">or</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string=</span> (<span style="color:#00f">system-name</span>) <span style="color:#ba2121">&#34;violet&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string=</span> (<span style="color:#00f">system-name</span>) <span style="color:#ba2121">&#34;eminence&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string=</span> (<span style="color:#00f">system-name</span>) <span style="color:#ba2121">&#34;iris&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/remote-server</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> <span style="color:#19177c">my/nested-emacs</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">elcord-buffer-details-format-function</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/elcord-buffer-details-format-functions</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#19177c">&#39;elcord--try-update-presence</span> <span style="color:#008000">:filter-args</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/elcord-update-presence-mask-advice</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;elcord-mode-text-alist</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">telega-chat-mode</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;Telega Chat&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">&#39;elcord-mode-text-alist</span> <span style="color:#666">&#39;</span>(<span style="color:#19177c">telega-root-mode</span> <span style="color:#666">.</span> <span style="color:#ba2121">&#34;Telega Root&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (elcord-mode)</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/elcord-symlink</span>))
</span></span></code></pre></div><h4 id="snow">Snow</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">snow</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;alphapapa/snow.el&#34;</span> <span style="color:#008000">:host</span> <span style="color:#19177c">github</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">snow</span>))
</span></span></code></pre></div><h4 id="power-mode">Power mode</h4>
<p>When Emacs doesn&rsquo;t feel powerful enough.</p>
<p>Watch out if you are using EXWM.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">power-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;elizagamedev/power-mode.el&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:disabled</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">power-mode</span>))
</span></span></code></pre></div><h4 id="redacted">Redacted</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">redacted</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">redacted-mode</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;bkaestner/redacted.el&#34;</span>))
</span></span></code></pre></div><h4 id="zone">Zone</h4>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">zone</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:ensure</span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">zone</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">original-zone-programs</span> (<span style="color:#00f">copy-sequence</span> <span style="color:#19177c">zone-programs</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/zone-with-select</span> ()
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">zone-programs</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">vector</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">intern</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">completing-read</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Zone programs&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-mapcar</span> <span style="color:#19177c">&#39;symbol-name</span> <span style="color:#19177c">original-zone-programs</span>))))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">zone</span>)))
</span></span></code></pre></div><h4 id="gource">Gource</h4>
<p><a href="https://gource.io/">Gource</a> is a program that draws an animated graph of users changing the repository over time.</p>
<p>Although it can work without extra effort (just run <code>gource</code> in a <a href="https://git-scm.com/">git</a> repo), there are some tweaks that can be done:</p>
<ul>
<li>Gource supports using custom pictures for users. <a href="https://en.gravatar.com/">Gravatar</a> is an obvious place to get these.</li>
<li>Occasionally, the same people have different names and/or emails in history.<br />
It may happen when people use forges like <a href="https://gitlab.com/">GitLab</a> or just have different settings on different machines. It would be nice to merge these names.</li>
<li>Visualizing the history of multiple repositories (e.g. frontend and backend) requires combining multiple gource logs.</li>
</ul>
<p>So, why not try doing that with Emacs?</p>
<h5 id="gravatars">Gravatars</h5>
<p>Much to my surprise, Emacs turned out to have a built-in package called <a href="https://github.com/emacs-mirror/emacs/blob/master/lisp/image/gravatar.el">gravatar.el</a>.</p>
<p>So, let&rsquo;s make a function to retrieve a gravatar and save it:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/gravatar-retrieve-sync</span> (<span style="color:#19177c">email</span> <span style="color:#19177c">file-name</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Get gravatar for EMAIL and save it to FILE-NAME.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">gravatar-default-image</span> <span style="color:#ba2121">&#34;identicon&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">gravatar-size</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">coding-system-for-write</span> <span style="color:#19177c">&#39;binary</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">write-region-annotate-functions</span> <span style="color:#800">nil</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">write-region-post-annotation-function</span> <span style="color:#800">nil</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">write-region</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">image-property</span> (<span style="color:#19177c">gravatar-retrieve-synchronously</span> <span style="color:#19177c">email</span>) <span style="color:#008000">:data</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span> <span style="color:#19177c">file-name</span> <span style="color:#800">nil</span> <span style="color:#008000">:silent</span>)))
</span></span></code></pre></div><p>To use these images, we need to save them to some folder and use usernames as file names. The folder:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/gravatar-folder</span> <span style="color:#ba2121">&#34;/home/pavel/.cache/gravatars/&#34;</span>)
</span></span></code></pre></div><p>And the function that downloads a gravatar if necessary:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/gravatar-save</span> (<span style="color:#19177c">email</span> <span style="color:#19177c">author</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Download gravatar for EMAIL.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">AUTHOR is the username.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">file-name</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">my/gravatar-folder</span> <span style="color:#19177c">author</span> <span style="color:#ba2121">&#34;.png&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">mkdir</span> <span style="color:#19177c">my/gravatar-folder</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#00f">file-exists-p</span> <span style="color:#19177c">file-name</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">&#34;Fetching gravatar for %s (%s)&#34;</span> <span style="color:#19177c">author</span> <span style="color:#19177c">email</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/gravatar-retrieve-sync</span> <span style="color:#19177c">email</span> <span style="color:#19177c">file-name</span>))))
</span></span></code></pre></div><h5 id="merging-authors">Merging authors</h5>
<p>Now to merging authors.</p>
<p>Gource itself uses only usernames (without emails), but we can use <code>git log</code> to get both. The required information can be extracted like that:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git log --pretty<span style="color:#666">=</span>format:<span style="color:#ba2121">&#34;%ae|%an&#34;</span> | sort | uniq -c | sed <span style="color:#ba2121">&#34;s/^[ \t]*//;s/ /|/&#34;</span>
</span></span></code></pre></div><p>The output is a list of pipe-separated strings, where the values are:</p>
<ul>
<li>Number of occurrences for this combination of username and email</li>
<li>Email</li>
<li>Username</li>
</ul>
<p>Of course, that part would have to be changed appropriately for other version control systems if you happen to use one.</p>
<p>So, below is one hell of a function that wraps this command and tries to merge emails and usernames belonging to one author:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/git-get-authors</span> (<span style="color:#19177c">repo</span> <span style="color:#008000">&amp;optional</span> <span style="color:#19177c">authors-init</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Extract and merge all combinations of authors &amp; emails from REPO.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">REPO is the path to a git repository.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">AUTHORS-INIT is the previous output of </span><span style="color:#19177c">`my/git-get-authors&#39;</span><span style="color:#ba2121">. It can
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">be used to extract that information from multiple repositories.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">The output is a list of alists with following keys:
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- emails: list of (&lt;email&gt; . &lt;count&gt;)
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- authors: list of (&lt;username&gt; . &lt;count&gt;)
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- email: the most popular email
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">- author: the most popular username
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">I.e. one alist is all emails and usernames of one author.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">default-directory</span> <span style="color:#19177c">repo</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">data</span> (<span style="color:#19177c">shell-command-to-string</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;git log --pretty=format:\&#34;%ae|%an\&#34; | sort | uniq -c | sed \&#34;s/^[ \t]*//;s/ /|/\&#34;&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">authors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#00f">string</span> <span style="color:#19177c">in</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">data</span> <span style="color:#ba2121">&#34;\n&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#00f">=</span> (<span style="color:#00f">length</span> (<span style="color:#19177c">split-string</span> <span style="color:#00f">string</span> <span style="color:#ba2121">&#34;|&#34;</span>)) <span style="color:#666">3</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">datum</span> (<span style="color:#19177c">split-string</span> <span style="color:#00f">string</span> <span style="color:#ba2121">&#34;|&#34;</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#19177c">count</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#00f">string-to-number</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">datum</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">email</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#00f">downcase</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">datum</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">author</span> <span style="color:#666">.</span> <span style="color:#666">,</span>(<span style="color:#00f">nth</span> <span style="color:#666">2</span> <span style="color:#19177c">datum</span>)))))))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">datum</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;author</span> <span style="color:#19177c">datum</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">car</span> (<span style="color:#19177c">cl-reduce</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">acc</span> <span style="color:#19177c">author</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">&gt;</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">author</span>) (<span style="color:#00f">cdr</span> <span style="color:#19177c">acc</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">author</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">acc</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;authors</span> <span style="color:#19177c">datum</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:initial-value</span> <span style="color:#666">&#39;</span>(<span style="color:#800">nil</span> <span style="color:#666">.</span> <span style="color:#666">-1</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;email</span> <span style="color:#19177c">datum</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">car</span> (<span style="color:#19177c">cl-reduce</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">acc</span> <span style="color:#19177c">email</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#00f">&gt;</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">email</span>) (<span style="color:#00f">cdr</span> <span style="color:#19177c">acc</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">email</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">acc</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;emails</span> <span style="color:#19177c">datum</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:initial-value</span> <span style="color:#666">&#39;</span>(<span style="color:#800">nil</span> <span style="color:#666">.</span> <span style="color:#666">-1</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">datum</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-reduce</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">acc</span> <span style="color:#19177c">val</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">author</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;author</span> <span style="color:#19177c">val</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">email</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;email</span> <span style="color:#19177c">val</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">count</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;count</span> <span style="color:#19177c">val</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">saved-value</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-find</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">cand</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">email</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;emails</span> <span style="color:#19177c">cand</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;string-equal</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">author</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;authors</span> <span style="color:#19177c">cand</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;string-equal</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">email</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;authors</span> <span style="color:#19177c">cand</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;string-equal</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">author</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;emails</span> <span style="color:#19177c">cand</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;string-equal</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">acc</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">saved-value</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">progn</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">email</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;emails</span> <span style="color:#19177c">saved-value</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;string-equal</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-incf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">email</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;emails</span> <span style="color:#19177c">saved-value</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;string-equal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">count</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> (<span style="color:#00f">cons</span> <span style="color:#19177c">email</span> <span style="color:#19177c">count</span>) (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;emails</span> <span style="color:#19177c">saved-value</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">author</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;authors</span> <span style="color:#19177c">saved-value</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;string-equal</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-incf</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">author</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;authors</span> <span style="color:#19177c">saved-value</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;string-equal</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">count</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> (<span style="color:#00f">cons</span> <span style="color:#19177c">author</span> <span style="color:#19177c">count</span>) (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;authors</span> <span style="color:#19177c">saved-value</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">saved-value</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">push</span> <span style="color:#666">`</span>((<span style="color:#19177c">emails</span> <span style="color:#666">.</span> ((<span style="color:#666">,</span><span style="color:#19177c">email</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">count</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">authors</span> <span style="color:#666">.</span> ((<span style="color:#666">,</span><span style="color:#19177c">author</span> <span style="color:#666">.</span> <span style="color:#666">,</span><span style="color:#19177c">count</span>))))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">acc</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">acc</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">authors</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:initial-value</span> <span style="color:#19177c">authors-init</span>))))
</span></span></code></pre></div><p>Despite the probable we-enjoy-typing-ness of the implementation, it&rsquo;s actually pretty simple:</p>
<ul>
<li>The output of <code>git log</code> is parsed into a list of alists with <code>count</code>, <code>email</code> and <code>author</code> as keys.</li>
<li>This list is reduced by <code>cl-reduce</code> into a list of alists with <code>emails</code> and <code>authors</code> as keys and the respective counts as values, e.g. <code>((&lt;email-1&gt; . 1) (&lt;email-2&gt; . 3))</code>.<br />
I&rsquo;ve seen a couple of cases where people would swap their username and email (lol), so <code>seq-find</code> also looks for an email in the list of authors and vice versa.</li>
<li>The <code>mapcar</code> call determines the most popular email and username for each authors.</li>
</ul>
<p>The output is another list of alists, now with the following keys:</p>
<ul>
<li><code>emails</code> - list of elements like <code>(&lt;email&gt; . &lt;count&gt;)</code></li>
<li><code>authors</code> - list of elements like <code>(&lt;author-name&gt; . &lt;count&gt;)</code></li>
<li><code>email</code> - the most popular email</li>
<li><code>author</code> - the most popular username.</li>
</ul>
<h5 id="running-for-multiple-repos">Running for multiple repos</h5>
<p>This section was mostly informed by <a href="https://github.com/acaudwell/Gource/wiki/Visualizing-Multiple-Repositories">this page</a> in the <a href="https://github.com/acaudwell/Gource/wiki">gource wiki</a>.</p>
<p>As I said above, by default <code>gource</code> just creates a visualization for the current repo. To change something in it, we need to invoke the program like that: <code>gource --output-custom-log PATH</code>, where <code>PATH</code> is either the path to the log file or <code>-</code> for stdout.</p>
<p>The log consists of lines of pipe-separated strings, e.g.:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>1600769568|dsofronov|A|/studentor/.dockerignore
</span></span><span style="display:flex;"><span>1600769568|dsofronov|A|/studentor/.editorconfig
</span></span><span style="display:flex;"><span>1600769568|dsofronov|A|/studentor/.flake8
</span></span><span style="display:flex;"><span>1600769568|dsofronov|A|/studentor/.gitignore
</span></span></code></pre></div><p>where the values of one line are:</p>
<ul>
<li>UNIX timestamp</li>
<li>Author name</li>
<li><code>A</code> for add, <code>M</code> for modify, and <code>D</code> for delete</li>
<li>Path to file</li>
</ul>
<p>The file has to be sorted by the timestamp in ascending order.</p>
<p>So, the function that prepares the log for one repository:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/gource-prepare-log</span> (<span style="color:#19177c">repo</span> <span style="color:#19177c">authors</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Create gource log string for REPO.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">AUTHORS is the output of </span><span style="color:#19177c">`my/git-get-authors&#39;</span><span style="color:#ba2121">.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#00f">log</span> (<span style="color:#19177c">shell-command-to-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;gource --output-custom-log - &#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">repo</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">authors-mapping</span> (<span style="color:#00f">make-hash-table</span> <span style="color:#008000">:test</span> <span style="color:#00f">#&#39;equal</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">prefix</span> (<span style="color:#19177c">file-name-base</span> <span style="color:#19177c">repo</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">author-datum</span> <span style="color:#19177c">in</span> <span style="color:#19177c">authors</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">author</span> <span style="color:#00f">=</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;author</span> <span style="color:#19177c">author-datum</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#19177c">my/gravatar-save</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;email</span> <span style="color:#19177c">author-datum</span>) <span style="color:#19177c">author</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">other-author</span> <span style="color:#19177c">in</span> (<span style="color:#19177c">alist-get</span> <span style="color:#19177c">&#39;authors</span> <span style="color:#19177c">author-datum</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">unless</span> (<span style="color:#00f">string-equal</span> (<span style="color:#00f">car</span> <span style="color:#19177c">other-author</span>) <span style="color:#19177c">author</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#00f">puthash</span> (<span style="color:#00f">car</span> <span style="color:#19177c">other-author</span>) <span style="color:#19177c">author</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">authors-mapping</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">line</span> <span style="color:#19177c">in</span> (<span style="color:#19177c">split-string</span> <span style="color:#00f">log</span> <span style="color:#ba2121">&#34;\n&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#00f">concat</span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">fragments</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">line</span> <span style="color:#ba2121">&#34;|&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">&gt;</span> (<span style="color:#00f">length</span> <span style="color:#19177c">fragments</span>) <span style="color:#666">3</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">when-let</span> (<span style="color:#19177c">mapped-author</span> (<span style="color:#00f">gethash</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">fragments</span>)
</span></span><span style="display:flex;"><span> <span style="color:#19177c">authors-mapping</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">fragments</span>) <span style="color:#19177c">mapped-author</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setf</span> (<span style="color:#00f">nth</span> <span style="color:#666">3</span> <span style="color:#19177c">fragments</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;/&#34;</span> <span style="color:#19177c">prefix</span> (<span style="color:#00f">nth</span> <span style="color:#666">3</span> <span style="color:#19177c">fragments</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-join</span> <span style="color:#19177c">fragments</span> <span style="color:#ba2121">&#34;|&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#00f">concat</span> <span style="color:#ba2121">&#34;\n&#34;</span>)))
</span></span></code></pre></div><p>This function:</p>
<ul>
<li>Downloads a gravatar for each author</li>
<li>Replaces all usernames of one author with the most frequent one</li>
<li>Prepends the file path with the repository name.</li>
</ul>
<p>The output is a string in the gource log format as described above.</p>
<p>Finally, as we need to invoke all of this for multiple repositories, why not do that with <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Dired.html">dired</a>:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/gource-dired-create-logs</span> (<span style="color:#19177c">repos</span> <span style="color:#19177c">log-name</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;Create combined gource log for REPOS.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">REPOS is a list of strings, where a string is a path to a git repo.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">LOG-NAME is the path to the resulting log file.
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">This function is meant to be invoked from </span><span style="color:#19177c">`dired&#39;</span><span style="color:#ba2121">, where the required
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">repositories are marked.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> (<span style="color:#00f">list</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">dired-get-marked-files</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00f">#&#39;file-directory-p</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">&#34;Select at least one directory&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">read-file-name</span> <span style="color:#ba2121">&#34;Log file name: &#34;</span> <span style="color:#800">nil</span> <span style="color:#ba2121">&#34;combined.log&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">authors</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-reduce</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">acc</span> <span style="color:#19177c">repo</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/git-get-authors</span> <span style="color:#19177c">repo</span> <span style="color:#19177c">acc</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">repos</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:initial-value</span> <span style="color:#800">nil</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-temp-file</span> <span style="color:#19177c">log-name</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-join</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">line</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">line</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-sort-by</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">line</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">if-let</span> (<span style="color:#19177c">time</span> (<span style="color:#00f">car</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">line</span> <span style="color:#ba2121">&#34;|&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#00f">string-to-number</span> <span style="color:#19177c">time</span>)
</span></span><span style="display:flex;"><span> <span style="color:#666">0</span>))
</span></span><span style="display:flex;"><span> <span style="color:#00f">#&#39;&lt;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">split-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapconcat</span>
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">repo</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/gource-prepare-log</span> <span style="color:#19177c">repo</span> <span style="color:#19177c">authors</span>))
</span></span><span style="display:flex;"><span> <span style="color:#19177c">repos</span> <span style="color:#ba2121">&#34;\n&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\n&#34;</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">&#34;\n&#34;</span>)))))
</span></span></code></pre></div><p>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.</p>
<h5 id="using-the-function">Using the function</h5>
<p>To use the function above, mark the required repos in a dired buffer and run <code>M-x my/gource-dired-create-logs</code>. This also works nicely with <a href="https://github.com/Fuco1/dired-hacks">dired-subtree</a>, in case your repos are located in different folders.</p>
<p>The function will create a combined log file (by default <code>combined.log</code>). To visualize the log, run:</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>gource &lt;log-file&gt; --user-image-dir &lt;path-to-gravatars&gt;
</span></span></code></pre></div><p>Check the <a href="https://github.com/acaudwell/Gource">README</a> for possible parameters, such as the speed of visualization, different elements, etc. That&rsquo;s it!</p>
<p>I thought about making something like a <a href="https://github.com/magit/transient">transient.el</a> wrapper around the <code>gource</code> command but figured it wasn&rsquo;t worth the effort for something that I run just a handful of times in a year.</p>
<h4 id="memes">Memes</h4>
<p>Generate memes from Emacs.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">imgur</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;larsmagne/imgur.el&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:defer</span> <span style="color:#800">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">meme</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;larsmagne/meme&#34;</span> <span style="color:#008000">:files</span> (<span style="color:#008000">:defaults</span> <span style="color:#ba2121">&#34;images&#34;</span>))
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">meme</span>))
</span></span></code></pre></div><h4 id="ed">Ed</h4>
<p>My text editor isn&rsquo;t old enough.</p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ed-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">&#34;ryanprior/ed-mode&#34;</span>)
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">ed</span>))
</span></span></code></pre></div><h2 id="guix-settings">Guix settings</h2>
<table>
<thead>
<tr>
<th>Guix dependency</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>emacs-vterm</td>
<td>The vterm package</td>
</tr>
<tr>
<td>ripgrep</td>
<td>A recursive search tool</td>
</tr>
<tr>
<td>the-silver-searcher</td>
<td>Another recursive search tool</td>
</tr>
<tr>
<td>texinfo</td>
<td></td>
</tr>
</tbody>
</table>
<p><a id="code-snippet--packages"></a></p>
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">when</span> (<span style="color:#00f">fboundp</span> <span style="color:#00f">#&#39;</span><span style="color:#19177c">my/format-guix-dependencies</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/format-guix-dependencies</span>))
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-scheme" data-lang="scheme"><span style="display:flex;"><span>(<span style="color:#00f">specifications-&gt;manifest</span>
</span></span><span style="display:flex;"><span> <span style="color:#666">&#39;</span>(<span style="color:#ba2121">&#34;emacs&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#19177c">&lt;&lt;packages</span>()<span style="color:#19177c">&gt;&gt;</span>))
</span></span></code></pre></div>
</div>
<div class="table-of-contents">
<div class="table-of-contents-text">
<b><a href="#">Table of Contents</a></b>
<nav id="TableOfContents">
<ul>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#some-remarks">Some remarks</a></li>
<li><a href="#initial-setup">Initial setup</a>
<ul>
<li><a href="#packages">Packages</a>
<ul>
<li><a href="#straight-dot-el">straight.el</a></li>
<li><a href="#use-package">use-package</a></li>
</ul>
</li>
<li><a href="#variables-and-environment">Variables &amp; environment</a></li>
<li><a href="#performance">Performance</a>
<ul>
<li><a href="#measure-startup-speed">Measure startup speed</a></li>
<li><a href="#garbage-collection">Garbage collection</a></li>
<li><a href="#run-garbage-collection-when-emacs-is-unfocused">Run garbage collection when Emacs is unfocused</a></li>
<li><a href="#measure-ram-usage">Measure RAM usage</a></li>
</ul>
</li>
<li><a href="#micromamba">Micromamba</a></li>
<li><a href="#config-files">Config files</a>
<ul>
<li><a href="#custom-file-location">Custom file location</a></li>
<li><a href="#authinfo">authinfo</a></li>
<li><a href="#private-config">Private config</a></li>
<li><a href="#no-littering">No littering</a></li>
</ul>
</li>
<li><a href="#helper-functions">Helper functions</a>
<ul>
<li><a href="#run-command-in-background">Run command in background</a></li>
<li><a href="#close-buffer-and-its-windows">Close buffer and its windows</a></li>
</ul>
</li>
<li><a href="#prevent-emacs-from-closing">Prevent Emacs from closing</a></li>
<li><a href="#scratch-buffer">Scratch buffer</a></li>
</ul>
</li>
<li><a href="#general-settings">General settings</a>
<ul>
<li><a href="#keybindings">Keybindings</a>
<ul>
<li><a href="#general-dot-el">general.el</a></li>
<li><a href="#which-key">which-key</a></li>
<li><a href="#evil">Evil</a></li>
<li><a href="#my-keybindings">My keybindings</a></li>
<li><a href="#termux">Termux</a></li>
</ul>
</li>
<li><a href="#i3-integration-1">i3 integration</a></li>
<li><a href="#editing-text">Editing text</a>
<ul>
<li><a href="#indentation-and-whitespace">Indentation &amp; whitespace</a></li>
<li><a href="#settings">Settings</a></li>
<li><a href="#undo-tree">Undo Tree</a></li>
<li><a href="#snippets">Snippets</a></li>
<li><a href="#input-method">Input Method</a></li>
<li><a href="#other-small-packages">Other small packages</a></li>
<li><a href="#random-editing-tricks">Random editing tricks</a></li>
</ul>
</li>
<li><a href="#working-with-projects">Working with projects</a>
<ul>
<li><a href="#projectile">Projectile</a></li>
<li><a href="#git-and-magit">Git &amp; Magit</a></li>
<li><a href="#forge-and-code-review">Forge and code-review</a></li>
<li><a href="#editorconfig">Editorconfig</a></li>
<li><a href="#editing-files">Editing files</a></li>
<li><a href="#deadgrep">Deadgrep</a></li>
</ul>
</li>
<li><a href="#navigation">Navigation</a>
<ul>
<li><a href="#registers">Registers</a></li>
<li><a href="#marks">Marks</a></li>
<li><a href="#avy">Avy</a></li>
</ul>
</li>
<li><a href="#completion">Completion</a>
<ul>
<li><a href="#vertico">vertico</a></li>
<li><a href="#vertico-extensions">vertico extensions</a></li>
<li><a href="#orderless">orderless</a></li>
<li><a href="#consult">consult</a></li>
<li><a href="#marginalia">marginalia</a></li>
<li><a href="#embark">embark</a></li>
<li><a href="#keybindings-1">keybindings</a></li>
<li><a href="#company">company</a></li>
</ul>
</li>
<li><a href="#help">Help</a></li>
<li><a href="#time-trackers">Time trackers</a>
<ul>
<li><a href="#wakatime">WakaTime</a></li>
<li><a href="#activitywatch">ActivityWatch</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#ui-settings">UI settings</a>
<ul>
<li><a href="#general-settings-1">General settings</a>
<ul>
<li><a href="#miscellaneous">Miscellaneous</a></li>
<li><a href="#line-numbers">Line numbers</a></li>
<li><a href="#word-wrapping">Word wrapping</a></li>
<li><a href="#custom-frame-format">Custom frame format</a></li>
<li><a href="#olivetti">Olivetti</a></li>
<li><a href="#keycast">Keycast</a></li>
</ul>
</li>
<li><a href="#themes-and-colors">Themes and colors</a>
<ul>
<li><a href="#theme-packages">Theme packages</a></li>
<li><a href="#custom-theme-1">Custom theme</a></li>
<li><a href="#dim-inactive-buffers">Dim inactive buffers</a></li>
<li><a href="#ansi-colors">ANSI colors</a></li>
</ul>
</li>
<li><a href="#fonts">Fonts</a>
<ul>
<li><a href="#frame-font">Frame font</a></li>
<li><a href="#other-fonts">Other fonts</a></li>
<li><a href="#ligatures">Ligatures</a></li>
<li><a href="#icons">Icons</a></li>
</ul>
</li>
<li><a href="#text-highlight">Text highlight</a></li>
<li><a href="#doom-modeline">Doom Modeline</a>
<ul>
<li><a href="#doom-modeline-as-tab-bar">Doom Modeline as Tab Bar</a></li>
</ul>
</li>
<li><a href="#perspective-dot-el">perspective.el</a>
<ul>
<li><a href="#functions-to-manage-buffers">Functions to manage buffers</a></li>
<li><a href="#automating-perspectives">Automating perspectives</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#programming">Programming</a>
<ul>
<li><a href="#general-setup">General setup</a>
<ul>
<li><a href="#treemacs">Treemacs</a></li>
<li><a href="#lsp">LSP</a></li>
<li><a href="#flycheck">Flycheck</a></li>
<li><a href="#general-additional-config">General additional config</a></li>
<li><a href="#tree-sitter">Tree-sitter</a></li>
<li><a href="#dap">DAP</a></li>
<li><a href="#reformatter">Reformatter</a></li>
<li><a href="#copilot">copilot</a></li>
</ul>
</li>
<li><a href="#web-development">Web development</a>
<ul>
<li><a href="#emmet">Emmet</a></li>
<li><a href="#prettier">Prettier</a></li>
<li><a href="#typescript">TypeScript</a></li>
<li><a href="#javascript">JavaScript</a></li>
<li><a href="#jest">Jest</a></li>
<li><a href="#web-mode">web-mode</a></li>
<li><a href="#scss">SCSS</a></li>
<li><a href="#php">PHP</a></li>
</ul>
</li>
<li><a href="#latex">LaTeX</a>
<ul>
<li><a href="#auctex">AUCTeX</a></li>
<li><a href="#import-dot-sty">Import *.sty</a></li>
<li><a href="#snippets-1">Snippets</a></li>
</ul>
</li>
<li><a href="#markup-and-natural-languages">Markup &amp; natural languages</a>
<ul>
<li><a href="#markdown">Markdown</a></li>
<li><a href="#ascii-doc">Ascii Doc</a></li>
<li><a href="#plantuml">PlantUML</a></li>
<li><a href="#subtitles">Subtitles</a></li>
<li><a href="#ltex">LTeX</a></li>
<li><a href="#languagetool">LanguageTool</a></li>
<li><a href="#reverso">Reverso</a></li>
</ul>
</li>
<li><a href="#lisp">Lisp</a>
<ul>
<li><a href="#meta-lisp">Meta Lisp</a></li>
<li><a href="#emacs-lisp">Emacs Lisp</a></li>
<li><a href="#common-lisp">Common lisp</a></li>
<li><a href="#clojure">Clojure</a></li>
<li><a href="#hy">Hy</a></li>
<li><a href="#scheme">Scheme</a></li>
<li><a href="#clips">CLIPS</a></li>
</ul>
</li>
<li><a href="#python">Python</a>
<ul>
<li><a href="#ein">ein</a></li>
<li><a href="#pyright">pyright</a></li>
<li><a href="#pipenv">pipenv</a></li>
<li><a href="#off--yapf"><span class="org-todo done OFF">OFF</span> (OFF) yapf</a></li>
<li><a href="#black">black</a></li>
<li><a href="#isort">isort</a></li>
<li><a href="#sphinx-doc"><span class="org-todo done OFF">OFF</span> sphinx-doc</a></li>
<li><a href="#numpydoc">numpydoc</a></li>
<li><a href="#pytest">pytest</a></li>
<li><a href="#code-cells">code-cells</a></li>
<li><a href="#tensorboard">tensorboard</a></li>
</ul>
</li>
<li><a href="#data-serialization">Data serialization</a>
<ul>
<li><a href="#json">JSON</a></li>
<li><a href="#csv">CSV</a></li>
<li><a href="#yaml">YAML</a></li>
</ul>
</li>
<li><a href="#configuration">Configuration</a>
<ul>
<li><a href="#dot-env">.env</a></li>
<li><a href="#dot-gitignore">.gitignore</a></li>
<li><a href="#docker">Docker</a></li>
<li><a href="#jenkins">Jenkins</a></li>
<li><a href="#crontab">crontab</a></li>
<li><a href="#nginx">nginx</a></li>
<li><a href="#hcl">HCL</a></li>
</ul>
</li>
<li><a href="#shell">Shell</a>
<ul>
<li><a href="#sh">sh</a></li>
<li><a href="#fish">fish</a></li>
</ul>
</li>
<li><a href="#query-languages">Query languages</a>
<ul>
<li><a href="#sql">SQL</a></li>
<li><a href="#sparql">SPARQL</a></li>
<li><a href="#graphql">GraphQL</a></li>
</ul>
</li>
<li><a href="#documents">Documents</a>
<ul>
<li><a href="#docview">DocView</a></li>
</ul>
</li>
<li><a href="#gnuplot">Gnuplot</a></li>
<li><a href="#x509">x509</a></li>
<li><a href="#java">Java</a></li>
<li><a href="#go">Go</a></li>
<li><a href="#dot-net">.NET</a>
<ul>
<li><a href="#c">C#</a></li>
<li><a href="#msbuild">MSBuild</a></li>
</ul>
</li>
<li><a href="#haskell">Haskell</a></li>
<li><a href="#nix">nix</a></li>
<li><a href="#lua">Lua</a></li>
</ul>
</li>
<li><a href="#org-mode">Org Mode</a>
<ul>
<li><a href="#installation-and-basic-settings">Installation &amp; basic settings</a>
<ul>
<li><a href="#encryption">Encryption</a></li>
<li><a href="#org-contrib">org-contrib</a></li>
<li><a href="#ol-notmuch">ol-notmuch</a></li>
<li><a href="#org-tempo">org-tempo</a></li>
<li><a href="#evil-org">evil-org</a></li>
<li><a href="#support-for-relative-urls">Support for relative URLs</a></li>
</ul>
</li>
<li><a href="#keybindings-and-stuff">Keybindings &amp; stuff</a>
<ul>
<li><a href="#general-keybindings">General keybindings</a></li>
<li><a href="#copy-a-link">Copy a link</a></li>
<li><a href="#navigating-source-blocks">Navigating source blocks</a></li>
<li><a href="#open-a-file-from-org-directory">Open a file from <code>org-directory</code></a></li>
</ul>
</li>
<li><a href="#ui-1">UI</a>
<ul>
<li><a href="#latex-fragments">LaTeX fragments</a></li>
<li><a href="#better-headers">Better headers</a></li>
<li><a href="#override-colors">Override colors</a></li>
<li><a href="#hide-stuff-in-buffer">Hide stuff in buffer</a></li>
</ul>
</li>
<li><a href="#literate-programing">Literate programing</a>
<ul>
<li><a href="#python-and-jupyter">Python &amp; Jupyter</a></li>
<li><a href="#hy-1">Hy</a></li>
<li><a href="#view-html-in-browser">View HTML in browser</a></li>
<li><a href="#plantuml-1">PlantUML</a></li>
<li><a href="#restclient">Restclient</a></li>
<li><a href="#org-babel-setup">Org Babel Setup</a></li>
<li><a href="#managing-jupyter-kernels">Managing Jupyter kernels</a></li>
<li><a href="#output-post-processing">Output post-processing</a></li>
<li><a href="#executing-stuff">Executing stuff</a></li>
<li><a href="#managing-a-literate-programming-project">Managing a literate programming project</a></li>
</ul>
</li>
<li><a href="#tools">Tools</a>
<ul>
<li><a href="#presentations">Presentations</a></li>
<li><a href="#toc">TOC</a></li>
<li><a href="#screenshots">Screenshots</a></li>
<li><a href="#transclusion">Transclusion</a></li>
<li><a href="#drawing">Drawing</a></li>
<li><a href="#managing-tables">Managing tables</a></li>
<li><a href="#partial-scrolling">Partial scrolling</a></li>
</ul>
</li>
<li><a href="#productivity-and-knowledge-management">Productivity &amp; Knowledge management</a>
<ul>
<li><a href="#org-agenda-and-project-management">Org Agenda &amp; Project Management</a></li>
<li><a href="#org-journal-1">Org Journal</a></li>
<li><a href="#bibliography">Bibliography</a></li>
<li><a href="#org-roam-1">Org Roam</a></li>
<li><a href="#review-workflow">Review workflow</a></li>
<li><a href="#contacts">Contacts</a></li>
<li><a href="#calendar-view">Calendar view</a></li>
<li><a href="#org-timeblock">org-timeblock</a></li>
<li><a href="#org-drill">org-drill</a></li>
</ul>
</li>
<li><a href="#export">Export</a>
<ul>
<li><a href="#hugo">Hugo</a></li>
<li><a href="#jupyter-notebook">Jupyter Notebook</a></li>
<li><a href="#html-export">Html export</a></li>
<li><a href="#org-ref-1">org-ref</a></li>
<li><a href="#latex-1">LaTeX</a></li>
</ul>
</li>
<li><a href="#system-configuration">System configuration</a>
<ul>
<li><a href="#tables-for-guix-dependencies">Tables for Guix Dependencies</a></li>
<li><a href="#noweb-evaluations">Noweb evaluations</a></li>
<li><a href="#yadm-hook">yadm hook</a></li>
<li><a href="#regenerate-desktop-config">Regenerate desktop config</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#applications">Applications</a>
<ul>
<li><a href="#dired">Dired</a>
<ul>
<li><a href="#basic-config-and-keybindings">Basic config &amp; keybindings</a></li>
<li><a href="#addons-1">Addons</a></li>
<li><a href="#subdirectories">Subdirectories</a></li>
<li><a href="#other-functions">Other functions</a></li>
<li><a href="#bookmarks">Bookmarks</a></li>
<li><a href="#integrations">Integrations</a></li>
</ul>
</li>
<li><a href="#tramp">TRAMP</a>
<ul>
<li><a href="#general-settings-4">General settings</a></li>
<li><a href="#package-optimizations">Package optimizations</a></li>
</ul>
</li>
<li><a href="#shells-terminals">Shells / Terminals</a>
<ul>
<li><a href="#vterm">vterm</a></li>
<li><a href="#eshell">eshell</a></li>
<li><a href="#eat">eat</a></li>
<li><a href="#shell-1">shell</a></li>
</ul>
</li>
<li><a href="#managing-dotfiles">Managing dotfiles</a>
<ul>
<li><a href="#open-emacs-config">Open Emacs config</a></li>
<li><a href="#open-magit-for-yadm">Open Magit for yadm</a></li>
<li><a href="#open-a-dotfile">Open a dotfile</a></li>
</ul>
</li>
<li><a href="#elfeed">Elfeed</a>
<ul>
<li><a href="#general-settings-5">General settings</a></li>
<li><a href="#some-additions">Some additions</a></li>
<li><a href="#custom-faces">Custom faces</a></li>
<li><a href="#elfeed-summary">elfeed-summary</a></li>
<li><a href="#elfeed-sync">elfeed-sync</a></li>
<li><a href="#youtube-podcasts-and-emms">YouTube, podcasts &amp; EMMS</a></li>
<li><a href="#rdrview">rdrview</a></li>
<li><a href="#latex-and-pandoc">LaTeX and pandoc</a></li>
<li><a href="#youtube-transcripts">YouTube transcripts</a></li>
</ul>
</li>
<li><a href="#internet-and-multimedia">Internet &amp; Multimedia</a>
<ul>
<li><a href="#notmuch">Notmuch</a></li>
<li><a href="#gnus">Gnus</a></li>
<li><a href="#emms">EMMS</a></li>
<li><a href="#eww">EWW</a></li>
<li><a href="#erc">ERC</a></li>
<li><a href="#mastodon">Mastodon</a></li>
<li><a href="#wallabag">wallabag</a></li>
<li><a href="#ement-dot-el">ement.el</a></li>
<li><a href="#telega">Telega</a></li>
<li><a href="#google-translate">Google Translate</a></li>
<li><a href="#biome">biome</a></li>
</ul>
</li>
<li><a href="#reading-documentation">Reading documentation</a>
<ul>
<li><a href="#tldr">tldr</a></li>
<li><a href="#man-and-info">man &amp; info</a></li>
<li><a href="#devdocs-dot-io">devdocs.io</a></li>
<li><a href="#stackexchange">StackExchange</a></li>
</ul>
</li>
<li><a href="#not-an-ai">Not-an-AI</a>
<ul>
<li><a href="#llms">LLMs</a></li>
<li><a href="#podcast-transcripts">Podcast transcripts</a></li>
</ul>
</li>
<li><a href="#declarative-filesystem-management">Declarative filesystem management</a>
<ul>
<li><a href="#idea">Idea</a></li>
<li><a href="#implementation">Implementation</a></li>
<li><a href="#org-tree">Org tree</a></li>
<li><a href="#commands">Commands</a></li>
<li><a href="#navigation-1">Navigation</a></li>
<li><a href="#export-tree">Export tree</a></li>
</ul>
</li>
<li><a href="#utilities">Utilities</a>
<ul>
<li><a href="#pass">pass</a></li>
<li><a href="#docker-1">Docker</a></li>
<li><a href="#screenshot-dot-el">screenshot.el</a></li>
<li><a href="#proced">proced</a></li>
<li><a href="#guix">Guix</a></li>
<li><a href="#atomic-chrome">Atomic Chrome</a></li>
<li><a href="#pinentry">Pinentry</a></li>
</ul>
</li>
<li><a href="#productivity">Productivity</a>
<ul>
<li><a href="#pomm">pomm</a></li>
<li><a href="#hledger">hledger</a></li>
<li><a href="#calendar">Calendar</a></li>
</ul>
</li>
<li><a href="#calc">Calc</a></li>
<li><a href="#chess">Chess</a>
<ul>
<li><a href="#chess-dot-el">chess.el</a></li>
<li><a href="#render-pgn">Render PGN</a></li>
</ul>
</li>
<li><a href="#fun">Fun</a>
<ul>
<li><a href="#discord-integration">Discord integration</a></li>
<li><a href="#snow">Snow</a></li>
<li><a href="#power-mode">Power mode</a></li>
<li><a href="#redacted">Redacted</a></li>
<li><a href="#zone">Zone</a></li>
<li><a href="#gource">Gource</a></li>
<li><a href="#memes">Memes</a></li>
<li><a href="#ed">Ed</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#guix-settings">Guix settings</a></li>
</ul>
</nav>
</div>
<a id="unhide-all-button" class="hidden">&lt;Expand&gt;</a>
<a id="hide-all-button" class="hidden">&lt;Collapse&gt;</a>
</div>
</div>
</div><div id="footer" class="mb-5">
<hr>
<div class="container text-center">
</div>
<div class="container text-center">
<a href="https://creativecommons.org/licenses/by/4.0/legalcode" title="Licensed under CC-BY 4.0"><small>Licensed under CC-BY 4.0</small></a>
|
<a href="https://plausible.io/" title="Uses Plausible Analytics"><small>Uses Plausible Analytics</small></a>
<br>
<a href="https://sqrtminusone.xyz/" title="Pavel Korytov, 2024"><small>Pavel Korytov, 2024</small></a>
</div>
</div>
</body>
</html>