deploy: bfd7977f09
BIN
avy-dired-img/screenshot.png
Normal file
|
After Width: | Height: | Size: 173 KiB |
BIN
biome-img/columns.png
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
biome-img/multi.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
biome-img/query.png
Normal file
|
After Width: | Height: | Size: 297 KiB |
BIN
biome-img/report.png
Normal file
|
After Width: | Height: | Size: 831 KiB |
BIN
biome-img/root.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
10
config/index.html
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<title>https://sqrtminusone.xyz/configs/readme/</title>
|
||||
<link rel="canonical" href="https://sqrtminusone.xyz/configs/readme/">
|
||||
<meta name="robots" content="noindex">
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0; url=https://sqrtminusone.xyz/configs/readme/">
|
||||
</head>
|
||||
</html>
|
||||
1213
configs/console/index.html
Normal file
4645
configs/desktop/index.html
Normal file
10317
configs/emacs/index.html
Normal file
887
configs/guix/index.html
Normal file
|
|
@ -0,0 +1,887 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>Guix</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">
|
||||
Guix
|
||||
<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">
|
||||
Guix
|
||||
<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>
|
||||
<p><a href="https://guix.gnu.org/">GNU Guix</a> is (1) a transactional package manager and (2) a GNU/Linux distribution.</p>
|
||||
<p>My personal selling points are declarative package configuration and transactional upgrades.</p>
|
||||
<p>References:</p>
|
||||
<ul>
|
||||
<li><a href="https://guix.gnu.org/en/help/">Official help</a></li>
|
||||
<li><a href="https://wiki.systemcrafters.cc/guix">System Crafters wiki</a></li>
|
||||
<li><a href="https://gitlab.com/pjotrp/guix-notes">Pjotr Prins’ Guix notes</a></li>
|
||||
<li><a href="https://www.youtube.com/watch?v=iBaqOK75cho&list=PLEoMzSkcN8oNxnj7jm5V2ZcGc52002pQU">Davil Wilson’s YouTube series</a></li>
|
||||
</ul>
|
||||
<h2 id="profiles">Profiles</h2>
|
||||
<p>A profile is a way to group Guix packages. Amongst its advantages, profiles can be defined by manifests, which in turn can be stored in VCS.</p>
|
||||
<p>References:</p>
|
||||
<ul>
|
||||
<li><a href="https://guix.gnu.org/en/cookbook/en/html_node/Guix-Profiles-in-Practice.html">Guix Profiles in Practice</a></li>
|
||||
</ul>
|
||||
<h3 id="activate-profiles">Activate profiles</h3>
|
||||
<p>A script to activate guix profiles. 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>activate-profiles [profile1] [profile2] ...
|
||||
</span></span></code></pre></div><p>Source: <a href="https://github.com/daviwil/dotfiles/blob/master/Systems.org#activating-profiles">David Wilson’s config</a></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:#19177c">GREEN</span><span style="color:#666">=</span><span style="color:#ba2121">'\033[1;32m'</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">RED</span><span style="color:#666">=</span><span style="color:#ba2121">'\033[1;30m'</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">NC</span><span style="color:#666">=</span><span style="color:#ba2121">'\033[0m'</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">GUIX_EXTRA_PROFILES</span><span style="color:#666">=</span><span style="color:#19177c">$HOME</span>/.guix-extra-profiles
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">profiles</span><span style="color:#666">=</span><span style="color:#19177c">$*</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">if</span> <span style="color:#666">[[</span> <span style="color:#19177c">$#</span> -eq <span style="color:#666">0</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">profiles</span><span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#19177c">$HOME</span><span style="color:#ba2121">/.config/guix/manifests/*.scm"</span>;
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">for</span> profile in <span style="color:#19177c">$profiles</span>; <span style="color:#008000;font-weight:bold">do</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic"># Remove the path and file extension, if any</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">profileName</span><span style="color:#666">=</span><span style="color:#008000;font-weight:bold">$(</span>basename <span style="color:#19177c">$profile</span><span style="color:#008000;font-weight:bold">)</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">profileName</span><span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#b68;font-weight:bold">${</span><span style="color:#19177c">profileName</span>%.*<span style="color:#b68;font-weight:bold">}</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">profilePath</span><span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#19177c">$GUIX_EXTRA_PROFILES</span><span style="color:#ba2121">/</span><span style="color:#19177c">$profileName</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">manifestPath</span><span style="color:#666">=</span><span style="color:#19177c">$HOME</span>/.config/guix/manifests/<span style="color:#19177c">$profileName</span>.scm
|
||||
</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:#666">[</span> -f <span style="color:#19177c">$manifestPath</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:#008000">echo</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span> -e <span style="color:#ba2121">"</span><span style="color:#b68;font-weight:bold">${</span><span style="color:#19177c">GREEN</span><span style="color:#b68;font-weight:bold">}</span><span style="color:#ba2121">Activating profile:"</span> <span style="color:#19177c">$manifestPath</span> <span style="color:#ba2121">"</span><span style="color:#b68;font-weight:bold">${</span><span style="color:#19177c">NC</span><span style="color:#b68;font-weight:bold">}</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> mkdir -p <span style="color:#19177c">$profilePath</span>
|
||||
</span></span><span style="display:flex;"><span> guix package --manifest<span style="color:#666">=</span><span style="color:#19177c">$manifestPath</span> --profile<span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#19177c">$profilePath</span><span style="color:#ba2121">/</span><span style="color:#19177c">$profileName</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic"># Source the new profile</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">GUIX_PROFILE</span><span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#19177c">$profilePath</span><span style="color:#ba2121">/</span><span style="color:#19177c">$profileName</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">if</span> <span style="color:#666">[</span> -f <span style="color:#19177c">$GUIX_PROFILE</span>/etc/profile <span style="color:#666">]</span>; <span style="color:#008000;font-weight:bold">then</span>
|
||||
</span></span><span style="display:flex;"><span> . <span style="color:#ba2121">"</span><span style="color:#19177c">$GUIX_PROFILE</span><span style="color:#ba2121">"</span>/etc/profile
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">else</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span> -e <span style="color:#ba2121">"</span><span style="color:#b68;font-weight:bold">${</span><span style="color:#19177c">RED</span><span style="color:#b68;font-weight:bold">}</span><span style="color:#ba2121">Couldn't find profile:"</span> <span style="color:#19177c">$GUIX_PROFILE</span>/etc/profile <span style="color:#ba2121">"</span><span style="color:#b68;font-weight:bold">${</span><span style="color:#19177c">NC</span><span style="color:#b68;font-weight:bold">}</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">else</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span> <span style="color:#ba2121">"No profile found at path"</span> <span style="color:#19177c">$profilePath</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">done</span>
|
||||
</span></span></code></pre></div><h3 id="update-profiles">Update profiles</h3>
|
||||
<p>A script to update Guix profiles. 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>update-profiles [profile1] [profile2] ...
|
||||
</span></span></code></pre></div><p>Source: once again, <a href="https://github.com/daviwil/dotfiles/blob/master/Systems.org#updating-profiles">David Wilson’s config</a>.</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:#19177c">GREEN</span><span style="color:#666">=</span><span style="color:#ba2121">'\033[1;32m'</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">NC</span><span style="color:#666">=</span><span style="color:#ba2121">'\033[0m'</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">GUIX_EXTRA_PROFILES</span><span style="color:#666">=</span><span style="color:#19177c">$HOME</span>/.guix-extra-profiles
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">profiles</span><span style="color:#666">=</span><span style="color:#19177c">$*</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">if</span> <span style="color:#666">[[</span> <span style="color:#19177c">$#</span> -eq <span style="color:#666">0</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">profiles</span><span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#19177c">$GUIX_EXTRA_PROFILES</span><span style="color:#ba2121">/*"</span>;
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">for</span> profile in <span style="color:#19177c">$profiles</span>; <span style="color:#008000;font-weight:bold">do</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">profileName</span><span style="color:#666">=</span><span style="color:#008000;font-weight:bold">$(</span>basename <span style="color:#19177c">$profile</span><span style="color:#008000;font-weight:bold">)</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">profilePath</span><span style="color:#666">=</span><span style="color:#19177c">$GUIX_EXTRA_PROFILES</span>/<span style="color:#19177c">$profileName</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span> -e <span style="color:#ba2121">"</span><span style="color:#b68;font-weight:bold">${</span><span style="color:#19177c">GREEN</span><span style="color:#b68;font-weight:bold">}</span><span style="color:#ba2121">Updating profile:"</span> <span style="color:#19177c">$profilePath</span> <span style="color:#ba2121">"</span><span style="color:#b68;font-weight:bold">${</span><span style="color:#19177c">NC</span><span style="color:#b68;font-weight:bold">}</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> guix package --profile<span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#19177c">$profilePath</span><span style="color:#ba2121">/</span><span style="color:#19177c">$profileName</span><span style="color:#ba2121">"</span> --manifest<span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#19177c">$HOME</span><span style="color:#ba2121">/.config/guix/manifests/</span><span style="color:#19177c">$profileName</span><span style="color:#ba2121">.scm"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">done</span>
|
||||
</span></span></code></pre></div><h3 id="run-guix-package-in-profile">Run <code>guix package</code> in profile</h3>
|
||||
<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:#19177c">GUIX_EXTRA_PROFILES</span><span style="color:#666">=</span><span style="color:#19177c">$HOME</span>/.guix-extra-profiles
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">profileName</span><span style="color:#666">=</span><span style="color:#008000;font-weight:bold">$(</span>basename <span style="color:#19177c">$1</span><span style="color:#008000;font-weight:bold">)</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">profileName</span><span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#b68;font-weight:bold">${</span><span style="color:#19177c">profileName</span>%.*<span style="color:#b68;font-weight:bold">}</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">profilePath</span><span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#19177c">$GUIX_EXTRA_PROFILES</span><span style="color:#ba2121">/</span><span style="color:#19177c">$profileName</span><span style="color:#ba2121">"</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:#666">[</span> -d <span style="color:#19177c">$profilePath</span> <span style="color:#666">]</span>; <span style="color:#008000;font-weight:bold">then</span>
|
||||
</span></span><span style="display:flex;"><span> guix package --profile<span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#19177c">$profilePath</span><span style="color:#ba2121">/</span><span style="color:#19177c">$profileName</span><span style="color:#ba2121">"</span> <span style="color:#b68;font-weight:bold">${</span>@:<span style="color:#19177c">2</span><span style="color:#b68;font-weight:bold">}</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">else</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span> -e <span style="color:#ba2121">"No profile found at path: "</span> <span style="color:#19177c">$profilePath</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span></code></pre></div><h2 id="channels">Channels</h2>
|
||||
<p>Specifying additional channels.</p>
|
||||
<p><a href="https://github.com/SqrtMinusOne/channel-q">channel-q</a> is my Guix channel. Don’t use it at home.</p>
|
||||
<p>References:</p>
|
||||
<ul>
|
||||
<li><a href="https://gitlab.com/nonguix/nonguix">nonguix channel repo</a></li>
|
||||
<li><a href="https://guix.gnu.org/manual/en/html_node/Channels.html">Guix channels 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-scheme" data-lang="scheme"><span style="display:flex;"><span>(<span style="color:#00f">cons*</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">channel</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">name</span> <span style="color:#19177c">'channel-q</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">url</span> <span style="color:#ba2121">"file:///home/pavel/_channel-q"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">channel</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">name</span> <span style="color:#19177c">'flat</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">url</span> <span style="color:#ba2121">"https://github.com/flatwhatson/guix-channel.git"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">introduction</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">make-channel-introduction</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"33f86a4b48205c0dc19d7c036c85393f0766f806"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">openpgp-fingerprint</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"736A C00E 1254 378B A982 7AF6 9DBE 8265 81B6 4490"</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">channel</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">name</span> <span style="color:#19177c">'nonguix</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">url</span> <span style="color:#ba2121">"https://gitlab.com/nonguix/nonguix"</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; (commit "d54973e47b89fe5772a5b6e2d0c0b86acb089e27")</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">introduction</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">make-channel-introduction</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"897c1a470da759236cc11798f4e0a5f7d4d59fbc"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">openpgp-fingerprint</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"2A39 3FFF 68F4 EF7A 3D29 12AF 6F51 20A0 22FB B2D5"</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">channel</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; What can possibly go wrong, huh</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">name</span> <span style="color:#19177c">'guix-gaming-games</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">url</span> <span style="color:#ba2121">"https://gitlab.com/guix-gaming-channels/games.git"</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Enable signature verification:</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">introduction</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">make-channel-introduction</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"c23d64f1b8cc086659f8781b27ab6c7314c5cca5"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">openpgp-fingerprint</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"50F3 3E2E 5B0C 3D90 0424 ABE8 9BDC F497 A4BB CC7F"</span>))))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">%default-channels</span>)
|
||||
</span></span></code></pre></div><h2 id="systems">Systems</h2>
|
||||
<p>Configuring systems with Guix.</p>
|
||||
<p>Yes, all my machines are named after colors I like.</p>
|
||||
<h3 id="base-configuration">Base configuration</h3>
|
||||
<p>The base configuration is shared between all the machines.</p>
|
||||
<p>While it’s possible to make a single <code>.scm</code> file with base configuration and load it, I noticed that it produces more cryptic error messages whenever there is an error in the base file, so I opt-in for noweb.</p>
|
||||
<p><code>guix system</code> invocation 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>sudo -E guix system reconfigure ~/.config/guix/systems/[system].scm
|
||||
</span></span></code></pre></div><p>Common modules:</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">use-modules</span> (<span style="color:#00f">gnu</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">gnu</span> <span style="color:#19177c">system</span> <span style="color:#19177c">nss</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">gnu</span> <span style="color:#19177c">packages</span> <span style="color:#19177c">bash</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> ((<span style="color:#00f">gnu</span> <span style="color:#19177c">packages</span> <span style="color:#19177c">base</span>) <span style="color:#666">#</span><span style="color:#19177c">:select</span> (<span style="color:#00f">coreutils</span> <span style="color:#19177c">glibc</span>)))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">gnu</span> <span style="color:#19177c">packages</span> <span style="color:#19177c">certs</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">gnu</span> <span style="color:#19177c">packages</span> <span style="color:#19177c">version-control</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">gnu</span> <span style="color:#19177c">packages</span> <span style="color:#19177c">vim</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">gnu</span> <span style="color:#19177c">packages</span> <span style="color:#19177c">gnome</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">gnu</span> <span style="color:#19177c">packages</span> <span style="color:#19177c">xorg</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">gnu</span> <span style="color:#19177c">packages</span> <span style="color:#19177c">wm</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">gnu</span> <span style="color:#19177c">packages</span> <span style="color:#19177c">openbox</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">gnu</span> <span style="color:#19177c">services</span> <span style="color:#19177c">docker</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">gnu</span> <span style="color:#19177c">services</span> <span style="color:#19177c">cups</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">gnu</span> <span style="color:#19177c">services</span> <span style="color:#19177c">virtualization</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">srfi</span> <span style="color:#19177c">srfi-1</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">guix</span> <span style="color:#19177c">channels</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">guix</span> <span style="color:#19177c">inferior</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">nongnu</span> <span style="color:#19177c">packages</span> <span style="color:#19177c">linux</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-modules</span> (<span style="color:#00f">nongnu</span> <span style="color:#19177c">system</span> <span style="color:#19177c">linux-initrd</span>))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-service-modules</span> <span style="color:#19177c">desktop</span> <span style="color:#19177c">networking</span> <span style="color:#19177c">ssh</span> <span style="color:#19177c">xorg</span> <span style="color:#19177c">nix</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">use-package-modules</span> <span style="color:#19177c">ssh</span>)
|
||||
</span></span></code></pre></div><p>In principle, we could define a variable called <code>base-operating-system</code> and extend it in ancestors. However, then we would have to define mandatory fields like <code>host-name</code>, <code>bootloader</code> with dummy values. Since I’m already using noweb, there is little point.</p>
|
||||
<p>The following code will be inserted at the top of the <code>operating-system</code> definition.</p>
|
||||
<p>Use the full Linux kernel. I hope I’ll be able to use Libre kernel somewhere later.</p>
|
||||
<p>Inferior in the kernel is used to avoid recompilation. It looks like I can pin these to different commits than in my <code>channels.scm</code></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">kernel</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">let*</span>
|
||||
</span></span><span style="display:flex;"><span> ((<span style="color:#00f">channels</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">list </span>(<span style="color:#00f">channel</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">name</span> <span style="color:#19177c">'nonguix</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">url</span> <span style="color:#ba2121">"https://gitlab.com/nonguix/nonguix"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">commit</span> <span style="color:#ba2121">"213be7ee6676fc4a3db0e3ac9ce5cd79e2ed209e"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">channel</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">name</span> <span style="color:#19177c">'guix</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">url</span> <span style="color:#ba2121">"https://git.savannah.gnu.org/git/guix.git"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">commit</span> <span style="color:#ba2121">"6311493d7a6271bfbc51f4693857f9a12fe9965d"</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">inferior</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">inferior-for-channels</span> <span style="color:#19177c">channels</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">first</span> (<span style="color:#00f">lookup-inferior-packages</span> <span style="color:#19177c">inferior</span> <span style="color:#ba2121">"linux"</span> <span style="color:#ba2121">"6.2.9"</span>))))
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; (kernel linux)</span>
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">initrd</span> <span style="color:#19177c">microcode-initrd</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">firmware</span> (<span style="color:#008000">list </span><span style="color:#19177c">linux-firmware</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">locale</span> <span style="color:#ba2121">"en_US.utf8"</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">timezone</span> <span style="color:#ba2121">"Europe/Moscow"</span>)
|
||||
</span></span></code></pre></div><p>US/RU keyboard layout, switch with Alt+Shift.</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">keyboard-layout</span> (<span style="color:#00f">keyboard-layout</span> <span style="color:#ba2121">"us,ru"</span> <span style="color:#666">#</span><span style="color:#19177c">:options</span> <span style="color:#666">'</span>(<span style="color:#ba2121">"grp:alt_shift_toggle"</span>)))
|
||||
</span></span></code></pre></div><p>User accounts.</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">users</span> (<span style="color:#00f">cons*</span> (<span style="color:#00f">user-account</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">name</span> <span style="color:#ba2121">"pavel"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">comment</span> <span style="color:#ba2121">"Pavel"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">group</span> <span style="color:#ba2121">"users"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">home-directory</span> <span style="color:#ba2121">"/home/pavel"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">supplementary-groups</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>(<span style="color:#ba2121">"wheel"</span> <span style="color:#408080;font-style:italic">;; sudo</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"netdev"</span> <span style="color:#408080;font-style:italic">;; network devices</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"audio"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"video"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"input"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"tty"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"docker"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"scanner"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"libvirt"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"lp"</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">%base-user-accounts</span>))
|
||||
</span></span></code></pre></div><p>Base packages, necessary right after the installation.</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">packages</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">list </span><span style="color:#19177c">nss-certs</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">git</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">i3-gaps</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">i3lock</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">openbox</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">xterm</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">vim</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">%base-packages</span>))
|
||||
</span></span></code></pre></div><p>Default services for each machine:</p>
|
||||
<ul>
|
||||
<li>override the default <code>%desktop-services</code> to add OpenVPN support</li>
|
||||
<li>add nix service</li>
|
||||
<li>add docker service</li>
|
||||
<li>add CUPS service</li>
|
||||
<li>add libvirt service</li>
|
||||
<li>add a symlink to ELF interpreter to where most Linux binaries expect it</li>
|
||||
</ul>
|
||||
<!--listend-->
|
||||
<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:#008000;font-weight:bold">define </span><span style="color:#19177c">%my-base-services</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">service</span> <span style="color:#19177c">openssh-service-type</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">screen-locker-service</span> <span style="color:#19177c">i3lock</span> <span style="color:#ba2121">"i3lock"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">extra-special-file</span> <span style="color:#ba2121">"/lib64/ld-linux-x86-64.so.2"</span> (<span style="color:#00f">file-append</span> <span style="color:#19177c">glibc</span> <span style="color:#ba2121">"/lib/ld-linux-x86-64.so.2"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">service</span> <span style="color:#19177c">nix-service-type</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">service</span> <span style="color:#19177c">cups-service-type</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cups-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">web-interface?</span> <span style="color:#800">#t</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">service</span> <span style="color:#19177c">docker-service-type</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">service</span> <span style="color:#19177c">libvirt-service-type</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">libvirt-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">unix-sock-group</span> <span style="color:#ba2121">"libvirt"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">tls-port</span> <span style="color:#ba2121">"16555"</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">service</span> <span style="color:#19177c">virtlog-service-type</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">bluetooth-service</span> <span style="color:#666">#</span><span style="color:#19177c">:auto-enable?</span> <span style="color:#800">#f</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">modify-services</span> <span style="color:#19177c">%desktop-services</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">network-manager-service-type</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">config</span> <span style="color:#19177c">=></span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">network-manager-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">inherit</span> <span style="color:#19177c">config</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">vpn-plugins</span> (<span style="color:#008000">list </span><span style="color:#19177c">network-manager-openvpn</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">guix-service-type</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">config</span> <span style="color:#19177c">=></span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">guix-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">inherit</span> <span style="color:#19177c">config</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substitute-urls</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">append </span>(<span style="color:#008000">list </span><span style="color:#ba2121">"https://substitutes.nonguix.org"</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">%default-substitute-urls</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">authorized-keys</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">append </span>(<span style="color:#008000">list </span>(<span style="color:#00f">local-file</span> <span style="color:#ba2121">"./signing-key.pub"</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">%default-authorized-guix-keys</span>)))))))
|
||||
</span></span></code></pre></div><h3 id="indigo">indigo</h3>
|
||||
<p><code>indigo</code> is my desktop PC.</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:#19177c"><<system-common>></span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">operating-system</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c"><<system-base>></span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">host-name</span> <span style="color:#ba2121">"indigo"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">services</span> (<span style="color:#00f">cons*</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-xorg-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">xorg-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">keyboard-layout</span> <span style="color:#19177c">keyboard-layout</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">%my-base-services</span>))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">bootloader</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">bootloader-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">bootloader</span> <span style="color:#19177c">grub-efi-bootloader</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">target</span> <span style="color:#ba2121">"/boot/efi"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">keyboard-layout</span> <span style="color:#19177c">keyboard-layout</span>)))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">swap-devices</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">list </span>(<span style="color:#00f">uuid</span> <span style="color:#ba2121">"3a77c542-7d24-46ff-8123-f7398d1c2677"</span>)))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-systems</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons*</span> (<span style="color:#00f">file-system</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mount-point</span> <span style="color:#ba2121">"/"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">device</span> (<span style="color:#00f">file-system-label</span> <span style="color:#ba2121">"my-root"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">type</span> <span style="color:#ba2121">"ext4"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-system</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mount-point</span> <span style="color:#ba2121">"/boot/efi"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">device</span> <span style="color:#ba2121">"/dev/sda1"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">type</span> <span style="color:#ba2121">"vfat"</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">%base-file-systems</span>)))
|
||||
</span></span></code></pre></div><h3 id="eminence">eminence</h3>
|
||||
<p><code>eminence</code> is a HP 15s laptop.</p>
|
||||
<p><code>%backlight-udev-rule</code> should enable members of <code>video</code> group change the display backlight. See the relevant page at <a href="https://wiki.archlinux.org/title/Backlight">Arch Wiki</a>.</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:#19177c"><<system-common>></span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000;font-weight:bold">define </span><span style="color:#19177c">%backlight-udev-rule</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">udev-rule</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"90-backlight.rules"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">string-append </span><span style="color:#ba2121">"ACTION==\"add\", SUBSYSTEM==\"backlight\", "</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\""</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"\n"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"ACTION==\"add\", SUBSYSTEM==\"backlight\", "</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\""</span>)))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">operating-system</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c"><<system-base>></span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">host-name</span> <span style="color:#ba2121">"eminence"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">services</span> (<span style="color:#00f">cons*</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-xorg-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">xorg-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">keyboard-layout</span> <span style="color:#19177c">keyboard-layout</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">modify-services</span> <span style="color:#19177c">%my-base-services</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">elogind-service-type</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">config</span> <span style="color:#19177c">=></span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">elogind-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">inherit</span> <span style="color:#19177c">config</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">handle-lid-switch-external-power</span> <span style="color:#19177c">'suspend</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">udev-service-type</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">config</span> <span style="color:#19177c">=></span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">udev-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">inherit</span> <span style="color:#19177c">config</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">rules</span> (<span style="color:#008000">cons </span><span style="color:#19177c">%backlight-udev-rule</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">udev-configuration-rules</span> <span style="color:#19177c">config</span>))))))))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">bootloader</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">bootloader-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">bootloader</span> <span style="color:#19177c">grub-efi-bootloader</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">target</span> <span style="color:#ba2121">"/boot/efi"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">keyboard-layout</span> <span style="color:#19177c">keyboard-layout</span>)))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">swap-devices</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">list </span>(<span style="color:#00f">uuid</span> <span style="color:#ba2121">"f93cf3f6-7ee7-42ec-8ee2-f3d896fdf9b5"</span>)))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-systems</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons*</span> (<span style="color:#00f">file-system</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mount-point</span> <span style="color:#ba2121">"/"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">device</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">uuid</span> <span style="color:#ba2121">"1d937704-bbeb-43b5-bc63-453886c426af"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">'ext4</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">type</span> <span style="color:#ba2121">"ext4"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-system</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mount-point</span> <span style="color:#ba2121">"/boot/efi"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">device</span> (<span style="color:#00f">uuid</span> <span style="color:#ba2121">"0031-3784"</span> <span style="color:#19177c">'fat32</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">type</span> <span style="color:#ba2121">"vfat"</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">%base-file-systems</span>)))
|
||||
</span></span></code></pre></div><h3 id="azure">azure</h3>
|
||||
<p><code>azure</code> is a Lenovo Ideapad 330 laptop.</p>
|
||||
<p><code>%backlight-udev-rule</code> should enable members of <code>video</code> group change the display backlight. See the relevant page at <a href="https://wiki.archlinux.org/title/Backlight">Arch Wiki</a>.</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:#19177c"><<system-common>></span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000;font-weight:bold">define </span><span style="color:#19177c">%backlight-udev-rule</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">udev-rule</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"90-backlight.rules"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">string-append </span><span style="color:#ba2121">"ACTION==\"add\", SUBSYSTEM==\"backlight\", "</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\""</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"\n"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"ACTION==\"add\", SUBSYSTEM==\"backlight\", "</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\""</span>)))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">operating-system</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c"><<system-base>></span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">host-name</span> <span style="color:#ba2121">"azure"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">services</span> (<span style="color:#00f">cons*</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-xorg-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">xorg-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">keyboard-layout</span> <span style="color:#19177c">keyboard-layout</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">modify-services</span> <span style="color:#19177c">%my-base-services</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">elogind-service-type</span> <span style="color:#19177c">config</span> <span style="color:#19177c">=></span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">elogind-configuration</span> (<span style="color:#00f">inherit</span> <span style="color:#19177c">config</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">handle-lid-switch-external-power</span> <span style="color:#19177c">'suspend</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">udev-service-type</span> <span style="color:#19177c">config</span> <span style="color:#19177c">=></span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">udev-configuration</span> (<span style="color:#00f">inherit</span> <span style="color:#19177c">config</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">rules</span> (<span style="color:#008000">cons </span><span style="color:#19177c">%backlight-udev-rule</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">udev-configuration-rules</span> <span style="color:#19177c">config</span>))))))))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">bootloader</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">bootloader-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">bootloader</span> <span style="color:#19177c">grub-efi-bootloader</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">target</span> <span style="color:#ba2121">"/boot/efi"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">keyboard-layout</span> <span style="color:#19177c">keyboard-layout</span>)))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">swap-devices</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">list </span>(<span style="color:#00f">uuid</span> <span style="color:#ba2121">"4b2dedb3-b111-4e69-8c05-6daa2b072c76"</span>)))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-systems</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">cons*</span> (<span style="color:#00f">file-system</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mount-point</span> <span style="color:#ba2121">"/"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">device</span> (<span style="color:#00f">file-system-label</span> <span style="color:#ba2121">"my-root"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">type</span> <span style="color:#ba2121">"ext4"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-system</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mount-point</span> <span style="color:#ba2121">"/boot/efi"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">device</span> <span style="color:#ba2121">"/dev/sda1"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">type</span> <span style="color:#ba2121">"vfat"</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">%base-file-systems</span>)))
|
||||
</span></span></code></pre></div><h3 id="iris">iris</h3>
|
||||
<p><code>iris</code> is my work machine.</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:#19177c"><<system-common>></span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#00f">operating-system</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c"><<system-base>></span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">host-name</span> <span style="color:#ba2121">"iris"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">services</span> (<span style="color:#00f">cons*</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-xorg-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">xorg-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">keyboard-layout</span> <span style="color:#19177c">keyboard-layout</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">%my-base-services</span>))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">bootloader</span> (<span style="color:#00f">bootloader-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">bootloader</span> <span style="color:#19177c">grub-bootloader</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">targets</span> (<span style="color:#008000">list </span><span style="color:#ba2121">"/dev/sdb"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">keyboard-layout</span> <span style="color:#19177c">keyboard-layout</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">swap-devices</span> (<span style="color:#008000">list </span>(<span style="color:#00f">swap-space</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">target</span> (<span style="color:#00f">uuid</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"bc284384-ff00-4fbc-abda-1c46f69c0505"</span>)))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapped-devices</span> (<span style="color:#008000">list </span>(<span style="color:#00f">mapped-device</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">source</span> (<span style="color:#00f">uuid</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"21876acb-e05a-4731-8df0-ba5761910ca8"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">target</span> <span style="color:#ba2121">"cryptroot"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">type</span> <span style="color:#19177c">luks-device-mapping</span>))))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-systems</span> (<span style="color:#00f">cons*</span> (<span style="color:#00f">file-system</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mount-point</span> <span style="color:#ba2121">"/"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">device</span> <span style="color:#ba2121">"/dev/mapper/cryptroot"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">type</span> <span style="color:#ba2121">"ext4"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">dependencies</span> <span style="color:#19177c">mapped-devices</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-system</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mount-point</span> <span style="color:#ba2121">"/boot/efi"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">device</span> (<span style="color:#00f">uuid</span> <span style="color:#ba2121">"782E-F6D3"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">'fat32</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">type</span> <span style="color:#ba2121">"vfat"</span>)) <span style="color:#19177c">%base-file-systems</span>)))
|
||||
</span></span></code></pre></div><h2 id="system-installation">System installation</h2>
|
||||
<h3 id="preparation">Preparation</h3>
|
||||
<p>In my case, the provided ISO doesn’t work because of the Libre kernel.</p>
|
||||
<p>Fortunately, David Wilson has made <a href="https://github.com/SystemCrafters/guix-installer">a repository</a> with a toolchain to make an ISO with the full kernel. In case it won’t be an option, the <a href="https://gitlab.com/nonguix/nonguix">nonguix repo</a> also has instructions on how to do that.</p>
|
||||
<p>When an ISO is there, we have to write it on a USB stick. Run <code>sudo fdisk -l</code> to get a list of disks.</p>
|
||||
<p>The approach given in the official instruction is to create a bootable USB with <code>dd</code>:</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>sudo dd of=/dev/sdxX if=<path-to-iso> status=progress && sync
|
||||
</span></span></code></pre></div><p>However, I couldn’t make it work for some strange reason. Fortunately, <code>gnome-disk-utility</code> was able to produce a bootable USB.</p>
|
||||
<h3 id="installation">Installation</h3>
|
||||
<p>Going further, the official instructions for installation & SystemCrafters wiki entry are pretty good, so it’s not necessary to repeat them here.</p>
|
||||
<h3 id="after-installation">After installation</h3>
|
||||
<p>After the installation, the strategy is as follows.</p>
|
||||
<p>Set a password for the main user (pavel). Login with openbox to get a tolerable interface because i3’s default config is horrible.</p>
|
||||
<p><a href="https://guix.gnu.org/en/manual/en/html_node/Keyboard-Layout-and-Networking-and-Partitioning.html#Keyboard-Layout-and-Networking-and-Partitioning">Connect to the internet</a>.</p>
|
||||
<p>Clone the dotfiles repo:</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>mkdir Code
|
||||
</span></span><span style="display:flex;"><span>cd Code
|
||||
</span></span><span style="display:flex;"><span>git clone https://github.com/SqrtMinusOne/dotfiles.git
|
||||
</span></span></code></pre></div><p>Copy the channels file and run guix pull:</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>cp ~/Code/dotfiles/.config/guix/channels.scm ~/.config/guix
|
||||
</span></span><span style="display:flex;"><span>guix pull
|
||||
</span></span></code></pre></div><p>The first pull usually takes a while. After that install yadm and pull dotfiles:</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>guix install yadm
|
||||
</span></span><span style="display:flex;"><span>guix clone https://github.com/SqrtMinusOne/dotfiles.git
|
||||
</span></span></code></pre></div><p>And activate the required profiles. Again, downloading & building Emacs, Starship and stuff will take a while.</p>
|
||||
<p>Don’t forget to install <code>JetBrainsMono Nerd Font</code>.</p>
|
||||
<h2 id="misc-software-and-notes">Misc software & notes</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Category</th>
|
||||
<th>Guix dependency</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>system</td>
|
||||
<td>patchelf</td>
|
||||
<td>A program to modify existsing ELF executables</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>system</td>
|
||||
<td>glibc</td>
|
||||
<td>A lot of stuff, including ELF interpeter and <code>ldd</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>system</td>
|
||||
<td>tor-client</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>system</td>
|
||||
<td>torsocks</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>system</td>
|
||||
<td>vnstat</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3 id="openvpn">OpenVPN</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Category</th>
|
||||
<th>Guix dependency</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>system</td>
|
||||
<td>openvpn</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>system</td>
|
||||
<td>openvpn-update-resolve-conf</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>system</td>
|
||||
<td>openresolv</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>system</td>
|
||||
<td>vpnc</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Update <span class="timestamp-wrapper"><span class="timestamp">[2023-06-29 Thu]</span></span>: My censors seem to be putting sticks in the wheels of OpenVPN… Switched to Wireguard for now. It can be configured with Network Manager.</p>
|
||||
<p>I’m not sure how to properly spin up VPN on Guix, so here is what ended I’m doing after some trial and error.</p>
|
||||
<p>I’m using Mullvad VPN. The <code>~/.vpn</code> folder stores its OpenVPN config (<code>openvpn.ovpn</code>), modified as follows:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>paths to <code>ca</code>, <code>cert</code> and <code>key</code> are made absolute</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span>ca <span style="color:#b68">/home/</span>pavel<span style="color:#b68">/.vpn/</span>ca.crt
|
||||
</span></span><span style="display:flex;"><span>cert <span style="color:#b68">/home/</span>pavel<span style="color:#b68">/.vpn/</span>client.crt
|
||||
</span></span><span style="display:flex;"><span>key <span style="color:#b68">/home/</span>pavel<span style="color:#b68">/.vpn/</span>client.key
|
||||
</span></span></code></pre></div></li>
|
||||
<li>
|
||||
<p>added <code>auth-user-pass</code> with a link to login info</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span>auth-user-pass <span style="color:#b68">/home/</span>pavel<span style="color:#b68">/.vpn/</span>auth.conf
|
||||
</span></span></code></pre></div><p><code>auth.conf</code> 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>login
|
||||
</span></span><span style="display:flex;"><span>password
|
||||
</span></span></code></pre></div></li>
|
||||
<li>
|
||||
<p>Run <a href="https://github.com/alfredopalhares/openvpn-update-resolv-conf">openvpn-update-resolv-conf</a> script to prevent DNS leaks. <code>openvpn-update-resolve-conf</code> originates in my <a href="https://github.com/SqrtMinusOne/channel-q">channel-q</a>.</p>
|
||||
<p>Edit <span class="timestamp-wrapper"><span class="timestamp"><2022-04-07 Thu></span></span>: Looks like this doesn’t work on some connections. See the next option in that case</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span>setenv PATH <span style="color:#b68">/home/</span>pavel<span style="color:#b68">/.guix-extra-profiles/</span>system<span style="color:#b68">/system/</span>bin:<span style="color:#b68">/home/</span>pavel<span style="color:#b68">/.guix-extra-profiles/</span>system<span style="color:#b68">/system/</span>sbin:<span style="color:#b68">/home/</span>pavel<span style="color:#b68">/.guix-extra-profiles/</span>console<span style="color:#b68">/console/</span>bin:<span style="color:#b68">/run/</span>current-system<span style="color:#b68">/profile/</span>bin:<span style="color:#b68">/run/</span>current-system<span style="color:#b68">/profile/</span>sbin
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>up <span style="color:#b68">/home/</span>pavel<span style="color:#b68">/.guix-extra-profiles/</span>system<span style="color:#b68">/system/</span>bin/update-resolv-conf.sh
|
||||
</span></span><span style="display:flex;"><span>down <span style="color:#b68">/home/</span>pavel<span style="color:#b68">/.guix-extra-profiles/</span>system<span style="color:#b68">/system/</span>bin/update-resolv-conf.sh
|
||||
</span></span></code></pre></div><p><code>setenv PATH</code> is necessary because both <code>resolvconf</code> (openresolve) and <code>update-resolv-conf.sh</code> are shell scripts which need GNU coreutils and stuff, and OpenVPN clears PATH by default.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Manually fix <code>etc/resolv.conf</code> to prevent DNS leaks</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>/home/pavel/.guix-extra-profiles/console/console/bin/cp /etc/resolv.conf /etc/resolv.conf-bak
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">echo</span> <span style="color:#ba2121">"nameserver 8.8.8.8"</span> > /etc/resolv.conf
|
||||
</span></span></code></pre></div><p>Restore <code>resolv.conf</code></p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>resolveconf -u
|
||||
</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-vim" data-lang="vim"><span style="display:flex;"><span>up <span style="color:#b68">/home/</span>pavel<span style="color:#b68">/bin/</span>scripts/fix-resolve-conf
|
||||
</span></span><span style="display:flex;"><span>down <span style="color:#b68">/home/</span>pavel<span style="color:#b68">/bin/</span>scripts/restore-resolve-conf
|
||||
</span></span></code></pre></div></li>
|
||||
<li>
|
||||
<p>run a script to fix Docker routes</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span>route-up <span style="color:#b68">/home/</span>pavel<span style="color:#b68">/bin/</span>scripts/vpn-fix-routes
|
||||
</span></span></code></pre></div><p>References:</p>
|
||||
<ul>
|
||||
<li><a href="https://github.com/moby/libnetwork/issues/779">Github issue</a></li>
|
||||
</ul>
|
||||
<p>The script itself:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#008000">echo</span> <span style="color:#ba2121">"Adding default route to </span><span style="color:#19177c">$route_vpn_gateway</span><span style="color:#ba2121"> with /0 mask..."</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">IP</span><span style="color:#666">=</span>/run/current-system/profile/sbin/ip
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">$IP</span> route add default via <span style="color:#19177c">$route_vpn_gateway</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">echo</span> <span style="color:#ba2121">"Removing /1 routes..."</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">$IP</span> route del 0.0.0.0/1 via <span style="color:#19177c">$route_vpn_gateway</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">$IP</span> route del 128.0.0.0/1 via <span style="color:#19177c">$route_vpn_gateway</span>
|
||||
</span></span></code></pre></div></li>
|
||||
</ul>
|
||||
<h4 id="vpn-start">vpn-start</h4>
|
||||
<p><del>As of now, CyberGhost doesn’t provide ipv6, so we have to disable it.</del></p>
|
||||
<p>Mullvad seems to provide it, so the script just launches <code>openvpn</code> with <code>pkexec</code>.</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">export</span> <span style="color:#19177c">DISPLAY</span><span style="color:#666">=</span>:0
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">CONN</span><span style="color:#666">=</span><span style="color:#008000;font-weight:bold">$(</span>nmcli -f NAME con show --active | grep -Ev <span style="color:#ba2121">"(.*docker.*|NAME|br-.*|veth.*|tun.*|vnet.*|virbr.*)"</span> | sed <span style="color:#ba2121">'s/ *$//g'</span><span style="color:#008000;font-weight:bold">)</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:#666">[</span> -z <span style="color:#ba2121">"</span><span style="color:#19177c">$CONN</span><span style="color:#ba2121">"</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:#008000">echo</span> <span style="color:#ba2121">"No connection!"</span>
|
||||
</span></span><span style="display:flex;"><span> notify-send <span style="color:#ba2121">"VPN"</span> <span style="color:#ba2121">"No connection for VPN to run"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">exit</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># if [[ "$CONN" != *"Wired"* ]]; then</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># echo "Connection: $CONN"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># notify-send "VPN" "Initializing for connection: $CONN"</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># pkexec nmcli con modify "$CONN" ipv6.method ignore</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># nmcli connection up "$CONN"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># fi</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">VPN_FILE</span><span style="color:#666">=</span>~/.vpn/sqrtminusone-<span style="color:#008000;font-weight:bold">$(</span>hostname<span style="color:#008000;font-weight:bold">)</span>.ovpn
|
||||
</span></span><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>hostname<span style="color:#008000;font-weight:bold">)</span> <span style="color:#666">==</span> <span style="color:#ba2121">'iris'</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">VPN_FILE</span><span style="color:#666">=</span>~/.vpn/mullvad_openvpn_linux_se_all/mullvad_se_all.conf
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">echo</span> <span style="color:#19177c">$VPN_FILE</span>
|
||||
</span></span><span style="display:flex;"><span>pkexec openvpn --config <span style="color:#19177c">$VPN_FILE</span>
|
||||
</span></span></code></pre></div><h4 id="377cab"><del>vpn-stop</del></h4>
|
||||
<p><del>Also a script to reverse the changes</del>
|
||||
Also not necessary now. Just <code>herd stop vpn</code> and <code>sudo pkill vpn</code>.</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:#19177c">CONN</span><span style="color:#666">=</span><span style="color:#008000;font-weight:bold">$(</span>nmcli -f NAME con show --active | grep -Ev <span style="color:#ba2121">"(.*docker.*|NAME|br-.*|veth.*|tun.*)"</span> | sed <span style="color:#ba2121">'s/ *$//g'</span><span style="color:#008000;font-weight:bold">)</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">echo</span> <span style="color:#ba2121">"Connection: </span><span style="color:#19177c">$CONN</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>pkexec nmcli con modify <span style="color:#ba2121">"</span><span style="color:#19177c">$CONN</span><span style="color:#ba2121">"</span> ipv6.method auto
|
||||
</span></span><span style="display:flex;"><span>nmcli connection up <span style="color:#ba2121">"</span><span style="color:#19177c">$CONN</span><span style="color:#ba2121">"</span>
|
||||
</span></span></code></pre></div><h3 id="wireguard">Wireguard</h3>
|
||||
<p>So, yeah, wireguard can be configured with <code>NetworkManager</code> just fine.</p>
|
||||
<p>The issue with DNS leaks remains, but fortunately <code>NetworkManager</code> runs all scripts in <code>/etc/NetworkManager/dispatcher.d/</code> when a connection changes, provided that scripts are:</p>
|
||||
<ul>
|
||||
<li>owned by root</li>
|
||||
<li>exectuable</li>
|
||||
<li>not readable by other users</li>
|
||||
<li>not setuid.</li>
|
||||
</ul>
|
||||
<p>See <a href="https://askubuntu.com/questions/13963/call-script-after-connecting-to-a-wireless-network">this answer</a> on StackExchange, and <a href="https://networkmanager.dev/docs/api/latest/NetworkManager-dispatcher.html">NetworkManager-dispatcher man page</a>.</p>
|
||||
<p><a id="code-snippet--get-nmcli"></a></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">echo</span> <span style="color:#008000;font-weight:bold">$(</span>guix build network-manager | grep -ve <span style="color:#ba2121">'-doc$'</span><span style="color:#008000;font-weight:bold">)</span>/bin/nmcli
|
||||
</span></span></code></pre></div><p>So, here’s the script:</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:#bc7a00">#!/bin/sh
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#bc7a00"></span><span style="color:#19177c">GREP</span><span style="color:#666">=</span>/run/current-system/profile/bin/grep
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">NMCLI</span><span style="color:#666">=</span><span style="color:#ba2121"><<get-nmcli()>>
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"># Run only if wireg</span>uard is active
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">if</span> <span style="color:#19177c">$NMCLI</span> connection show --active | <span style="color:#19177c">$GREP</span> -q wireguard; <span style="color:#008000;font-weight:bold">then</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span> <span style="color:#ba2121">"nameserver 8.8.8.8"</span> > /etc/resolv.conf
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span></code></pre></div><p>Expand the noweb with <code>C-c C-v v</code>, put it in <code>dispatcher.d</code> and run <code>chmod 700</code>.</p>
|
||||
<h3 id="flatpak">flatpak</h3>
|
||||
<p>As for now, the easiest way to install most of proprietary software is via flatpak. See the relevant section in <a href="/configs/desktop/">Desktop.org</a>.</p>
|
||||
<h3 id="micromamba">micromamba</h3>
|
||||
<p><del><a href="https://docs.conda.io/en/latest/">conda</a></del> <a href="https://github.com/mamba-org/mamba">mamba</a> is a package manager that I use for managing various versions of Python & Node.js.</p>
|
||||
<p><code>mamba</code> is a reimplementation of <code>conda</code> in C++. <code>mamba</code> is notably much faster and mostly compatible with <code>conda</code>, and <code>micromamba</code> is a tiny version of <code>mamba</code> that is contained in one statically linked exectuable. I’ve migrated to <code>micromamba</code> mostly because of speed.</p>
|
||||
<p><code>conda</code> is packaged for Guix with its fair share of quirks, mostly concerning the impossibility of changing the base environment in <code>/gnu/store/</code>. <code>micromamba</code> has none of that because it doesn’t ship with a base environment. It’s not packaged for Guix yet, so I’ve made a definition with <code>binary-build-system</code> in my channel.</p>
|
||||
<p>You may need to unset <code>$PYTHONPATH</code> if you have any global packages installed, otherwise Python from the environemnt will try to import them instead of the conda versions.</p>
|
||||
<p>I also want to have an ability to use global npm. Some settings for that are located in <a href="Console">Console.org</a>. Here we want to unset <code>NPM_CONFIG_USERCONFIG</code> if there is npm available in the environment.</p>
|
||||
<p>So here is a script to set up conda hooks:</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:#408080;font-style:italic"># Get writable conda envs with npm & without it</span>
|
||||
</span></span><span style="display:flex;"><span>readarray -t CONDA_ENVS_ALL <span style="color:#666"><<<</span> <span style="color:#008000;font-weight:bold">$(</span>micromamba env list --json | jq <span style="color:#ba2121">'.envs[]'</span><span style="color:#008000;font-weight:bold">)</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">CONDA_ENVS_NPM</span><span style="color:#666">=()</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">CONDA_ENVS_NO_NPM</span><span style="color:#666">=()</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">for</span> env in <span style="color:#ba2121">"</span><span style="color:#b68;font-weight:bold">${</span><span style="color:#19177c">CONDA_ENVS_ALL</span>[@]<span style="color:#b68;font-weight:bold">}</span><span style="color:#ba2121">"</span>; <span style="color:#008000;font-weight:bold">do</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">env</span><span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#b68;font-weight:bold">${</span><span style="color:#19177c">env</span>:<span style="color:#19177c">1</span>:<span style="color:#b68;font-weight:bold">${#</span><span style="color:#19177c">env</span><span style="color:#b68;font-weight:bold">}</span>-2<span style="color:#b68;font-weight:bold">}</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">if</span> <span style="color:#666">[</span> -w <span style="color:#ba2121">"</span><span style="color:#19177c">$env</span><span style="color:#ba2121">"</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:#008000;font-weight:bold">if</span> <span style="color:#666">[</span> -f <span style="color:#ba2121">"</span><span style="color:#19177c">$env</span><span style="color:#ba2121">/bin/npm"</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">CONDA_ENVS_NPM</span><span style="color:#666">+=(</span><span style="color:#19177c">$env</span><span style="color:#666">)</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">else</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">CONDA_ENVS_NO_NPM</span><span style="color:#666">+=(</span><span style="color:#19177c">$env</span><span style="color:#666">)</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">done</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">for</span> env in <span style="color:#ba2121">"</span><span style="color:#b68;font-weight:bold">${</span><span style="color:#19177c">CONDA_ENVS_NPM</span>[@]<span style="color:#b68;font-weight:bold">}</span><span style="color:#ba2121">"</span>; <span style="color:#008000;font-weight:bold">do</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span> <span style="color:#ba2121">"Found npm in </span><span style="color:#19177c">$env</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span> mkdir -p <span style="color:#ba2121">"</span><span style="color:#19177c">$env</span><span style="color:#ba2121">/etc/conda/activate.d"</span>
|
||||
</span></span><span style="display:flex;"><span> mkdir -p <span style="color:#ba2121">"</span><span style="color:#19177c">$env</span><span style="color:#ba2121">/etc/conda/deactivate.d"</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span> <span style="color:#ba2121">"unset NPM_CONFIG_USERCONFIG"</span> > <span style="color:#ba2121">"</span><span style="color:#19177c">$env</span><span style="color:#ba2121">/etc/conda/activate.d/conda.sh"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span> <span style="color:#ba2121">"set -e NPM_CONFIG_USERCONFIG"</span> > <span style="color:#ba2121">"</span><span style="color:#19177c">$env</span><span style="color:#ba2121">/etc/conda/activate.d/conda.fish"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span> <span style="color:#ba2121">"export NPM_CONFIG_USERCONFIG=</span><span style="color:#19177c">$HOME</span><span style="color:#ba2121">/._npmrc"</span> > <span style="color:#ba2121">"</span><span style="color:#19177c">$env</span><span style="color:#ba2121">/etc/conda/deactivate.d/conda.sh"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span> <span style="color:#ba2121">"export NPM_CONFIG_USERCONFIG=</span><span style="color:#19177c">$HOME</span><span style="color:#ba2121">/._npmrc"</span> > <span style="color:#ba2121">"</span><span style="color:#19177c">$env</span><span style="color:#ba2121">/etc/conda/deactivate.d/conda.fish"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">done</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">for</span> env in <span style="color:#ba2121">"</span><span style="color:#b68;font-weight:bold">${</span><span style="color:#19177c">CONDA_ENVS_NO_NPM</span><span style="color:#b68;font-weight:bold">}</span><span style="color:#ba2121">"</span>; <span style="color:#008000;font-weight:bold">do</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">echo</span> <span style="color:#ba2121">"Did not found npm in </span><span style="color:#19177c">$env</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span> rm -rf <span style="color:#ba2121">"</span><span style="color:#19177c">$env</span><span style="color:#ba2121">/etc/conda/activate.d/conda.sh"</span> <span style="color:#666">||</span> <span style="color:#008000">true</span>
|
||||
</span></span><span style="display:flex;"><span> rm -rf <span style="color:#ba2121">"</span><span style="color:#19177c">$env</span><span style="color:#ba2121">/etc/conda/activate.d/conda.fish"</span> <span style="color:#666">||</span> <span style="color:#008000">true</span>
|
||||
</span></span><span style="display:flex;"><span> rm -rf <span style="color:#ba2121">"</span><span style="color:#19177c">$env</span><span style="color:#ba2121">/etc/conda/deactivate.d/conda.sh"</span> <span style="color:#666">||</span> <span style="color:#008000">true</span>
|
||||
</span></span><span style="display:flex;"><span> rm -rf <span style="color:#ba2121">"</span><span style="color:#19177c">$env</span><span style="color:#ba2121">/etc/conda/deactivate.d/conda.fish"</span> <span style="color:#666">||</span> <span style="color:#008000">true</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">done</span>
|
||||
</span></span></code></pre></div><h3 id="slack">Slack</h3>
|
||||
<p>What a nonsense of a program.</p>
|
||||
<p>I was able to launch the nix version with the following wrapper script:</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">export</span> <span style="color:#19177c">PATH</span><span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#19177c">$HOME</span><span style="color:#ba2121">/bin/dummies:</span><span style="color:#19177c">$PATH</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span>mkdir -p ~/.cache/slack
|
||||
</span></span><span style="display:flex;"><span>slack -r ~/.cache/slack
|
||||
</span></span></code></pre></div><p>Also, it requires a <code>lsb_release</code> in the PATH, 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-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#008000">echo</span> <span style="color:#ba2121">"LSB Version: Hey. I spent an hour figuring out why Slack doesn't launch."</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">echo</span> <span style="color:#ba2121">"Distributor ID: It seems like it requires an lsb_release."</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">echo</span> <span style="color:#ba2121">"Description: But GNU Guix doesn't have one."</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">echo</span> <span style="color:#ba2121">"Release: 42.2"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">echo</span> <span style="color:#ba2121">"Codename: n/a"</span>
|
||||
</span></span></code></pre></div><h3 id="virt-manager">virt-manager</h3>
|
||||
<p>Run the following to fix the network:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>sudo virsh net-define /run/current-system/profile/etc/libvirt/qemu/networks/default.xml
|
||||
</span></span><span style="display:flex;"><span>sudo virsh net-start default
|
||||
</span></span><span style="display:flex;"><span>sudo herd restart libvirtd
|
||||
</span></span></code></pre></div><h3 id="wakatime-cli">wakatime-cli</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Note</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>TODO</td>
|
||||
<td>Package this for Guix</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<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>
|
||||
<h3 id="docker">Docker</h3>
|
||||
<p>Docker Compose plugin v2 isn’t yet available on Guix, but can be installed as follows:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>curl -SL https://github.com/docker/compose/releases/download/v2.17.2/docker-compose-linux-x86_64 -o <span style="color:#19177c">$HOME</span>/.docker/cli-plugins/docker-compose
|
||||
</span></span><span style="display:flex;"><span>sudo chmod +x <span style="color:#19177c">$HOME</span>/.docker/cli-plugins/docker-compose
|
||||
</span></span></code></pre></div><h3 id="manifest">Manifest</h3>
|
||||
<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:#19177c">my/format-guix-dependencies</span> <span style="color:#19177c">category</span>)
|
||||
</span></span></code></pre></div><p>System</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->manifest</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>(
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c"><<packages</span>(<span style="color:#ba2121">"system"</span>)<span style="color:#19177c">>></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="#profiles">Profiles</a>
|
||||
<ul>
|
||||
<li><a href="#activate-profiles">Activate profiles</a></li>
|
||||
<li><a href="#update-profiles">Update profiles</a></li>
|
||||
<li><a href="#run-guix-package-in-profile">Run <code>guix package</code> in profile</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#channels">Channels</a></li>
|
||||
<li><a href="#systems">Systems</a>
|
||||
<ul>
|
||||
<li><a href="#base-configuration">Base configuration</a></li>
|
||||
<li><a href="#indigo">indigo</a></li>
|
||||
<li><a href="#eminence">eminence</a></li>
|
||||
<li><a href="#azure">azure</a></li>
|
||||
<li><a href="#iris">iris</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#system-installation">System installation</a>
|
||||
<ul>
|
||||
<li><a href="#preparation">Preparation</a></li>
|
||||
<li><a href="#installation">Installation</a></li>
|
||||
<li><a href="#after-installation">After installation</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#misc-software-and-notes">Misc software & notes</a>
|
||||
<ul>
|
||||
<li><a href="#openvpn">OpenVPN</a>
|
||||
<ul>
|
||||
<li><a href="#vpn-start">vpn-start</a></li>
|
||||
<li><a href="#377cab">vpn-stop</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#wireguard">Wireguard</a></li>
|
||||
<li><a href="#flatpak">flatpak</a></li>
|
||||
<li><a href="#micromamba">micromamba</a></li>
|
||||
<li><a href="#slack">Slack</a></li>
|
||||
<li><a href="#virt-manager">virt-manager</a></li>
|
||||
<li><a href="#wakatime-cli">wakatime-cli</a></li>
|
||||
<li><a href="#docker">Docker</a></li>
|
||||
<li><a href="#manifest">Manifest</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
115
configs/index.html
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>Configs</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">
|
||||
|
||||
|
||||
<link rel="alternate" type="application/rss+xml" href="https://sqrtminusone.xyz/configs/index.xml" title="SqrtMinusOne" />
|
||||
|
||||
|
||||
|
||||
|
||||
<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">
|
||||
<div class="container">
|
||||
<h1>Configs</h1>
|
||||
<ul>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/configs/console/">0001-01-01 | Console</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/configs/desktop/">0001-01-01 | Desktop</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/configs/emacs/">0001-01-01 | Emacs config</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/configs/guix/">0001-01-01 | Guix</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/configs/mail/">0001-01-01 | Mail</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/configs/readme/">0001-01-01 | My dotfiles</a></li>
|
||||
|
||||
</ul>
|
||||
</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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
53
configs/index.xml
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>Configs on SqrtMinusOne</title>
|
||||
<link>https://sqrtminusone.xyz/configs/</link>
|
||||
<description>Recent content in Configs on SqrtMinusOne</description>
|
||||
<generator>Hugo -- gohugo.io</generator>
|
||||
<language>en-us</language>
|
||||
<atom:link href="https://sqrtminusone.xyz/configs/index.xml" rel="self" type="application/rss+xml" />
|
||||
<item>
|
||||
<title>Console</title>
|
||||
<link>https://sqrtminusone.xyz/configs/console/</link>
|
||||
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
||||
<guid>https://sqrtminusone.xyz/configs/console/</guid>
|
||||
<description>No matter from which side you approach penguins, more always come from behind
A friend of mine Colors Noweb function to get colors.
(let ((color (or (my/color-value name)))) (if (&gt; quote 0) (concat &#34;\&#34;&#34; color &#34;\&#34;&#34;) color)) (let ((val (if (ct-light-p (my/color-value name)) (my/color-value &#39;black) (my/color-value &#39;white)))) (if (eq quote 1) (concat &#34;\&#34;&#34; val &#34;\&#34;&#34;) val)) (setq-local org-confirm-babel-evaluate nil) .profile Environment export QT_QPA_PLATFORMTHEME=&#34;qt5ct&#34; export QT_AUTO_SCREEN_SCALE_FACTOR=0 Set ripgrep config path</description>
|
||||
</item>
|
||||
<item>
|
||||
<title>Desktop</title>
|
||||
<link>https://sqrtminusone.xyz/configs/desktop/</link>
|
||||
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
||||
<guid>https://sqrtminusone.xyz/configs/desktop/</guid>
|
||||
<description>My general desktop environment configuration.
Parts prefixed with (OFF) are not used, but kept for historic purposes. For some reason GitHub&rsquo;s org renderer ignores TODO status, hence such a prefix. Round brackets instead of square ones to prevent GitHub&rsquo;s org renderer from screwing up.
References:
A few cases of literate configuration. A few interesting ways in which literate configuration is used in this file. Some remarks Removed features:
Feature Last commit rofi-buku e22476b0cc6315e104e5ce4de5559a61c830c429 Global customization Colors I used to define color codes here (see previous version of the file), now I just get colors from the current Emacs theme.</description>
|
||||
</item>
|
||||
<item>
|
||||
<title>Emacs config</title>
|
||||
<link>https://sqrtminusone.xyz/configs/emacs/</link>
|
||||
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
||||
<guid>https://sqrtminusone.xyz/configs/emacs/</guid>
|
||||
<description>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.
Me, &lt;2021-05-27 Thu 17:35&gt; in commit 93a0573. Adapted from The Dark Element - &ldquo;The Pallbearer Walks Alone&rdquo;. T_T Introduction My configuration of GNU Emacs, an awesome text editor piece of software that can do almost anything.
At the moment of writing this, that &ldquo;almost anything&rdquo; includes:</description>
|
||||
</item>
|
||||
<item>
|
||||
<title>Guix</title>
|
||||
<link>https://sqrtminusone.xyz/configs/guix/</link>
|
||||
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
||||
<guid>https://sqrtminusone.xyz/configs/guix/</guid>
|
||||
<description>GNU Guix is (1) a transactional package manager and (2) a GNU/Linux distribution.
My personal selling points are declarative package configuration and transactional upgrades.
References:
Official help System Crafters wiki Pjotr Prins&rsquo; Guix notes Davil Wilson&rsquo;s YouTube series Profiles A profile is a way to group Guix packages. Amongst its advantages, profiles can be defined by manifests, which in turn can be stored in VCS.
References:
Guix Profiles in Practice Activate profiles A script to activate guix profiles.</description>
|
||||
</item>
|
||||
<item>
|
||||
<title>Mail</title>
|
||||
<link>https://sqrtminusone.xyz/configs/mail/</link>
|
||||
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
||||
<guid>https://sqrtminusone.xyz/configs/mail/</guid>
|
||||
<description>:TOC: :include all :depth 3
My email configration. Currently I use lieer to fetch emails from Gmail, davmail &amp; offlineimap to fetch emails from MS Exchange, notmuch to index, msmtp to send emails. Also using notmuch frontend from Emacs.
My problem with any particular mail setup was that I use Gmail labels quite extensively, and handling these over IMAP is rather awkward. Notmuch seems to be the only software that provides the same first-class support for labels.</description>
|
||||
</item>
|
||||
<item>
|
||||
<title>My dotfiles</title>
|
||||
<link>https://sqrtminusone.xyz/configs/readme/</link>
|
||||
<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
|
||||
<guid>https://sqrtminusone.xyz/configs/readme/</guid>
|
||||
<description>These are my GNU/Linux configuration files. View at GitHub.
I use the literate configuration strategy via Emacs&rsquo; Org Mode wherever possible. It has its pros and cons, but I find it pretty nice to keep the configs interweaved with comments in a handful of files.
The files themselves are managed and deployed via yadm, although I use Org Mode for things like config templating.
My current GNU/Linux distribution is GNU Guix.</description>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
771
configs/mail/index.html
Normal file
|
|
@ -0,0 +1,771 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>Mail</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">
|
||||
Mail
|
||||
<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">
|
||||
Mail
|
||||
<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>
|
||||
<p>:TOC: :include all :depth 3</p>
|
||||
<p>My email configration. Currently I use <a href="https://github.com/gauteh/lieer">lieer</a> to fetch emails from Gmail, <a href="http://davmail.sourceforge.net/">davmail</a> & <a href="http://www.offlineimap.org/">offlineimap</a> to fetch emails from MS Exchange, <a href="https://notmuchmail.org/">notmuch</a> to index, <a href="https://marlam.de/msmtp/">msmtp</a> to send emails. Also using notmuch frontend from Emacs.</p>
|
||||
<p>My problem with any particular mail setup was that I use Gmail labels quite extensively, and handling these over IMAP is rather awkward. Notmuch seems to be the only software that provides the same first-class support for labels.</p>
|
||||
<p>But I also have an Exchange account, with which I communicate via IMAP/SMTP adapter, and in this case, I synchronize notmuch tags and IMAP folders.</p>
|
||||
<p>References:</p>
|
||||
<ul>
|
||||
<li><a href="https://sqrtminusone.xyz/posts/2021-02-27-gmail/">My post</a> about email configuration. I wrote it some time ago, but the general idea remains.</li>
|
||||
</ul>
|
||||
<h2 id="lieer">Lieer</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Guix dependency</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>python-lieer</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Lieer is a program to link up Gmail and notmuch. Basically, it downloads mail from Gmail via API, stores them in Maildir, and synchronizes labels with notmuch.</p>
|
||||
<p>I have a separate directory in my <code>~/Mail</code> for each address. To init lieer, run the following command 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-text" data-lang="text"><span style="display:flex;"><span>gmi init <address>
|
||||
</span></span></code></pre></div><p>After which the settings will be stored in <code>gmailieer.json</code> and the credentials in <code>.credentials.gmailieer.json</code>. The latter file is stored encrypted.</p>
|
||||
<p>My preferred settings:</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>gmi set --replace-slash-with-dot
|
||||
</span></span><span style="display:flex;"><span>gmi set --ignore-tags-local new
|
||||
</span></span></code></pre></div><p>Running <code>gmi sync</code> in the required directory performs the synchronization. The first sync takes a while, the subsequent syncs are pretty fast.</p>
|
||||
<h2 id="davmail">DavMail</h2>
|
||||
<p>is a gateway between MS Exchange and the rest of the world, which uses IMAP/SMTP/LDAP/etc. As I have one corporate MS Exchange address, this is just the program I need. As of yet, it isn’t packaged for Guix, but it’s easy enough to download.</p>
|
||||
<p>It has a GUI mode, but I prefer headless 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">davmail.server</span><span style="color:#666">=</span><span style="color:#ba2121">true</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">davmail.mode</span><span style="color:#666">=</span><span style="color:#ba2121">Auto</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">davmail.url</span><span style="color:#666">=</span><span style="color:#ba2121">https://mail.etu.ru/owa/</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">davmail.server.certificate.hash</span><span style="color:#666">=</span><span style="color:#ba2121">0C:9E:CF:D3:62:26:DB:FA:F1:EE:36:9D:60:E7:31:71:CF:1F:92:85</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">davmail.caldavPort</span><span style="color:#666">=</span><span style="color:#ba2121">1080</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">davmail.imapPort</span><span style="color:#666">=</span><span style="color:#ba2121">1143</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">davmail.ldapPort</span><span style="color:#666">=</span><span style="color:#ba2121">1389</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">davmail.popPort</span><span style="color:#666">=</span><span style="color:#ba2121">1110</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">davmail.smtpPort</span><span style="color:#666">=</span><span style="color:#ba2121">1025</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">davmail.imapAutoExpunge</span><span style="color:#666">=</span><span style="color:#ba2121">false</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">davmail.enableKeepalive</span><span style="color:#666">=</span><span style="color:#ba2121">false</span>
|
||||
</span></span></code></pre></div><p>Also it’s a bit of problem to get it launched as it looks for its jars in the pwd, so here is a script.</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">cd</span> <span style="color:#19177c">$HOME</span>/bin/davmail-6.0.0-3375
|
||||
</span></span><span style="display:flex;"><span>./davmail davmail.properties
|
||||
</span></span></code></pre></div><p>Shepherd service is defined in <a href="/configs/desktop/#davmail">Desktop.org</a>.</p>
|
||||
<h2 id="offlineimap">OfflineIMAP</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Guix dependency</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>offlineimap</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><a href="https://github.com/OfflineIMAP/offlineimap">OfflineIMAP</a> is a program that can synchronize IMAP mailbox and Maildir. Lieer does everything by itself, but my pirate Exchange IMAP needs this program. There is also <a href="https://isync.sourceforge.io/">isync</a>, but there I had some weird issues with duplicate UIDs, which don’t occur for OfflineIMAP.</p>
|
||||
<p>I have a few options for setting a username and password. First, I can run <code>pass</code> in <code>remotepasswordeval</code>, and while this will work, it will keep my keyring unlocked because I want to run <code>offlineimap</code> every couple of minutes.</p>
|
||||
<p>Another option is to use noweb and not push the file below to the version control. Then I have a plaintext password of email on my computer, but I think it’s a lesser evil than the entire keyring.</p>
|
||||
<p>I would use <code>password-store-get</code> from password-store.el, but I want this to be able to run without any 3rd party packages, so it’s just bash.</p>
|
||||
<p><a id="code-snippet--mail-username"></a></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>pass show Job/Digital/Email/pvkorytov@etu.ru | sed -n <span style="color:#ba2121">'s/username: //;2p'</span>
|
||||
</span></span></code></pre></div><p><a id="code-snippet--mail-password"></a></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>pass show Job/Digital/Email/pvkorytov@etu.ru | head -n <span style="color:#666">1</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-ini" data-lang="ini"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">[general]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">accounts</span> <span style="color:#666">=</span> <span style="color:#ba2121">pvkorytov</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">[Account pvkorytov]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">localrepository</span> <span style="color:#666">=</span> <span style="color:#ba2121">pvkorytov-local</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">remoterepository</span> <span style="color:#666">=</span> <span style="color:#ba2121">pvkorytov-remote</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">[Repository pvkorytov-local]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">type</span> <span style="color:#666">=</span> <span style="color:#ba2121">Maildir</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">localfolders</span> <span style="color:#666">=</span> <span style="color:#ba2121">~/Mail/pvkorytov_etu/</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">[Repository pvkorytov-remote]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">type</span> <span style="color:#666">=</span> <span style="color:#ba2121">IMAP</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">remotehost</span> <span style="color:#666">=</span> <span style="color:#ba2121">localhost</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">remoteuser</span> <span style="color:#666">=</span> <span style="color:#ba2121"><<mail-username()>></span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">remotepass</span> <span style="color:#666">=</span> <span style="color:#ba2121"><<mail-password()>></span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">remoteport</span> <span style="color:#666">=</span> <span style="color:#ba2121">1143</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">starttls</span> <span style="color:#666">=</span> <span style="color:#ba2121">no</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">ssl</span> <span style="color:#666">=</span> <span style="color:#ba2121">no</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">sslcacertfile</span> <span style="color:#666">=</span> <span style="color:#ba2121">/etc/ssl/certs/ca-certificates.crt</span>
|
||||
</span></span></code></pre></div><h2 id="notmuch">Notmuch</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Guix dependency</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>notmuch</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>parallel</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Notmuch is an email indexer program, which handles labels in a way somewhat similar to Gmail. It also provides a frontend for Emacs, but it’s not the only one available.</p>
|
||||
<h3 id="config">Config</h3>
|
||||
<p>Not much is going on here.</p>
|
||||
<p>First, the database path.</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">[database]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">path</span><span style="color:#666">=</span><span style="color:#ba2121">/home/pavel/Mail</span>
|
||||
</span></span></code></pre></div><p>My name and list of emails. It’s not like it’s a secret anyhow.</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">[user]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">name</span><span style="color:#666">=</span><span style="color:#ba2121">Pavel Korytov</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">primary_email</span><span style="color:#666">=</span><span style="color:#ba2121">thexcloud@gmail.com</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">other_email</span><span style="color:#666">=</span><span style="color:#ba2121">progin6304@gmail.com;pvkorytov@etu.ru</span>
|
||||
</span></span></code></pre></div><p>A list of tags which will be added by <code>notmuch new</code> and directory names which will be ignored by <code>notmuch new</code>.</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">[new]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">tags</span><span style="color:#666">=</span><span style="color:#ba2121">new;</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">ignore</span><span style="color:#666">=</span><span style="color:#ba2121">.osync_workdir;.mbsyncstate;.uidvalidity;.lock;/.*gmailieer\.json.*/</span>
|
||||
</span></span></code></pre></div><p>Exclude these tags from search by default.</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">[search]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">exclude_tags</span><span style="color:#666">=</span><span style="color:#ba2121">trash;spam;</span>
|
||||
</span></span></code></pre></div><p>Maildir compatibility.</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">[maildir]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">synchronize_flags</span><span style="color:#666">=</span><span style="color:#ba2121">true</span>
|
||||
</span></span></code></pre></div><h3 id="hooks">Hooks</h3>
|
||||
<p>Now we have to link up lieer & davmail’s maildir and with notmuch. This is done via the notmuch hook system, which allows running custom scripts before and after any command.</p>
|
||||
<p>With lieer and Gmail, it is enough to simply run the program, because Gmail has first-class support for tags. Maildir does not, so I decide to synchronize notmuch tags and IMAP folders. In essence, the idea is to:</p>
|
||||
<ul>
|
||||
<li>move emails to their folders by tags <em>before</em> the synchronization</li>
|
||||
<li>tag mails by their folders <em>after</em> the synchronization</li>
|
||||
</ul>
|
||||
<p>The problem is that with that approach one email can have only one tag, but it’s better than nothing.</p>
|
||||
<p>So, here are the rules which match tags & folders:</p>
|
||||
<p><a id="table--pvkorytov-tags"></a></p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>tag</th>
|
||||
<th>folder</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>inbox</td>
|
||||
<td>INBOX</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>sent</td>
|
||||
<td>Sent</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>spam</td>
|
||||
<td>Junk</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>trash</td>
|
||||
<td>Trash</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>job.digital</td>
|
||||
<td>Job_Digital</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>job.digital.docs</td>
|
||||
<td>Job_Digital.Docs</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>job.digital.support</td>
|
||||
<td>Job_Digital.Support</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>job.digital.superservice</td>
|
||||
<td>Job_Digital.Superservice</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>job.digital.applicants</td>
|
||||
<td>Job_Digital.Applicants</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>job.moevm</td>
|
||||
<td>Job_Moevm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>etu</td>
|
||||
<td>Etu</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>And below is a noweb function, which generates the following commands for notmuch to execute:</p>
|
||||
<ul>
|
||||
<li><em>before</em> sync:
|
||||
<ul>
|
||||
<li><code>notmuch search --output files "NOT path:[PATH] AND tag:[TAG] AND tag:[ROOT_TAG]" | xargs -I ! mv ! [PATH]</code>
|
||||
Move emails with <code>TAG</code> but outside the matching <code>PATH</code> to the latter</li>
|
||||
<li><code>notmuch search --output=files "NOT path:[ARCHIVE_PATH] AND tag:[ROOT_TAG] AND NOT tag:[TAG1] ... AND NOT tag:[TAGN]" | xargs -I ! mv ! [ARCHIVE_PATH]</code>
|
||||
Move untagged emails to the <code>ARCHIVE_PATH</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><em>after</em> sync:
|
||||
<ul>
|
||||
<li><code>notmuch tag +[TAG] "path:[PATH] AND NOT tag:[TAG]"</code>
|
||||
Tag emails in <code>PATH</code> which do not yet have the matching <code>TAG</code></li>
|
||||
<li><code>notmuch tag -[TAG] "NOT path:[PATH] AND tag:[TAG] AND tag:[ROOT_TAG]"</code>
|
||||
Remove <code>TAG</code> from emails which are outside the matching <code>PATH</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>These rules are getting included in the respective hooks.</p>
|
||||
<p><a id="code-snippet--mail-tags"></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/maildir-root</span> <span style="color:#ba2121">"~/Mail"</span>)
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">let</span> ((<span style="color:#19177c">rules</span> <span style="color:#666">'</span>()))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">row</span> <span style="color:#19177c">tags</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">tag</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">row</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">folder</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">row</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">make_tag</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">'rules</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">"notmuch tag +%s \"path:%s/%s/cur/** AND NOT tag:%s\""</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">tag</span> <span style="color:#19177c">root</span> <span style="color:#19177c">folder</span> <span style="color:#19177c">tag</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">unless</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">remove</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">'rules</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">"notmuch tag -%s \"NOT path:%s/%s/cur/** AND tag:%s AND tag:%s\""</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">tag</span> <span style="color:#19177c">root</span> <span style="color:#19177c">folder</span> <span style="color:#19177c">tag</span> <span style="color:#19177c">root_tag</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">unless</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">move</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">'rules</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">format</span> <span style="color:#ba2121">"notmuch search --output=files \"NOT path:%s/%s/cur/** AND tag:%s AND tag:%s\""</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">root</span> <span style="color:#19177c">folder</span> <span style="color:#19177c">tag</span> <span style="color:#19177c">root_tag</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">" | xargs -I ! mv ! %s/%s/%s/cur/"</span> <span style="color:#19177c">my/maildir-root</span> <span style="color:#19177c">root</span> <span style="color:#19177c">folder</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">unless</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">archive_root</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">'rules</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">format</span> <span style="color:#ba2121">"notmuch search --output=files \"NOT path:%s/%s/cur/** AND %s AND tag:%s\""</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">root</span> <span style="color:#19177c">archive_root</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">row</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">"NOT tag:%s"</span> (<span style="color:#00f">car</span> <span style="color:#19177c">row</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">tags</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">" AND "</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">root_tag</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">" | xargs -I ! mv ! %s/%s/%s/cur/"</span> <span style="color:#19177c">my/maildir-root</span> <span style="color:#19177c">root</span> <span style="color:#19177c">archive_root</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">string-join</span> <span style="color:#19177c">rules</span> <span style="color:#ba2121">"\n"</span>))
|
||||
</span></span></code></pre></div><h4 id="pre-new"><code>pre_new</code></h4>
|
||||
<p>This hook runs fetch from Gmail & offlineimap in parallel before the <code>notmuch new</code> command. The <code>parallel</code> command is provided by <a href="https://www.gnu.org/software/parallel/">GNU Parallel</a>.</p>
|
||||
<p>It isn’t necessary to run <code>cd</code> for offlineimap, but it’s easier to write that way.</p>
|
||||
<p><a id="code-snippet--pre-new-pvkorytov-tags"></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">my/mail-format-tags-rules</span> <span style="color:#19177c">tags</span> <span style="color:#ba2121">"pvkorytov_etu"</span> <span style="color:#ba2121">"pvkorytov"</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#800">t</span> <span style="color:#ba2121">"Archive"</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-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># GMI="/home/pavel/Programs/miniconda3/envs/mail/bin/gmi"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">GMI</span><span style="color:#666">=</span><span style="color:#ba2121">"gmi"</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">echo</span> <span style="color:#ba2121">"Running pre-new filters"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#ba2121"><<mail-tags(move="t",archive_root="Archive")>>
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">echo "Pre-new filters 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">parallel --link -j0 "(cd /home/pavel/Mail/{1}/ && {2} {3})" ::: thexcloud progin6304 pvkorytov_etu ::: "$GMI" "$GMI" "offlineima</span>p<span style="color:#ba2121">" ::: sync sync ""
|
||||
</span></span></span></code></pre></div><h4 id="post-new"><code>post_new</code></h4>
|
||||
<p>And this hook tags different mailboxes with different tags.</p>
|
||||
<p><a id="code-snippet--post-new-pvkorytov-tags"></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">my/mail-format-tags-rules</span> <span style="color:#19177c">tags</span> <span style="color:#ba2121">"pvkorytov_etu"</span> <span style="color:#ba2121">"pvkorytov"</span> <span style="color:#800">t</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-bash" data-lang="bash"><span style="display:flex;"><span>notmuch tag +main <span style="color:#ba2121">"path:thexcloud/** AND tag:new"</span>
|
||||
</span></span><span style="display:flex;"><span>notmuch tag +progin <span style="color:#ba2121">"path:progin6304/** AND tag:new"</span>
|
||||
</span></span><span style="display:flex;"><span>notmuch tag +pvkorytov <span style="color:#ba2121">"path:pvkorytov_etu/** AND tag:new"</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">echo</span> <span style="color:#ba2121">"Running post-new filters"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#ba2121"><<mail-tags(ma</span>ke_tag<span style="color:#666">=</span><span style="color:#ba2121">"t"</span>,remove<span style="color:#666">=</span><span style="color:#ba2121">"t"</span><span style="color:#666">)</span>>>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">echo</span> <span style="color:#ba2121">"Post-new filters done"</span>
|
||||
</span></span><span style="display:flex;"><span>notmuch tag -new <span style="color:#ba2121">"tag:new"</span>
|
||||
</span></span></code></pre></div><h2 id="sync-script">Sync script</h2>
|
||||
<p>A script to run <code>notmuch new</code> and push a notification if there is new mail.</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">export</span> <span style="color:#19177c">DISPLAY</span><span style="color:#666">=</span>:0
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">CHECK_FILE</span><span style="color:#666">=</span><span style="color:#ba2121">"/home/pavel/Mail/.last_check"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">QUERY</span><span style="color:#666">=</span><span style="color:#ba2121">"tag:unread"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">ALL_QUERY</span><span style="color:#666">=</span><span style="color:#ba2121">"tag:unread"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">if</span> <span style="color:#666">[</span> -f <span style="color:#ba2121">"</span><span style="color:#19177c">$CHECK_FILE</span><span style="color:#ba2121">"</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">DATE</span><span style="color:#666">=</span><span style="color:#008000;font-weight:bold">$(</span>cat <span style="color:#ba2121">"</span><span style="color:#19177c">$CHECK_FILE</span><span style="color:#ba2121">"</span><span style="color:#008000;font-weight:bold">)</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">QUERY</span><span style="color:#666">=</span><span style="color:#ba2121">"</span><span style="color:#19177c">$QUERY</span><span style="color:#ba2121"> and date:@</span><span style="color:#19177c">$DATE</span><span style="color:#ba2121">.."</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>notmuch new
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">NEW_UNREAD</span><span style="color:#666">=</span><span style="color:#008000;font-weight:bold">$(</span>notmuch count <span style="color:#ba2121">"</span><span style="color:#19177c">$QUERY</span><span style="color:#ba2121">"</span><span style="color:#008000;font-weight:bold">)</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">ALL_UNREAD</span><span style="color:#666">=</span><span style="color:#008000;font-weight:bold">$(</span>notmuch count <span style="color:#ba2121">"</span><span style="color:#19177c">$ALL_QUERY</span><span style="color:#ba2121">"</span><span style="color:#008000;font-weight:bold">)</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:#666">[</span> <span style="color:#19177c">$NEW_UNREAD</span> -gt <span style="color:#666">0</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">MAIN_UNREAD</span><span style="color:#666">=</span><span style="color:#008000;font-weight:bold">$(</span>notmuch count <span style="color:#ba2121">"tag:unread AND tag:main"</span><span style="color:#008000;font-weight:bold">)</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">PROGIN_UNREAD</span><span style="color:#666">=</span><span style="color:#008000;font-weight:bold">$(</span>notmuch count <span style="color:#ba2121">"tag:unread AND tag:progin"</span><span style="color:#008000;font-weight:bold">)</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">ETU_UNREAD</span><span style="color:#666">=</span><span style="color:#008000;font-weight:bold">$(</span>notmuch count <span style="color:#ba2121">"tag:unread AND tag:pvkorytov"</span><span style="color:#008000;font-weight:bold">)</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">read</span> -r -d <span style="color:#ba2121">''</span> NOTIFICATION <span style="color:#ba2121"><<EOM
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">$NEW_UNREAD new messages
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">$MAIN_UNREAD thexcloud@gmail.com
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">$PROGIN_UNREAD progin6304@gmail.com
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">$ETU_UNREAD pvkorytov@etu.ru
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">$ALL_UNREAD total
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">EOM</span>
|
||||
</span></span><span style="display:flex;"><span> notify-send <span style="color:#ba2121">"New Mail"</span> <span style="color:#ba2121">"</span><span style="color:#19177c">$NOTIFICATION</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">echo</span> <span style="color:#ba2121">"</span><span style="color:#008000;font-weight:bold">$(</span>date +%s<span style="color:#008000;font-weight:bold">)</span><span style="color:#ba2121">"</span> > <span style="color:#19177c">$CHECK_FILE</span>
|
||||
</span></span></code></pre></div><p>The script is ran via GNU Mcron every 5 minutes.</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">job</span> <span style="color:#ba2121">"*/5 * * * * "</span> <span style="color:#ba2121">"~/bin/scripts/check-email"</span>)
|
||||
</span></span></code></pre></div><h2 id="msmtp">MSMTP</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Guix dependency</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>msmtp</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Sending emails can be done with MSMTP. It automatially chooses the email address and server based on the contents of the message, which is handy if there are multiple mailboxes to be managed.</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span>defaults
|
||||
</span></span><span style="display:flex;"><span>auth on
|
||||
</span></span><span style="display:flex;"><span>tls on
|
||||
</span></span><span style="display:flex;"><span>tls_trust_file <span style="color:#b68">/etc/</span>ssl<span style="color:#b68">/certs/</span>ca-certificates.crt
|
||||
</span></span><span style="display:flex;"><span>logfile ~/.msmtp.log
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>account main
|
||||
</span></span><span style="display:flex;"><span>host smtp.gmail.com
|
||||
</span></span><span style="display:flex;"><span>port <span style="color:#666">587</span>
|
||||
</span></span><span style="display:flex;"><span>from thexcloud@gmail.com
|
||||
</span></span><span style="display:flex;"><span>user thexcloud@gmail.com
|
||||
</span></span><span style="display:flex;"><span>passwordeval <span style="color:#ba2121">"pass show My_Online/APIs/google-main-app-password | head -n 1"</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>account progin
|
||||
</span></span><span style="display:flex;"><span>host smtp.gmail.com
|
||||
</span></span><span style="display:flex;"><span>port <span style="color:#666">587</span>
|
||||
</span></span><span style="display:flex;"><span>from progin6304@gmail.com
|
||||
</span></span><span style="display:flex;"><span>user progin6304@gmail.com
|
||||
</span></span><span style="display:flex;"><span>passwordeval <span style="color:#ba2121">"pass show My_Online/ETU/progin6304@gmail.com | head -n 1"</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>account pvkorytov
|
||||
</span></span><span style="display:flex;"><span>tls off
|
||||
</span></span><span style="display:flex;"><span>auth plain
|
||||
</span></span><span style="display:flex;"><span>host localhost
|
||||
</span></span><span style="display:flex;"><span>port <span style="color:#666">1025</span>
|
||||
</span></span><span style="display:flex;"><span>from pvkorytov@etu.ru
|
||||
</span></span><span style="display:flex;"><span>user pvkorytov
|
||||
</span></span><span style="display:flex;"><span>passwordeval <span style="color:#ba2121">"pass show Job/Digital/Email/pvkorytov@etu.ru | head -n 1"</span>
|
||||
</span></span></code></pre></div><h2 id="emacs">Emacs</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Guix dependency</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>emacs-notmuch</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Finally, Emacs configuration. Let’s start with some variables:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">user-mail-address</span> <span style="color:#ba2121">"thexcloud@gmail.com"</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#00f">user-full-name</span> <span style="color:#ba2121">"Pavel Korytov"</span>)
|
||||
</span></span></code></pre></div><p>Then, the problem with my Guix setup is that Emacs by default doesn’t see the elisp files of notmuch, 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">let</span> ((<span style="color:#19177c">default-directory</span> <span style="color:#ba2121">"/home/pavel/.guix-extra-profiles/mail/mail/share/emacs/site-lisp"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">normal-top-level-add-subdirs-to-load-path</span>))
|
||||
</span></span></code></pre></div><p>Some functions to toggle tags:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-toggle-trash</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-collection-notmuch-toggle-tag</span> <span style="color:#ba2121">"trash"</span> <span style="color:#ba2121">"search"</span> <span style="color:#00f">#'</span><span style="color:#19177c">ignore</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/notmuch-toggle-inbox</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-collection-notmuch-toggle-tag</span> <span style="color:#ba2121">"inbox"</span> <span style="color:#ba2121">"search"</span> <span style="color:#00f">#'</span><span style="color:#19177c">ignore</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/notmuch-toggle-unread</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-collection-notmuch-toggle-tag</span> <span style="color:#ba2121">"unread"</span> <span style="color:#ba2121">"search"</span> <span style="color:#00f">#'</span><span style="color:#19177c">ignore</span>))
|
||||
</span></span></code></pre></div><p>And notmuch 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">use-package</span> <span style="color:#19177c">notmuch</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; :ensure nil</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">notmuch</span> <span style="color:#19177c">notmuch-search</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/use-colors</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">notmuch-wash-cited-text</span> <span style="color:#008000">:foreground</span> (<span style="color:#19177c">doom-color</span> <span style="color:#19177c">'yellow</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">mail-specify-envelope-from</span> <span style="color:#800">t</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">message-sendmail-envelope-from</span> <span style="color:#19177c">'header</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">mail-envelope-from</span> <span style="color:#19177c">'header</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">notmuch-always-prompt-for-sender</span> <span style="color:#800">t</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">message-send-mail-function</span> <span style="color:#00f">#'</span><span style="color:#19177c">message-send-mail-with-sendmail</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">sendmail-program</span> (<span style="color:#19177c">executable-find</span> <span style="color:#ba2121">"msmtp"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">send-mail-function</span> <span style="color:#00f">#'</span><span style="color:#19177c">sendmail-send-it</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">mml-secure-openpgp-sign-with-sender</span> <span style="color:#800">t</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">notmuch-mua-user-agent-function</span> <span style="color:#19177c">'notmuch-mua-user-agent-full</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">'notmuch-search-mode-map</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">'</span>(<span style="color:#19177c">normal</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"d"</span> <span style="color:#00f">#'</span><span style="color:#19177c">my/notmuch-toggle-trash</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"i"</span> <span style="color:#00f">#'</span><span style="color:#19177c">my/notmuch-toggle-inbox</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"u"</span> <span style="color:#00f">#'</span><span style="color:#19177c">my/notmuch-toggle-unread</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Use org-contacts for completion</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">require</span> <span style="color:#19177c">'org-contacts</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">notmuch-address-command</span> <span style="color:#19177c">'as-is</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">'notmuch-hello-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">0</span>))))
|
||||
</span></span></code></pre></div><p>The file is read in <code>init.el</code>.</p>
|
||||
<h3 id="keybindings">Keybindings</h3>
|
||||
<p>I used to have a more complicated keybinding system here, but that seemed to go against the Dao.</p>
|
||||
<p>Root 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:#ba2121">"am"</span> (<span style="color:#19177c">my/command-in-persp</span> <span style="color:#ba2121">"notmuch"</span> <span style="color:#ba2121">"mail"</span> <span style="color:#666">0</span> (<span style="color:#19177c">notmuch</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/persp-add-rule</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">notmuch-hello-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">"mail"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">notmuch-search-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">"mail"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">notmuch-tree-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">"mail"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">notmuch-message-mode</span> <span style="color:#666">0</span> <span style="color:#ba2121">"mail"</span>)
|
||||
</span></span></code></pre></div><p><a id="table--root-tags"></a></p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Root tag</th>
|
||||
<th>Prefix</th>
|
||||
<th>Keybinding description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>main</td>
|
||||
<td>m</td>
|
||||
<td><a href="mailto:thexcloud@gmail.com">thexcloud@gmail.com</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>progin</td>
|
||||
<td>p</td>
|
||||
<td><a href="mailto:progin6304@gmail.com">progin6304@gmail.com</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>pvkorytov</td>
|
||||
<td>v</td>
|
||||
<td><a href="mailto:pvkorytov@etu.ru">pvkorytov@etu.ru</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><a id="table--filter-tags"></a></p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tag</th>
|
||||
<th>Prefix</th>
|
||||
<th>Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>inbox</td>
|
||||
<td>i</td>
|
||||
<td>inbox</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>unread</td>
|
||||
<td>u</td>
|
||||
<td>unread</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>sent</td>
|
||||
<td>s</td>
|
||||
<td>sent</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>a</td>
|
||||
<td>all mail</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The following formats the tables above to a proper syntax for <code>setq notmuch-saved-searches</code>:</p>
|
||||
<p><a id="code-snippet--format-notmuch-saved-searches"></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">let</span> ((<span style="color:#19177c">searches</span> <span style="color:#666">'</span>()))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">root_tag</span> <span style="color:#19177c">root_tags</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">tag</span> <span style="color:#19177c">filter_tags</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">'searches</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">"(:name \"%s\" :query \"%s\" :key \"%s\")"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">"%s (%s)"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">root_tag</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">nth</span> <span style="color:#666">2</span> <span style="color:#19177c">tag</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">"tag:"</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">root_tag</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#19177c">string-empty-p</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">tag</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">" AND tag:"</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">tag</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">root_tag</span>) (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">tag</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">string-join</span> <span style="color:#19177c">searches</span> <span style="color:#ba2121">"\n"</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">notmuch-saved-searches</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>((<span style="color:#008000">:name</span> <span style="color:#ba2121">"drafts"</span> <span style="color:#008000">:query</span> <span style="color:#ba2121">"tag:draft"</span> <span style="color:#008000">:key</span> <span style="color:#ba2121">"d"</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c"><<format-notmuch-saved-searches</span>()<span style="color:#19177c">>></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">general-define-key</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:states</span> <span style="color:#666">'</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">'</span>(<span style="color:#19177c">notmuch-hello-mode-map</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"f"</span> <span style="color:#00f">#'</span><span style="color:#19177c">notmuch-jump-search</span>)
|
||||
</span></span></code></pre></div><h3 id="signing-messages">Signing messages</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">with-eval-after-load</span> <span style="color:#19177c">'notmuch</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">'message-setup-hook</span> <span style="color:#19177c">'mml-secure-sign-pgpmime</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">mml-secure-key-preferences</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">sign</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"thexcloud@gmail.com"</span> <span style="color:#ba2121">"914472A1FD6775C166F96EBEED739ADF81C78160"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">encrypt</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">sign</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">encrypt</span>))))
|
||||
</span></span></code></pre></div><h3 id="tuning-signature">Tuning signature</h3>
|
||||
<p>By default, <code>message.el</code> inserts the signature at the bottom of the message, 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><message text>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>Person <person@mail.org> writes:
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>> Stuff
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>--
|
||||
</span></span><span style="display:flex;"><span>Yours,
|
||||
</span></span><span style="display:flex;"><span>me
|
||||
</span></span></code></pre></div><p>This creates issues with certain email clients. For instance, MS Exchange often just cuts the text at <code>Person <person@mail.org>....</code>, so there’s no way to see the signature from the UI.</p>
|
||||
<p>What’s more, MS Exchange, Gmail and other such clients add the signature before the quotation block, 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><message text>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>--
|
||||
</span></span><span style="display:flex;"><span>Yours,
|
||||
</span></span><span style="display:flex;"><span>me
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>Person <person@mail.org> writes:
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>> Stuff
|
||||
</span></span></code></pre></div><p>So here I modifiy the citation function to insert the signature like in the second example for <del>certain cases</del>.</p>
|
||||
<p>Edit <span class="timestamp-wrapper"><span class="timestamp"><2022-10-27 Thu></span></span>: for consistency’s sake, I’ll make the signature on the top for all 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:#008000">defun</span> <span style="color:#19177c">my/message-insert-signature-need-on-top</span> ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#800">t</span>)
|
||||
</span></span></code></pre></div><p>Then advice the <code>notmuch-mua-reply</code> 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/message-maybe-fix-signature</span> (<span style="color:#008000">&rest</span> <span style="color:#19177c">_</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#19177c">my/message-insert-signature-need-on-top</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:#008000">when</span> (<span style="color:#00f">re-search-forward</span> <span style="color:#19177c">message-signature-separator</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">move-beginning-of-line</span> <span style="color:#666">0</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">kill-region</span> (<span style="color:#00f">point</span>) (<span style="color:#00f">point-max</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">message-goto-body</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">re-search-forward</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">"sign=pgpmime"</span>) <span style="color:#800">nil</span> <span style="color:#800">t</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">forward-line</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#19177c">current-kill</span> <span style="color:#666">0</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#ba2121">"\n\n"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">set-buffer-modified-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">with-eval-after-load</span> <span style="color:#19177c">'notmuch-mua</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#'</span><span style="color:#19177c">notmuch-mua-reply</span> <span style="color:#008000">:after</span> <span style="color:#00f">#'</span><span style="color:#19177c">my/message-maybe-fix-signature</span>))
|
||||
</span></span></code></pre></div><h3 id="warn-if-no-subject">Warn if no subject</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">defun</span> <span style="color:#19177c">my/message-ensure-subject</span> ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">message-field-value</span> <span style="color:#ba2121">"Subject"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">y-or-n-p</span> <span style="color:#ba2121">"No subject. Send? "</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">user-error</span> <span style="color:#ba2121">"Aborting."</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">'notmuch-mua-send-hook</span> <span style="color:#00f">#'</span><span style="color:#19177c">my/message-ensure-subject</span>)
|
||||
</span></span></code></pre></div><h3 id="capitalize-formal-pronous">Capitalize formal pronous</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">defvar</span> <span style="color:#19177c">my/ru-formal-pronous</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>(<span style="color:#ba2121">"вы"</span> <span style="color:#ba2121">"вас"</span> <span style="color:#ba2121">"вам"</span> <span style="color:#ba2121">"вами"</span> <span style="color:#ba2121">"ваш"</span> <span style="color:#ba2121">"ваша"</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:#ba2121">"вашей"</span> <span style="color:#ba2121">"вашему"</span> <span style="color:#ba2121">"вашим"</span> <span style="color:#ba2121">"вашем"</span> <span style="color:#ba2121">"вашеми"</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/ru-formal-pronous-regex</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">regexp-opt</span> <span style="color:#19177c">my/ru-formal-pronous</span> <span style="color:#19177c">'words</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/message-ensure-capitalized-formal-pronouns</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">message-goto-body</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-block</span> <span style="color:#800">nil</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">case-fold-search</span> <span style="color:#800">nil</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">confirmed</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">my/ru-formal-pronous-regex</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">match</span> (<span style="color:#19177c">match-string</span> <span style="color:#666">0</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">capitalized</span> (<span style="color:#00f">capitalize</span> <span style="color:#19177c">match</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">beg</span> (<span style="color:#00f">match-beginning</span> <span style="color:#666">0</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">end</span> (<span style="color:#00f">match-end</span> <span style="color:#666">0</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">or</span> <span style="color:#19177c">confirmed</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">"Replace %s with %s? "</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">match</span> <span style="color:#19177c">capitalized</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-region</span> <span style="color:#19177c">beg</span> <span style="color:#19177c">end</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> <span style="color:#19177c">capitalized</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">confirmed</span> <span style="color:#800">t</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-return</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">'notmuch-mua-send-hook</span> <span style="color:#00f">#'</span><span style="color:#19177c">my/message-ensure-capitalized-formal-pronouns</span>)
|
||||
</span></span></code></pre></div><h3 id="ensure-password-is-loaded">Ensure password is loaded</h3>
|
||||
<p>Otherwise <code>msmtp</code> may call <code>pinentry</code> while Emacs is locked, which means EXWM can’t process the password window.</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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/ensure-password</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/password-store-get</span> <span style="color:#ba2121">"Job/Digital/Email/pvkorytov@etu.ru"</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">'notmuch-mua-send-hook</span> <span style="color:#00f">#'</span><span style="color:#19177c">my/ensure-password</span>)
|
||||
</span></span></code></pre></div><h2 id="mailcap">mailcap</h2>
|
||||
<p>mailcap file is a file which defines how to read to different MIME types. Notmuch also uses it, so why not keep it here.</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>audio/*; mpc add %s
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>image/*; feh %s
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>application/msword; /usr/bin/xdg-open %s
|
||||
</span></span><span style="display:flex;"><span>application/pdf; zathura %s
|
||||
</span></span><span style="display:flex;"><span>application/postscript ; zathura %s
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>text/html; firefox %s
|
||||
</span></span></code></pre></div><h2 id="guix-settings">Guix settings</h2>
|
||||
<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:#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->manifest</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>(
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c"><<packages</span>()<span style="color:#19177c">>></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="#lieer">Lieer</a></li>
|
||||
<li><a href="#davmail">DavMail</a></li>
|
||||
<li><a href="#offlineimap">OfflineIMAP</a></li>
|
||||
<li><a href="#notmuch">Notmuch</a>
|
||||
<ul>
|
||||
<li><a href="#config">Config</a></li>
|
||||
<li><a href="#hooks">Hooks</a>
|
||||
<ul>
|
||||
<li><a href="#pre-new"><code>pre_new</code></a></li>
|
||||
<li><a href="#post-new"><code>post_new</code></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#sync-script">Sync script</a></li>
|
||||
<li><a href="#msmtp">MSMTP</a></li>
|
||||
<li><a href="#emacs">Emacs</a>
|
||||
<ul>
|
||||
<li><a href="#keybindings">Keybindings</a></li>
|
||||
<li><a href="#signing-messages">Signing messages</a></li>
|
||||
<li><a href="#tuning-signature">Tuning signature</a></li>
|
||||
<li><a href="#warn-if-no-subject">Warn if no subject</a></li>
|
||||
<li><a href="#capitalize-formal-pronous">Capitalize formal pronous</a></li>
|
||||
<li><a href="#ensure-password-is-loaded">Ensure password is loaded</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#mailcap">mailcap</a></li>
|
||||
<li><a href="#guix-settings">Guix settings</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
208
configs/readme/index.html
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>My dotfiles</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">
|
||||
My dotfiles
|
||||
<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">
|
||||
My dotfiles
|
||||
<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>
|
||||
<figure><img src="/ox-hugo/works-on-my-machine.svg"/>
|
||||
</figure>
|
||||
|
||||
<p>These are my GNU/Linux configuration files. <a href="https://github.com/SqrtMinusOne/dotfiles">View at GitHub</a>.</p>
|
||||
<p>I use the <a href="https://leanpub.com/lit-config/read">literate configuration</a> strategy via Emacs’ <a href="https://orgmode.org/">Org Mode</a> wherever possible. It has its pros and cons, but I find it pretty nice to keep the configs interweaved with comments in a handful of files.</p>
|
||||
<p>The files themselves are managed and deployed via <a href="https://yadm.io/">yadm</a>, although I use Org Mode for things like config templating.</p>
|
||||
<p>My current GNU/Linux distribution is <a href="https://guix.gnu.org/">GNU Guix</a>. I like Guix because, among other things, it allows <a href="https://guix.gnu.org/cookbook/en/html_node/Advanced-package-management.html#Advanced-package-management">to declare the required software</a> in configuration files, so I can have the same set of programs across multiple machines (look for tables with “Guix dependency” in the header).</p>
|
||||
<p>The central program to all of that is, of course, <a href="https://www.gnu.org/software/emacs/">GNU Emacs</a>. At the time of this writing, it takes ~50% of my screen time and has the largest share of configuration here.</p>
|
||||
<p>Table of contents and software:</p>
|
||||
<ul>
|
||||
<li><a href="/configs/emacs/">Emacs.org</a>
|
||||
<ul>
|
||||
<li><a href="/configs/emacs/">GNU Emacs</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="/configs/desktop/">Desktop.org</a>
|
||||
<ul>
|
||||
<li><em>Active</em>: <a href="/configs/desktop/#exwm">EXWM</a>, <a href="/configs/desktop/#polybar">Polybar</a>, <a href="/configs/desktop/#rofi">Rofi</a>, <a href="/configs/desktop/#flameshot">Flameshot</a>, <a href="/configs/desktop/#dunst">dunst</a>, <a href="/configs/desktop/#picom">Picom</a>, <a href="/configs/desktop/#zathura">Zathura</a></li>
|
||||
<li><em>In Limbo</em>: <a href="/configs/desktop/#i3wm">i3wm</a>, <a href="/configs/desktop/#keynav">keynav</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="/configs/console/">Console.org</a>
|
||||
<ul>
|
||||
<li><em>Active</em>: <a href="/configs/console/#dot-profile">.profile</a>, <a href="/configs/console/#bash">Bash</a>, <a href="/configs/console/#fish">Fish</a>, <a href="/configs/console/#starship-prompt">Starship</a>, <a href="/configs/console/#tmux">Tmux</a>, <a href="/configs/console/#alacritty">Alacritty</a></li>
|
||||
<li><em>In Limbo</em>: <a href="/configs/console/#nushell">Nushell</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="/configs/guix/">Guix.org</a></li>
|
||||
<li><a href="/configs/mail/">Mail.org</a>
|
||||
<ul>
|
||||
<li><em>Active</em>: <a href="/configs/mail/#lieer">Lieer</a>, <a href="/configs/mail/#davmail">DavMail</a>, <a href="/configs/mail/#offlineimap">OfflineIMAP</a>, <a href="/configs/mail/#notmuch">Notmuch</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>(<em>Apparently, links on the second level work only in Emacs 🙁</em>)</p>
|
||||
<p>A few other repositories I may consider a part of my config:</p>
|
||||
<ul>
|
||||
<li><a href="https://github.com/SqrtMinusOne/channel-q">channel-q</a> is my Guix channel</li>
|
||||
<li><a href="https://github.com/SqrtMinusOne/sqrt-data">sqrt-data</a> is a home for my statistics gathering effort</li>
|
||||
<li>Emacs packages that I wrote (some of them originated in my Emacs config):
|
||||
<ul>
|
||||
<li><a href="https://github.com/SqrtMinusOne/lyrics-fetcher.el">lyrics-fetcher.el</a></li>
|
||||
<li><a href="https://github.com/SqrtMinusOne/pomm.el">pomm.el</a></li>
|
||||
<li><a href="https://github.com/SqrtMinusOne/perspective-exwm.el">perspective-exwm.el</a></li>
|
||||
<li><a href="https://github.com/SqrtMinusOne/exwm-modeline">exwm-modeline.el</a></li>
|
||||
<li><a href="https://github.com/SqrtMinusOne/org-journal-tags">org-journal-tags</a></li>
|
||||
<li><a href="https://github.com/SqrtMinusOne/elfeed-summary">elfeed-summary</a></li>
|
||||
<li><a href="https://github.com/SqrtMinusOne/password-store-ivy">password-store-ivy</a></li>
|
||||
<li><a href="https://github.com/SqrtMinusOne/elfeed-sync">elfeed-sync</a></li>
|
||||
<li><a href="https://github.com/SqrtMinusOne?tab=repositories&q=&type=&language=emacs+lisp&sort=">…</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>See also <a href="https://sqrtminusone.xyz/posts/">my blog posts</a>.</p>
|
||||
<h2 id="some-statistics">Some statistics</h2>
|
||||
<figure><img src="https://sqrtminusone.xyz/stats/all.png"/>
|
||||
</figure>
|
||||
|
||||
<figure><img src="https://sqrtminusone.xyz/stats/emacs-vim.png"/>
|
||||
</figure>
|
||||
|
||||
<figure><img src="https://sqrtminusone.xyz/stats/literate-config.png"/>
|
||||
</figure>
|
||||
|
||||
<h2 id="misc">Misc</h2>
|
||||
<h3 id="notes">Notes</h3>
|
||||
<ul>
|
||||
<li><code>M-u C-c C-v t</code> to tangle a particular block</li>
|
||||
<li><code>M-u M-u C-c C-v t</code> to tangle a particular file</li>
|
||||
<li><code>C-c C-v d</code> to demarcate a block</li>
|
||||
</ul>
|
||||
<p>Uses yadm’s <code>post_alt</code> hook to create symlinks</p>
|
||||
<h3 id="encrypted-files">Encrypted files</h3>
|
||||
<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>Mail/thexcloud/.credentials.gmailieer.json
|
||||
</span></span><span style="display:flex;"><span>Mail/progin6304/.credentials.gmailieer.json
|
||||
</span></span><span style="display:flex;"><span>.emacs.d/private.org
|
||||
</span></span><span style="display:flex;"><span>.emacs.d/private.el
|
||||
</span></span><span style="display:flex;"><span>.emacs.d/.trello/sqrtminusone.el
|
||||
</span></span><span style="display:flex;"><span>.emacs.d/gnus/*
|
||||
</span></span><span style="display:flex;"><span>./.vpn/*
|
||||
</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="#some-statistics">Some statistics</a></li>
|
||||
<li><a href="#misc">Misc</a>
|
||||
<ul>
|
||||
<li><a href="#notes">Notes</a></li>
|
||||
<li><a href="#encrypted-files">Encrypted files</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
elfeed-summary-img/screenshot.png
Normal file
|
After Width: | Height: | Size: 321 KiB |
BIN
elfeed-sync-img/screenshot.png
Normal file
|
After Width: | Height: | Size: 332 KiB |
BIN
exwm-modeline-img/screenshot.png
Normal file
|
After Width: | Height: | Size: 7 KiB |
BIN
lyrics-fetcher-img/screenshot.png
Normal file
|
After Width: | Height: | Size: 547 KiB |
BIN
org-clock-agg-img/screenshot.png
Normal file
|
After Width: | Height: | Size: 110 KiB |
BIN
org-journal-tags-img/query-results.png
Normal file
|
After Width: | Height: | Size: 325 KiB |
BIN
org-journal-tags-img/query.png
Normal file
|
After Width: | Height: | Size: 190 KiB |
BIN
org-journal-tags-img/status.png
Normal file
|
After Width: | Height: | Size: 382 KiB |
48
ox-hugo/works-on-my-machine.svg
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="works_on_my_machine" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px" y="0px" viewBox="0 0 240.4 35" style="enable-background:new 0 0 240.4 35;" xml:space="preserve" width="147.1" height="21.3">
|
||||
<style type="text/css">
|
||||
.st0{fill:#C1282D;}
|
||||
.st1{fill:#EF4041;}
|
||||
.st2{fill:#FFFFFF;}
|
||||
</style>
|
||||
<path class="st0" d="M112.5,0h127.8v35H112.5V0z"/>
|
||||
<path class="st1" d="M0,0h112.5v35H0V0z"/>
|
||||
<g>
|
||||
<path class="st2" d="M22.7,19.7L22.7,19.7l1.3-6.2h1.5l-2,8.5h-1.3L20.4,16h0L18.7,22h-1.3l-2-8.5h1.5l1.3,6.1h0l1.6-6.1h1.3
|
||||
L22.7,19.7z"/>
|
||||
<path class="st2" d="M35.9,18.6c0,1-0.3,1.9-1,2.6s-1.5,1-2.6,1c-1,0-1.8-0.3-2.5-1s-1-1.5-1-2.6V17c0-1,0.3-1.9,1-2.6s1.5-1,2.5-1
|
||||
c1,0,1.9,0.3,2.5,1s1,1.6,1,2.6V18.6z M34.5,17c0-0.7-0.2-1.3-0.6-1.8s-0.9-0.7-1.5-0.7c-0.6,0-1.1,0.2-1.5,0.7s-0.5,1-0.5,1.8v1.5
|
||||
c0,0.7,0.2,1.3,0.5,1.8s0.9,0.7,1.5,0.7c0.7,0,1.2-0.2,1.5-0.7s0.6-1,0.6-1.8V17z"/>
|
||||
<path class="st2" d="M41.5,18.5V22H40v-8.5H43c0.9,0,1.7,0.2,2.2,0.6s0.8,1,0.8,1.8c0,0.4-0.1,0.8-0.3,1.1s-0.6,0.6-1,0.8
|
||||
c0.5,0.2,0.8,0.4,1,0.7s0.3,0.8,0.3,1.3v0.7c0,0.3,0,0.5,0.1,0.7s0.2,0.4,0.3,0.5V22h-1.5c-0.2-0.1-0.3-0.3-0.3-0.6
|
||||
s-0.1-0.5-0.1-0.8v-0.7c0-0.4-0.1-0.8-0.4-1s-0.6-0.4-1-0.4H41.5z M41.5,17.4h1.4c0.6,0,1-0.1,1.2-0.3s0.4-0.6,0.4-1
|
||||
c0-0.4-0.1-0.8-0.4-1s-0.7-0.4-1.2-0.4h-1.5V17.4z"/>
|
||||
<path class="st2" d="M52.4,18.4h-0.7V22h-1.4v-8.5h1.4v3.6h0.6l2.8-3.6h1.7l0,0l-3.2,4L57,22h-1.8L52.4,18.4z"/>
|
||||
<path class="st2" d="M65.1,19.9c0-0.4-0.1-0.6-0.4-0.9s-0.7-0.4-1.3-0.6c-0.9-0.3-1.6-0.6-2.1-1s-0.7-1-0.7-1.6
|
||||
c0-0.7,0.3-1.3,0.8-1.7s1.3-0.7,2.1-0.7c0.9,0,1.7,0.2,2.2,0.7s0.8,1.1,0.8,1.8l0,0h-1.4c0-0.4-0.1-0.8-0.4-1.1s-0.7-0.4-1.2-0.4
|
||||
c-0.5,0-0.9,0.1-1.1,0.3s-0.4,0.5-0.4,0.9c0,0.3,0.1,0.6,0.4,0.8s0.8,0.4,1.4,0.6c0.9,0.3,1.6,0.6,2,1s0.7,1,0.7,1.7
|
||||
c0,0.7-0.3,1.3-0.8,1.7s-1.3,0.6-2.2,0.6c-0.9,0-1.6-0.2-2.3-0.7s-1-1.1-0.9-2l0,0h1.4c0,0.5,0.2,0.9,0.5,1.2S63,21,63.5,21
|
||||
c0.5,0,0.9-0.1,1.2-0.3S65.1,20.2,65.1,19.9z"/>
|
||||
<path class="st2" d="M82.9,18.6c0,1-0.3,1.9-1,2.6s-1.5,1-2.6,1c-1,0-1.8-0.3-2.5-1s-1-1.5-1-2.6V17c0-1,0.3-1.9,1-2.6s1.5-1,2.5-1
|
||||
c1,0,1.9,0.3,2.5,1s1,1.6,1,2.6V18.6z M81.5,17c0-0.7-0.2-1.3-0.6-1.8s-0.9-0.7-1.5-0.7c-0.6,0-1.1,0.2-1.5,0.7s-0.5,1-0.5,1.8v1.5
|
||||
c0,0.7,0.2,1.3,0.5,1.8s0.9,0.7,1.5,0.7c0.7,0,1.2-0.2,1.5-0.7s0.6-1,0.6-1.8V17z"/>
|
||||
<path class="st2" d="M93.8,22h-1.4l-3.8-6.1l0,0V22h-1.4v-8.5h1.4l3.8,6.1l0,0v-6.1h1.4V22z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st2" d="M129.5,21.8l0-4.5l-2.2,3.6h-1.1l-2.1-3.5v4.3h-2.2v-8.4h2l3,4.8l2.9-4.8h2l0,8.4H129.5z"/>
|
||||
<path class="st2" d="M140.5,18.8v3h-2.4v-3l-3.2-5.4h2.5l2,3.3l2-3.3h2.3L140.5,18.8z"/>
|
||||
<path class="st2" d="M160.6,21.8l0-4.5l-2.2,3.6h-1.1l-2.1-3.5v4.3H153v-8.4h2l3,4.8l2.9-4.8h2l0,8.4H160.6z"/>
|
||||
<path class="st2" d="M172.8,20.2h-3.6l-0.7,1.6h-2.4l3.7-8.4h2.3l3.7,8.4h-2.5L172.8,20.2z M172.1,18.4l-1.1-2.7l-1.1,2.7H172.1z"
|
||||
/>
|
||||
<path class="st2" d="M180.9,21.4c-0.7-0.4-1.3-0.9-1.7-1.6s-0.6-1.4-0.6-2.3s0.2-1.6,0.6-2.3s1-1.2,1.7-1.6
|
||||
c0.7-0.4,1.5-0.6,2.4-0.6c0.8,0,1.5,0.1,2.1,0.4c0.6,0.3,1.1,0.7,1.5,1.2l-1.5,1.4c-0.5-0.7-1.2-1-2-1c-0.5,0-0.9,0.1-1.2,0.3
|
||||
c-0.4,0.2-0.6,0.5-0.8,0.8c-0.2,0.4-0.3,0.8-0.3,1.3c0,0.5,0.1,0.9,0.3,1.3c0.2,0.4,0.5,0.6,0.8,0.8c0.4,0.2,0.8,0.3,1.2,0.3
|
||||
c0.8,0,1.4-0.3,2-1l1.5,1.4c-0.4,0.5-0.9,0.9-1.5,1.2c-0.6,0.3-1.3,0.4-2.1,0.4C182.4,22,181.6,21.8,180.9,21.4z"/>
|
||||
<path class="st2" d="M198.6,13.4v8.4h-2.4v-3.3H193v3.3h-2.4v-8.4h2.4v3.2h3.2v-3.2H198.6z"/>
|
||||
<path class="st2" d="M202.9,13.4h2.4v8.4h-2.4V13.4z"/>
|
||||
<path class="st2" d="M217.6,13.4v8.4h-2l-3.7-4.5v4.5h-2.3v-8.4h2l3.7,4.5v-4.5H217.6z"/>
|
||||
<path class="st2" d="M228.7,19.9v1.8h-6.7v-8.4h6.6v1.8h-4.2v1.4h3.7v1.8h-3.7v1.5H228.7z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
127
packages/avy-dired/index.html
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>avy-dired</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">
|
||||
avy-dired
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=avy-dired&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">
|
||||
avy-dired
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=avy-dired&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
|
||||
|
||||
</h1>
|
||||
<p>Doing some experimentation with avy & dired. Still somewhat flaky.</p>
|
||||
<figure><img src="/avy-dired-img/screenshot.png"/>
|
||||
</figure>
|
||||
|
||||
<p>The only available command is <code>M-x avy-dired-goto-line</code>. Use <code>K</code> and <code>J</code> to scroll up and down while in the avy state, <code>C-g</code> or <code>q</code> to quit.</p>
|
||||
|
||||
</div>
|
||||
<div class="table-of-contents">
|
||||
<div class="table-of-contents-text">
|
||||
<b><a href="#">Table of Contents</a></b>
|
||||
<nav id="TableOfContents"></nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
215
packages/biome/index.html
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>BIOME - Bountiful Interface to Open Meteo for Emacs</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">
|
||||
BIOME - Bountiful Interface to Open Meteo for Emacs
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=biome&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">
|
||||
BIOME - Bountiful Interface to Open Meteo for Emacs
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=biome&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
|
||||
|
||||
</h1>
|
||||
<figure><a href="https://melpa.org/#/biome"><img src="https://melpa.org/packages/biome-badge.svg"/></a>
|
||||
</figure>
|
||||
|
||||
<p>Interface to <a href="https://open-meteo.com/">Open Meteo</a> for Emacs. The service provides weather forecasts, historical weather data, climate change projections, and more.</p>
|
||||
<p>The service is AGPL-licensed; the hosted API is free for non-commercial use if you make less than 10000 requests per day.</p>
|
||||
<figure><img src="/biome-img/report.png"/>
|
||||
</figure>
|
||||
|
||||
<h2 id="installation">Installation</h2>
|
||||
<p>The package is available on MELPA. Install it however you normally install packages, I prefer <a href="https://github.com/jwiegley/use-package">use-package</a> and <a href="https://github.com/radian-software/straight.el">straight.el</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">biome</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>Or clone the repository, add it to <code>load-path</code>, and <code>require</code> the package.</p>
|
||||
<h2 id="usage">Usage</h2>
|
||||
<p>The main entry point is <code>M-x biome</code>. Each item under “Open Meteo Data” corresponds to a particular endpoint of the service. For instance, <code>M-x biome ww</code> is a generic weather forecast. Check out the <a href="https://open-meteo.com/en/docs">API docs</a> for more detailed descriptions.</p>
|
||||
<figure><img src="/biome-img/root.png"/>
|
||||
</figure>
|
||||
|
||||
<p>Each of these items opens a query interface. A query consists of “global” variables, such as location, units, etc., and “group variables”. Groups are usually “hourly” and “daily”.</p>
|
||||
<figure><img src="/biome-img/query.png"/>
|
||||
</figure>
|
||||
|
||||
<p>Global variables must always include a location (section “Select Coordinates or City”). To enter a location, you can either enter latitude and longitude (Open Meteo has an <a href="https://open-meteo.com/en/docs/geocoding-api">API for those</a> as well) or select a location from <code>biome-query-coords</code>. Example 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">setq</span> <span style="color:#19177c">biome-query-coords</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>((<span style="color:#ba2121">"Helsinki, Finland"</span> <span style="color:#666">60.16952</span> <span style="color:#666">24.93545</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"Berlin, Germany"</span> <span style="color:#666">52.52437</span> <span style="color:#666">13.41053</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"Dubai, UAE"</span> <span style="color:#666">25.0657</span> <span style="color:#666">55.17128</span>)))
|
||||
</span></span></code></pre></div><p>A timezone is also often required (“Settings” > “Timezone”).</p>
|
||||
<p>The current group is switched with <code><tab></code>. Each group’s section has a set of variables that can be toggled on and off, such as temperature, precipitation, etc. Check out the <a href="https://open-meteo.com/en/docs">API docs</a> if you’re interested in the meaning of more esoteric ones.</p>
|
||||
<p>Press <code>RET</code> after you’ve configured the query to call the API. If something goes wrong, it will output an error, such 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>Open Meteo has returned an error.
|
||||
</span></span><span style="display:flex;"><span>Error: (error http 400)
|
||||
</span></span><span style="display:flex;"><span>Reason: Timezone is required
|
||||
</span></span></code></pre></div><p>Or it will open the results table (the first screenshot).</p>
|
||||
<p><code>tabulated-list</code> doesn’t support horizontal scrolling, so press <code>c</code> to toggle columns’ visibility.</p>
|
||||
<figure><img src="/biome-img/columns.png"/>
|
||||
</figure>
|
||||
|
||||
<h2 id="more-configuration">More configuration</h2>
|
||||
<p>To save a query for later, press <code>P</code> in the root of the query interface. This will generate a definition like 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:#19177c">biome-def-preset</span> <span style="color:#19177c">biome-query-preset-177</span>
|
||||
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">:name</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Weather Forecast"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:group</span> <span style="color:#666">.</span> <span style="color:#ba2121">"hourly"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:params</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"hourly"</span> <span style="color:#ba2121">"windgusts_10m"</span> <span style="color:#ba2121">"windspeed_10m"</span> <span style="color:#ba2121">"cloudcover"</span> <span style="color:#ba2121">"surface_pressure"</span> <span style="color:#ba2121">"weathercode"</span> <span style="color:#ba2121">"snowfall"</span> <span style="color:#ba2121">"showers"</span> <span style="color:#ba2121">"rain"</span> <span style="color:#ba2121">"relativehumidity_2m"</span> <span style="color:#ba2121">"temperature_2m"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"longitude"</span> <span style="color:#666">.</span> <span style="color:#666">24.93545</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"latitude"</span> <span style="color:#666">.</span> <span style="color:#666">60.16952</span>))))
|
||||
</span></span></code></pre></div><p>Add this somewhere in your config after the package is loaded, e.g., in the <code>:config</code> section of the <code>use-package</code> form or wrapped in <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Hooks-for-Loading.html#index-with_002deval_002dafter_002dload">with-eval-after-load</a>. Running <code>M-x biome-query-preset-177</code> will create a query interface with this preset.</p>
|
||||
<p>Table formatting can be configured with <code>biome-grid-format</code>; check the docstring for more information. For instance, if you want to disable all gradients:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">biome-grid-format</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:#00f">eq</span> (<span style="color:#00f">car-safe</span> (<span style="color:#00f">nth</span> <span style="color:#666">2</span> <span style="color:#19177c">f</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">'gradient</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">biome-grid-format</span>))
|
||||
</span></span></code></pre></div><h2 id="composite-queries">Composite queries</h2>
|
||||
<p>The package also allows executing multiple queries at once to join their results. This can be useful for comparing weather in different locations or for viewing different reports about the same location.</p>
|
||||
<p>Run <code>M-x biome-multi</code> to invoke the-multi query dialog.</p>
|
||||
<figure><img src="/biome-img/multi.png"/>
|
||||
</figure>
|
||||
|
||||
<p>(<em>yes, I’ve switched to a light theme since the time of the previous screenshot</em>)</p>
|
||||
<p>Pressing <code>a</code> invokes the standard query dialog, where pressing <code>RET</code> returns to the root dialog, adding the query to the list. Pressing <code>RET</code> in the root dialog executes the queries in the list.</p>
|
||||
<p>Queries are executed concurrently. The results are shown if all queries have been successfully completed.</p>
|
||||
<p><code>P</code> generates a preset defintion for the current query:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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">biome-def-multi-preset</span> <span style="color:#19177c">biome-query-preset-601</span>
|
||||
</span></span><span style="display:flex;"><span> (((<span style="color:#008000">:name</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Air Quality"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:group</span> <span style="color:#666">.</span> <span style="color:#ba2121">"hourly"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:params</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"hourly"</span> <span style="color:#ba2121">"uv_index"</span> <span style="color:#ba2121">"european_aqi"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"longitude"</span> <span style="color:#666">.</span> <span style="color:#666">24.93545</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"latitude"</span> <span style="color:#666">.</span> <span style="color:#666">60.16952</span>)))
|
||||
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">:name</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Weather Forecast"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:group</span> <span style="color:#666">.</span> <span style="color:#ba2121">"hourly"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:params</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"hourly"</span> <span style="color:#ba2121">"weathercode"</span> <span style="color:#ba2121">"snowfall"</span> <span style="color:#ba2121">"showers"</span> <span style="color:#ba2121">"rain"</span> <span style="color:#ba2121">"temperature_2m"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"longitude"</span> <span style="color:#666">.</span> <span style="color:#666">24.93545</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"latitude"</span> <span style="color:#666">.</span> <span style="color:#666">60.16952</span>)))))
|
||||
</span></span></code></pre></div><p>Just note that the macro is called <code>biome-def-multi-preset</code>.</p>
|
||||
<h2 id="implementation-notes">Implementation notes</h2>
|
||||
<p>This isn’t the most complicated thing I’ve done, but it’s probably the most over-engineered one.</p>
|
||||
<p>As you may have guessed, the interfaces mirror the <a href="https://open-meteo.com/en/docs">API docs</a>. I’ve implemented <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Parsing-HTML_002fXML.html">parsing of these HTMLs</a> in <code>biome-api-parse--generate</code>, which generates the value of <code>biome-api-data</code>. Initially, it downloaded the HTML pages by itself, but - imagine that - the website was migrated to Svelte after I implemented maybe 80% of the parsing logic, and the Svelte version populates the accordions via JavaScript. So, as of now, the function requires opening the website in the browser, manually toggling all the accordions, and copying the HTML from DevTools. Fortunately, the parsing is a one-off operation.</p>
|
||||
<p>Then, the interface… I like <a href="https://github.com/magit/transient/">transient.el</a>, so I wanted to make the interface generated dynamically from <code>biome-api-data</code>, which turned out harder than I expected. I probably should’ve just used <a href="https://www.gnu.org/software/emacs/manual/html_mono/widget.html">widget.el</a>.</p>
|
||||
<p>Generating sensible keys was a challenge. I’ve made an algorithm in <code>biome-query--unique-keys</code> that sort of works well.</p>
|
||||
<p>And as for populating transient prefixes, I tried to use <code>:setup-children</code> in a few places, but it’s not general enough, namely, it doesn’t seem to support specifying <code>:class</code> for child groups… So I ended up overriding <code>transient--layout</code> in the prefix setup. This doesn’t seem to have any undesirable side effects.</p>
|
||||
<p>Also, the only way I found to use custom infix classes in these dynamic definitions was to eval <code>transient-define-infix</code> for each required place. Unfortunately, that adds a lot of stuff to the interactive functions namespace.</p>
|
||||
<p>Getting to the results display, Lars Ingebrigtsen’s <a href="https://lars.ingebrigtsen.no/2022/04/13/more-vtable-fun/">vtable</a> comes only in Emacs 29, so I used <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Tabulated-List-Mode.html">tabulated-list</a>. The only disadvantage of the latter is the lack of horizontal scroll support, which can be worked around by hiding columns with <code>biome-grid-columns</code>.</p>
|
||||
<p>Most variables are formatted with a gradient, colors for which were mostly inspired by <a href="https://www.windy.com/">Windy</a>. Formatting for things like air quality variables is probably all over the place, so take the red color with a grain of salt.</p>
|
||||
|
||||
</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="#installation">Installation</a></li>
|
||||
<li><a href="#usage">Usage</a></li>
|
||||
<li><a href="#more-configuration">More configuration</a></li>
|
||||
<li><a href="#composite-queries">Composite queries</a></li>
|
||||
<li><a href="#implementation-notes">Implementation notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
526
packages/elfeed-summary/index.html
Normal file
|
|
@ -0,0 +1,526 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>elfeed-summary</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">
|
||||
elfeed-summary
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=elfeed-summary&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">
|
||||
elfeed-summary
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=elfeed-summary&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
|
||||
|
||||
</h1>
|
||||
<figure><a href="https://melpa.org/#/elfeed-summary"><img src="https://melpa.org/packages/elfeed-summary-badge.svg"/></a>
|
||||
</figure>
|
||||
|
||||
<p>The package provides a tree-based feed summary interface for <a href="https://github.com/skeeto/elfeed">elfeed</a>. The tree can include individual feeds, <a href="https://github.com/skeeto/elfeed#filter-syntax">searches</a>, and groups. It mainly serves as an easier “jumping point” for elfeed, so to make querying a subset of the elfeed database one action away.</p>
|
||||
<p>Inspired by <a href="https://github.com/newsboat/newsboat">newsboat</a>.</p>
|
||||
<figure><img src="/elfeed-summary-img/screenshot.png"/>
|
||||
</figure>
|
||||
|
||||
<h2 id="installation">Installation</h2>
|
||||
<p>The package is available on MELPA, so install it however you normally install packages. My preferred way is <code>use-package</code> with <code>straight</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">elfeed-summary</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>Of course, you have to have <a href="https://github.com/skeeto/elfeed">elfeed</a> configured.</p>
|
||||
<h2 id="usage">Usage</h2>
|
||||
<p>Running <code>M-x elfeed-summary</code> opens up the summary buffer, as shown on the screenshot.</p>
|
||||
<p>The tree consists of:</p>
|
||||
<ul>
|
||||
<li>feeds;</li>
|
||||
<li>searches;</li>
|
||||
<li>groups, that can include other groups, feeds, and searches.</li>
|
||||
</ul>
|
||||
<p>Groups can also be generated automatically.</p>
|
||||
<p>Available keybindings in the summary mode:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Keybinding</th>
|
||||
<th>Command</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>RET</code></td>
|
||||
<td><code>elfeed-summary--action</code></td>
|
||||
<td>Open thing under the cursor (a feed, search, or a group). If there is at least one unread item, it will show only unread items.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>M-RET</code></td>
|
||||
<td><code>elfeed-summary--action-show-read</code></td>
|
||||
<td>Open thing under the cursor, but always include read items</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>q</code></td>
|
||||
<td>…</td>
|
||||
<td>Quit the summary buffer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>r</code></td>
|
||||
<td><code>elfeed-summary--refresh</code></td>
|
||||
<td>Refresh the summary buffer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>R</code></td>
|
||||
<td><code>elfeed-summary-update</code></td>
|
||||
<td>Run update for elfeed feeds</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>u</code></td>
|
||||
<td><code>elfeed-summary-toggle-only-unread</code></td>
|
||||
<td>Toggle showing only unread entries</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>U</code></td>
|
||||
<td><code>elfeed-summary--action-mark-read</code></td>
|
||||
<td>Mark everything in the entry under the cursor as read</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The standard keybindings from <a href="https://magit.vc/manual/magit.html#Sections">magit-section</a> are also available, for instance <code>TAB</code> toggles the visibility of the current group. <a href="https://github.com/emacs-evil/evil">evil-mode</a> is also supported.</p>
|
||||
<h2 id="configuration">Configuration</h2>
|
||||
<h3 id="tree-configuration">Tree configuration</h3>
|
||||
<p>The structure of the tree is determined by the <code>elfeed-summary-settings</code> variable.</p>
|
||||
<p>This is a list of these possible items:</p>
|
||||
<ul>
|
||||
<li>Group <code>(group . <group-params>)</code>
|
||||
Groups are used to group elements under collapsible sections.</li>
|
||||
<li>Query <code>(query . <query-params>)</code>
|
||||
Query extracts a subset of elfeed feeds based on the given criteria. Each found feed will be represented as a line.</li>
|
||||
<li>Search <code>(search . <search-params>)</code>
|
||||
Elfeed search, as defined by <code>elfeed-search-set-filter</code>.</li>
|
||||
<li>Tags tree <code>(auto-tags . <auto-tags-params>)</code>
|
||||
A tree generated automatically from the available tags.</li>
|
||||
<li>Tag groups <code>(tag-groups . <tag-group-params>)</code>
|
||||
Insert one tag as one group.</li>
|
||||
<li>a few special forms</li>
|
||||
</ul>
|
||||
<p><code><group-params></code> is an alist with the following keys:</p>
|
||||
<ul>
|
||||
<li><code>:title</code> (mandatory)</li>
|
||||
<li><code>:elements</code> (mandatory) - elements of the group. The structure is the same as in the root definition.</li>
|
||||
<li><code>:face</code> - group face. The default face is <code>elfeed-summary-group-face</code>.</li>
|
||||
<li><code>:hide</code> - if non-nil, the group is collapsed by default.</li>
|
||||
</ul>
|
||||
<p><code><query-params></code> can be:</p>
|
||||
<ul>
|
||||
<li>A symbol of a tag.
|
||||
A feed will be matched if it has that tag.</li>
|
||||
<li><code>:all</code>. Will match anything.</li>
|
||||
<li><code>(title . "string")</code> or <code>(title . <form>)</code>
|
||||
Match feed title with <code>string-match-p</code>. <form> makes sense if you
|
||||
want to pass something like <code>rx</code>.</li>
|
||||
<li><code>(author . "string")</code> or <code>(author . <form>)</code></li>
|
||||
<li><code>(url . "string")</code> or <code>(url . <form>)</code></li>
|
||||
<li><code>(and <q-1> <q-2> ... <q-n>)</code>
|
||||
Match if all the conditions 1, 2, …, n match.</li>
|
||||
<li><code>(or <q-1> <q-2> ... <q-n>)</code> or <code>(<q-1> <q-2> ... <q-n>)</code>
|
||||
Match if any of the conditions 1, 2, …, n match.</li>
|
||||
<li><code>(not <query>)</code></li>
|
||||
</ul>
|
||||
<p>Feed tags for the query are determined by the <code>elfeed-feeds</code> variable.</p>
|
||||
<p>Query examples:</p>
|
||||
<ul>
|
||||
<li><code>(emacs lisp)</code>
|
||||
Return all feeds that have either “emacs” or “lisp” tags.</li>
|
||||
<li><code>(and emacs lisp)</code>
|
||||
Return all feeds that have both “emacs” and “lisp” tags.</li>
|
||||
<li><code>(and (title . "Emacs") (not planets))</code>
|
||||
Return all feeds that have “Emacs” in their title and don’t have
|
||||
the “planets” tag.</li>
|
||||
</ul>
|
||||
<p><code><search-params></code> is an alist with the following keys:</p>
|
||||
<ul>
|
||||
<li><code>:filter</code> (mandatory) filter string, as defined by
|
||||
<code>elfeed-search-set-filter</code></li>
|
||||
<li><code>:title</code> (mandatory) title.</li>
|
||||
<li><code>:tags</code> - list of tags to get the face of the entry.</li>
|
||||
</ul>
|
||||
<p><code><auto-tags-params></code> is an alist with the following keys:</p>
|
||||
<ul>
|
||||
<li><code>:max-level</code> - maximum level of the tree (default 2)</li>
|
||||
<li><code>:source</code> - which feeds to use to build the tree.
|
||||
Can be <code>:misc</code> (default) or <code>(query . <query-params>)</code>.</li>
|
||||
<li><code>:original-order</code> - do not try to build a more concise tree by
|
||||
putting the most frequent tags closer to the root of the tree.</li>
|
||||
<li><code>:faces</code> - list of faces for groups.</li>
|
||||
</ul>
|
||||
<p><code><tag-group-params></code> is an alist with the following keys:</p>
|
||||
<ul>
|
||||
<li><code>:source</code> - which feeds to use to build the tree.
|
||||
Can be <code>:misc</code> (default) or <code>(query . <query-params>)</code>.</li>
|
||||
<li><code>:repeat-feeds</code> - allow feeds to repeat. Otherwise, each feed is
|
||||
assigned to group with the least amount of members.</li>
|
||||
<li><code>:face</code> - face for groups.</li>
|
||||
</ul>
|
||||
<p>Available special forms:</p>
|
||||
<ul>
|
||||
<li><code>:misc</code> - print out feeds, not found by any query above.</li>
|
||||
</ul>
|
||||
<p>Also keep in mind that <code>'(key . ((values)))</code> is the same as <code>'(key (values))</code>. This helps to shorten the form in many cases.</p>
|
||||
<p>Also, this variable is not validated by any means, so wrong values can produce somewhat cryptic errors. Sorry about that.</p>
|
||||
<h3 id="example">Example</h3>
|
||||
<p>Here is an excerpt from my configuration that was used to produce this screenshot:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">elfeed-summary-settings</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>((<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"GitHub"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#19177c">url</span> <span style="color:#666">.</span> <span style="color:#ba2121">"SqrtMinusOne.private.atom"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> <span style="color:#666">.</span> ((<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Guix packages"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">github</span> <span style="color:#19177c">guix_packages</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:hide</span> <span style="color:#800">t</span>)))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Blogs [Software]"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> <span style="color:#19177c">software_blogs</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Blogs [People]"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">blogs</span> <span style="color:#19177c">people</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">emacs</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Emacs"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">blogs</span> <span style="color:#19177c">people</span> <span style="color:#19177c">emacs</span>))))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Podcasts"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> <span style="color:#19177c">podcasts</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Videos"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Music"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">music</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Tech"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">tech</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"History"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">query</span> <span style="color:#666">.</span> (<span style="color:#008000">and</span> <span style="color:#19177c">videos</span> <span style="color:#19177c">history</span>))))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; ...</span>
|
||||
</span></span><span style="display:flex;"><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">group</span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Miscellaneous"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Searches"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">search</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:filter</span> <span style="color:#666">.</span> <span style="color:#ba2121">"@6-months-ago sqrtminusone"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"About me"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">search</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:filter</span> <span style="color:#666">.</span> <span style="color:#ba2121">"+later"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Check later"</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:title</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Ungrouped"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:elements</span> <span style="color:#008000">:misc</span>))))))
|
||||
</span></span></code></pre></div><h3 id="automatic-generation-of-groups">Automatic generation of groups</h3>
|
||||
<h4 id="auto-tags"><code>auto-tags</code></h4>
|
||||
<p>As described in the <a href="#tree-configuration-1">tree configuration</a> section, there are two ways to avoid defining all the relevant groups manually, <code>auto-tags</code> and <code>tag-groups</code>. Both use tags that are defined in <code>elfeed-feeds</code>.</p>
|
||||
<p><code>auto-tags</code> tries to build the most concise tree from these tags. E.g. if we have feeds:</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>feed1 tag1 tag2
|
||||
</span></span><span style="display:flex;"><span>feed2 tag1 tag2
|
||||
</span></span><span style="display:flex;"><span>feed3 tag1 tag3
|
||||
</span></span><span style="display:flex;"><span>feed4 tag1 tag3
|
||||
</span></span></code></pre></div><p>It will create the following tree:</p>
|
||||
<ul>
|
||||
<li>tag1
|
||||
<ul>
|
||||
<li>tag2
|
||||
<ul>
|
||||
<li>feed1</li>
|
||||
<li>feed2</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>tag3
|
||||
<ul>
|
||||
<li>feed3</li>
|
||||
<li>feed4</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>The tree is truncated by <code>:max-level</code>, which is 2 by default.</p>
|
||||
<p>If tags don’t form this kind of hierarchy in <code>elfeed-feeds</code>, the algorithm will still try to build the most “optimal” tree, where the most frequent tags are on the top.</p>
|
||||
<p>To avoid that you can set <code>(:original-order . t)</code>, in which case each feed will be placed at the path <code>tag1 tag2 ... tagN feed</code>, where the order of tags is the same as in <code>elfeed-feeds</code>. By the way, this allows reproducing the hierarchy of <a href="https://github.com/remyhonig/elfeed-org">elfeed-org</a>, e.g. this structure:</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 :tag1:
|
||||
</span></span><span style="display:flex;"><span>** feed1
|
||||
</span></span><span style="display:flex;"><span>** feed2 :tag2:
|
||||
</span></span><span style="display:flex;"><span>** feed3 :tag2:
|
||||
</span></span><span style="display:flex;"><span>* tag3 :tag3:
|
||||
</span></span><span style="display:flex;"><span>** feed4 :tag2:
|
||||
</span></span><span style="display:flex;"><span>** feed5 :tag2:
|
||||
</span></span><span style="display:flex;"><span>** feed6 :tag2:
|
||||
</span></span></code></pre></div><p>Will be converted to this:</p>
|
||||
<ul>
|
||||
<li>tag1
|
||||
<ul>
|
||||
<li>feed1</li>
|
||||
<li>tag2
|
||||
<ul>
|
||||
<li>feed2</li>
|
||||
<li>feed3</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>tag3
|
||||
<ul>
|
||||
<li>tag2
|
||||
<ul>
|
||||
<li>feed4</li>
|
||||
<li>feed5</li>
|
||||
<li>feed6</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Whereas without <code>:original-order</code> the structure will be:</p>
|
||||
<ul>
|
||||
<li>tag1
|
||||
<ul>
|
||||
<li>feed1</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>tag2
|
||||
<ul>
|
||||
<li>tag1
|
||||
<ul>
|
||||
<li>feed2</li>
|
||||
<li>feed3</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>tag3
|
||||
<ul>
|
||||
<li>feed4</li>
|
||||
<li>feed5</li>
|
||||
<li>feed6</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h4 id="tag-groups"><code>tag-groups</code></h4>
|
||||
<p>The second option is <code>tag-groups</code>, which creates a group for each tag.</p>
|
||||
<p>By default, each feed is assigned to its less frequent tag. This can be turned off by setting <code>(:repeat-feeds . t)</code>.</p>
|
||||
<p>E.g., the elfeed-org setup from the section above will be converted to this structure:</p>
|
||||
<ul>
|
||||
<li>tag1
|
||||
<ul>
|
||||
<li>feed1</li>
|
||||
<li>feed2</li>
|
||||
<li>feed3</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>tag3
|
||||
<ul>
|
||||
<li>feed4</li>
|
||||
<li>feed5</li>
|
||||
<li>feed6</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>And with <code>:repeat-feeds</code>:</p>
|
||||
<ul>
|
||||
<li>tag1
|
||||
<ul>
|
||||
<li>feed1</li>
|
||||
<li>feed2</li>
|
||||
<li>feed3</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>tag2
|
||||
<ul>
|
||||
<li>feed2</li>
|
||||
<li>feed3</li>
|
||||
<li>feed4</li>
|
||||
<li>feed5</li>
|
||||
<li>feed6</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>tag3
|
||||
<ul>
|
||||
<li>feed4</li>
|
||||
<li>feed5</li>
|
||||
<li>feed6</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h4 id="common-options">Common options</h4>
|
||||
<p>Both <code>auto-tags</code> and <code>tag-groups</code> allow setting the <code>:search</code> parameter.</p>
|
||||
<p>The default value is <code>(:search . :misc)</code>, i.e. use feeds that weren’t found by other queries.</p>
|
||||
<p>Passing <code>(:search . (query . <query-params>))</code> is another option.</p>
|
||||
<h3 id="faces">Faces</h3>
|
||||
<p>Group faces by default use the <code>elfeed-summary-group-faces</code> variable, which serves as a list of faces for each level of the tree. Individual group faces can be overridden with the <code>:face</code> attribute.</p>
|
||||
<p>Feed faces by default reuse <a href="https://github.com/skeeto/elfeed#custom-tag-faces">the existing elfeed mechanism</a>. The tags for feeds are taken from the <code>elfeed-feeds</code> variable; if a feed has at least one unread entry, the unread tag is added to the list. This can be overridden by setting the <code>elfeed-summary-feed-face-fn</code> variable.</p>
|
||||
<p>Searches are mostly the same as feeds, but tags for the search are taken from the <code>:tags</code> attribute. This also can be overridden with <code>elfeed-summary-search-face-fn</code> variable.</p>
|
||||
<h3 id="opening-elfeed-search-in-other-window">Opening <code>elfeed-search</code> in other window</h3>
|
||||
<p>If you set:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">elfeed-summary-other-window</span> <span style="color:#800">t</span>)
|
||||
</span></span></code></pre></div><p>Then <code>RET</code> and <code>M-RET</code> in the <code>elfeed-summary</code> buffer will open the search buffer in other window.</p>
|
||||
<p><code>elfeed-summary-width</code> regulates the width of the remaining summary window in this case. It is useful because the data in the search buffer is generally wider than in the summary buffer. The variable can also be set to <code>nil</code> to disable this behavior.</p>
|
||||
<h3 id="skipping-feeds">Skipping feeds</h3>
|
||||
<p><a href="https://tt-rss.org/">tt-rss</a> has a feature to disable updating a particular feed but keep it in the feed list. I also want that for elfeed.</p>
|
||||
<p>To use that, set <code>elfeed-summary-skip-sync-tag</code> to some 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">elfeed-summary-skip-sync-tag</span> <span style="color:#19177c">'skip</span>)
|
||||
</span></span></code></pre></div><p>And tag the feeds you want to skip with this tag. Then, running <code>M-x elfeed-summary-update</code> will skip them. This won’t affect <code>M-x elfeed-update</code> unless you:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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">advice-add</span> <span style="color:#00f">#'</span><span style="color:#19177c">elfeed-update</span> <span style="color:#008000">:override</span> <span style="color:#00f">#'</span><span style="color:#19177c">elfeed-summary-update</span>)
|
||||
</span></span></code></pre></div><p>Also watch out if you use <a href="https://github.com/remyhonig/elfeed-org">elfeed-org</a> and want to use the <code>ignore</code> tag, because this package omits feeds with this tag altogether (configurable by <code>rmh-elfeed-org-ignore-tag</code>).</p>
|
||||
<h3 id="other-options">Other options</h3>
|
||||
<p>Also take a look at <code>M-x customize-group elfeed-summary</code> for the rest of available options.</p>
|
||||
<h2 id="ideas-and-alternatives">Ideas and alternatives</h2>
|
||||
<p>The default interface of elfeed is just a list of all entries. Naturally, it gets hard to navigate when there are a lot of sources with varying frequencies of posts.</p>
|
||||
<p>Elfeed itself provides one solution, which is using <a href="https://github.com/skeeto/elfeed#bookmarks">bookmarks</a> to save individual <a href="https://github.com/skeeto/elfeed#filter-syntax">searches</a>. This can work, but it can be somewhat cumbersome.</p>
|
||||
<p><a href="https://github.com/sp1ff/elfeed-score">elfeed-score</a> is another solution, which introduces scoring rules for entries. Thus, with proper rules set, the most important entries should be on the top of the list. You can take a look at <a href="https://www.youtube.com/watch?v=rvWbUGx9U5E">this video by John Kitchin</a> to see how this can work.</p>
|
||||
<p>However, I mostly had <code>elfeed-score</code> to group entries to sets with equal scores, and I then processed one such set or the other. This is why I decided this package is a better fit for my workflow.</p>
|
||||
<p>Another idea I used often before that is this 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/elfeed-search-filter-source</span> (<span style="color:#19177c">entry</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Filter elfeed search buffer by the feed under the cursor."</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">"@6-months-ago "</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"+unread "</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"="</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">"?"</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">""</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>I’ve bound it to <code>o</code>, so I would open <code>elfeed</code>, press <code>o</code>, and only see unread entries from a particular feed. Then I cleaned the filter and switched to the next feed. Once again, a tree with feeds is obviously a better tool for such a workflow.</p>
|
||||
<p>The last solution I want to mention is <a href="https://github.com/manojm321/elfeed-dashboard">elfeed-dashboard</a>, although I didn’t test this one. It looks similar to this package but seems to require much more fine-tuning, for instance, it doesn’t allow to list all the feeds with a certain tag in a group.</p>
|
||||
|
||||
</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="#installation">Installation</a></li>
|
||||
<li><a href="#usage">Usage</a></li>
|
||||
<li><a href="#configuration">Configuration</a>
|
||||
<ul>
|
||||
<li><a href="#tree-configuration">Tree configuration</a></li>
|
||||
<li><a href="#example">Example</a></li>
|
||||
<li><a href="#automatic-generation-of-groups">Automatic generation of groups</a>
|
||||
<ul>
|
||||
<li><a href="#auto-tags"><code>auto-tags</code></a></li>
|
||||
<li><a href="#tag-groups"><code>tag-groups</code></a></li>
|
||||
<li><a href="#common-options">Common options</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#faces">Faces</a></li>
|
||||
<li><a href="#opening-elfeed-search-in-other-window">Opening <code>elfeed-search</code> in other window</a></li>
|
||||
<li><a href="#skipping-feeds">Skipping feeds</a></li>
|
||||
<li><a href="#other-options">Other options</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#ideas-and-alternatives">Ideas and alternatives</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
216
packages/elfeed-sync/index.html
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>elfeed-sync</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">
|
||||
elfeed-sync
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=elfeed-sync&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">
|
||||
elfeed-sync
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=elfeed-sync&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
|
||||
|
||||
</h1>
|
||||
<p>Sync read/marked status of entries between <a href="https://github.com/skeeto/elfeed">elfeed</a> and <a href="https://tt-rss.org/">tt-rss</a>. Supports <a href="https://github.com/SqrtMinusOne/elfeed-summary">elfeed-summary</a>.</p>
|
||||
<p>DISCLAIMER: It’s still an alpha version of the package, so you may want to backup your elfeed index and tt-rss database.</p>
|
||||
<figure><img src="/elfeed-sync-img/screenshot.png"/>
|
||||
</figure>
|
||||
|
||||
<h2 id="installation">Installation</h2>
|
||||
<p>The project consists of the tt-rss plugin and the Emacs package.</p>
|
||||
<p>If you are using the <a href="https://git.tt-rss.org/fox/ttrss-docker-compose.git/tree/README.md">tt-rss docker</a> setup, the steps are as follows. Change them accordingly if you are not.</p>
|
||||
<ol>
|
||||
<li>
|
||||
<p>Mount the <code>/var/www/html</code> directory from the container somewhere to the filesystem as described <a href="https://git.tt-rss.org/fox/ttrss-docker-compose.wiki.git/tree/Home.md#how-do-i-use-dynamic-image-for-development">here</a>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Put the repository to the <code>tt-rss/plugins.local/elfeed_sync</code> folder:</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">cd</span> ./html/tt-rss/plugins.local/
|
||||
</span></span><span style="display:flex;"><span>git clone https://github.com/SqrtMinusOne/elfeed-sync.git elfeed_sync
|
||||
</span></span></code></pre></div></li>
|
||||
<li>
|
||||
<p>Add <code>elfeed_sync</code> to the <code>TTRSS_PLUGINS</code> environment variable.</p>
|
||||
<pre tabindex="0"><code class="language-dotenv" data-lang="dotenv">TTRSS_PLUGINS=auth_internal, auth_remote, nginx_xaccel, elfeed_sync
|
||||
</code></pre></li>
|
||||
<li>
|
||||
<p>Allow larger request body sizes in nginx. Add the following to the <code>server</code> directive:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#7d9029">client_max_body_size 10M;</span>
|
||||
</span></span></code></pre></div><p>For me, the sync payload is around 3M.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Increase the read timeout in nginx. Add the following to the php location directive:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#7d9029">fastcgi_read_timeout 600;</span>
|
||||
</span></span></code></pre></div><p>Syncing the entries is usually pretty fast, but the first feed sync takes a while.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Then restart tt-rss. Check if the plugin appears in the Preferences > Plugins section.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Enable “Allows accessing this account through the API” in the Preferences > Preferences. You also may want to disable “Purge unread articles”, because elfeed doesn’t do that.</p>
|
||||
</li>
|
||||
</ol>
|
||||
<p>Install the Emacs package however you normally install packages, I prefer use-package and straight.el. Make sure to enable <code>elfeed-sync-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">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">"SqrtMinusOne/elfeed-sync"</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></code></pre></div><p>Then set up the following variables:</p>
|
||||
<ul>
|
||||
<li><code>elfeed-sync-tt-rss-instance</code> - point that to your tt-rss instance, e.g.
|
||||
<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>https://example.com/tt-rss
|
||||
</span></span></code></pre></div>(No trailing slash)</li>
|
||||
<li><code>elfeed-sync-tt-rss-login</code></li>
|
||||
<li><code>elfeed-sync-tt-rss-password</code></li>
|
||||
<li><code>elfeed-sync-unread-tag</code> - elfeed tag to map to read status in tt-rss. <code>unread</code> by default.</li>
|
||||
<li><code>elfeed-sync-marked-tag</code> - elfeed tag to map to marked status in tt-rss. <code>later</code> by default.</li>
|
||||
</ul>
|
||||
<h2 id="usage">Usage</h2>
|
||||
<h3 id="syncing-the-feed-list">Syncing the feed list</h3>
|
||||
<p>The first thing you probably want to do is to sync the feed list.</p>
|
||||
<p>It makes little sense to sync tt-rss feeds to elfeed, because people often use projects like <a href="https://github.com/remyhonig/elfeed-org">elfeed-org</a>. But it’s possible to sync elfeed feeds to tt-rss.</p>
|
||||
<p>The function <code>M-x elfeed-sync-feeds</code> does exactly that. If you have <a href="https://github.com/SqrtMinusOne/elfeed-summary">elfeed-summary</a> installed and tt-rss categories enabled, the function will recreate the elfeed-summary tree in tt-rss.</p>
|
||||
<p>The first run of the function takes a while because tt-rss has to fetch the feed at the moment of the first subscription. Which is why increasing the timeout may be necessary.</p>
|
||||
<p>However, running the function multiple times until it succeeds should also work.</p>
|
||||
<h3 id="syncing-the-entry-list">Syncing the entry list</h3>
|
||||
<p>To sync the entry list, run <code>M-x elfeed-sync</code>. The sync usually takes a couple of seconds.</p>
|
||||
<p>The sync finishes at the “Sync complete!” message. Check the <code>*elfeed-log*</code> buffer for statistics.</p>
|
||||
<p>Occasionally, some entries do not match. Here are the possible cases:</p>
|
||||
<ul>
|
||||
<li>Entry exists in the elfeed database, but not in tt-rss.
|
||||
Run <code>M-x elfeed-sync-search-missing</code> to display such entries.</li>
|
||||
<li>Entry exists in the tt-rss database, but not in elfeed:
|
||||
<ul>
|
||||
<li>Entry appeared in the feed after the last <code>elfeed-update</code>.
|
||||
Run <code>M-x elfeed-update</code> and then <code>M-x elfeed-sync</code>.</li>
|
||||
<li>Entry appeared and disappeared in the feed after the last <code>elfeed-update</code>.
|
||||
Such an entry will never get to the elfeed database. If you want to, run <code>M-x elfeed-sync</code> and then <code>M-x elfeed-sync-read-ttrss-missing</code> to mark all such entries as read.</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Entry appeared in the feed before <code>elfeed-sync-look-back</code>.
|
||||
Such an entry will never be matched. This is an inconvenience if you have just set up tt-rss, it fetched old entries from the feeds and such entries remain permanently unread because they are untouched by the <code>M-x elfeed-sync</code>.
|
||||
To mark such entries as read, run <code>M-x elfeed-sync-read-ttrss-old</code>.</li>
|
||||
</ul>
|
||||
<h2 id="implementation-details">Implementation details</h2>
|
||||
<p>The heavy-lifting is done on the elisp side because I ran into strange performance issues with associative arrays in PHP.</p>
|
||||
<p>Check the <code>elfeed-sync--do-sync</code> function for the description of the synchronization algorithm. The tl;dr is to download all entries from tt-rss and match each entry against the elfeed database. In the case of discrepancy update whichever entry has the lower priority.</p>
|
||||
|
||||
</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="#installation">Installation</a></li>
|
||||
<li><a href="#usage">Usage</a>
|
||||
<ul>
|
||||
<li><a href="#syncing-the-feed-list">Syncing the feed list</a></li>
|
||||
<li><a href="#syncing-the-entry-list">Syncing the entry list</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#implementation-details">Implementation details</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
158
packages/exwm-modeline/index.html
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>exwm-modeline</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">
|
||||
exwm-modeline
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=exwm-modeline&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">
|
||||
exwm-modeline
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=exwm-modeline&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
|
||||
|
||||
</h1>
|
||||
<figure><a href="https://melpa.org/#/exwm-modeline"><img src="https://melpa.org/packages/exwm-modeline-badge.svg"/></a>
|
||||
</figure>
|
||||
|
||||
<p>A modeline segment to display exwm workspaces.</p>
|
||||
<p>Here’s how it looks near the list of <a href="https://github.com/nex3/perspective-el">perspectives</a> (the segment of the current package is to the left):
|
||||
<img src="/exwm-modeline-img/screenshot.png" alt=""></p>
|
||||
<ul>
|
||||
<li>workspaces 0 and 5 do not have any X windows</li>
|
||||
<li>workspace 1 is the current workspace</li>
|
||||
<li>workspace 2 has at least one X window.</li>
|
||||
</ul>
|
||||
<p>Features:</p>
|
||||
<ul>
|
||||
<li>Supports <code>exwm-randr</code> to display only workspaces related to the current monitor.</li>
|
||||
<li>Numbers are clickable.</li>
|
||||
</ul>
|
||||
<h2 id="installation">Installation</h2>
|
||||
<p>The package is available on MELPA. Install it however you usually install packages, I use <a href="https://github.com/jwiegley/use-package">use-package</a> and <a href="https://github.com/raxod502/straight.el">straight.el</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">exwm-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:#008000">:after</span> (<span style="color:#19177c">exwm</span>))
|
||||
</span></span></code></pre></div><p>Then put a call to <code>exwm-modeline-mode</code> somewhere after the moment when EXWM has been initialized, for instance:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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">'exwm-init-hook</span> <span style="color:#00f">#'</span><span style="color:#19177c">exwm-modeline-mode</span>)
|
||||
</span></span></code></pre></div><h2 id="customization">Customization</h2>
|
||||
<p>Set <code>exwm-modeline-randr</code> to nil to turn off filtering of workspaces by monitor.</p>
|
||||
<p>Set <code>exwm-modeline-short</code> to <code>t</code> display only the current workspace in the modeline.</p>
|
||||
<p>Set <code>exwm-modeline-display-urgent</code> to nil to turn off displaying whether a workspace has an urgent window. This will significantly decrease the number of modeline updates, which may help with performance issues.</p>
|
||||
<h2 id="credits">Credits</h2>
|
||||
<p><a href="https://github.com/nex3/perspective-el">perspective.el</a> by <a href="https://github.com/nex3">@nex3</a> was extremely instructive on how to make a modeline segment individual to a particular frame and avoid recalculating it too often.</p>
|
||||
<p><a href="https://github.com/elken/doom-modeline-exwm">doom-modeline-exwm</a> by <a href="https://github.com/elken">@elken</a> also was a source of inspiration.</p>
|
||||
|
||||
</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="#installation">Installation</a></li>
|
||||
<li><a href="#customization">Customization</a></li>
|
||||
<li><a href="#credits">Credits</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
129
packages/index.html
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>Packages</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">
|
||||
|
||||
|
||||
<link rel="alternate" type="application/rss+xml" href="https://sqrtminusone.xyz/packages/index.xml" title="SqrtMinusOne" />
|
||||
|
||||
|
||||
|
||||
|
||||
<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">
|
||||
<div class="container">
|
||||
<h1>Packages</h1>
|
||||
<ul>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/packages/org-clock-agg/">2023-12-17 | org-clock-agg</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/packages/biome/">2023-07-22 | BIOME - Bountiful Interface to Open Meteo for Emacs</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/packages/micromamba/">2023-06-20 | micromamba.el</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/packages/reverso/">2022-08-28 | reverso.el</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/packages/elfeed-sync/">2022-05-29 | elfeed-sync</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/packages/avy-dired/">2022-04-01 | avy-dired</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/packages/elfeed-summary/">2022-03-26 | elfeed-summary</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/packages/password-store-ivy/">2022-02-13 | password-store-ivy</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/packages/org-journal-tags/">2022-02-06 | org-journal-tags</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/packages/exwm-modeline/">2021-12-22 | exwm-modeline</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/packages/perspective-exwm/">2021-12-01 | perspective-exwm</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/packages/pomm/">2021-11-05 | pomm.el</a></li>
|
||||
|
||||
<li><a href="https://sqrtminusone.xyz/packages/lyrics-fetcher/">2021-08-14 | lyrics-fetcher.el</a></li>
|
||||
|
||||
</ul>
|
||||
</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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
1702
packages/index.xml
Normal file
236
packages/lyrics-fetcher/index.html
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>lyrics-fetcher.el</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">
|
||||
lyrics-fetcher.el
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=lyrics-fetcher.el&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">
|
||||
lyrics-fetcher.el
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=lyrics-fetcher.el&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
|
||||
|
||||
</h1>
|
||||
<figure><a href="https://melpa.org/#/lyrics-fetcher"><img src="https://melpa.org/packages/lyrics-fetcher-badge.svg"/></a>
|
||||
</figure>
|
||||
|
||||
<p>A package to fetch song lyrics and album covers. Integrates with EMMS.</p>
|
||||
<figure><img src="/lyrics-fetcher-img/screenshot.png"/>
|
||||
</figure>
|
||||
|
||||
<p>The available backends are <a href="https://genius.com">genius.com</a> and <a href="https://music.163.com/">music.163.com</a>.</p>
|
||||
<h2 id="installation">Installation</h2>
|
||||
<p>The package is available on MELPA. Install it however you normally install packages, I prefer <code>use-package</code> with <code>straight</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">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></code></pre></div><p>Install <a href="https://imagemagick.org/index.php">imagemagick</a> if you want to download covers.</p>
|
||||
<p>If you want to use the genius backend, you have to set <a href="https://docs.genius.com/">genius.com</a> client access token. To do that, <a href="https://genius.com/api-clients/new">create a new client,</a> click “Generate Access Token” and put the result to the <code>lyrics-fetcher-genius-access-token</code> variable. I do this with password-store:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">lyrics-fetcher-genius-access-token</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">password-store-get</span> <span style="color:#ba2121">"My_Online/APIs/genius.com"</span>))
|
||||
</span></span></code></pre></div><p>But of course, you can just hardcode the string.</p>
|
||||
<h2 id="usage">Usage</h2>
|
||||
<p>Available commands:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>M-x lyrics-fetcher-show-lyrics</code> - show lyrics for the current playing track.</p>
|
||||
<p>The resulting lyric files are saved to the <code>lyrics-fetcher-lyrics-folder</code> and have the <code>lyrics-fetcher-lyrics-file-extension</code> extension. The folder will be created if it doesn’t exist.</p>
|
||||
<p>By default, the function opens an already saved lyrics file if one exists, otherwise tries to fetch the lyrics.</p>
|
||||
<p>If called with <code>C-u</code>, then tries to fetch the text regardless of the latter.</p>
|
||||
<p>If called with <code>C-u C-u</code>, prompts the user to select a matching song. That is helpful when there are multiple songs with similar names, and the top one isn’t the right one.</p>
|
||||
<p>If called with <code>C-u C-u C-u</code>, edit the search query in minibuffer before sending. This is helpful when there is extra information in the song title which prevents the API from finding the song.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>M-x lyrics-fetcher-show-lyrics-query</code> - fetch lyrics by a text query.</p>
|
||||
<p>Modified by <code>C-u</code> the same way as <code>lyrics-fetcher-show-lyrics</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>M-x lyrics-fetcher-use-backend</code> - select a backend to use.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>EMMS integration:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>M-x lyrics-fetcher-emms-browser-show-at-point</code> - fetch data for the current point in EMMS browser.</p>
|
||||
<p>If the point contains just one song, it will be fetched the usual way and lyrics will be shown upon successful completion.</p>
|
||||
<p>If the point contains many songs (e.g. it’s an album), the lyrics will be fetched consequentially for every song. The process then will stop at the first failure.</p>
|
||||
<p>Modified by <code>C-u</code> the same way as <code>lyrics-fetcher-show-lyrics</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>M-x lyrics-fetcher-emms-browser-fetch-covers-at-point</code> - fetch album covers for the current point in the EMMS browser.</p>
|
||||
<p>This functionality requires songs’ directories to be grouped by albums, i.e. one album per one folder.</p>
|
||||
<p>The files will be saved to the folder with names like “cover_small.jpg”, “cover_med.jpg”, “cover_large.jpg”.</p>
|
||||
<p>You can customize the sizes via the <code>lyrics-fetcher-small-cover-size</code> and <code>lyrics-fetcher-medium-cover-size</code> variables.</p>
|
||||
<p>Modified by <code>C-u</code> the same way as <code>lyrics-fetcher-show-lyrics</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>M-x lyrics-fetcher-emms-browser-open-large-cover-at-point</code> - open large_cover for the current point in EMMS browser.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>M-x lyrics-fetcher-lyrics-catchup</code> - feed the LRC file for the current track to EMMS.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Lyric view mode keybindings:</p>
|
||||
<ul>
|
||||
<li><code>q</code> - close the lyrics buffer</li>
|
||||
<li><code>r</code> - refetch the lyrics in the buffer</li>
|
||||
</ul>
|
||||
<h2 id="available-backends">Available backends</h2>
|
||||
<p>As of now, the available backends are <code>genius</code> and <code>neteasecloud</code> (thanks <a href="https://github.com/Elilif">@Elilif</a>). Backends can be switched with <code>M-x lyrics-fetcher-use-backend</code>, or from the Lisp 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">lyrics-fetcher-use-backend</span> <span style="color:#19177c">'neteasecloud</span>)
|
||||
</span></span></code></pre></div><p>The <code>genius</code> backend fetches lyrics in a simple text format.</p>
|
||||
<p><code>neteasecloud</code> fetches in the <a href="https://en.wikipedia.org/wiki/LRC_(file_format)">LRC</a> format, which contains timestamps for each line of the lyrics text.</p>
|
||||
<p>LRC files can also be read by <code>emms-lyrics</code>. <code>lyrics-fetcher-use-backend</code> sets up <code>lyrics-fetcher</code> and EMMS variables so that EMMS could see the lyrics, downloaded by <code>lyrics-fetcher</code>. Running <code>M-x emms-lyrics</code> then should enable lyric display for newly played tracks, or you can run <code>M-x lyrics-fetcher-lyrics-catchup</code> to manually feed the current LRC file to EMMS.</p>
|
||||
<h2 id="customization-and-extension">Customization and extension</h2>
|
||||
<h3 id="lyrics-file-naming-and-location">Lyrics file naming and location</h3>
|
||||
<p>As was outlined above, lyrics files are saved to <code>lyrics-fetcher-lyrics-folder</code> and have an extension set in <code>lyrics-fetcher-lyrics-file-extension</code>.</p>
|
||||
<p>Take a look at the <code>lyrics-fetcher-format-song-name-method</code> and <code>lyrics-fetcher-format-file-name-method</code> variables if you want to customize the lyrics buffer and file naming.</p>
|
||||
<p>Also note that integration with <code>emms-lyrics</code> requires these variables to be set with <code>lyrics-fetcher-use-backend</code></p>
|
||||
<h3 id="using-other-player-than-emms">Using other player than EMMS</h3>
|
||||
<p>To use another player, customize <code>lyrics-fetcher-current-track-method</code>.</p>
|
||||
<p>This variable contains a function that returns the current playing track. The return format has to be either a string or (recommended) an EMMS-like alist, which has to have the following fields:</p>
|
||||
<ul>
|
||||
<li><code>info-artist</code> or <code>info-albumartist</code></li>
|
||||
<li><code>info-title</code></li>
|
||||
</ul>
|
||||
<h3 id="adding-another-backend">Adding another backend</h3>
|
||||
<p>A function to perform the lyric fetching is set in <code>lyrics-fetcher-fetch-method</code>.</p>
|
||||
<p>The function has to receive 3 arguments:</p>
|
||||
<ul>
|
||||
<li><code>track</code> - a string or alist, as outlined <a href="#using-other-player-than-emms-1">above</a>.</li>
|
||||
<li><code>callback</code> - the function which has to be called with the resulting lyrics string</li>
|
||||
<li><code>sync</code> - if non-nil, inquire the user about the possible choices. This is called <code>sync</code> because then it is reasonable to perform the request synchronously, as otherwise, it won’t be nice to suddenly throw a prompt at the user.</li>
|
||||
</ul>
|
||||
<p>The album cover fetching is similar. The corresponding function is set in <code>lyrics-fetcher-download-cover-method</code> and has to receive the following parameters:</p>
|
||||
<ul>
|
||||
<li><code>track</code> - as above</li>
|
||||
<li><code>callback</code> - has to be called with the path to the resulting file. This file should be named <code>cover_large.<extension></code>.</li>
|
||||
<li><code>folder</code> - where the file has to be put</li>
|
||||
<li><code>sync</code> - as above.</li>
|
||||
</ul>
|
||||
<p>The first argument is <code>track</code> because in EMMS all the required information is stored in tracks, and album data is deduced from tracks. So this package just takes a sample track in the album.</p>
|
||||
<h2 id="troubleshooting">Troubleshooting</h2>
|
||||
<p>I’ve noticed that Genius can give pages with different DOMs to different people. If you have an empty buffer instead of lyrics, please attach the <code>curl-cookie-jar</code> file to the issue. It usually resides in <code>.emacs.d/request</code>.</p>
|
||||
|
||||
</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="#installation">Installation</a></li>
|
||||
<li><a href="#usage">Usage</a></li>
|
||||
<li><a href="#available-backends">Available backends</a></li>
|
||||
<li><a href="#customization-and-extension">Customization and extension</a>
|
||||
<ul>
|
||||
<li><a href="#lyrics-file-naming-and-location">Lyrics file naming and location</a></li>
|
||||
<li><a href="#using-other-player-than-emms">Using other player than EMMS</a></li>
|
||||
<li><a href="#adding-another-backend">Adding another backend</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#troubleshooting">Troubleshooting</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
153
packages/micromamba/index.html
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>micromamba.el</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">
|
||||
micromamba.el
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=micromamba.el&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">
|
||||
micromamba.el
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=micromamba.el&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
|
||||
|
||||
</h1>
|
||||
<figure><a href="https://melpa.org/#/micromamba"><img src="https://melpa.org/packages/micromamba-badge.svg"/></a>
|
||||
</figure>
|
||||
|
||||
<p>Emacs package for working with <a href="https://mamba.readthedocs.io/en/latest/user_guide/micromamba.html">micromamba</a> environments.</p>
|
||||
<p><a href="https://mamba.readthedocs.io/en/latest/index.html">mamba</a> is a reimplementation of the <a href="https://docs.conda.io/en/latest/">conda</a> package manager in C++. <code>mamba</code> is notably much faster and essentially compatible with <code>conda</code>, so it also works with <a href="https://github.com/necaris/conda.el">conda.el</a>. <code>micromamba</code>, however, implements only a subset of <code>mamba</code> commands, and as such requires a separate integration.</p>
|
||||
<h2 id="installation">Installation</h2>
|
||||
<p>The package is available on MELPA. Install it however you normally install packages, I prefer <code>use-package</code> and <code>straight</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">micromamba</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>Or clone the repository, add it to the <code>load-path</code> and <code>require</code> the package.</p>
|
||||
<p>If your <code>micromamba</code> binary is located in some place unknown to <code>executable-find</code>, set the <code>micromamba-executable</code> variable.</p>
|
||||
<p>If you are running shells (e.g. <a href="https://github.com/akermu/emacs-libvterm">vterm</a>) from Emacs, you probably want to set <code>auto_activate_base</code> in your <a href="https://docs.conda.io/projects/conda/en/latest/user-guide/configuration/index.html">.condarc</a> or <a href="https://mamba.readthedocs.io/en/latest/user_guide/configuration.html">.mambarc</a>, because the shells are launched in the correct environment anyway.</p>
|
||||
<h2 id="usage">Usage</h2>
|
||||
<p>The package has two entrypoints:</p>
|
||||
<ul>
|
||||
<li><code>M-x micromamba-activate</code> - activate the environment</li>
|
||||
<li><code>M-x micromamba-deactivate</code> - deactivate the environment</li>
|
||||
</ul>
|
||||
<p><code>micromamba-activate</code> prompts for the environment (by parsing <code>micromamba env list</code>). If some environments have duplicate names, these names are replaced by full paths.</p>
|
||||
<p>I’ve noticed that <code>micromamba</code> also sees <code>conda</code> environments, so migrating from <code>conda</code> was rather painless for me.</p>
|
||||
<h2 id="implementation-notes">Implementation notes</h2>
|
||||
<p>I initially wanted to extend <a href="https://github.com/necaris/conda.el">conda.el</a>, but decided it would be counterproductive for a few reasons.</p>
|
||||
<p>First, <code>conda</code> is rather slow, so <code>conda.el</code> does various tricks to avoid calling the <code>conda</code> executable. For instance, it gets the environment list from scanning the anaconda home directory instead of running <code>conda env list</code>. This is really not necessary with <code>micromamba</code>, which is written in C++.</p>
|
||||
<p>Second, and more importantly, <code>conda.el</code> relies heavily on passing <code>shell.posix+json</code> to <code>conda</code>. <code>micromamba</code> doesn’t support that. It supports the <code>--json</code> flag in some places, but not in the <code>activate</code> command, so I have to parse the output of <code>micromamba shell -s bash activate</code> and <code>micromamba shell -s bash deactivate</code> to get the environment configuration.</p>
|
||||
<p>This also means the package most likely won’t work out-of-the-box on Windows.</p>
|
||||
|
||||
</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="#installation">Installation</a></li>
|
||||
<li><a href="#usage">Usage</a></li>
|
||||
<li><a href="#implementation-notes">Implementation notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
367
packages/org-clock-agg/index.html
Normal file
|
|
@ -0,0 +1,367 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>org-clock-agg</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">
|
||||
org-clock-agg
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=org-clock-agg&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">
|
||||
org-clock-agg
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=org-clock-agg&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
|
||||
|
||||
</h1>
|
||||
<p>Aggregate <a href="https://orgmode.org/manual/Clocking-Work-Time.html">org-clock</a> records and display the results in an interactive buffer. The records are grouped by predicates such as file name, their outline path in the file, etc. Each record is placed in a tree structure; each node of the tree shows the total time spent in that node and its children. The top-level node shows the total time spent in all records found by the query.</p>
|
||||
<figure><img src="/org-clock-agg-img/screenshot.png"/>
|
||||
</figure>
|
||||
|
||||
<h2 id="installation">Installation</h2>
|
||||
<p>The package isn’t yet available anywhere but in this repository. My preferred way for such cases is <a href="https://github.com/jwiegley/use-package">use-package</a> and <a href="https://github.com/radian-software/straight.el">straight.el</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">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">"SqrtMinusOne/org-clock-agg"</span>))
|
||||
</span></span></code></pre></div><p>Alternatively, clone the repository, add it to the <code>load-path</code>, and <code>require</code> the package.</p>
|
||||
<h2 id="usage">Usage</h2>
|
||||
<p>Run <code>M-x org-clock-agg</code> to open the interactive buffer (as depicted in the screenshot above).</p>
|
||||
<p>The interactive buffer provides the following controls:</p>
|
||||
<ul>
|
||||
<li><strong>Files</strong>: Specifies the org files from which to select (defaults to <a href="https://orgmode.org/manual/Agenda-Files.html">org-agenda</a>).</li>
|
||||
<li><strong>Date from</strong> and <strong>To</strong>: Define the date range.</li>
|
||||
<li><strong>Group by</strong>: Determines how <code>org-clock</code> records are grouped.</li>
|
||||
<li><strong>Show elements</strong>: Whether to display raw <code>org-clock</code> records in each node.</li>
|
||||
<li><strong>Add “Ungrouped”</strong>: Option to include the “Ungrouped” node. This is particularly useful with <a href="#custom-grouping-predicates">custom grouping predicates</a>.</li>
|
||||
</ul>
|
||||
<p>Press <code>[Refresh]</code> to update the buffer. The initial search might take some time, but subsequent searches are generally faster due to the caching mechanism employed by <a href="https://github.com/alphapapa/org-ql">org-ql</a>.</p>
|
||||
<p>The buffer uses <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Outline-Mode.html">outline-mode</a> to display the tree, so each node becomes an <code>outline-mode</code> header. Refer to the linked manual for available commands/keybindings, or, if you use <code>evil-mode</code>, check <a href="https://github.com/emacs-evil/evil-collection/blob/master/modes/outline/evil-collection-outline.el">the relevant evil-collection file</a>.</p>
|
||||
<h3 id="files">Files</h3>
|
||||
<p>By default, the package selects <code>org-clock</code> records from <code>(org-agenda-files)</code>. Additional options can be included by customizing the <code>org-clock-agg-files-preset</code> variable. For instance:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-clock-agg-files-preset</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>((<span style="color:#ba2121">"Org Agenda + Archive"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">.</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span>(<span style="color:#00f">append</span> (<span style="color:#19177c">org-agenda-files</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-remove-if</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">f</span>) (<span style="color:#19177c">string-match-p</span> (<span style="color:#008000">rx</span> <span style="color:#ba2121">"."</span> <span style="color:#19177c">eos</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">"/archive/"</span>) <span style="color:#800">t</span>))))))
|
||||
</span></span></code></pre></div><p>Note that after updating any of these variables, you’ll need to reopen the <code>*org-clock-agg*</code> buffer to view the changes.</p>
|
||||
<p>Alternatively, you can directly specify the list of files within the buffer by selecting “Custom list” in the “Files” control.</p>
|
||||
<h3 id="date-range">Date Range</h3>
|
||||
<p>Dates can take the following values:</p>
|
||||
<ul>
|
||||
<li>A number: Represents a relative number of days from the current date. E.g. the default value of <code>-7</code> to <code>0</code> menas the previous week up to today.</li>
|
||||
<li>A date string in the format <code>YYYY-MM-DD HH:mm:ss</code>, with or without the time part.</li>
|
||||
</ul>
|
||||
<p>By default, the interval is inclusive. For instance, specifying an interval like 2023-12-12 .. 2023-12-13 includes all records from 2023-12-12 00:00:00 to 2023-12-13 23:59:59.</p>
|
||||
<h3 id="group-by">Group By</h3>
|
||||
<p>Records are grouped based on the sequence of grouping predicates.</p>
|
||||
<p>For example, with the following content in <code>tasks.org</code>:</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>* Tasks
|
||||
</span></span><span style="display:flex;"><span>** DONE Thing 1
|
||||
</span></span><span style="display:flex;"><span>:LOGBOOK:
|
||||
</span></span><span style="display:flex;"><span>CLOCK: [2023-12-13 Wed 19:01]--[2023-12-13 Wed 19:29] => 0:28
|
||||
</span></span><span style="display:flex;"><span>CLOCK: [2023-12-13 Wed 19:30]--[2023-12-13 Wed 19:40] => 0:10
|
||||
</span></span><span style="display:flex;"><span>:END:
|
||||
</span></span></code></pre></div><p>And predicates “Org file”, “Day”, and “Outline path”, the records for “Thing 1” will be processed as follows:</p>
|
||||
<ul>
|
||||
<li>“Day” -> <code>2023-12-13</code></li>
|
||||
<li>“Org file” -> <code>tasks.org</code></li>
|
||||
<li>“Outline path” -> <code>Tasks</code>, <code>Thing 1</code></li>
|
||||
</ul>
|
||||
<p>Consequently, the node will be placed at the path <code>2023-12-13</code> / <code>tasks.org</code> / <code>Tasks</code> / <code>Thing 1</code> in the resulting 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>* Results Root 0:38
|
||||
</span></span><span style="display:flex;"><span>** 2023-12-13 Day 0:38
|
||||
</span></span><span style="display:flex;"><span>*** tasks.org Org File 0:38
|
||||
</span></span><span style="display:flex;"><span>**** Tasks Outline path 0:38
|
||||
</span></span><span style="display:flex;"><span>***** Thing 1 Outline path 0:38
|
||||
</span></span><span style="display:flex;"><span>- [2023-12-13 Wed 19:01]--[2023-12-13 Wed 19:29] => 0:28 : DONE Thing 1
|
||||
</span></span><span style="display:flex;"><span>- [2023-12-13 Wed 19:30]--[2023-12-13 Wed 19:40] => 0:10 : DONE Thing 1
|
||||
</span></span></code></pre></div><p>The following built-in predicates are currently available:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Comment</th>
|
||||
<th>Customization variables</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Category</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Org file</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Outline path</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tags</td>
|
||||
<td>Sorted alphabetically</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Headline</td>
|
||||
<td>Last item of the outline path</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Day</td>
|
||||
<td></td>
|
||||
<td><code>org-clock-agg-day-format</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Week</td>
|
||||
<td></td>
|
||||
<td><code>org-clock-agg-week-format</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Month</td>
|
||||
<td></td>
|
||||
<td><code>org-clock-agg-month-format</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TODO keyword</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Is done</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Selected props</td>
|
||||
<td></td>
|
||||
<td><code>org-clock-agg-properties</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Ensure to use <code>setopt</code> to set the variables; otherwise, the customization logic will not be invoked:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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">setopt</span> <span style="color:#19177c">org-clock-agg-properties</span> <span style="color:#666">'</span>(<span style="color:#ba2121">"PROJECT_NAME"</span>))
|
||||
</span></span></code></pre></div><p>Refer also to <a href="#custom-grouping-predicates-1">custom grouping predicates</a>.</p>
|
||||
<h2 id="customization">Customization</h2>
|
||||
<h3 id="node-formatting">Node Formatting</h3>
|
||||
<p>The <code>org-clock-agg-node-format</code> variable determines the formatting of individual tree nodes. This uses a <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Custom-Format-Strings.html">format string</a> that with the following format specifiers avaiable:</p>
|
||||
<ul>
|
||||
<li><code>%t</code>: Node title with the level prefix, truncated to <code>title-width</code> characters (refer to below)</li>
|
||||
<li><code>%c</code>: Name of the grouping function that generated the node</li>
|
||||
<li><code>%z</code>: Time spent in the node, formatted according to <code>org-clock-agg-duration-format</code>.</li>
|
||||
<li><code>%s</code>: Time share of the node against the parent node</li>
|
||||
<li><code>%S</code>: Time share of the node against the top-level node</li>
|
||||
</ul>
|
||||
<p>The default value is:</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>%-%(+ title-width)t %20c %8z
|
||||
</span></span></code></pre></div><p>Where <code>%(+ title-width)</code> is <code>(- (window-width) org-clock-agg-node-title-width-delta)</code>, with the default value of the latter set to <code>40</code>.</p>
|
||||
<p>Thefore, in the default configuration, the node title is truncated to <code>title-width</code> characters, while 40 symbols are allocated for the rest of the header, i.e. " %20c %8z" (30 symbols), along with additional space for folding symbols of <code>outline-minor-mode</code>, line numbers, etc.</p>
|
||||
<h3 id="record-formatting">Record Formatting</h3>
|
||||
<p>When the “Show records” flag is enabled, associated records for each node are displayed. The formatting of these is defined by <code>org-clock-agg-elem-format</code>, which is also a format string with the following specifiers:
|
||||
Customize the formatting of these records through <code>org-clock-agg-elem-format</code>, which also utilizes a format string comprising the following specifiers:</p>
|
||||
<ul>
|
||||
<li><code>%s</code>: Start of the time range</li>
|
||||
<li><code>%e</code>: End of the time range</li>
|
||||
<li><code>%d</code>: Duration of the time range</li>
|
||||
<li><code>%t</code>: Title of the record.</li>
|
||||
</ul>
|
||||
<p>The default value is:</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>- [%s]--[%e] => %d : %t
|
||||
</span></span></code></pre></div><h3 id="custom-grouping-predicates-2">Custom grouping predicates</h3>
|
||||
<p>It’s possible to define custom grouping predicates in addition to the default ones. In fact, it’s probably the only way to get grouping that is tailored to your particular org workflow; I haven’t included my predicates in the package because they aren’t general enough.</p>
|
||||
<p>To create new predicates, use <code>org-clock-agg-defgroupby</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">org-clock-agg-defgroupby</span> <span style="color:#19177c"><name></span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:key1</span> <span style="color:#19177c">value1</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:key2</span> <span style="color:#19177c">value2</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c"><body></span>)
|
||||
</span></span></code></pre></div><p>The available keyword arguments include:</p>
|
||||
<ul>
|
||||
<li><code>:readable-name</code>: Function name for the UI.</li>
|
||||
<li><code>:default-sort</code>: Default sorting function.</li>
|
||||
</ul>
|
||||
<p>The body binds two variables - <code>elem</code> and <code>extra-params</code>, and must return a list of strings.</p>
|
||||
<p>The <code>elem</code> variable is an alist that represents one org-clock record. The keys are as follows:</p>
|
||||
<ul>
|
||||
<li><code>:start</code>: Start time in seconds since the epoch</li>
|
||||
<li><code>:end</code>: End time in seconds since the epoch</li>
|
||||
<li><code>:duration</code>: Duration in seconds</li>
|
||||
<li><code>:headline</code>: Instance of <a href="https://orgmode.org/worg/dev/org-element-api.html">org-element</a> for the headline</li>
|
||||
<li><code>:tags</code>: List of tags</li>
|
||||
<li><code>:file</code>: File name</li>
|
||||
<li><code>:outline-path</code>: titles of all headlines from the root to the current headline</li>
|
||||
<li><code>:properties</code>: List of properties; <code>org-clock-agg-properties</code> sets the selection list</li>
|
||||
<li><code>:category</code>: <a href="https://orgmode.org/manual/Categories.html">Category</a> of the current headline.</li>
|
||||
</ul>
|
||||
<p>The <code>extra-params</code> variable is an alist of global parameters controlling the function’s behavior. Additional parameters can be added by customizing <code>org-clock-agg-extra-params</code>. This alist has keys as parameter names and values as <a href="https://www.gnu.org/software/emacs/manual/html_mono/widget.html">widget.el</a> expressions (applied to <code>widget-create</code>) controlling the UI. Each widget must contain an <code>:extras-key</code> key.</p>
|
||||
<p>For instance:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-clock-agg-extra-params</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>((<span style="color:#ba2121">"Events: Offline / Online"</span> <span style="color:#666">.</span> (<span style="color:#19177c">checkbox</span> <span style="color:#008000">:extras-key</span> <span style="color:#008000">:events-online</span>))))
|
||||
</span></span></code></pre></div><p>This adds a checkbox to the form that appears 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>Events: Offline / Online [ ]
|
||||
</span></span></code></pre></div><p>When checked, <code>extra-params</code> takes the value <code>((:extras-keys . t))</code>.</p>
|
||||
<p>Here’s an example predicate. I store meetings the following way:</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>* Some project
|
||||
</span></span><span style="display:flex;"><span>** Meetings
|
||||
</span></span><span style="display:flex;"><span>*** Some meeting 1
|
||||
</span></span><span style="display:flex;"><span>*** Some meeting 2
|
||||
</span></span><span style="display:flex;"><span>* Another project
|
||||
</span></span><span style="display:flex;"><span>** Meetings
|
||||
</span></span><span style="display:flex;"><span>*** Another meeting 1
|
||||
</span></span><span style="display:flex;"><span>*** Another meeting 2 (offline)
|
||||
</span></span></code></pre></div><p>I want to group these meetings by title, i.e. group all instances of “Some meeting”, “Another meeting”, etc. Optionally I want to group online and offline meetings.</p>
|
||||
<p>This can be done the following way:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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">org-clock-agg-defgroupby</span> <span style="color:#19177c">event</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:readable-name</span> <span style="color:#ba2121">"Event"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:default-sort</span> <span style="color:#19177c">total</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">title</span> (<span style="color:#19177c">org-element-property</span> <span style="color:#008000">:raw-value</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:headline</span> <span style="color:#19177c">elem</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">is-meeting</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">"meeting"</span> (<span style="color:#00f">downcase</span> <span style="color:#19177c">title</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:tags</span> <span style="color:#19177c">elem</span>) <span style="color:#ba2121">"mt"</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">is-offline</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">"offline"</span> (<span style="color:#00f">downcase</span> <span style="color:#19177c">title</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-contains-p</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:tags</span> <span style="color:#19177c">elem</span>) <span style="color:#ba2121">"offline"</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">title-without-stuff</span> (<span style="color:#19177c">string-trim</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:#008000">or</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">group</span> (<span style="color:#00f">+</span> (<span style="color:#008000">or</span> <span style="color:#19177c">digit</span> <span style="color:#ba2121">"."</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"(offline)"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq</span> <span style="color:#ba2121">"["</span> (<span style="color:#00f">+</span> <span style="color:#19177c">alnum</span>) <span style="color:#ba2121">"]"</span>) ))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">""</span> <span style="color:#19177c">title</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">is-meeting</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#ba2121">"Meeting"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">,@</span>(<span style="color:#008000">when</span> (<span style="color:#19177c">alist-get</span> <span style="color:#008000">:events-online</span> <span style="color:#19177c">extra-params</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">is-offline</span> <span style="color:#666">'</span>(<span style="color:#ba2121">"Offline"</span>) <span style="color:#666">'</span>(<span style="color:#ba2121">"Online"</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">,</span><span style="color:#19177c">title-without-stuff</span>))))
|
||||
</span></span></code></pre></div><p>For the following result:</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>* Results
|
||||
</span></span><span style="display:flex;"><span>** Meetings
|
||||
</span></span><span style="display:flex;"><span>*** Some meeting
|
||||
</span></span><span style="display:flex;"><span>*** Another meeting
|
||||
</span></span><span style="display:flex;"><span>** Ungrouped
|
||||
</span></span></code></pre></div><p>This can be coupled with a project predicate to analyze the time spent per project in a particular kind of meeting.</p>
|
||||
|
||||
</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="#installation">Installation</a></li>
|
||||
<li><a href="#usage">Usage</a>
|
||||
<ul>
|
||||
<li><a href="#files">Files</a></li>
|
||||
<li><a href="#date-range">Date Range</a></li>
|
||||
<li><a href="#group-by">Group By</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#customization">Customization</a>
|
||||
<ul>
|
||||
<li><a href="#node-formatting">Node Formatting</a></li>
|
||||
<li><a href="#record-formatting">Record Formatting</a></li>
|
||||
<li><a href="#custom-grouping-predicates-2">Custom grouping predicates</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
309
packages/org-journal-tags/index.html
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>org-journal-tags</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">
|
||||
org-journal-tags
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=org-journal-tags&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">
|
||||
org-journal-tags
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=org-journal-tags&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
|
||||
|
||||
</h1>
|
||||
<figure><a href="https://melpa.org/#/org-journal-tags"><img src="https://melpa.org/packages/org-journal-tags-badge.svg"/></a>
|
||||
</figure>
|
||||
|
||||
<p>A package to make sense of <del>my life</del> <a href="https://github.com/bastibe/org-journal">org-journal</a> records.</p>
|
||||
<p>The package adds the <code>org-journal:</code> link type to Org Mode. When placed in an org-journal file, the link serves as a “tag” that references one or many paragraphs of the journal or the entire section. These tags are aggregated in the database that can be queried in various ways.</p>
|
||||
<h2 id="rationale">Rationale</h2>
|
||||
<p>Journal files, by their very nature, are weakly structured. A single journal note can reference multiple entities (or none) and can itself be composed of multiple parts that have in common only the date and time when they were written. Needless to say, it’s hard to find anything in such records.</p>
|
||||
<p>This package attempts to improve the accessibility of the journal by:</p>
|
||||
<ul>
|
||||
<li>Taking advantage of temporal data, e.g. allowing to query entries in some date range.</li>
|
||||
<li>Allowing to extract (and reference) only certain parts of a particular journal entry.</li>
|
||||
<li>Compensating weak structure by with more advanced query engine.</li>
|
||||
</ul>
|
||||
<p>For instance, when I’m writing down the progress on a job project, I can leave a tag like <code>job.<project-name></code> in the paragraph(s) related to that project. Later, I can query only those paragraphs that are referenced by this particular tag. The query results can then be narrowed, for instance, to include the word “backend”, or extended with some other tag.</p>
|
||||
<p>If no tag matches the subject matter, the journal can be queried with a regular expression, e.g. by searching some regex within a specific time frame. Subsequent searches are also significantly faster than the built-in <code>org-journal</code> search functionality due to the to caching mechanism.</p>
|
||||
<h2 id="installation">Installation</h2>
|
||||
<p>The package is available on MELPA. Install it however you normally install packages, my preferred way is <code>use-package</code> with <code>straight</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-journal-tags</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-journal</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></code></pre></div><h2 id="basic-usage">Basic usage</h2>
|
||||
<h3 id="adding-tags">Adding tags</h3>
|
||||
<p>To add an inline tag, you can manually create a link of the following format:</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>[[org-journal:<tag-name>][<tag-description>]]
|
||||
</span></span></code></pre></div><p>Or run <code>M-x org-journal-tags-insert-tag</code> to insert a tag with a completion interface. The description is not aggregated and thus optional. Also, <code><tag-name></code> cannot contain <code>:</code>.</p>
|
||||
<p>The link will reference the current Org Mode paragraph. If you want to reference more paragraphs, you can set the number of paragraphs like this:</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>[[org-journal:<tag-name>::<number-of-paragraphs>][<tag-description>]]
|
||||
</span></span></code></pre></div><p>Run <code>M-x org-journal-tags-link-get-region-at-point</code> to select the referenced region of the buffer.</p>
|
||||
<p>To add a tag to the entire section, run <code>M-x org-journal-tags-prop-set</code>, which will create or update the <code>Tags</code> property in the property drawer of the current time section. This command features a notmuch-like UI, i.e. completing read for multiple entries, where <code>+<tag></code> adds a tag and <code>-<tag></code> deletes a tag.</p>
|
||||
<p>If you decide to rename a tag, there’s <code>M-x org-journal-tags-refactor</code>.</p>
|
||||
<h3 id="tag-kinds">Tag kinds</h3>
|
||||
<p>Tag kind is a predefined class of tag with some extra functionality. The link format fo such tags 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>[[org-journal:<kind>:<tag-name>][<tag-description>]]
|
||||
</span></span><span style="display:flex;"><span>[[org-journal:<kind>:<tag-name>::<number-of-paragraphs>][<tag-description>]]
|
||||
</span></span></code></pre></div><p>If <code><kind></code> is omitted, a tag is considered “normal”.</p>
|
||||
<p>Running <code>C-u M-x org-journal-tags-insert-tag</code> will first prompt for the tag kind and then for the tag itself from the set of already used tags of that kind.</p>
|
||||
<p>Running <code>C-u C-u M-x org-journal-tags-insert-tag</code> will also first prompt for the tag kind, but then will try to invoke the kind-specific tag selection logic, if such is available. For instance, the <code>contact</code> kind will prompt the <code>org-contacts</code> database.</p>
|
||||
<p>For now, the only available tag kind is <a href="https://repo.or.cz/org-contacts.git">org-contacts</a>.</p>
|
||||
<h3 id="adding-timestamps">Adding timestamps</h3>
|
||||
<p>In addition to tags, the package also aggregates inline timestamps, i.e. timestamps that are left in the text 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>This is a text. This is a text with <2022-04-07 Thu> a timestamp. This is a text again.
|
||||
</span></span></code></pre></div><p>A timestamp will reference just the current paragraph.</p>
|
||||
<p>Other forms of timestamps (<code>SCHEDULED</code>, <code>DEADLINE</code>, etc.) are not supported at the moment, because this functionality is implemented well enough by <a href="https://orgmode.org/manual/Agenda-Views.html">org-agenda</a>.</p>
|
||||
<p>The envisioned use case for this functionality to leave references for the future to be seen at a particular date.</p>
|
||||
<h3 id="database">Database</h3>
|
||||
<p>The package stores tags and references to these tags in a database.</p>
|
||||
<p><code>org-journal-tags-autosync-mode</code> enables synchronizing the database at the moment of saving of the org-journal buffer. You can also run the synchronization manually:</p>
|
||||
<ul>
|
||||
<li><code>M-x org-journal-tags-process-buffer</code> to process the current buffer.</li>
|
||||
<li><code>M-x org-journal-tags-db-sync</code> to sync changed org-journal files in the filesystem.</li>
|
||||
</ul>
|
||||
<p>The same mode enables saving the database on killing Emacs, but you can always run <code>M-x org-journal-tags-db-save</code> manually.</p>
|
||||
<p><code>M-x org-journal-tags-db-unload</code> saves and unloads the database from the memory, <code>M-x org-journal-tags-db-reset</code> creates a new database.</p>
|
||||
<h3 id="status-buffer">Status buffer</h3>
|
||||
<figure><img src="/org-journal-tags-img/status.png"/>
|
||||
</figure>
|
||||
|
||||
<p><em>(I replaced tag names with “X” just for the screenshot)</em></p>
|
||||
<p><code>M-x org-journal-tags-status</code> opens the status buffer with some statistics about the journal and tags. Press <code>?</code> to see the available keybindings.</p>
|
||||
<p>Pressing <code>RET</code> on a tag name in the “All tags” section should open a query buffer set to return all references for this tag.</p>
|
||||
<h3 id="query-constructor">Query constructor</h3>
|
||||
<figure><img src="/org-journal-tags-img/query.png"/>
|
||||
</figure>
|
||||
|
||||
<p>Pressing <code>s</code> in the status buffer or running <code>M-x org-journal-tags-transient-query</code> opens a <a href="https://magit.vc/manual/transient/">transient.el</a> buffer with query settings.</p>
|
||||
<p>The options are as follows:</p>
|
||||
<ul>
|
||||
<li><strong>Include tags</strong> filters the references so that each reference had at least one of these tags.</li>
|
||||
<li><strong>Exclude tags</strong> filters the references so that each reference didn’t have any of these tags.</li>
|
||||
<li><strong>Include children</strong> includes child tags to the previous two lists.</li>
|
||||
<li><strong>Tag location</strong> can filter only section tags on inline tags.</li>
|
||||
<li><strong>Start date</strong> and <strong>End date</strong> filter the references by date.</li>
|
||||
<li><strong>Filter timestamps</strong> filters the references so that they include a timestamp.</li>
|
||||
<li><strong>Timestamp start date</strong> and <strong>Timestamp end date</strong> filter
|
||||
timestamps by their date.</li>
|
||||
<li><strong>Regex</strong> filter the references by a regular expression. It can be a string or <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Rx-Notation.html">rx</a> expression (it just has to start with <code>(rx</code> in this case).</li>
|
||||
<li><strong>Narrow to regex</strong> makes it so that each reference had only paragraphs that have a regex match.</li>
|
||||
<li><strong>Sort</strong> sorts the result in ascending order. It’s descending by default.</li>
|
||||
</ul>
|
||||
<p>Pressing <code>RET</code> or <code>e</code> executes the query. Journal files are cached, so subsequent queries within one session are much faster.</p>
|
||||
<h3 id="query-results">Query results</h3>
|
||||
<figure><img src="/org-journal-tags-img/query-results.png"/>
|
||||
</figure>
|
||||
|
||||
<p>After the query completes, the package opens the results buffer. Press <code>?</code> to see the available keybindings there.</p>
|
||||
<p>Pressing <code>RET</code> opens the corresponding org-journal entry.</p>
|
||||
<p>Pressing <code>s</code> opens the query constructor buffer. If opened from inside the query results, the query constructor has 4 additional options:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Command</th>
|
||||
<th>Set operation</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Union</strong></td>
|
||||
<td>old ∪ new</td>
|
||||
<td>Add records of the new query to the displayed records</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Intersection</strong></td>
|
||||
<td>old ∩ new</td>
|
||||
<td>Leave only those records that are both displayed and in the new query</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Difference from current</strong></td>
|
||||
<td>old \ new</td>
|
||||
<td>Exclude records of the new query from the displayed records</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Difference to current</strong></td>
|
||||
<td>new \ old</td>
|
||||
<td>Exclude displayed records from ones of the new query</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Thus it is possible to make any query that can be described as a sequence of such set operations.</p>
|
||||
<h2 id="advanced-usage">Advanced usage</h2>
|
||||
<h3 id="automatic-tagging">Automatic tagging</h3>
|
||||
<p>org-journal provides a hook to automatically add information to the journal entries.</p>
|
||||
<p>It can be used to automatically assign tags, for instance, based on hostname. Here’s an excerpt from my 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/set-journal-header</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">"host.%s"</span> (<span style="color:#00f">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">'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></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">'org-journal-after-entry-create-hook</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#00f">#'</span><span style="color:#19177c">my/set-journal-header</span>)
|
||||
</span></span></code></pre></div><h3 id="encryption">Encryption</h3>
|
||||
<p>There are two ways how org-journal can be encrypted:</p>
|
||||
<ul>
|
||||
<li>With <a href="https://orgmode.org/manual/Org-Crypt.html">org-crypt</a>, by setting <code>org-journal-enable-encryption</code>.</li>
|
||||
<li>With <a href="https://www.gnu.org/software/emacs/manual/html_node/epa/Encrypting_002fdecrypting-gpg-files.html">epa</a>, by setting <code>org-journal-encrypt-journal</code>.</li>
|
||||
</ul>
|
||||
<p>Both ways are supported by this package (I use the first). The decryption of entries takes some time, but this is alleviated by caching.</p>
|
||||
<p>The cache is stored in the <code>org-journal-tags--files-cache</code> variable, so in principle, someone could come to your computer and inspect the value of this variable (who would ever do that?). If that’s an issue, you can do something like:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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">run-with-idle-timer</span> (<span style="color:#00f">*</span> <span style="color:#666">60</span> <span style="color:#666">15</span>) <span style="color:#800">t</span> <span style="color:#00f">#'</span><span style="color:#19177c">org-journal-tags-cache-reset</span>)
|
||||
</span></span></code></pre></div><p>To clear the cache on Emacs being idle after 15 minutes.</p>
|
||||
<p>Also, as said above, <code>org-journal-tags</code> uses its own database, which is more like persistent cache for tags and references. You can encrypt it as well with <a href="https://www.gnu.org/software/emacs/manual/html_node/epa/Encrypting_002fdecrypting-gpg-files.html">epa</a> by adding <code>.gpg</code> to the <code>org-journal-tags-db-file</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">setq</span> <span style="color:#19177c">org-journal-tags-db-file</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">user-emacs-directory</span> <span style="color:#ba2121">"var/org-journal-tags/index.gpg"</span>))
|
||||
</span></span></code></pre></div><p>The database is also stored in memory in <code>org-journal-tags-db</code> variable, so once again, someone could inspect the value of the variable or just run <code>M-x org-journal-tags-status</code>.</p>
|
||||
<p>To avoid that, you can manually run <code>M-x org-journal-tags-db-unload</code> or add it to <code>run-with-idle-timer</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">run-with-idle-timer</span> (<span style="color:#00f">*</span> <span style="color:#666">60</span> <span style="color:#666">15</span>) <span style="color:#800">t</span> <span style="color:#00f">#'</span><span style="color:#19177c">org-journal-tags-db-unload</span>)
|
||||
</span></span></code></pre></div><p>If you have everything set up correctly, encrypting a file shouldn’t ask for a passphrase, so this function can be run automatically.</p>
|
||||
<h3 id="advanced-querying">Advanced querying</h3>
|
||||
<p>This package provides an API for doing queries from the Lisp code.</p>
|
||||
<p>The central function there <code>org-journal-tags-query</code>, which has an interface corresponding to the flags in the query constructor. Take a look at its docstring for more info.</p>
|
||||
<p>Also, you can use some of the following operations on the set of journal references:</p>
|
||||
<ul>
|
||||
<li><code>org-journal-tags--query-union-refs</code> - union</li>
|
||||
<li><code>org-journal-tags--query-diff-refs</code> - difference</li>
|
||||
<li><code>org-journal-tags--query-intersect-refs</code> - intersection</li>
|
||||
<li><code>org-journal-tags--query-merge-refs</code> - merge intersecting references within one set</li>
|
||||
<li><code>org-journal-tags--query-sort-refs</code> - order references by date</li>
|
||||
<li><code>org-journal-tags--string-extract-refs</code> - collect strings corresponding to references</li>
|
||||
</ul>
|
||||
<h2 id="final-notes">Final notes</h2>
|
||||
<p>This package turned out to be almost as long and complex as <a href="https://github.com/bastibe/org-journal">org-journal</a> itself, and it also introduces some new dependencies. Hence I decided it would be better off as a separate package.</p>
|
||||
<p>Also, I want to list some sources of inspiration. The database logic is heavily inspired by <a href="https://github.com/skeeto/elfeed">elfeed</a>. The UI with <a href="https://www.gnu.org/software/emacs/manual/html_mono/widget.html">Emacs widgets</a> for tags & <code>completing-read-multiple</code> and the tagging system in general is inspired by <a href="https://notmuchmail.org/">notmuch</a>. Finally, <a href="https://github.com/magit/transient">transient.el</a> and <a href="https://magit.vc/manual/magit-section.html">magit-section</a> are the UI packages that made this one possible, or at least much easier to implement.</p>
|
||||
|
||||
</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="#rationale">Rationale</a></li>
|
||||
<li><a href="#installation">Installation</a></li>
|
||||
<li><a href="#basic-usage">Basic usage</a>
|
||||
<ul>
|
||||
<li><a href="#adding-tags">Adding tags</a></li>
|
||||
<li><a href="#tag-kinds">Tag kinds</a></li>
|
||||
<li><a href="#adding-timestamps">Adding timestamps</a></li>
|
||||
<li><a href="#database">Database</a></li>
|
||||
<li><a href="#status-buffer">Status buffer</a></li>
|
||||
<li><a href="#query-constructor">Query constructor</a></li>
|
||||
<li><a href="#query-results">Query results</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#advanced-usage">Advanced usage</a>
|
||||
<ul>
|
||||
<li><a href="#automatic-tagging">Automatic tagging</a></li>
|
||||
<li><a href="#encryption">Encryption</a></li>
|
||||
<li><a href="#advanced-querying">Advanced querying</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#final-notes">Final notes</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
183
packages/password-store-ivy/index.html
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>password-store-ivy</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">
|
||||
password-store-ivy
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=password-store-ivy&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">
|
||||
password-store-ivy
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=password-store-ivy&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
|
||||
|
||||
</h1>
|
||||
<p>A <a href="https://www.passwordstore.org/">pass</a> frontend based on <a href="https://github.com/abo-abo/swiper#ivy">Ivy</a>, made primarily to use with <a href="https://github.com/ch11ng/exwm">EXWM</a> and <a href="https://github.com/tumashu/ivy-posframe">ivy-posframe</a>. Types fields from entries.</p>
|
||||
<p>Also take a look at Nicolas Petton’s <a href="https://github.com/NicolasPetton/pass">pass</a>, <code>password-store-ivy</code> is designed as complementary to the Nicolas’ package.</p>
|
||||
<p>This package is made with Ivy because I need some fine-tuning like actions and turning off sorting in some completions, and Ivy happens to be the completion system I’m using now.</p>
|
||||
<h2 id="installation">Installation</h2>
|
||||
<p>As the package isn’t yet available anywhere but in this repository, you can clone the repository, add it to the load-path and require the package. My preferred way is <code>use-package</code> with <code>straight</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">password-store-ivy</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">"SqrtMinusOne/password-store-ivy"</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">exwm</span>))
|
||||
</span></span></code></pre></div><p>This package types stuff with <code>xdotool</code>, so you need to have that available in your <code>$PATH</code>.</p>
|
||||
<h2 id="usage">Usage</h2>
|
||||
<p>Emacs’ built-in <a href="https://www.gnu.org/software/emacs/manual/html_node/auth/The-Unix-password-store.html">password store</a> integration has to be set up.</p>
|
||||
<p>The only command is <code>M-x password-store-ivy</code>, which invokes Ivy to select an entry from the pass database. Available commands in the selection buffer:</p>
|
||||
<ul>
|
||||
<li><code>M-a</code>. Perform autotype</li>
|
||||
<li><code>M-p</code>. Type password</li>
|
||||
<li><code>M-u</code>. Type username</li>
|
||||
<li><code>M-U</code>. Type url</li>
|
||||
<li><code>M-f</code>. Select a field to type</li>
|
||||
</ul>
|
||||
<h2 id="customization">Customization</h2>
|
||||
<p>There are a few parameters that control delays:</p>
|
||||
<ul>
|
||||
<li><code>password-store-ivy-initial-wait</code> controls the initial delay before starting to type a sequence (in milliseconds)</li>
|
||||
<li><code>password-store-ivy-delay</code> controls the delay between typing characters (in milliseconds)</li>
|
||||
</ul>
|
||||
<p>There is also <code>password-store-ivy-sequences</code> that determines the sequence of actions <code>password-store-ivy</code> performs.</p>
|
||||
<p>It is an alist with the following required keys (corresponding to the basic actions):</p>
|
||||
<ul>
|
||||
<li><code>autotype</code></li>
|
||||
<li><code>password</code></li>
|
||||
<li><code>username</code></li>
|
||||
<li><code>url</code></li>
|
||||
</ul>
|
||||
<p>The values are lists of the following elements:</p>
|
||||
<ul>
|
||||
<li><code>wait</code>. Wait for <code>password-store-ivy-initial-wait</code> milliseconds</li>
|
||||
<li><code>(wait <milliseconds>)</code>. Wait for <code><milliseconds></code>.</li>
|
||||
<li><code>(key <key>)</code>. Type <code><key></code>.</li>
|
||||
<li><code>(field <field>)</code>. Type <code><field></code> of entry.</li>
|
||||
</ul>
|
||||
<p>For example, the starting values:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span><span style="color:#666">'</span>((<span style="color:#19177c">autotype</span> <span style="color:#666">.</span> (<span style="color:#19177c">wait</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#ba2121">"username"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">key</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Tab"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#19177c">secret</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">key</span> <span style="color:#666">.</span> <span style="color:#ba2121">"Return"</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">password</span> <span style="color:#666">.</span> (<span style="color:#19177c">wait</span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#19177c">secret</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">username</span> <span style="color:#666">.</span> (<span style="color:#19177c">wait</span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#ba2121">"username"</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url</span> <span style="color:#666">.</span> (<span style="color:#19177c">wait</span> (<span style="color:#19177c">field</span> <span style="color:#666">.</span> <span style="color:#ba2121">"url"</span>))))
|
||||
</span></span></code></pre></div><p>In addition to the global override, sequences can be overriden per-entry with a field called <code>sequence-<name></code>, where <code><name></code> is a key of <code>password-store-ivy-sequences</code>.</p>
|
||||
<p>For example, here is an override to press <code>Tab</code> twice:</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><pass>
|
||||
</span></span><span style="display:flex;"><span>username: thexcloud@gmail.com
|
||||
</span></span><span style="display:flex;"><span>url: <url>
|
||||
</span></span><span style="display:flex;"><span>sequence-autotype: (wait (field . "username") (key . "Tab") (key . "Tab") (field . secret) (key . "Return"))
|
||||
</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="#installation">Installation</a></li>
|
||||
<li><a href="#usage">Usage</a></li>
|
||||
<li><a href="#customization">Customization</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
216
packages/perspective-exwm/index.html
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>perspective-exwm</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">
|
||||
perspective-exwm
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=perspective-exwm.el&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">
|
||||
perspective-exwm
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=perspective-exwm.el&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
|
||||
|
||||
</h1>
|
||||
<figure><a href="https://melpa.org/#/perspective-exwm"><img src="https://melpa.org/packages/perspective-exwm-badge.svg"/></a>
|
||||
</figure>
|
||||
|
||||
<p>A couple of tricks and fixes to make using <a href="https://github.com/ch11ng/exwm">EXWM</a> and <a href="https://github.com/nex3/perspective-el">perspective.el</a> a better experience.</p>
|
||||
<h2 id="installation">Installation</h2>
|
||||
<p>This package is available on MELPA. Install it however you usually install packages, I use <a href="https://github.com/jwiegley/use-package">use-package</a> and <a href="https://github.com/raxod502/straight.el">straight.el</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">perspective-exwm</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>Or clone the repository, add the package to the <code>load-path</code> and load it with <code>require</code>.</p>
|
||||
<p>The package provides a minor mode, <code>perspective-exwm-mode</code>, which is meant to be loaded before <code>exwm-init</code>. For instance, if you use <code>use-package</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">exwm</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">...</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">perspective-exwm-mode</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">exwm-init</span>))
|
||||
</span></span></code></pre></div><h2 id="usage-and-details">Usage and details</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>perspective-exwm-mode</code><br />
|
||||
The mode does a couple of things:</p>
|
||||
<ul>
|
||||
<li>advises away a bug with half-killing the current perspective when closing a floating window. <del>I haven’t tested this as thoroughly</del> I haven’t run into this issue for nearly a month, so it seems to be fixed. But there’s <code>M-x perspective-exwm-revive-perspectives</code> if the problem arises anyway.</li>
|
||||
<li>fixes a bug with running <code>persp-set-buffer</code> on an EXWM buffer that was moved between workspaces by advising <code>persp-buffer-in-other-p</code>.</li>
|
||||
<li>fixes a bug with <code>persp-set-buffer</code> copying all the perspectives from other workspaces to the current one.</li>
|
||||
<li>adjusts the name of the initial perspective in the new workspace. It tries to get the name from the <code>perspective-exwm-override-initial-name</code> variable and fallbacks to <code>main-<index></code>.</li>
|
||||
</ul>
|
||||
<p>For the last point, I have the following in my 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">setq</span> <span style="color:#19177c">perspective-exwm-override-initial-name</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>((<span style="color:#666">0</span> <span style="color:#666">.</span> <span style="color:#ba2121">"misc"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">1</span> <span style="color:#666">.</span> <span style="color:#ba2121">"core"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">2</span> <span style="color:#666">.</span> <span style="color:#ba2121">"browser"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">3</span> <span style="color:#666">.</span> <span style="color:#ba2121">"comms"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">4</span> <span style="color:#666">.</span> <span style="color:#ba2121">"dev"</span>)))
|
||||
</span></span></code></pre></div><p>Having distinct perspective names between frames also serves a purpose, because otherwise there are issues with multiple perspectives sharing the same scratch buffer.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>M-x perspective-exwm-cycle-exwm-buffers-forward</code>, <code>perspective-exwm-cycle-exwm-buffers-backward</code><br />
|
||||
Cycle EXWM buffers in the current perspective.</p>
|
||||
<figure><img src="/perspective-exwm-img/cycle-buffers.png"/>
|
||||
</figure>
|
||||
|
||||
<p>The buffer highlighted in yellow is the current one, the buffer highlighted in blue is shown in another window of the perspective so it will be omitted from the cycle.</p>
|
||||
<p>Set <code>perspective-exwm-get-exwm-buffer-name</code> to customize the displayed name, by default it’s <code>exwm-class-name</code>.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>M-x perspective-exwm-cycle-all-buffers-forward</code>, <code>perspective-exwm-cycle-exwm-all-backward</code><br />
|
||||
The same as above, but not restricted to EXWM buffers.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>M-x perspective-exwm-switch-perspective</code><br />
|
||||
Select a perspective from the list of all perspectives on all workspaces.</p>
|
||||
<figure><img src="/perspective-exwm-img/switch-perspective.png"/>
|
||||
</figure>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<p><code>M-x perspective-exwm-copy-to-workspace</code><br />
|
||||
Copy the current perspective to another EXWM workspace.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>M-x perspective-exwm-move-to-workspace</code><br />
|
||||
Move the current perspective to another EXWM workspace.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>perspective-exwm-assign-windows</code><br />
|
||||
A handy function to move the current window to a given workspace and/or perspective. Example usage:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-configure-window</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">pcase</span> <span style="color:#19177c">exwm-class-name</span>
|
||||
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">or</span> <span style="color:#ba2121">"Firefox"</span> <span style="color:#ba2121">"Nightly"</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:#666">2</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:persp-name</span> <span style="color:#ba2121">"browser"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"Alacritty"</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">:persp-name</span> <span style="color:#ba2121">"term"</span>))
|
||||
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">or</span> <span style="color:#ba2121">"VK"</span> <span style="color:#ba2121">"Slack"</span> <span style="color:#ba2121">"Discord"</span> <span style="color:#ba2121">"TelegramDesktop"</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:#666">3</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:persp-name</span> <span style="color:#ba2121">"comms"</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">'exwm-manage-finish-hook</span> <span style="color:#00f">#'</span><span style="color:#19177c">my/exwm-configure-window</span>)
|
||||
</span></span></code></pre></div></li>
|
||||
</ul>
|
||||
<h2 id="known-issues">Known issues</h2>
|
||||
<ul>
|
||||
<li><code>perspective-exwm-move-to-workspace</code> kills X windows in the perspective it tries to move. Have no idea how to fix this at the moment.</li>
|
||||
</ul>
|
||||
|
||||
</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="#installation">Installation</a></li>
|
||||
<li><a href="#usage-and-details">Usage and details</a></li>
|
||||
<li><a href="#known-issues">Known issues</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
320
packages/pomm/index.html
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>pomm.el</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">
|
||||
pomm.el
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=pomm.el&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">
|
||||
pomm.el
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=pomm.el&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
|
||||
|
||||
</h1>
|
||||
<figure><a href="https://melpa.org/#/pomm"><img src="https://melpa.org/packages/pomm-badge.svg"/></a>
|
||||
</figure>
|
||||
|
||||
<p>Implementation of <a href="https://en.wikipedia.org/wiki/Pomodoro_Technique">Pomodoro</a> and <a href="https://www.lesswrong.com/posts/RWu8eZqbwgB9zaerh/third-time-a-better-way-to-work">Third Time</a> techniques for Emacs.</p>
|
||||
<figure><img src="/pomm-img/screenshot.png"/>
|
||||
</figure>
|
||||
|
||||
<p>Features:</p>
|
||||
<ul>
|
||||
<li>Managing the timer with the excellent <a href="https://github.com/magit/transient/blob/master/lisp/transient.el">transient.el</a>.</li>
|
||||
<li>Persistent state between Emacs sessions.
|
||||
The timer state isn’t reset if you close Emacs. If necessary, the state file can be synchronized between machines.</li>
|
||||
<li>History.
|
||||
History of the timer can be stored in a CSV file. Eventually, I want to join this with <a href="https://activitywatch.net/">other activity data</a> to see if the state of the timer changes how I use the computer.</li>
|
||||
</ul>
|
||||
<h2 id="installation">Installation</h2>
|
||||
<p>The package is available on MELPA. Install it however you usually install Emacs packages, 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>M-x package-install pomm
|
||||
</span></span></code></pre></div><p>My preferred way is <code>use-package</code> with <code>straight.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">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:#008000">:commands</span> (<span style="color:#19177c">pomm</span> <span style="color:#19177c">pomm-third-time</span>))
|
||||
</span></span></code></pre></div><p>Or you can clone the repository, add the package to the <code>load-path</code> and load it with <code>require</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">require</span> <span style="color:#19177c">'pomm</span>)
|
||||
</span></span></code></pre></div><p>The package requires Emacs 27.1 because the time API of the previous versions is kinda crazy and 27.1 has <code>time-convert</code>.</p>
|
||||
<h2 id="usage">Usage</h2>
|
||||
<h3 id="pomodoro">Pomodoro</h3>
|
||||
<p>Run <code>M-x pomm</code> to open the transient buffer.</p>
|
||||
<p>The listed commands are rather self-descriptive and match the Pomodoro ideology.</p>
|
||||
<p>The timer can have 3 states:</p>
|
||||
<ul>
|
||||
<li><strong>Stopped</strong>. Can be started with “s” or <code>M-x pomm-start</code>. A new iteration of the timer will be started.</li>
|
||||
<li><strong>Paused</strong>. Can be continuted with “s” / <code>M-x pomm-start</code> or stopped competely with “S” / <code>M-x pomm-stop</code>.</li>
|
||||
<li><strong>Running</strong>. Can be paused with “p” / <code>M-x pomm-pause</code> or stopped with “S” / <code>M-x pomm-stop</code>.</li>
|
||||
</ul>
|
||||
<p>The state of the timer can be reset with “R” or <code>M-x pomm-reset</code>.</p>
|
||||
<p>“u” updates the transient buffer. The update is manual because I didn’t figure out how to automate this, and I think this is not <em>really</em> necessary.</p>
|
||||
<p>With “r” or <code>M-x pomm-set-context</code> you can set the current “context”, that is some description of the task you are currently working on. This description will show up in history and in the csv file. Also, <code>M-x pomm-start-with-context</code> will prompt for the context and then start the timer.</p>
|
||||
<h3 id="third-time">Third Time</h3>
|
||||
<p>Run <code>M-x pomm-third-time</code> to open the transient buffer for the Third Time technique.</p>
|
||||
<figure><img src="/pomm-img/screenshot-tt.png"/>
|
||||
</figure>
|
||||
|
||||
<p>Essentially, the techique is designed aroud the formula:</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>Time of break = 1/3 x Time of work.
|
||||
</span></span></code></pre></div><p>I.e. you work as long as you want or need, and then take a break with the maximum duration <code>1/3</code> of the time worked. If you take a shorter break, the remaining break time is saved and added to the next break within the same session. <a href="https://www.lesswrong.com/posts/RWu8eZqbwgB9zaerh/third-time-a-better-way-to-work">Here is a more detailed explanation</a>.</p>
|
||||
<p>The Third Time timer can have 2 states:</p>
|
||||
<ul>
|
||||
<li><strong>Stopped</strong>. Can be started with “s” or <code>M-x pomm-third-time-start</code>.</li>
|
||||
<li><strong>Running</strong>. Can be stopped with “S” or <code>M-x pomm-third-time-stop</code>. This resets the accumulated break time.</li>
|
||||
</ul>
|
||||
<p>Use “b” or <code>M-x pomm-third-time-switch</code> to switch the current period type (work or break). If the break time runs out, the timer automatically switches to work.</p>
|
||||
<h2 id="customization">Customization</h2>
|
||||
<p>Some settings are available in the transient buffer, but you can customize the relevant variables to make them permanent. Check <code>M-x customize-group</code> <code>pomm</code> and <code>M-x customize-group pomm-third-time</code> for more information.</p>
|
||||
<h3 id="alerts">Alerts</h3>
|
||||
<p>The package sends alerts via <code>alert.el</code>. The default style of alert is a plain <code>message</code>, but if you want an actual notification, set <code>alert-default-style</code> accordingly:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">alert-default-style</span> <span style="color:#19177c">'libnotify</span>)
|
||||
</span></span></code></pre></div><h3 id="sounds">Sounds</h3>
|
||||
<p>By default sounds are disabled. Set <code>pomm-audio-enabled</code> to <code>t</code> to toggle them. Set <code>pomm-audio-tick-enabled</code> to <code>t</code> if you want the ticking sound.</p>
|
||||
<p>This functionality needs <code>pomm-audio-player-executable</code> to be set so that the program could be invoked like: <code><executable> /path/to/sound.wav</code>.</p>
|
||||
<p>The package ships with some built-it sounds, which you can replace by customizing the <code>pomm-audio-files</code> variable.</p>
|
||||
<h3 id="modeline">Modeline</h3>
|
||||
<p>If you want the timer to display in the modeline, activate the <code>pomm-mode-line-mode</code> minor mode.</p>
|
||||
<h3 id="polybar-module">Polybar module</h3>
|
||||
<p>If you want to display the Pomodoro status in something like polybar, you can add the following lines to your 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:#19177c">add-hook</span> <span style="color:#19177c">'pomm-on-tick-hook</span> <span style="color:#19177c">'pomm-update-mode-line-string</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">'pomm-on-status-changed-hook</span> <span style="color:#19177c">'pomm-update-mode-line-string</span>)
|
||||
</span></span></code></pre></div><p>Create a script like this:</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> ps -e | grep emacs >> /dev/null; <span style="color:#008000;font-weight:bold">then</span>
|
||||
</span></span><span style="display:flex;"><span> emacsclient --eval <span style="color:#ba2121">"(if (boundp 'pomm-current-mode-line-string) pomm-current-mode-line-string \"\") "</span> | xargs <span style="color:#008000">echo</span> -e
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span></code></pre></div><p>And add a polybar module definition to your polybar config:</p>
|
||||
<pre tabindex="0"><code class="language-conf-windows" data-lang="conf-windows">[module/pomm]
|
||||
type = custom/script
|
||||
exec = /home/pavel/bin/polybar/pomm.sh
|
||||
interval = 1
|
||||
</code></pre><h3 id="state-file-location">State file location</h3>
|
||||
<p>To implement pesistence between Emacs sessions, the package stores its state in the following files:</p>
|
||||
<ul>
|
||||
<li><code>pomm-state-file-location</code>, <code>.emacs.d/pomm</code> by default</li>
|
||||
<li><code>pomm-third-time-state-file-location</code>, <code>/.emacs.d/pomm-third-time</code> by default</li>
|
||||
</ul>
|
||||
<p>Set these paths however like.</p>
|
||||
<h3 id="history">History</h3>
|
||||
<p>If you set the <code>pomm-csv-history-file</code> (and/or <code>pomm-third-time-csv-history-file</code>) variable, the package will log its history in CSV format. Just keep in mind that the parent directory has to exist.</p>
|
||||
<p>The file for the Pomodoro technique has the following columns:</p>
|
||||
<ul>
|
||||
<li><code>timestamp</code></li>
|
||||
<li><code>status</code> (<code>stopped</code>, <code>paused</code> or <code>running</code>, according to the <a href="#usage-1">usage</a> section)</li>
|
||||
<li><code>kind</code> (<code>work</code>, <code>short-break</code>, <code>long-break</code> or <code>nil</code>)</li>
|
||||
<li><code>iteration</code></li>
|
||||
<li><code>context</code></li>
|
||||
</ul>
|
||||
<p>One for the Third Time technique has an extra column called <code>break-time-remaining</code>.</p>
|
||||
<p>A new entry is written after a particular state of the timer comes into being.</p>
|
||||
<p>To customize timestamp, set the <code>pomm-csv-history-file-timestamp-format</code> variable. For example, for traditional <code>YYYY-MM-DD HH:mm: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">pomm-csv-history-file-timestamp-format</span> <span style="color:#ba2121">"%F %T"</span>)
|
||||
</span></span></code></pre></div><p>The format is the same as in <code>format-time-string</code>.</p>
|
||||
<h2 id="alternatives">Alternatives</h2>
|
||||
<p>There is a number of packages with a similar purpose, here is a rough comparison of features:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Package</th>
|
||||
<th>3rd party integrations</th>
|
||||
<th>Control method (1)</th>
|
||||
<th>Persistent history</th>
|
||||
<th>Persistent state</th>
|
||||
<th>Notifications</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="https://github.com/SqrtMinusOne/pomm.el">pomm.el</a></td>
|
||||
<td>-</td>
|
||||
<td>transient.el</td>
|
||||
<td>CSV</td>
|
||||
<td>+</td>
|
||||
<td>alert.el + sounds</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/marcinkoziej/org-pomodoro/tree/master">org-pomodoro</a></td>
|
||||
<td>Org Mode!</td>
|
||||
<td>via Org commands</td>
|
||||
<td>via Org mode</td>
|
||||
<td>-</td>
|
||||
<td>alert.el + sounds</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/TatriX/pomidor/">pomidor</a></td>
|
||||
<td>-</td>
|
||||
<td>self-cooked interactive buffer</td>
|
||||
<td>custom delimited format?</td>
|
||||
<td>+, but saving on-demand</td>
|
||||
<td>alert.el + sounds</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/baudtack/pomodoro.el/">pomodoro.el</a></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>notifications.el + sounds</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/konr/tomatinho/">tomatinho</a></td>
|
||||
<td>-</td>
|
||||
<td>self-cooked interactive buffer</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>message + sounds</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/ferfebles/redtick">redtick</a></td>
|
||||
<td>-</td>
|
||||
<td>mode-line icon</td>
|
||||
<td>+</td>
|
||||
<td>-</td>
|
||||
<td>sounds</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="https://github.com/abo-abo/gtk-pomodoro-indicator">gtk-pomodoro-indicator</a></td>
|
||||
<td>GTK panel</td>
|
||||
<td>CLI</td>
|
||||
<td>-</td>
|
||||
<td>-, but the program is independent from Emacs</td>
|
||||
<td>GTK notifications</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Be sure to check those out if this one doesn’t quite fit your workflow!</p>
|
||||
<p>(1) Means of timer control with exception of Emacs interactive commands</p>
|
||||
<p>Also take a look at <a href="https://github.com/telotortium/org-pomodoro-third-time">org-pomodoro-third-time</a>, which adapts <code>org-pomodoro</code> for the Third Time technique.</p>
|
||||
<h2 id="p-dot-s-dot">P.S.</h2>
|
||||
<p>The package name is not an abbreviation. I just hope it doesn’t mean something horrible in some language I don’t know.</p>
|
||||
<p>The sounds are made by Mike Koening under <a href="https://creativecommons.org/licenses/by/3.0/legalcode">CC BY 3.0</a>.</p>
|
||||
|
||||
</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="#installation">Installation</a></li>
|
||||
<li><a href="#usage">Usage</a>
|
||||
<ul>
|
||||
<li><a href="#pomodoro">Pomodoro</a></li>
|
||||
<li><a href="#third-time">Third Time</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#customization">Customization</a>
|
||||
<ul>
|
||||
<li><a href="#alerts">Alerts</a></li>
|
||||
<li><a href="#sounds">Sounds</a></li>
|
||||
<li><a href="#modeline">Modeline</a></li>
|
||||
<li><a href="#polybar-module">Polybar module</a></li>
|
||||
<li><a href="#state-file-location">State file location</a></li>
|
||||
<li><a href="#history">History</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#alternatives">Alternatives</a></li>
|
||||
<li><a href="#p-dot-s-dot">P.S.</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
271
packages/reverso/index.html
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang=""><head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<title>reverso.el</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">
|
||||
reverso.el
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=reverso.el&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">
|
||||
reverso.el
|
||||
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=SqrtMinusOne&repo=reverso.el&type=star&count=true" frameborder="0" scrolling="0" width="150" height="20" title="GitHub"></iframe>
|
||||
|
||||
</h1>
|
||||
<p>Emacs client for <a href="https://www.reverso.net/">Reverso</a>. The implemented features are:</p>
|
||||
<ul>
|
||||
<li><a href="https://www.reverso.net/text-translation">Translation</a></li>
|
||||
<li><a href="https://context.reverso.net/translation/">Context</a> (AKA bilingual concordances)</li>
|
||||
<li><a href="https://www.reverso.net/spell-checker/english-spelling-grammar/">Grammar check</a></li>
|
||||
<li><a href="https://synonyms.reverso.net/synonym/">Synonyms search</a></li>
|
||||
</ul>
|
||||
<h2 id="installation">Installation</h2>
|
||||
<p>The package isn’t yet available anywhere but in this repository. My preferred way for such cases is <a href="https://github.com/jwiegley/use-package">use-package</a> and <a href="https://github.com/radian-software/straight.el">straight.el</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">"SqrtMinusOne/reverso.el"</span>))
|
||||
</span></span></code></pre></div><p>Or clone the repository, add it to the <code>load-path</code> and <code>require</code> the package.</p>
|
||||
<h2 id="usage">Usage</h2>
|
||||
<p>There’s a single entrypoint for all implemented functions: <code>M-x reverso</code>. The UI is implemented using the excellent <a href="https://github.com/magit/transient/">transient.el</a>.</p>
|
||||
<h3 id="input-handling">Input Handling</h3>
|
||||
<p>All commands handle input as follows:</p>
|
||||
<p>By default, the input string is empty. If a command is launched with a region selected, use the string of that region. If launched with the prefix argument (<code>C-u</code>), use the entire buffer.</p>
|
||||
<p>Results are displayed in <code>reverso-result-mode</code> buffers. When launched within that buffer, the command uses the input string specific to the buffer. If launched with <code>C-u</code>, it uses the output string from that buffer (if available).</p>
|
||||
<h3 id="translation">Translation</h3>
|
||||
<p>Use <code>M-x reverso t</code> or <code>M-x reverso-translate</code> to invoke the translation transient.</p>
|
||||
<figure><img src="/reverso-img/translation-transient.png"/>
|
||||
</figure>
|
||||
|
||||
<p>The “Source language” and “Target language” parameters are self-explanatory. Note that not every language is compatible with every other language in the general case. “Swap languages” attempts to swap them.</p>
|
||||
<p>Enabling “Brief translation output” will display only the translated version of the string in the output buffer.</p>
|
||||
<figure><img src="/reverso-img/translation-res.png"/>
|
||||
</figure>
|
||||
|
||||
<p>Otherwise, the result buffer may contain the following sections:</p>
|
||||
<ul>
|
||||
<li><strong>Source text</strong> and <strong>Translation</strong></li>
|
||||
<li><strong>Corrected text</strong>, if available</li>
|
||||
<li><strong>Context results</strong>, if available</li>
|
||||
</ul>
|
||||
<p>Context results typically appear for short strings, as seen in the example from the screenshot.</p>
|
||||
<h3 id="context">Context</h3>
|
||||
<p>Use <code>M-x reverso c</code> or <code>M-x reverso-context</code> to invoke context search (or <a href="https://en.wikipedia.org/w/index.php?title=Online_bilingual_concordance&redirect=no">bilingual concordances</a>, essentially a Rosetta stone generator).</p>
|
||||
<p>The input/output UI resembles that of the translation command.</p>
|
||||
<p>Interestingly, direct context search often yields different results than the “Context results” section of the translation command. Hence, checking both might provide more comprehensive data.</p>
|
||||
<h3 id="synonyms">Synonyms</h3>
|
||||
<p>Use <code>M-x reverso s</code> or <code>M-x reverso-synonyms</code> to invoke the synonyms search.</p>
|
||||
<figure><img src="/reverso-img/synonyms-transient.png"/>
|
||||
</figure>
|
||||
|
||||
<figure><img src="/reverso-img/synonyms-res.png"/>
|
||||
</figure>
|
||||
|
||||
<p>If necessary, results are segmented by parts of speech.</p>
|
||||
<p>Each part of speech section contains up to three subsections:</p>
|
||||
<ul>
|
||||
<li>Synonyms</li>
|
||||
<li>Examples</li>
|
||||
<li>Antonyms</li>
|
||||
</ul>
|
||||
<h3 id="grammar-check">Grammar check</h3>
|
||||
<p>Use <code>M-x reverso g</code> or <code>M-x reverso-grammar</code> to invoke the grammar check.</p>
|
||||
<figure><img src="/reverso-img/grammar-transient.png"/>
|
||||
</figure>
|
||||
|
||||
<p>Currently, only English, French, Spanish, and Italian languages are available.</p>
|
||||
<figure><img src="/reverso-img/grammar-res.png"/>
|
||||
</figure>
|
||||
|
||||
<p>The results may contain the following sections:</p>
|
||||
<ul>
|
||||
<li><strong>Source text</strong>, highlighting errors with <code>reverso-error-face</code></li>
|
||||
<li><strong>Corrected text</strong></li>
|
||||
<li><strong>Corrections</strong></li>
|
||||
</ul>
|
||||
<h3 id="grammar-check-in-buffer">Grammar check in buffer</h3>
|
||||
<p>It can be convenient to apply the grammar check directly to the current buffer without displaying results in another buffer. Use <code>M-x reverso b</code> or <code>M-x reverso-grammar-buffer</code> for this.</p>
|
||||
<figure><img src="/reverso-img/grammar-buffer-transient.png"/>
|
||||
</figure>
|
||||
|
||||
<p>Running <code>e</code> there (or <code>M-x reverso-check-buffer</code>) utilizes the current buffer as input and highlights any found errors using overlays. If a region is selected, the check is confined to that region.</p>
|
||||
<p>There are a couple of caveats there. First, the service considers each linebreak as a new line, which is incompatible with <a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Filling.html">filling text</a>, i.e. breaking it into lines of a specified width. The “Remove linebreaks” option (<code>l</code>) is a workaround for this.</p>
|
||||
<p>Secondly, the service usually freaks out with special syntax, for instance, Org Mode links.</p>
|
||||
<p>The third issue partly follows from the second one, as the service often finds “errors” within hidden parts of Org links. Either skip these errors or execute <code>M-x org-toggle-link-display</code> in Org files beforehand.</p>
|
||||
<p>Lastly (and this applies to all other methods as well), the API usually restricts input size. If the service returns an error, try running the command on a smaller region of the buffer.</p>
|
||||
<figure><img src="/reverso-img/grammar-buffer-res.png"/>
|
||||
</figure>
|
||||
|
||||
<p>When the cursor is placed on an error, the “Information” section provides details.</p>
|
||||
<p>“Fix error” (<code>f</code> or <code>M-x reverso-check-fix-at-point</code>) opens a completion interface with potential fixes. “Ignore error” (<code>i</code> or <code>M-x reverso-check-ignore-error</code>) simply removes the overlay and moves to the next error.</p>
|
||||
<p>“Previous error” (<code>p</code> or <code>M-x reverso-check-prev-error</code>), “Next error” (<code>n</code> or <code>M-x reverso-check-next-error</code>), “First error” (<code>P</code> or <code>M-x reverso-check-first-error</code>) and “Last error” (<code>L</code> or <code>M-x reverso-check-last-error</code>) serve to navigate the error list.</p>
|
||||
<p>“Clear” (<code>c</code> or <code>M-x reverso-clear</code>) removes error overlays. If a region is selected, it removes overlays only in that region; otherwise, it removes them from the entire buffer.</p>
|
||||
<h3 id="history">History</h3>
|
||||
<p>Enable <code>reverso-history-mode</code> to keep history:</p>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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">reverso-history-mode</span>)
|
||||
</span></span></code></pre></div><p>I haven’t implemented persistence yet, but I might in the future.</p>
|
||||
<p>After enabling the minor mode, <code>M-x reverso-history</code> or <code>M-x reverso h</code> will display recent commans. <code>RET</code> on shows the results of each command.</p>
|
||||
<h2 id="caveats">Caveats</h2>
|
||||
<p>Before proceeding further, here are some general caveats to be aware of.</p>
|
||||
<p>Firstly, the package uses a reverse-engineered API, so all the typical consequences apply, such as sudden irreparable breakages. Although I’ve been using it for over a year, so… maybe not.</p>
|
||||
<p>Secondly, the limit on input size has been mentioned. The obvious is executing commands on a smaller region.</p>
|
||||
<p>Thirdly, there have been reports that Reverso dispatches <strong>IP bans</strong> to particularly enthusiastic users, so be cautious if you’re sending lots of automated queries. This is also why I didn’t implement running one command for multiple consecutive regions.</p>
|
||||
<p>Lastly, exercise caution with the content sent to the service. Avoid inadvertently sharing confidential information (like passwords) or anything that could be used against you in other ways. While the service claims to be <a href="https://www.reverso.net/privacy.aspx?lang=EN">GDPR-compliant</a>, we can’t actually check that.</p>
|
||||
<h2 id="customization">Customization</h2>
|
||||
<p>Run <code>M-x customize-group reverso</code> to view the available parameters. Here are a few.</p>
|
||||
<p>If you don’t need all 17 languages, customize the <code>reverso-languages</code> variable to narrow down 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">setq</span> <span style="color:#19177c">reverso-languages</span> <span style="color:#666">'</span>(<span style="color:#19177c">english</span> <span style="color:#19177c">german</span> <span style="color:#19177c">russian</span>))
|
||||
</span></span></code></pre></div><p>If the length of <code>reverso-languages</code> exceeds <code>reverso-language-completing-read-threshold</code>, switching a language in transient buffers will invoke <code>completing-read</code> (minibuffer completion). Otherwise, it will simply switch to the next language available.</p>
|
||||
<p><code>reverso-max-display-lines-in-input</code> controls the maximum number of lines displayed in the input section of a transient buffer.</p>
|
||||
<p>The available faces:</p>
|
||||
<ul>
|
||||
<li><code>reverso-highlight-face</code></li>
|
||||
<li><code>reverso-error-face</code></li>
|
||||
<li><code>reverso-heading-face</code></li>
|
||||
<li><code>reverso-keyword-face</code></li>
|
||||
<li><code>reverso-definition-face</code></li>
|
||||
</ul>
|
||||
<p>are inherited from the faces of <code>transient.el</code> and <code>basic-faces</code> to look nice.</p>
|
||||
<h2 id="elisp-api">Elisp API</h2>
|
||||
<p>In Emacs Lisp, there are four primary functions that interact with the Reverso API:</p>
|
||||
<ul>
|
||||
<li><code>reverso--translate</code></li>
|
||||
<li><code>reverso--get-context</code></li>
|
||||
<li><code>reverso--get-grammar</code></li>
|
||||
<li><code>reverso--get-context</code></li>
|
||||
</ul>
|
||||
<p>Refer to the docstrings for more detailed information.</p>
|
||||
<p>Each function is asynchronous, and the results are retrieved via a callback.</p>
|
||||
<p>As Reverso sometimes modifies its available languages and compatibility matrix, so if you change that, execute <code>reverso-verify-settings</code> to check for potential errors.</p>
|
||||
<h2 id="alternatives-and-observations">Alternatives and Observations</h2>
|
||||
<p>A widely recognized translation service is <a href="https://translate.google.com/">Google Translate</a>, so of course, there’s an <a href="https://github.com/atykhonov/google-translate">Emacs client</a> for it.</p>
|
||||
<p>The <a href="https://github.com/emacs-grammarly">emacs-grammarly</a> package series provides the Elisp API for <a href="https://www.grammarly.com/">Grammarly</a> (a grammar checking service) along with multiple frontends. Unlike Reverso, Grammarly has an official API (so you don’t risk getting an IP ban), and it allows a much larger input size.</p>
|
||||
<p>Additionally, Grammarly is less bothered by Org and Markdown syntax, although it struggles with inline code blocks. It seems to do work generally better than Reverso, but it also generates a lot of false positives. For instance, it finds a lot of issues in <a href="https://www.economist.com/">The Economist</a> articles, which, I think, have beautiful English.</p>
|
||||
<p>Another notable grammar-checking solution is <a href="https://languagetool.org/">LanguageTool</a>, which can be <a href="https://dev.languagetool.org/http-server">run offline</a> and used with its <a href="https://github.com/mhayashi1120/Emacs-langtool">Emacs package</a>. This tool offers the advantage of unlimited usage and doesn’t transmit your data to a third-party server you can’t control. But it still doesn’t like markup syntaxes.</p>
|
||||
<p>Also, I’ve been pretty happy with <a href="https://github.com/valentjn/ltex-ls">LTeX LS</a>, which is a LanguageTool-based language server explicitly designed to support markup formats like Org, Markdown, LaTeX, among others.</p>
|
||||
<p>The <a href="https://www.npmjs.com/package/reverso-api">reverso-api</a> npm package implements the same commands in JavaScript. It also provided invaluable information for creating this package.</p>
|
||||
|
||||
</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="#installation">Installation</a></li>
|
||||
<li><a href="#usage">Usage</a>
|
||||
<ul>
|
||||
<li><a href="#input-handling">Input Handling</a></li>
|
||||
<li><a href="#translation">Translation</a></li>
|
||||
<li><a href="#context">Context</a></li>
|
||||
<li><a href="#synonyms">Synonyms</a></li>
|
||||
<li><a href="#grammar-check">Grammar check</a></li>
|
||||
<li><a href="#grammar-check-in-buffer">Grammar check in buffer</a></li>
|
||||
<li><a href="#history">History</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#caveats">Caveats</a></li>
|
||||
<li><a href="#customization">Customization</a></li>
|
||||
<li><a href="#elisp-api">Elisp API</a></li>
|
||||
<li><a href="#alternatives-and-observations">Alternatives and Observations</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<a id="unhide-all-button" class="hidden"><Expand></a>
|
||||
<a id="hide-all-button" class="hidden"><Collapse></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, 2023"><small>Pavel Korytov, 2023</small></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
perspective-exwm-img/cycle-buffers.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
perspective-exwm-img/switch-perspective.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
pomm-img/screenshot-tt.png
Normal file
|
After Width: | Height: | Size: 445 KiB |
BIN
pomm-img/screenshot.png
Normal file
|
After Width: | Height: | Size: 273 KiB |
BIN
reverso-img/grammar-buffer-res.png
Normal file
|
After Width: | Height: | Size: 454 KiB |
BIN
reverso-img/grammar-buffer-transient.png
Normal file
|
After Width: | Height: | Size: 143 KiB |
BIN
reverso-img/grammar-res.png
Normal file
|
After Width: | Height: | Size: 190 KiB |
BIN
reverso-img/grammar-transient.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
reverso-img/synonyms-res.png
Normal file
|
After Width: | Height: | Size: 210 KiB |
BIN
reverso-img/synonyms-transient.png
Normal file
|
After Width: | Height: | Size: 129 KiB |
BIN
reverso-img/translation-res.png
Normal file
|
After Width: | Height: | Size: 258 KiB |
BIN
reverso-img/translation-transient.png
Normal file
|
After Width: | Height: | Size: 219 KiB |
62
sitemap.xml
|
|
@ -2,14 +2,20 @@
|
|||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||
xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
||||
<url>
|
||||
<loc>https://sqrtminusone.xyz/</loc>
|
||||
<lastmod>2023-12-17T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/packages/org-clock-agg/</loc>
|
||||
<lastmod>2023-12-17T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/packages/</loc>
|
||||
<lastmod>2023-12-17T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/posts/2023-11-11-index/</loc>
|
||||
<lastmod>2023-11-11T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/tags/emacs/</loc>
|
||||
<lastmod>2023-11-11T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/</loc>
|
||||
<lastmod>2023-11-11T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/tags/orgmode/</loc>
|
||||
<lastmod>2023-11-11T00:00:00+00:00</lastmod>
|
||||
|
|
@ -19,6 +25,12 @@
|
|||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/tags/</loc>
|
||||
<lastmod>2023-11-11T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/packages/biome/</loc>
|
||||
<lastmod>2023-07-22T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/packages/micromamba/</loc>
|
||||
<lastmod>2023-06-20T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/posts/2023-04-13-emacs/</loc>
|
||||
<lastmod>2023-04-13T00:00:00+00:00</lastmod>
|
||||
|
|
@ -31,21 +43,48 @@
|
|||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/posts/2022-09-16-vosk/</loc>
|
||||
<lastmod>2022-09-16T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/packages/reverso/</loc>
|
||||
<lastmod>2022-08-28T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/packages/elfeed-sync/</loc>
|
||||
<lastmod>2022-05-29T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/posts/2022-05-09-pdf/</loc>
|
||||
<lastmod>2022-05-10T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/tags/org-mode/</loc>
|
||||
<lastmod>2022-05-10T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/packages/avy-dired/</loc>
|
||||
<lastmod>2022-04-01T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/packages/elfeed-summary/</loc>
|
||||
<lastmod>2022-03-26T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/packages/password-store-ivy/</loc>
|
||||
<lastmod>2022-02-13T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/posts/2022-02-12-literate/</loc>
|
||||
<lastmod>2022-02-12T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/packages/org-journal-tags/</loc>
|
||||
<lastmod>2022-02-06T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/tags/exwm/</loc>
|
||||
<lastmod>2022-01-03T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/posts/2022-01-03-exwm/</loc>
|
||||
<lastmod>2022-01-03T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/packages/exwm-modeline/</loc>
|
||||
<lastmod>2021-12-22T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/packages/perspective-exwm/</loc>
|
||||
<lastmod>2021-12-01T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/packages/pomm/</loc>
|
||||
<lastmod>2021-11-05T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/</loc>
|
||||
<lastmod>2021-10-06T00:00:00+00:00</lastmod>
|
||||
|
|
@ -58,6 +97,9 @@
|
|||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/posts/2021-09-07-emms/</loc>
|
||||
<lastmod>2021-09-08T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/packages/lyrics-fetcher/</loc>
|
||||
<lastmod>2021-08-14T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/tags/org/</loc>
|
||||
<lastmod>2021-05-01T00:00:00+00:00</lastmod>
|
||||
|
|
@ -75,6 +117,20 @@
|
|||
<lastmod>2021-02-01T00:00:00+00:00</lastmod>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/categories/</loc>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/configs/</loc>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/configs/console/</loc>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/configs/desktop/</loc>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/configs/emacs/</loc>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/configs/guix/</loc>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/configs/mail/</loc>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/configs/readme/</loc>
|
||||
</url><url>
|
||||
<loc>https://sqrtminusone.xyz/emacs-packages/</loc>
|
||||
</url>
|
||||
|
|
|
|||