deploy: c984faad58
|
|
@ -59,6 +59,7 @@
|
|||
<hr>
|
||||
<div id="content">
|
||||
<div class="container">
|
||||
<h1>Guix</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>
|
||||
|
|
@ -121,79 +122,79 @@
|
|||
</ul>
|
||||
<h3 id="activate-profiles">Activate profiles</h3>
|
||||
<p>A script to activate guix profiles. Usage:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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] ...
|
||||
<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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>GREEN<span style="color:#f92672">=</span><span style="color:#e6db74">'\033[1;32m'</span>
|
||||
</span></span><span style="display:flex;"><span>RED<span style="color:#f92672">=</span><span style="color:#e6db74">'\033[1;30m'</span>
|
||||
</span></span><span style="display:flex;"><span>NC<span style="color:#f92672">=</span><span style="color:#e6db74">'\033[0m'</span>
|
||||
</span></span><span style="display:flex;"><span>GUIX_EXTRA_PROFILES<span style="color:#f92672">=</span>$HOME/.guix-extra-profiles
|
||||
<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>profiles<span style="color:#f92672">=</span>$*
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> $# -eq <span style="color:#ae81ff">0</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
|
||||
</span></span><span style="display:flex;"><span> profiles<span style="color:#f92672">=</span><span style="color:#e6db74">"</span>$HOME<span style="color:#e6db74">/.config/guix/manifests/*.scm"</span>;
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</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:#66d9ef">for</span> profile in $profiles; <span style="color:#66d9ef">do</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e"># Remove the path and file extension, if any</span>
|
||||
</span></span><span style="display:flex;"><span> profileName<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>basename $profile<span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span> profileName<span style="color:#f92672">=</span><span style="color:#e6db74">"</span><span style="color:#e6db74">${</span>profileName%.*<span style="color:#e6db74">}</span><span style="color:#e6db74">"</span>
|
||||
</span></span><span style="display:flex;"><span> profilePath<span style="color:#f92672">=</span><span style="color:#e6db74">"</span>$GUIX_EXTRA_PROFILES<span style="color:#e6db74">/</span>$profileName<span style="color:#e6db74">"</span>
|
||||
</span></span><span style="display:flex;"><span> manifestPath<span style="color:#f92672">=</span>$HOME/.config/guix/manifests/$profileName.scm
|
||||
</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:#66d9ef">if</span> <span style="color:#f92672">[</span> -f $manifestPath <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
|
||||
</span></span><span style="display:flex;"><span> echo
|
||||
</span></span><span style="display:flex;"><span> echo -e <span style="color:#e6db74">"</span><span style="color:#e6db74">${</span>GREEN<span style="color:#e6db74">}</span><span style="color:#e6db74">Activating profile:"</span> $manifestPath <span style="color:#e6db74">"</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">"</span>
|
||||
</span></span><span style="display:flex;"><span> echo
|
||||
</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 $profilePath
|
||||
</span></span><span style="display:flex;"><span> guix package --manifest<span style="color:#f92672">=</span>$manifestPath --profile<span style="color:#f92672">=</span><span style="color:#e6db74">"</span>$profilePath<span style="color:#e6db74">/</span>$profileName<span style="color:#e6db74">"</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:#75715e"># Source the new profile</span>
|
||||
</span></span><span style="display:flex;"><span> GUIX_PROFILE<span style="color:#f92672">=</span><span style="color:#e6db74">"</span>$profilePath<span style="color:#e6db74">/</span>$profileName<span style="color:#e6db74">"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -f $GUIX_PROFILE/etc/profile <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
|
||||
</span></span><span style="display:flex;"><span> . <span style="color:#e6db74">"</span>$GUIX_PROFILE<span style="color:#e6db74">"</span>/etc/profile
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">else</span>
|
||||
</span></span><span style="display:flex;"><span> echo -e <span style="color:#e6db74">"</span><span style="color:#e6db74">${</span>RED<span style="color:#e6db74">}</span><span style="color:#e6db74">Couldn't find profile:"</span> $GUIX_PROFILE/etc/profile <span style="color:#e6db74">"</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fi</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">else</span>
|
||||
</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">"No profile found at path"</span> $profilePath
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fi</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</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="color:#f8f8f2;background-color:#272822;-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] ...
|
||||
<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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>GREEN<span style="color:#f92672">=</span><span style="color:#e6db74">'\033[1;32m'</span>
|
||||
</span></span><span style="display:flex;"><span>NC<span style="color:#f92672">=</span><span style="color:#e6db74">'\033[0m'</span>
|
||||
</span></span><span style="display:flex;"><span>GUIX_EXTRA_PROFILES<span style="color:#f92672">=</span>$HOME/.guix-extra-profiles
|
||||
<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>profiles<span style="color:#f92672">=</span>$*
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> $# -eq <span style="color:#ae81ff">0</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
|
||||
</span></span><span style="display:flex;"><span> profiles<span style="color:#f92672">=</span><span style="color:#e6db74">"</span>$GUIX_EXTRA_PROFILES<span style="color:#e6db74">/*"</span>;
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</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:#66d9ef">for</span> profile in $profiles; <span style="color:#66d9ef">do</span>
|
||||
</span></span><span style="display:flex;"><span> profileName<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>basename $profile<span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span> profilePath<span style="color:#f92672">=</span>$GUIX_EXTRA_PROFILES/$profileName
|
||||
</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> echo
|
||||
</span></span><span style="display:flex;"><span> echo -e <span style="color:#e6db74">"</span><span style="color:#e6db74">${</span>GREEN<span style="color:#e6db74">}</span><span style="color:#e6db74">Updating profile:"</span> $profilePath <span style="color:#e6db74">"</span><span style="color:#e6db74">${</span>NC<span style="color:#e6db74">}</span><span style="color:#e6db74">"</span>
|
||||
</span></span><span style="display:flex;"><span> echo
|
||||
</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:#f92672">=</span><span style="color:#e6db74">"</span>$profilePath<span style="color:#e6db74">/</span>$profileName<span style="color:#e6db74">"</span> --manifest<span style="color:#f92672">=</span><span style="color:#e6db74">"</span>$HOME<span style="color:#e6db74">/.config/guix/manifests/</span>$profileName<span style="color:#e6db74">.scm"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>GUIX_EXTRA_PROFILES<span style="color:#f92672">=</span>$HOME/.guix-extra-profiles
|
||||
<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>profileName<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>basename $1<span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span>profileName<span style="color:#f92672">=</span><span style="color:#e6db74">"</span><span style="color:#e6db74">${</span>profileName%.*<span style="color:#e6db74">}</span><span style="color:#e6db74">"</span>
|
||||
</span></span><span style="display:flex;"><span>profilePath<span style="color:#f92672">=</span><span style="color:#e6db74">"</span>$GUIX_EXTRA_PROFILES<span style="color:#e6db74">/</span>$profileName<span style="color:#e6db74">"</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:#66d9ef">if</span> <span style="color:#f92672">[</span> -d $profilePath <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
|
||||
</span></span><span style="display:flex;"><span> guix package --profile<span style="color:#f92672">=</span><span style="color:#e6db74">"</span>$profilePath<span style="color:#e6db74">/</span>$profileName<span style="color:#e6db74">"</span> <span style="color:#e6db74">${</span>@:2<span style="color:#e6db74">}</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
|
||||
</span></span><span style="display:flex;"><span> echo -e <span style="color:#e6db74">"No profile found at path: "</span> $profilePath
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</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>
|
||||
|
|
@ -203,38 +204,38 @@
|
|||
<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="color:#f8f8f2;background-color:#272822;-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:#a6e22e">cons*</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">channel</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">name</span> <span style="color:#e6db74">'channel-q</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">url</span> <span style="color:#e6db74">"file:///home/pavel/Code/channel-q"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">channel</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">name</span> <span style="color:#e6db74">'flat</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">url</span> <span style="color:#e6db74">"https://github.com/flatwhatson/guix-channel.git"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">introduction</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">make-channel-introduction</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"33f86a4b48205c0dc19d7c036c85393f0766f806"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">openpgp-fingerprint</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"736A C00E 1254 378B A982 7AF6 9DBE 8265 81B6 4490"</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">channel</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">name</span> <span style="color:#e6db74">'nonguix</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">url</span> <span style="color:#e6db74">"https://gitlab.com/nonguix/nonguix"</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; (commit "d54973e47b89fe5772a5b6e2d0c0b86acb089e27")</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">introduction</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">make-channel-introduction</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"897c1a470da759236cc11798f4e0a5f7d4d59fbc"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">openpgp-fingerprint</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"2A39 3FFF 68F4 EF7A 3D29 12AF 6F51 20A0 22FB B2D5"</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">channel</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; What can possibly go wrong, huh</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">name</span> <span style="color:#e6db74">'guix-gaming-games</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">url</span> <span style="color:#e6db74">"https://gitlab.com/guix-gaming-channels/games.git"</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; Enable signature verification:</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">introduction</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">make-channel-introduction</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"c23d64f1b8cc086659f8781b27ab6c7314c5cca5"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">openpgp-fingerprint</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"50F3 3E2E 5B0C 3D90 0424 ABE8 9BDC F497 A4BB CC7F"</span>))))
|
||||
</span></span><span style="display:flex;"><span> %default-channels)
|
||||
<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/Code/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>
|
||||
|
|
@ -242,84 +243,84 @@
|
|||
<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="color:#f8f8f2;background-color:#272822;-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
|
||||
<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="color:#f8f8f2;background-color:#272822;-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:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> system nss))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages bash))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> ((<span style="color:#a6e22e">gnu</span> packages base) <span style="color:#f92672">#</span>:select (<span style="color:#a6e22e">coreutils</span> glibc)))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages certs))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages version-control))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages vim))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages gnome))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages xorg))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages wm))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> packages openbox))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> services docker))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> services cups))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">gnu</span> services virtualization))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">srfi</span> srfi-1))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">guix</span> channels))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">guix</span> inferior))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">nongnu</span> packages linux))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-modules</span> (<span style="color:#a6e22e">nongnu</span> system linux-initrd))
|
||||
<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:#a6e22e">use-service-modules</span> desktop networking ssh xorg nix)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">use-package-modules</span> ssh)
|
||||
</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="color:#f8f8f2;background-color:#272822;-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:#a6e22e">kernel</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">let*</span>
|
||||
</span></span><span style="display:flex;"><span> ((<span style="color:#a6e22e">channels</span>
|
||||
</span></span><span style="display:flex;"><span> (list (<span style="color:#a6e22e">channel</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">name</span> <span style="color:#e6db74">'nonguix</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">url</span> <span style="color:#e6db74">"https://gitlab.com/nonguix/nonguix"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">commit</span> <span style="color:#e6db74">"393b8e0405f44835c498d7735a8ae9ff4682b07f"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">channel</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">name</span> <span style="color:#e6db74">'guix</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">url</span> <span style="color:#e6db74">"https://git.savannah.gnu.org/git/guix.git"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">commit</span> <span style="color:#e6db74">"4c812db049d5c9f2c438748e180f9486ad221b0a"</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">inferior</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">inferior-for-channels</span> channels)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">first</span> (<span style="color:#a6e22e">lookup-inferior-packages</span> inferior <span style="color:#e6db74">"linux"</span> <span style="color:#e6db74">"5.15.12"</span>))))
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; (kernel linux)</span>
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">initrd</span> microcode-initrd)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">firmware</span> (list linux-firmware))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">locale</span> <span style="color:#e6db74">"en_US.utf8"</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">timezone</span> <span style="color:#e6db74">"Europe/Moscow"</span>)
|
||||
<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">"393b8e0405f44835c498d7735a8ae9ff4682b07f"</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">"4c812db049d5c9f2c438748e180f9486ad221b0a"</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">"5.15.12"</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="color:#f8f8f2;background-color:#272822;-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:#a6e22e">keyboard-layout</span> (<span style="color:#a6e22e">keyboard-layout</span> <span style="color:#e6db74">"us,ru"</span> <span style="color:#f92672">#</span>:options <span style="color:#f92672">'</span>(<span style="color:#e6db74">"grp:alt_shift_toggle"</span>)))
|
||||
<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="color:#f8f8f2;background-color:#272822;-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:#a6e22e">users</span> (<span style="color:#a6e22e">cons*</span> (<span style="color:#a6e22e">user-account</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">name</span> <span style="color:#e6db74">"pavel"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">comment</span> <span style="color:#e6db74">"Pavel"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">group</span> <span style="color:#e6db74">"users"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">home-directory</span> <span style="color:#e6db74">"/home/pavel"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">supplementary-groups</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">'</span>(<span style="color:#e6db74">"wheel"</span> <span style="color:#75715e">;; sudo</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"netdev"</span> <span style="color:#75715e">;; network devices</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"audio"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"video"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"input"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"tty"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"docker"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"scanner"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"libvirt"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"lp"</span>)))
|
||||
</span></span><span style="display:flex;"><span> %base-user-accounts))
|
||||
<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="color:#f8f8f2;background-color:#272822;-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:#a6e22e">packages</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">append</span>
|
||||
</span></span><span style="display:flex;"><span> (list nss-certs
|
||||
</span></span><span style="display:flex;"><span> git
|
||||
</span></span><span style="display:flex;"><span> i3-gaps
|
||||
</span></span><span style="display:flex;"><span> i3lock
|
||||
</span></span><span style="display:flex;"><span> openbox
|
||||
</span></span><span style="display:flex;"><span> xterm
|
||||
</span></span><span style="display:flex;"><span> vim)
|
||||
</span></span><span style="display:flex;"><span> %base-packages))
|
||||
<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>
|
||||
|
|
@ -330,173 +331,173 @@
|
|||
<li>add a symlink to ELF interpreter to where most Linux binaries expect it</li>
|
||||
</ul>
|
||||
<!--listend-->
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#66d9ef">define </span>%my-base-services
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">cons*</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">service</span> openssh-service-type)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">screen-locker-service</span> i3lock <span style="color:#e6db74">"i3lock"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">extra-special-file</span> <span style="color:#e6db74">"/lib64/ld-linux-x86-64.so.2"</span> (<span style="color:#a6e22e">file-append</span> glibc <span style="color:#e6db74">"/lib/ld-linux-x86-64.so.2"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">service</span> nix-service-type)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">service</span> cups-service-type
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">cups-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">web-interface?</span> <span style="color:#66d9ef">#t</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">service</span> docker-service-type)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">service</span> libvirt-service-type
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">libvirt-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">unix-sock-group</span> <span style="color:#e6db74">"libvirt"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">tls-port</span> <span style="color:#e6db74">"16555"</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">service</span> virtlog-service-type)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">modify-services</span> %desktop-services
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">network-manager-service-type</span>
|
||||
</span></span><span style="display:flex;"><span> config =>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">network-manager-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">inherit</span> config)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">vpn-plugins</span> (list network-manager-openvpn)))))))
|
||||
<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">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></code></pre></div><h3 id="indigo">indigo</h3>
|
||||
<p><code>indigo</code> is my desktop PC.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-scheme" data-lang="scheme"><span style="display:flex;"><span><<system-common>>
|
||||
<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:#a6e22e">operating-system</span>
|
||||
</span></span><span style="display:flex;"><span> <<system-base>>
|
||||
</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:#a6e22e">host-name</span> <span style="color:#e6db74">"indigo"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">services</span> (<span style="color:#a6e22e">cons*</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">set-xorg-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">xorg-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">keyboard-layout</span> keyboard-layout)))
|
||||
</span></span><span style="display:flex;"><span> %my-base-services))
|
||||
</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:#a6e22e">bootloader</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">bootloader-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">bootloader</span> grub-efi-bootloader)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">target</span> <span style="color:#e6db74">"/boot/efi"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">keyboard-layout</span> keyboard-layout)))
|
||||
</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:#a6e22e">swap-devices</span>
|
||||
</span></span><span style="display:flex;"><span> (list (<span style="color:#a6e22e">uuid</span> <span style="color:#e6db74">"3a77c542-7d24-46ff-8123-f7398d1c2677"</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:#a6e22e">file-systems</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">cons*</span> (<span style="color:#a6e22e">file-system</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mount-point</span> <span style="color:#e6db74">"/"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">device</span> (<span style="color:#a6e22e">file-system-label</span> <span style="color:#e6db74">"my-root"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">type</span> <span style="color:#e6db74">"ext4"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">file-system</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mount-point</span> <span style="color:#e6db74">"/boot/efi"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">device</span> <span style="color:#e6db74">"/dev/sda1"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">type</span> <span style="color:#e6db74">"vfat"</span>))
|
||||
</span></span><span style="display:flex;"><span> %base-file-systems)))
|
||||
</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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-scheme" data-lang="scheme"><span style="display:flex;"><span><<system-common>>
|
||||
<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:#66d9ef">define </span>%backlight-udev-rule
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">udev-rule</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"90-backlight.rules"</span>
|
||||
</span></span><span style="display:flex;"><span> (string-append <span style="color:#e6db74">"ACTION==\"add\", SUBSYSTEM==\"backlight\", "</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\""</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"\n"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"ACTION==\"add\", SUBSYSTEM==\"backlight\", "</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\""</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:#a6e22e">operating-system</span>
|
||||
</span></span><span style="display:flex;"><span> <<system-base>>
|
||||
</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:#a6e22e">host-name</span> <span style="color:#e6db74">"eminence"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">services</span> (<span style="color:#a6e22e">cons*</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">set-xorg-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">xorg-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">keyboard-layout</span> keyboard-layout)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">modify-services</span> %my-base-services
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">elogind-service-type</span>
|
||||
</span></span><span style="display:flex;"><span> config =>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">elogind-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">inherit</span> config)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">handle-lid-switch-external-power</span> <span style="color:#e6db74">'suspend</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">udev-service-type</span>
|
||||
</span></span><span style="display:flex;"><span> config =>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">udev-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">inherit</span> config)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">rules</span> (cons %backlight-udev-rule
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">udev-configuration-rules</span> config))))))))
|
||||
</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:#a6e22e">bootloader</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">bootloader-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">bootloader</span> grub-efi-bootloader)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">target</span> <span style="color:#e6db74">"/boot/efi"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">keyboard-layout</span> keyboard-layout)))
|
||||
</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:#a6e22e">swap-devices</span>
|
||||
</span></span><span style="display:flex;"><span> (list (<span style="color:#a6e22e">uuid</span> <span style="color:#e6db74">"f93cf3f6-7ee7-42ec-8ee2-f3d896fdf9b5"</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:#a6e22e">file-systems</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">cons*</span> (<span style="color:#a6e22e">file-system</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mount-point</span> <span style="color:#e6db74">"/"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">device</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">uuid</span> <span style="color:#e6db74">"1d937704-bbeb-43b5-bc63-453886c426af"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'ext4</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">type</span> <span style="color:#e6db74">"ext4"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">file-system</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mount-point</span> <span style="color:#e6db74">"/boot/efi"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">device</span> (<span style="color:#a6e22e">uuid</span> <span style="color:#e6db74">"0031-3784"</span> <span style="color:#e6db74">'fat32</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">type</span> <span style="color:#e6db74">"vfat"</span>))
|
||||
</span></span><span style="display:flex;"><span> %base-file-systems)))
|
||||
</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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-scheme" data-lang="scheme"><span style="display:flex;"><span><<system-common>>
|
||||
<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:#66d9ef">define </span>%backlight-udev-rule
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">udev-rule</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"90-backlight.rules"</span>
|
||||
</span></span><span style="display:flex;"><span> (string-append <span style="color:#e6db74">"ACTION==\"add\", SUBSYSTEM==\"backlight\", "</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\""</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"\n"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"ACTION==\"add\", SUBSYSTEM==\"backlight\", "</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\""</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:#a6e22e">operating-system</span>
|
||||
</span></span><span style="display:flex;"><span> <<system-base>>
|
||||
</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:#a6e22e">host-name</span> <span style="color:#e6db74">"azure"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">services</span> (<span style="color:#a6e22e">cons*</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">set-xorg-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">xorg-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">keyboard-layout</span> keyboard-layout)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">modify-services</span> %my-base-services
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">elogind-service-type</span> config =>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">elogind-configuration</span> (<span style="color:#a6e22e">inherit</span> config)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">handle-lid-switch-external-power</span> <span style="color:#e6db74">'suspend</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">udev-service-type</span> config =>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">udev-configuration</span> (<span style="color:#a6e22e">inherit</span> config)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">rules</span> (cons %backlight-udev-rule
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">udev-configuration-rules</span> config))))))))
|
||||
</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:#a6e22e">bootloader</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">bootloader-configuration</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">bootloader</span> grub-efi-bootloader)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">target</span> <span style="color:#e6db74">"/boot/efi"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">keyboard-layout</span> keyboard-layout)))
|
||||
</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:#a6e22e">swap-devices</span>
|
||||
</span></span><span style="display:flex;"><span> (list (<span style="color:#a6e22e">uuid</span> <span style="color:#e6db74">"4b2dedb3-b111-4e69-8c05-6daa2b072c76"</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:#a6e22e">file-systems</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">cons*</span> (<span style="color:#a6e22e">file-system</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mount-point</span> <span style="color:#e6db74">"/"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">device</span> (<span style="color:#a6e22e">file-system-label</span> <span style="color:#e6db74">"my-root"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">type</span> <span style="color:#e6db74">"ext4"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">file-system</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mount-point</span> <span style="color:#e6db74">"/boot/efi"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">device</span> <span style="color:#e6db74">"/dev/sda1"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">type</span> <span style="color:#e6db74">"vfat"</span>))
|
||||
</span></span><span style="display:flex;"><span> %base-file-systems)))
|
||||
</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><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="color:#f8f8f2;background-color:#272822;-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
|
||||
<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>
|
||||
|
|
@ -505,14 +506,14 @@
|
|||
<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="color:#f8f8f2;background-color:#272822;-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
|
||||
<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="color:#f8f8f2;background-color:#272822;-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
|
||||
<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="color:#f8f8f2;background-color:#272822;-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
|
||||
<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>
|
||||
|
|
@ -570,80 +571,80 @@
|
|||
<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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">ca</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.vpn/</span><span style="color:#a6e22e">ca</span>.<span style="color:#a6e22e">crt</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">cert</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.vpn/</span><span style="color:#a6e22e">client</span>.<span style="color:#a6e22e">crt</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">key</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.vpn/</span><span style="color:#a6e22e">client</span>.<span style="color:#a6e22e">key</span><span style="color:#960050;background-color:#1e0010">
|
||||
<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 style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>cert <span style="color:#b68">/home/</span>pavel<span style="color:#b68">/.vpn/</span>client.crt<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>key <span style="color:#b68">/home/</span>pavel<span style="color:#b68">/.vpn/</span>client.key<span style="">
|
||||
</span></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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">auth</span>-<span style="color:#a6e22e">user</span>-<span style="color:#a6e22e">pass</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.vpn/</span><span style="color:#a6e22e">auth</span>.<span style="color:#a6e22e">conf</span><span style="color:#960050;background-color:#1e0010">
|
||||
<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 style="">
|
||||
</span></span></span></code></pre></div><p><code>auth.conf</code> looks like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>login
|
||||
<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 fix DNS. <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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">setenv</span> <span style="color:#a6e22e">PATH</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.guix-extra-profiles/</span><span style="color:#a6e22e">system</span><span style="color:#e6db74">/system/</span><span style="color:#a6e22e">bin</span>:<span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.guix-extra-profiles/</span><span style="color:#a6e22e">system</span><span style="color:#e6db74">/system/</span><span style="color:#a6e22e">sbin</span>:<span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.guix-extra-profiles/</span><span style="color:#a6e22e">console</span><span style="color:#e6db74">/console/</span><span style="color:#a6e22e">bin</span>:<span style="color:#e6db74">/run/</span><span style="color:#a6e22e">current</span>-<span style="color:#a6e22e">system</span><span style="color:#e6db74">/profile/</span><span style="color:#a6e22e">bin</span>:<span style="color:#e6db74">/run/</span><span style="color:#a6e22e">current</span>-<span style="color:#a6e22e">system</span><span style="color:#e6db74">/profile/</span><span style="color:#a6e22e">sbin</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">up</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.guix-extra-profiles/</span><span style="color:#a6e22e">system</span><span style="color:#e6db74">/system/</span><span style="color:#a6e22e">bin</span>/<span style="color:#a6e22e">update</span>-<span style="color:#a6e22e">resolv</span>-<span style="color:#a6e22e">conf</span>.<span style="color:#a6e22e">sh</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">down</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/.guix-extra-profiles/</span><span style="color:#a6e22e">system</span><span style="color:#e6db74">/system/</span><span style="color:#a6e22e">bin</span>/<span style="color:#a6e22e">update</span>-<span style="color:#a6e22e">resolv</span>-<span style="color:#a6e22e">conf</span>.<span style="color:#a6e22e">sh</span><span style="color:#960050;background-color:#1e0010">
|
||||
<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 style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></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 style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></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 style="">
|
||||
</span></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>Fix <code>etc/resolv.conf</code></p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>cp /etc/resolv.conf /etc/resolv.conf-bak
|
||||
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">"nameserver 8.8.8.8"</span> > /etc/resolv.conf
|
||||
<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>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="color:#f8f8f2;background-color:#272822;-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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">up</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/bin/</span><span style="color:#a6e22e">scripts</span>/<span style="color:#a6e22e">fix</span>-<span style="color:#a6e22e">resolve</span>-<span style="color:#a6e22e">conf</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">down</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/bin/</span><span style="color:#a6e22e">scripts</span>/<span style="color:#a6e22e">restore</span>-<span style="color:#a6e22e">resolve</span>-<span style="color:#a6e22e">conf</span><span style="color:#960050;background-color:#1e0010">
|
||||
<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 style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>down <span style="color:#b68">/home/</span>pavel<span style="color:#b68">/bin/</span>scripts/restore-resolve-conf<span style="">
|
||||
</span></span></span></code></pre></div></li>
|
||||
<li>
|
||||
<p>run a script to fix Docker routes</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">route</span>-<span style="color:#a6e22e">up</span> <span style="color:#e6db74">/home/</span><span style="color:#a6e22e">pavel</span><span style="color:#e6db74">/bin/</span><span style="color:#a6e22e">scripts</span>/<span style="color:#a6e22e">vpn</span>-<span style="color:#a6e22e">fix</span>-<span style="color:#a6e22e">routes</span><span style="color:#960050;background-color:#1e0010">
|
||||
<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 style="">
|
||||
</span></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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>echo <span style="color:#e6db74">"Adding default route to </span>$route_vpn_gateway<span style="color:#e6db74"> with /0 mask..."</span>
|
||||
<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>IP<span style="color:#f92672">=</span>/run/current-system/profile/sbin/ip
|
||||
</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>$IP route add default via $route_vpn_gateway
|
||||
</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>echo <span style="color:#e6db74">"Removing /1 routes..."</span>
|
||||
</span></span><span style="display:flex;"><span>$IP route del 0.0.0.0/1 via $route_vpn_gateway
|
||||
</span></span><span style="display:flex;"><span>$IP route del 128.0.0.0/1 via $route_vpn_gateway
|
||||
</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>As of now, CyberGhost doesn’t provide ipv6, so we have to disable it.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>export DISPLAY<span style="color:#f92672">=</span>:0
|
||||
</span></span><span style="display:flex;"><span>CONN<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>nmcli -f NAME con show --active | grep -Ev <span style="color:#e6db74">"(.*docker.*|NAME|br-.*|veth.*|tun.*|vnet.*|virbr.*)"</span> | sed <span style="color:#e6db74">'s/ *$//g'</span><span style="color:#66d9ef">)</span>
|
||||
<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:#66d9ef">if</span> <span style="color:#f92672">[</span> -z <span style="color:#e6db74">"</span>$CONN<span style="color:#e6db74">"</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
|
||||
</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">"No connection!"</span>
|
||||
</span></span><span style="display:flex;"><span> notify-send <span style="color:#e6db74">"VPN"</span> <span style="color:#e6db74">"No connection for VPN to run"</span>
|
||||
</span></span><span style="display:flex;"><span> exit
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</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:#75715e"># if [[ "$CONN" != *"Wired"* ]]; then</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># echo "Connection: $CONN"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># notify-send "VPN" "Initializing for connection: $CONN"</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:#75715e"># pkexec nmcli con modify "$CONN" ipv6.method ignore</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># nmcli connection up "$CONN"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># fi</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>pkexec openvpn --config ~/.vpn/openvpn.ovpn
|
||||
</span></span></code></pre></div><h4 id="vpn-stop">vpn-stop</h4>
|
||||
<p>Also a script to reverse the changes.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>CONN<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>nmcli -f NAME con show --active | grep -Ev <span style="color:#e6db74">"(.*docker.*|NAME|br-.*|veth.*|tun.*)"</span> | sed <span style="color:#e6db74">'s/ *$//g'</span><span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">"Connection: </span>$CONN<span style="color:#e6db74">"</span>
|
||||
<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:#e6db74">"</span>$CONN<span style="color:#e6db74">"</span> ipv6.method auto
|
||||
</span></span><span style="display:flex;"><span>nmcli connection up <span style="color:#e6db74">"</span>$CONN<span style="color:#e6db74">"</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="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="conda">conda</h3>
|
||||
|
|
@ -652,59 +653,59 @@
|
|||
<p>First, it’s impossible to perform <code>conda init</code> to patch files like <code>.bashrc</code>, because the command is hell-bent on modifying <code>/gnu/store/</code>. So I do this manually, look for the <code>init_conda</code> procedures in <a href="/configs/console/">Console.org</a>.</p>
|
||||
<p>Second, the base environment has <code>/gnu/store/...</code> as a root, so don’t install anything there (and don’t run <code>conda</code> with superuser rights!).</p>
|
||||
<p>Third, by default it tries to create envronments in <code>/gnu/store</code>. It’s enough to create one environment like this to fix it:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>mkdir -p ~/.conda/envs
|
||||
<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>mkdir -p ~/.conda/envs
|
||||
</span></span><span style="display:flex;"><span>conda create -p ~/.conda/envs/test
|
||||
</span></span></code></pre></div><p>Fourth, you may need to unset <code>$PYTHONPATH</code> if you have any global packages installed, otherwise Python from anaconda will try to import them instead of the conda versions.</p>
|
||||
<p>Finally, 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="color:#f8f8f2;background-color:#272822;-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:#75715e"># Get writable conda envs with npm & without it</span>
|
||||
</span></span><span style="display:flex;"><span>readarray -t CONDA_ENVS_ALL <span style="color:#f92672"><<<</span> <span style="color:#66d9ef">$(</span>conda env list --json | jq <span style="color:#e6db74">'.envs[]'</span><span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span>CONDA_ENVS_NPM<span style="color:#f92672">=()</span>
|
||||
</span></span><span style="display:flex;"><span>CONDA_ENVS_NO_NPM<span style="color:#f92672">=()</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> env in <span style="color:#e6db74">"</span><span style="color:#e6db74">${</span>CONDA_ENVS_ALL[@]<span style="color:#e6db74">}</span><span style="color:#e6db74">"</span>; <span style="color:#66d9ef">do</span>
|
||||
</span></span><span style="display:flex;"><span> env<span style="color:#f92672">=</span><span style="color:#e6db74">"</span><span style="color:#e6db74">${</span>env:1:<span style="color:#e6db74">${#</span>env<span style="color:#e6db74">}</span>-2<span style="color:#e6db74">}</span><span style="color:#e6db74">"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -w <span style="color:#e6db74">"</span>$env<span style="color:#e6db74">"</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -f <span style="color:#e6db74">"</span>$env<span style="color:#e6db74">/bin/npm"</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
|
||||
</span></span><span style="display:flex;"><span> CONDA_ENVS_NPM<span style="color:#f92672">+=(</span>$env<span style="color:#f92672">)</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">else</span>
|
||||
</span></span><span style="display:flex;"><span> CONDA_ENVS_NO_NPM<span style="color:#f92672">+=(</span>$env<span style="color:#f92672">)</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fi</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">fi</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
|
||||
<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>conda 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:#66d9ef">for</span> env in <span style="color:#e6db74">"</span><span style="color:#e6db74">${</span>CONDA_ENVS_NPM[@]<span style="color:#e6db74">}</span><span style="color:#e6db74">"</span>; <span style="color:#66d9ef">do</span>
|
||||
</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">"Found npm in </span>$env<span style="color:#e6db74">"</span>
|
||||
</span></span><span style="display:flex;"><span> mkdir -p <span style="color:#e6db74">"</span>$env<span style="color:#e6db74">/etc/conda/activate.d"</span>
|
||||
</span></span><span style="display:flex;"><span> mkdir -p <span style="color:#e6db74">"</span>$env<span style="color:#e6db74">/etc/conda/deactivate.d"</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> echo <span style="color:#e6db74">"unset NPM_CONFIG_USERCONFIG"</span> > <span style="color:#e6db74">"</span>$env<span style="color:#e6db74">/etc/conda/activate.d/conda.sh"</span>
|
||||
</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">"set -e NPM_CONFIG_USERCONFIG"</span> > <span style="color:#e6db74">"</span>$env<span style="color:#e6db74">/etc/conda/activate.d/conda.fish"</span>
|
||||
</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">"export NPM_CONFIG_USERCONFIG=</span>$HOME<span style="color:#e6db74">/._npmrc"</span> > <span style="color:#e6db74">"</span>$env<span style="color:#e6db74">/etc/conda/deactivate.d/conda.sh"</span>
|
||||
</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">"export NPM_CONFIG_USERCONFIG=</span>$HOME<span style="color:#e6db74">/._npmrc"</span> > <span style="color:#e6db74">"</span>$env<span style="color:#e6db74">/etc/conda/deactivate.d/conda.fish"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</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:#66d9ef">for</span> env in <span style="color:#e6db74">"</span><span style="color:#e6db74">${</span>CONDA_ENVS_NO_NPM<span style="color:#e6db74">}</span><span style="color:#e6db74">"</span>; <span style="color:#66d9ef">do</span>
|
||||
</span></span><span style="display:flex;"><span> echo <span style="color:#e6db74">"Did not found npm in </span>$env<span style="color:#e6db74">"</span>
|
||||
</span></span><span style="display:flex;"><span> rm -rf <span style="color:#e6db74">"</span>$env<span style="color:#e6db74">/etc/conda/activate.d/conda.sh"</span> <span style="color:#f92672">||</span> true
|
||||
</span></span><span style="display:flex;"><span> rm -rf <span style="color:#e6db74">"</span>$env<span style="color:#e6db74">/etc/conda/activate.d/conda.fish"</span> <span style="color:#f92672">||</span> true
|
||||
</span></span><span style="display:flex;"><span> rm -rf <span style="color:#e6db74">"</span>$env<span style="color:#e6db74">/etc/conda/deactivate.d/conda.sh"</span> <span style="color:#f92672">||</span> true
|
||||
</span></span><span style="display:flex;"><span> rm -rf <span style="color:#e6db74">"</span>$env<span style="color:#e6db74">/etc/conda/deactivate.d/conda.fish"</span> <span style="color:#f92672">||</span> true
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>export PATH<span style="color:#f92672">=</span><span style="color:#e6db74">"</span>$HOME<span style="color:#e6db74">/bin/dummies:</span>$PATH<span style="color:#e6db74">"</span>
|
||||
<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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>echo <span style="color:#e6db74">"LSB Version: Hey. I spent an hour figuring out why Slack doesn't launch."</span>
|
||||
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">"Distributor ID: It seems like it requires an lsb_release."</span>
|
||||
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">"Description: But GNU Guix doesn't have one."</span>
|
||||
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">"Release: 42.2"</span>
|
||||
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">"Codename: n/a"</span>
|
||||
<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="color:#f8f8f2;background-color:#272822;-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
|
||||
<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>
|
||||
|
|
@ -730,11 +731,11 @@
|
|||
</ul>
|
||||
<h3 id="manifest">Manifest</h3>
|
||||
<p><a id="code-snippet--packages"></a></p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(my/format-guix-dependencies category)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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="color:#f8f8f2;background-color:#272822;-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:#a6e22e">specifications->manifest</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">'</span>(
|
||||
</span></span><span style="display:flex;"><span> <<packages(<span style="color:#e6db74">"system"</span>)>>))
|
||||
<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>
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
<hr>
|
||||
<div id="content">
|
||||
<div class="container">
|
||||
<h1>Mail</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>
|
||||
|
|
@ -112,31 +113,31 @@
|
|||
</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="color:#f8f8f2;background-color:#272822;-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>
|
||||
<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="color:#f8f8f2;background-color:#272822;-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
|
||||
<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="color:#f8f8f2;background-color:#272822;-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:#a6e22e">davmail.server</span><span style="color:#f92672">=</span><span style="color:#e6db74">true</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">davmail.mode</span><span style="color:#f92672">=</span><span style="color:#e6db74">Auto</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">davmail.url</span><span style="color:#f92672">=</span><span style="color:#e6db74">https://mail.etu.ru/owa/</span>
|
||||
<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:#a6e22e">davmail.server.certificate.hash</span><span style="color:#f92672">=</span><span style="color:#e6db74">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 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:#a6e22e">davmail.caldavPort</span><span style="color:#f92672">=</span><span style="color:#e6db74">1080</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">davmail.imapPort</span><span style="color:#f92672">=</span><span style="color:#e6db74">1143</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">davmail.ldapPort</span><span style="color:#f92672">=</span><span style="color:#e6db74">1389</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">davmail.popPort</span><span style="color:#f92672">=</span><span style="color:#e6db74">1110</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">davmail.smtpPort</span><span style="color:#f92672">=</span><span style="color:#e6db74">1025</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:#a6e22e">davmail.imapAutoExpunge</span><span style="color:#f92672">=</span><span style="color:#e6db74">false</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">davmail.enableKeepalive</span><span style="color:#f92672">=</span><span style="color:#e6db74">false</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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cd $HOME/bin/davmail-6.0.0-3375
|
||||
<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>
|
||||
|
|
@ -157,29 +158,29 @@
|
|||
<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="color:#f8f8f2;background-color:#272822;-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:#e6db74">'s/username: //;2p'</span>
|
||||
<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="color:#f8f8f2;background-color:#272822;-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:#ae81ff">1</span>
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#66d9ef">[general]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">accounts</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">pvkorytov</span>
|
||||
<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:#66d9ef">[Account pvkorytov]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">localrepository</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">pvkorytov-local</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">remoterepository</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">pvkorytov-remote</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:#66d9ef">[Repository pvkorytov-local]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">type</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">Maildir</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">localfolders</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">~/Mail/pvkorytov_etu/</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:#66d9ef">[Repository pvkorytov-remote]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">type</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">IMAP</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">remotehost</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">localhost</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">remoteuser</span> <span style="color:#f92672">=</span> <span style="color:#e6db74"><<mail-username()>></span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">remotepass</span> <span style="color:#f92672">=</span> <span style="color:#e6db74"><<mail-password()>></span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">remoteport</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">1143</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">starttls</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">no</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ssl</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">no</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">sslcacertfile</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">/etc/ssl/certs/ca-certificates.crt</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>
|
||||
|
|
@ -200,23 +201,23 @@
|
|||
<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="color:#f8f8f2;background-color:#272822;-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:#66d9ef">[database]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">path</span><span style="color:#f92672">=</span><span style="color:#e6db74">/home/pavel/Mail</span>
|
||||
<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="color:#f8f8f2;background-color:#272822;-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:#66d9ef">[user]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">name</span><span style="color:#f92672">=</span><span style="color:#e6db74">Pavel Korytov</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">primary_email</span><span style="color:#f92672">=</span><span style="color:#e6db74">thexcloud@gmail.com</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">other_email</span><span style="color:#f92672">=</span><span style="color:#e6db74">progin6304@gmail.com;pvkorytov@etu.ru</span>
|
||||
<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="color:#f8f8f2;background-color:#272822;-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:#66d9ef">[new]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">tags</span><span style="color:#f92672">=</span><span style="color:#e6db74">new;</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ignore</span><span style="color:#f92672">=</span><span style="color:#e6db74">.osync_workdir;.mbsyncstate;.uidvalidity;.lock;/.*gmailieer\.json.*/</span>
|
||||
<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="color:#f8f8f2;background-color:#272822;-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:#66d9ef">[search]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">exclude_tags</span><span style="color:#f92672">=</span><span style="color:#e6db74">trash;spam;</span>
|
||||
<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="color:#f8f8f2;background-color:#272822;-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:#66d9ef">[maildir]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">synchronize_flags</span><span style="color:#f92672">=</span><span style="color:#e6db74">true</span>
|
||||
<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>
|
||||
|
|
@ -294,104 +295,104 @@ Remove <code>TAG</code> from emails which are outside the matching <code>PATH</c
|
|||
</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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq my/maildir-root <span style="color:#e6db74">"~/Mail"</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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>(let ((rules <span style="color:#f92672">'</span>()))
|
||||
</span></span><span style="display:flex;"><span> (dolist (row tags)
|
||||
</span></span><span style="display:flex;"><span> (let ((tag (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> row))
|
||||
</span></span><span style="display:flex;"><span> (folder (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> row)))
|
||||
</span></span><span style="display:flex;"><span> (unless (string-empty-p make_tag)
|
||||
</span></span><span style="display:flex;"><span> (add-to-list
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'rules</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">"notmuch tag +%s \"path:%s/%s/cur/** AND NOT tag:%s\""</span>
|
||||
</span></span><span style="display:flex;"><span> tag root folder tag)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">t</span>))
|
||||
</span></span><span style="display:flex;"><span> (unless (string-empty-p remove)
|
||||
</span></span><span style="display:flex;"><span> (add-to-list
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'rules</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">"notmuch tag -%s \"NOT path:%s/%s/cur/** AND tag:%s AND tag:%s\""</span>
|
||||
</span></span><span style="display:flex;"><span> tag root folder tag root_tag)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">t</span>))
|
||||
</span></span><span style="display:flex;"><span> (unless (string-empty-p move)
|
||||
</span></span><span style="display:flex;"><span> (add-to-list
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'rules</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">concat</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">"notmuch search --output=files \"NOT path:%s/%s/cur/** AND tag:%s AND tag:%s\""</span>
|
||||
</span></span><span style="display:flex;"><span> root folder tag root_tag)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">" | xargs -I ! mv ! %s/%s/%s/cur/"</span> my/maildir-root root folder))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">t</span>))))
|
||||
</span></span><span style="display:flex;"><span> (unless (string-empty-p archive_root)
|
||||
</span></span><span style="display:flex;"><span> (add-to-list
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'rules</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">concat</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">"notmuch search --output=files \"NOT path:%s/%s/cur/** AND %s AND tag:%s\""</span>
|
||||
</span></span><span style="display:flex;"><span> root archive_root
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mapconcat</span>
|
||||
</span></span><span style="display:flex;"><span> (lambda (row)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">"NOT tag:%s"</span> (<span style="color:#a6e22e">car</span> row)))
|
||||
</span></span><span style="display:flex;"><span> tags
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" AND "</span>)
|
||||
</span></span><span style="display:flex;"><span> root_tag)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">" | xargs -I ! mv ! %s/%s/%s/cur/"</span> my/maildir-root root archive_root))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">t</span>))
|
||||
</span></span><span style="display:flex;"><span> (string-join rules <span style="color:#e6db74">"\n"</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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(my/mail-format-tags-rules tags <span style="color:#e6db74">"pvkorytov_etu"</span> <span style="color:#e6db74">"pvkorytov"</span> <span style="color:#66d9ef">nil</span> <span style="color:#66d9ef">nil</span> <span style="color:#66d9ef">t</span> <span style="color:#e6db74">"Archive"</span>)
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#75715e"># GMI="/home/pavel/Programs/miniconda3/envs/mail/bin/gmi"</span>
|
||||
</span></span><span style="display:flex;"><span>GMI<span style="color:#f92672">=</span><span style="color:#e6db74">"gmi"</span>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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>echo <span style="color:#e6db74">"Running pre-new filters"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#e6db74"><<mail-tags(move="t",archive_root="Archive")>>
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">echo "Pre-new filters done"
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">parallel --link -j0 "(cd /home/pavel/Mail/{1}/ && {2} {3})" ::: thexcloud progin6304 pvkorytov_etu ::: "$GMI" "$GMI" "offlineima</span>p<span style="color:#e6db74">" ::: sync sync ""
|
||||
</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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(my/mail-format-tags-rules tags <span style="color:#e6db74">"pvkorytov_etu"</span> <span style="color:#e6db74">"pvkorytov"</span> <span style="color:#66d9ef">t</span> <span style="color:#66d9ef">t</span>)
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#e6db74">"path:thexcloud/** AND tag:new"</span>
|
||||
</span></span><span style="display:flex;"><span>notmuch tag +progin <span style="color:#e6db74">"path:progin6304/** AND tag:new"</span>
|
||||
</span></span><span style="display:flex;"><span>notmuch tag +pvkorytov <span style="color:#e6db74">"path:pvkorytov_etu/** AND tag:new"</span>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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>echo <span style="color:#e6db74">"Running post-new filters"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#e6db74"><<mail-tags(ma</span>ke_tag<span style="color:#f92672">=</span><span style="color:#e6db74">"t"</span>,remove<span style="color:#f92672">=</span><span style="color:#e6db74">"t"</span><span style="color:#f92672">)</span>>>
|
||||
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">"Post-new filters done"</span>
|
||||
</span></span><span style="display:flex;"><span>notmuch tag -new <span style="color:#e6db74">"tag:new"</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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>export DISPLAY<span style="color:#f92672">=</span>:0
|
||||
</span></span><span style="display:flex;"><span>CHECK_FILE<span style="color:#f92672">=</span><span style="color:#e6db74">"/home/pavel/Mail/.last_check"</span>
|
||||
</span></span><span style="display:flex;"><span>QUERY<span style="color:#f92672">=</span><span style="color:#e6db74">"tag:unread"</span>
|
||||
</span></span><span style="display:flex;"><span>ALL_QUERY<span style="color:#f92672">=</span><span style="color:#e6db74">"tag:unread"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -f <span style="color:#e6db74">"</span>$CHECK_FILE<span style="color:#e6db74">"</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
|
||||
</span></span><span style="display:flex;"><span> DATE<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>cat <span style="color:#e6db74">"</span>$CHECK_FILE<span style="color:#e6db74">"</span><span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span> QUERY<span style="color:#f92672">=</span><span style="color:#e6db74">"</span>$QUERY<span style="color:#e6db74"> and date:@</span>$DATE<span style="color:#e6db74">.."</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
|
||||
<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>NEW_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>notmuch count <span style="color:#e6db74">"</span>$QUERY<span style="color:#e6db74">"</span><span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span>ALL_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>notmuch count <span style="color:#e6db74">"</span>$ALL_QUERY<span style="color:#e6db74">"</span><span style="color:#66d9ef">)</span>
|
||||
</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:#66d9ef">if</span> <span style="color:#f92672">[</span> $NEW_UNREAD -gt <span style="color:#ae81ff">0</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
|
||||
</span></span><span style="display:flex;"><span> MAIN_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>notmuch count <span style="color:#e6db74">"tag:unread AND tag:main"</span><span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span> PROGIN_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>notmuch count <span style="color:#e6db74">"tag:unread AND tag:progin"</span><span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span> ETU_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>notmuch count <span style="color:#e6db74">"tag:unread AND tag:pvkorytov"</span><span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span> read -r -d <span style="color:#e6db74">''</span> NOTIFICATION <span style="color:#e6db74"><<EOM
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$NEW_UNREAD new messages
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$MAIN_UNREAD thexcloud@gmail.com
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$PROGIN_UNREAD progin6304@gmail.com
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$ETU_UNREAD pvkorytov@etu.ru
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$ALL_UNREAD total
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">EOM</span>
|
||||
</span></span><span style="display:flex;"><span> notify-send <span style="color:#e6db74">"New Mail"</span> <span style="color:#e6db74">"</span>$NOTIFICATION<span style="color:#e6db74">"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</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>echo <span style="color:#e6db74">"</span><span style="color:#66d9ef">$(</span>date +%s<span style="color:#66d9ef">)</span><span style="color:#e6db74">"</span> > $CHECK_FILE
|
||||
</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="color:#f8f8f2;background-color:#272822;-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:#a6e22e">job</span> <span style="color:#e6db74">"*/5 * * * * "</span> <span style="color:#e6db74">"~/bin/scripts/check-email"</span>)
|
||||
<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>
|
||||
|
|
@ -406,34 +407,34 @@ Remove <code>TAG</code> from emails which are outside the matching <code>PATH</c
|
|||
</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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">defaults</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">auth</span> <span style="color:#a6e22e">on</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">tls</span> <span style="color:#a6e22e">on</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">tls_trust_file</span> <span style="color:#e6db74">/etc/</span><span style="color:#a6e22e">ssl</span><span style="color:#e6db74">/certs/</span><span style="color:#a6e22e">ca</span>-<span style="color:#a6e22e">certificates</span>.<span style="color:#a6e22e">crt</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">logfile</span> ~/.<span style="color:#a6e22e">msmtp</span>.<span style="color:#a6e22e">log</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">account</span> <span style="color:#a6e22e">main</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">host</span> <span style="color:#a6e22e">smtp</span>.<span style="color:#a6e22e">gmail</span>.<span style="color:#a6e22e">com</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">port</span> <span style="color:#ae81ff">587</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">from</span> <span style="color:#a6e22e">thexcloud</span>@<span style="color:#a6e22e">gmail</span>.<span style="color:#a6e22e">com</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">user</span> <span style="color:#a6e22e">thexcloud</span>@<span style="color:#a6e22e">gmail</span>.<span style="color:#a6e22e">com</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">passwordeval</span> <span style="color:#e6db74">"pass show My_Online/APIs/google-main-app-password | head -n 1"</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">account</span> <span style="color:#a6e22e">progin</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">host</span> <span style="color:#a6e22e">smtp</span>.<span style="color:#a6e22e">gmail</span>.<span style="color:#a6e22e">com</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">port</span> <span style="color:#ae81ff">587</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">from</span> <span style="color:#a6e22e">progin6304</span>@<span style="color:#a6e22e">gmail</span>.<span style="color:#a6e22e">com</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">user</span> <span style="color:#a6e22e">progin6304</span>@<span style="color:#a6e22e">gmail</span>.<span style="color:#a6e22e">com</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">passwordeval</span> <span style="color:#e6db74">"pass show My_Online/ETU/progin6304@gmail.com | head -n 1"</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">account</span> <span style="color:#a6e22e">pvkorytov</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">tls</span> <span style="color:#a6e22e">off</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">auth</span> <span style="color:#a6e22e">plain</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">host</span> <span style="color:#a6e22e">localhost</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">port</span> <span style="color:#ae81ff">1025</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">from</span> <span style="color:#a6e22e">pvkorytov</span>@<span style="color:#a6e22e">etu</span>.<span style="color:#a6e22e">ru</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">user</span> <span style="color:#a6e22e">pvkorytov</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">passwordeval</span> <span style="color:#e6db74">"pass show Job/Digital/Email/pvkorytov@etu.ru | head -n 1"</span><span style="color:#960050;background-color:#1e0010">
|
||||
<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 style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>auth on<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>tls on<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>tls_trust_file <span style="color:#b68">/etc/</span>ssl<span style="color:#b68">/certs/</span>ca-certificates.crt<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>logfile ~/.msmtp.log<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>account main<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>host smtp.gmail.com<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>port <span style="color:#666">587</span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>from thexcloud@gmail.com<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>user thexcloud@gmail.com<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>passwordeval <span style="color:#ba2121">"pass show My_Online/APIs/google-main-app-password | head -n 1"</span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>account progin<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>host smtp.gmail.com<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>port <span style="color:#666">587</span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>from progin6304@gmail.com<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>user progin6304@gmail.com<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>passwordeval <span style="color:#ba2121">"pass show My_Online/ETU/progin6304@gmail.com | head -n 1"</span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>account pvkorytov<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>tls off<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>auth plain<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>host localhost<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>port <span style="color:#666">1025</span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>from pvkorytov@etu.ru<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>user pvkorytov<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>passwordeval <span style="color:#ba2121">"pass show Job/Digital/Email/pvkorytov@etu.ru | head -n 1"</span><span style="">
|
||||
</span></span></span></code></pre></div><h2 id="emacs">Emacs</h2>
|
||||
<table>
|
||||
<thead>
|
||||
|
|
@ -448,59 +449,59 @@ Remove <code>TAG</code> from emails which are outside the matching <code>PATH</c
|
|||
</tbody>
|
||||
</table>
|
||||
<p>Finally, Emacs configuration. Let’s start with some variables:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq user-mail-address <span style="color:#e6db74">"thexcloud@gmail.com"</span>)
|
||||
</span></span><span style="display:flex;"><span>(setq <span style="color:#a6e22e">user-full-name</span> <span style="color:#e6db74">"Pavel Korytov"</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(let ((default-directory <span style="color:#e6db74">"/home/pavel/.guix-extra-profiles/mail/mail/share/emacs/site-lisp"</span>))
|
||||
</span></span><span style="display:flex;"><span> (normal-top-level-add-subdirs-to-load-path))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/notmuch-toggle-trash ()
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (evil-collection-notmuch-toggle-tag <span style="color:#e6db74">"trash"</span> <span style="color:#e6db74">"search"</span> <span style="color:#a6e22e">#'</span>ignore))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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>(defun my/notmuch-toggle-inbox ()
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (evil-collection-notmuch-toggle-tag <span style="color:#e6db74">"inbox"</span> <span style="color:#e6db74">"search"</span> <span style="color:#a6e22e">#'</span>ignore))
|
||||
</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>(defun my/notmuch-toggle-unread ()
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (evil-collection-notmuch-toggle-tag <span style="color:#e6db74">"unread"</span> <span style="color:#e6db74">"search"</span> <span style="color:#a6e22e">#'</span>ignore))
|
||||
</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>Finally the proper notmuch settings:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package notmuch
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; :ensure nil</span>
|
||||
</span></span><span style="display:flex;"><span> :commands (notmuch notmuch-search)
|
||||
</span></span><span style="display:flex;"><span> :init
|
||||
</span></span><span style="display:flex;"><span> (my/use-doom-colors
|
||||
</span></span><span style="display:flex;"><span> (notmuch-wash-cited-text :foreground (doom-color <span style="color:#e6db74">'yellow</span>)))
|
||||
</span></span><span style="display:flex;"><span> :config
|
||||
</span></span><span style="display:flex;"><span> (setq mail-specify-envelope-from <span style="color:#66d9ef">t</span>)
|
||||
</span></span><span style="display:flex;"><span> (setq message-sendmail-envelope-from <span style="color:#e6db74">'header</span>)
|
||||
</span></span><span style="display:flex;"><span> (setq mail-envelope-from <span style="color:#e6db74">'header</span>)
|
||||
</span></span><span style="display:flex;"><span> (setq notmuch-always-prompt-for-sender <span style="color:#66d9ef">t</span>)
|
||||
</span></span><span style="display:flex;"><span> (setq message-send-mail-function <span style="color:#a6e22e">#'</span>message-send-mail-with-sendmail)
|
||||
</span></span><span style="display:flex;"><span> (setq sendmail-program (executable-find <span style="color:#e6db74">"msmtp"</span>))
|
||||
</span></span><span style="display:flex;"><span> (setq send-mail-function <span style="color:#a6e22e">#'</span>sendmail-send-it)
|
||||
</span></span><span style="display:flex;"><span> (setq mml-secure-openpgp-sign-with-sender <span style="color:#66d9ef">t</span>)
|
||||
</span></span><span style="display:flex;"><span> (setq notmuch-mua-user-agent-function <span style="color:#e6db74">'notmuch-mua-user-agent-full</span>)
|
||||
</span></span><span style="display:flex;"><span> (general-define-key
|
||||
</span></span><span style="display:flex;"><span> :keymaps <span style="color:#e6db74">'notmuch-search-mode-map</span>
|
||||
</span></span><span style="display:flex;"><span> :states <span style="color:#f92672">'</span>(normal)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"d"</span> <span style="color:#a6e22e">#'</span>my/notmuch-toggle-trash
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"i"</span> <span style="color:#a6e22e">#'</span>my/notmuch-toggle-inbox
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"u"</span> <span style="color:#a6e22e">#'</span>my/notmuch-toggle-unread)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; Use org-contacts for completion</span>
|
||||
</span></span><span style="display:flex;"><span> (require <span style="color:#e6db74">'org-contacts</span>)
|
||||
</span></span><span style="display:flex;"><span> (setq notmuch-address-command <span style="color:#e6db74">'as-is</span>)
|
||||
</span></span><span style="display:flex;"><span> (add-hook <span style="color:#e6db74">'notmuch-hello-mode-hook</span>
|
||||
</span></span><span style="display:flex;"><span> (lambda () (display-line-numbers-mode <span style="color:#ae81ff">0</span>))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-doom-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 to which this is tangled is read in the init.el.</p>
|
||||
<h3 id="saved-filters-and-keybindings">Saved filters and keybindings</h3>
|
||||
<p>I want to have the saved filters available in both notmuch interface as as keybindings. So a bit more of abusing org tables.</p>
|
||||
<p>Root keybindings:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(my-leader-def
|
||||
</span></span><span style="display:flex;"><span> :infix <span style="color:#e6db74">"am"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">""</span> <span style="color:#f92672">'</span>(:which-key <span style="color:#e6db74">"notmuch"</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"m"</span> (my/command-in-persp <span style="color:#e6db74">"notmuch"</span> <span style="color:#e6db74">"mail"</span> <span style="color:#ae81ff">0</span> (notmuch)))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">"am"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">""</span> <span style="color:#666">'</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">"notmuch"</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"m"</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><p><a id="table--root-tags"></a></p>
|
||||
<table>
|
||||
<thead>
|
||||
|
|
@ -562,63 +563,63 @@ Remove <code>TAG</code> from emails which are outside the matching <code>PATH</c
|
|||
</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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(let ((searches <span style="color:#f92672">'</span>()))
|
||||
</span></span><span style="display:flex;"><span> (dolist (root_tag root_tags)
|
||||
</span></span><span style="display:flex;"><span> (dolist (tag filter_tags)
|
||||
</span></span><span style="display:flex;"><span> (add-to-list
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'searches</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">"(:name \"%s\" :query \"%s\")"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">"%s (%s)"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> root_tag)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">2</span> tag))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">"tag:"</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> root_tag)
|
||||
</span></span><span style="display:flex;"><span> (unless (string-empty-p (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> tag))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">" AND tag:"</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> tag)))))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">t</span>)))
|
||||
</span></span><span style="display:flex;"><span> (string-join searches <span style="color:#e6db74">"\n"</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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\")"</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:#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><p>And the following does the same for my general.el definer:</p>
|
||||
<p><a id="code-snippet--format-notmuch-keybindings"></a></p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(let ((bindings <span style="color:#f92672">'</span>()))
|
||||
</span></span><span style="display:flex;"><span> (dolist (root_tag root_tags)
|
||||
</span></span><span style="display:flex;"><span> (add-to-list
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'bindings</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">"\"%s\" '(:which-key \"%s\")"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> root_tag)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">2</span> root_tag))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">t</span>)
|
||||
</span></span><span style="display:flex;"><span> (dolist (tag filter_tags)
|
||||
</span></span><span style="display:flex;"><span> (add-to-list
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'bindings</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">"\"%s\" (my/command-in-persp \"%s\" \"mail\" 0 (notmuch-search \"%s\"))"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">concat</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> root_tag) (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> tag))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">"tag:"</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> root_tag)
|
||||
</span></span><span style="display:flex;"><span> (unless (string-empty-p (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> tag))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">" AND tag:"</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> tag))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">2</span> tag))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">t</span>)))
|
||||
</span></span><span style="display:flex;"><span> (string-join bindings <span style="color:#e6db74">"\n"</span>))
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq notmuch-saved-searches
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">'</span>((:name <span style="color:#e6db74">"drafts"</span> :query <span style="color:#e6db74">"tag:draft"</span>)
|
||||
</span></span><span style="display:flex;"><span> <<format-notmuch-saved-searches()>>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">bindings</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:#19177c">add-to-list</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">'bindings</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">"\"%s\" '(:which-key \"%s\")"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">nth</span> <span style="color:#666">1</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">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">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">'bindings</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">"\"%s\" (my/command-in-persp \"%s\" \"mail\" 0 (notmuch-search \"%s\"))"</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:#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">nth</span> <span style="color:#666">2</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">bindings</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></span><span style="display:flex;"><span> <span style="color:#19177c"><<format-notmuch-saved-searches</span>()<span style="color:#19177c">>></span>))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(my-leader-def
|
||||
</span></span><span style="display:flex;"><span> :infix <span style="color:#e6db74">"am"</span>
|
||||
</span></span><span style="display:flex;"><span> <<format-notmuch-keybindings()>>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">"am"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c"><<format-notmuch-keybindings</span>()<span style="color:#19177c">>></span>)
|
||||
</span></span></code></pre></div><h3 id="signing-messages">Signing messages</h3>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(with-eval-after-load <span style="color:#e6db74">'notmuch</span>
|
||||
</span></span><span style="display:flex;"><span> (add-hook <span style="color:#e6db74">'message-setup-hook</span> <span style="color:#e6db74">'mml-secure-sign-pgpmime</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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>(setq mml-secure-key-preferences
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">'</span>((OpenPGP
|
||||
</span></span><span style="display:flex;"><span> (sign
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"thexcloud@gmail.com"</span> <span style="color:#e6db74">"914472A1FD6775C166F96EBEED739ADF81C78160"</span>))
|
||||
</span></span><span style="display:flex;"><span> (encrypt))
|
||||
</span></span><span style="display:flex;"><span> (CMS
|
||||
</span></span><span style="display:flex;"><span> (sign)
|
||||
</span></span><span style="display:flex;"><span> (encrypt))))
|
||||
</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><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="color:#f8f8f2;background-color:#272822;-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
|
||||
<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>
|
||||
|
|
@ -629,10 +630,10 @@ Remove <code>TAG</code> from emails which are outside the matching <code>PATH</c
|
|||
</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="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(my/format-guix-dependencies)
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#a6e22e">specifications->manifest</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">'</span>(
|
||||
</span></span><span style="display:flex;"><span> <<packages()>>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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>
|
||||
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
<hr>
|
||||
<div id="content">
|
||||
<div class="container">
|
||||
<h1>My dotfiles</h1>
|
||||
<figure><img src="https://forthebadge.com/images/badges/works-on-my-machine.svg"/>
|
||||
</figure>
|
||||
|
||||
|
|
@ -137,7 +138,7 @@
|
|||
</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="color:#f8f8f2;background-color:#272822;-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
|
||||
<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
|
||||
|
|
|
|||
BIN
ox-hugo/pdf-emacs.png
Normal file
|
After Width: | Height: | Size: 344 KiB |
BIN
ox-hugo/pdf-prot.png
Normal file
|
After Width: | Height: | Size: 671 KiB |
BIN
ox-hugo/pdf-subed.png
Normal file
|
After Width: | Height: | Size: 724 KiB |
|
|
@ -59,6 +59,7 @@
|
|||
<hr>
|
||||
<div id="content">
|
||||
<div class="container">
|
||||
<h1>Multiple Gmail accounts & labels with Emacs</h1>
|
||||
<h2 id="intro">Intro</h2>
|
||||
<p>For quite some time, e-mail seemed like an anomaly in my workflow. I am a long time Gmail user, and my decade-old account has a somewhat formidable quantity of labels and filters. My messages are often assigned multiple labels, and I also like to keep only a bunch of messages in the inbox.</p>
|
||||
<p>Although, in my opinion, Gmail web UI was and still is leagues ahead of many of its competitors and even allows keyboard-centric workflow, it’s awkward to use with a keyboard-driven browser, and for no money on Earth I would enable browser notifications.</p>
|
||||
|
|
@ -82,82 +83,82 @@
|
|||
<h3 id="lieer">lieer</h3>
|
||||
<p><a href="https://github.com/gauteh/lieer">lieer</a> (formerly gmailieer) is a program that uses Gmail API to download email and synchronize Gmail labels with notmuch tags. Because of its usage of Gmail API instead of IMAP, there are no problems with duplicating emails in different labels, etc.</p>
|
||||
<p>As I need to use multiple versions of Python & Node.js for other reasons, I manage my installations of them with <a href="https://anaconda.org">Anaconda</a> (Miniconda, to be precise). You may instead use <a href="https://docs.python.org/3/library/venv.html">venv</a> or even the system-wide installation of Python and omit the <code>conda</code> clauses, but in my experience Anaconda makes life easier in that regard.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#75715e"># Create an environment with the name "mail"</span>
|
||||
<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"># Create an environment with the name "mail"</span>
|
||||
</span></span><span style="display:flex;"><span>conda create --name mail
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Activate the environment</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># Activate the environment</span>
|
||||
</span></span><span style="display:flex;"><span>conda activate mail
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Install Python</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># Install Python</span>
|
||||
</span></span><span style="display:flex;"><span>conda install python
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Download and install lieer</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># Download and install lieer</span>
|
||||
</span></span><span style="display:flex;"><span>git clone https://github.com/gauteh/lieer.git
|
||||
</span></span><span style="display:flex;"><span>cd lieer
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">cd</span> lieer
|
||||
</span></span><span style="display:flex;"><span>pip install .
|
||||
</span></span></code></pre></div><p>After which we may check if the <code>gmi</code> executable is available:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>which gmi
|
||||
<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>which gmi
|
||||
</span></span></code></pre></div><h3 id="notmuch">Notmuch</h3>
|
||||
<p><a href="https://notmuchmail.org/">Notmuch</a> is present in most of the package repositories, so you can install it with your package manager, which is <code>pacman</code> in my case.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo pacman -S notmuch
|
||||
<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>sudo pacman -S notmuch
|
||||
</span></span></code></pre></div><p>After the installation, run <code>notmuch setup</code>. That will inquire the parameters and create the <code>.notmuch-config</code> file with the answers.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>Your full name <span style="color:#f92672">[</span>Pavel<span style="color:#f92672">]</span>: Pavel Korytov
|
||||
</span></span><span style="display:flex;"><span>Your primary email address <span style="color:#f92672">[</span>pavel@pdsk.<span style="color:#f92672">(</span>none<span style="color:#f92672">)]</span>: thexcloud@gmail.com
|
||||
</span></span><span style="display:flex;"><span>Additional email address <span style="color:#f92672">[</span>Press <span style="color:#e6db74">'Enter'</span> <span style="color:#66d9ef">if</span> none<span style="color:#f92672">]</span>:
|
||||
</span></span><span style="display:flex;"><span>Top-level directory of your email archive <span style="color:#f92672">[</span>/home/pavel/mail<span style="color:#f92672">]</span>: /home/pavel/Mail
|
||||
</span></span><span style="display:flex;"><span>Tags to apply to all new messages <span style="color:#f92672">(</span>separated by spaces<span style="color:#f92672">)</span> <span style="color:#f92672">[</span>unread inbox<span style="color:#f92672">]</span>: new
|
||||
</span></span><span style="display:flex;"><span>Tags to exclude when searching messages <span style="color:#f92672">(</span>separated by spaces<span style="color:#f92672">)</span> <span style="color:#f92672">[</span>deleted spam<span style="color:#f92672">]</span>:
|
||||
<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>Your full name <span style="color:#666">[</span>Pavel<span style="color:#666">]</span>: Pavel Korytov
|
||||
</span></span><span style="display:flex;"><span>Your primary email address <span style="color:#666">[</span>pavel@pdsk.<span style="color:#666">(</span>none<span style="color:#666">)]</span>: thexcloud@gmail.com
|
||||
</span></span><span style="display:flex;"><span>Additional email address <span style="color:#666">[</span>Press <span style="color:#ba2121">'Enter'</span> <span style="color:#008000;font-weight:bold">if</span> none<span style="color:#666">]</span>:
|
||||
</span></span><span style="display:flex;"><span>Top-level directory of your email archive <span style="color:#666">[</span>/home/pavel/mail<span style="color:#666">]</span>: /home/pavel/Mail
|
||||
</span></span><span style="display:flex;"><span>Tags to apply to all new messages <span style="color:#666">(</span>separated by spaces<span style="color:#666">)</span> <span style="color:#666">[</span>unread inbox<span style="color:#666">]</span>: new
|
||||
</span></span><span style="display:flex;"><span>Tags to exclude when searching messages <span style="color:#666">(</span>separated by spaces<span style="color:#666">)</span> <span style="color:#666">[</span>deleted spam<span style="color:#666">]</span>:
|
||||
</span></span></code></pre></div><p>It is important to set the <code>new</code> tag for the new messages instead of the default <code>unread</code> and <code>inbox</code>.</p>
|
||||
<p>Next, add the rule to ignore JSON files to the <code>[new]</code> section of the <code>.notmuch-config</code> file, so it would look like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#f92672">[</span>new<span style="color:#f92672">]</span>
|
||||
</span></span><span style="display:flex;"><span>tags<span style="color:#f92672">=</span>new
|
||||
</span></span><span style="display:flex;"><span>ignore<span style="color:#f92672">=</span>/.*<span style="color:#f92672">[</span>.<span style="color:#f92672">](</span>json|lock|bak<span style="color:#f92672">)</span>$/
|
||||
<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:#666">[</span>new<span style="color:#666">]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">tags</span><span style="color:#666">=</span>new
|
||||
</span></span><span style="display:flex;"><span><span style="color:#19177c">ignore</span><span style="color:#666">=</span>/.*<span style="color:#666">[</span>.<span style="color:#666">](</span>json|lock|bak<span style="color:#666">)</span>$/
|
||||
</span></span></code></pre></div><p>That is needed to ignore the lieer config files. Although, as I have noticed, notmuch is generally pretty good at detecting wrong files in its directories, an explicit ignore rule won’t hurt.</p>
|
||||
<p>Now, create the mail directory and run the <a href="https://notmuchmail.org/manpages/notmuch-new-1/">notmuch new</a> command. As notmuch has probably already noticed you, it uses the <a href="https://en.wikipedia.org/wiki/Maildir">maildir</a> format, which basically means that one message is stored in one file.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#75715e"># The same directory mentioned in the 4th question</span>
|
||||
<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"># The same directory mentioned in the 4th question</span>
|
||||
</span></span><span style="display:flex;"><span>mkdir ~/Mail
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Initialize notmuch</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># Initialize notmuch</span>
|
||||
</span></span><span style="display:flex;"><span>notmuch new
|
||||
</span></span></code></pre></div><h3 id="add-an-account">Add an account</h3>
|
||||
<p>After that, we can create a directory for a mail account and initialize lieer.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cd ~/Mail
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Use whatever name you want</span>
|
||||
<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> ~/Mail
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># Use whatever name you want</span>
|
||||
</span></span><span style="display:flex;"><span>mkdir thexcloud
|
||||
</span></span><span style="display:flex;"><span>cd thexcloud
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Intialize lieer</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">cd</span> thexcloud
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># Intialize lieer</span>
|
||||
</span></span><span style="display:flex;"><span>gmi init thexcloud@gmail.com
|
||||
</span></span></code></pre></div><p>Running <code>gmi init</code> will run an OAuth authentication to your Gmail account. The credentials will be stored in <code>.credentials.gmailieer.json</code> file, so make sure not to expose it somewhere.</p>
|
||||
<p>We also can add a few settings for lieer, which will make life easier. First, dots seem to be less awkward to type than slashes for the nested tags:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>gmi set --replace-slash-with-dot
|
||||
<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>gmi <span style="color:#008000">set</span> --replace-slash-with-dot
|
||||
</span></span></code></pre></div><p>Then, we don’t want the <code>new</code> tag to be pushed back to Gmail</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>gmi set --ignore-tags-local new
|
||||
<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>gmi <span style="color:#008000">set</span> --ignore-tags-local new
|
||||
</span></span></code></pre></div><p>Now we can finally download the mail directory. To initiate the download, run</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>gmi sync
|
||||
<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>gmi sync
|
||||
</span></span></code></pre></div><p>The first download can easily take several hours, depending on the size of your email and the speed of your internet connection, but subsequent runs will be much faster.</p>
|
||||
<p>The last thing to do here is to add the <code>gmi sync</code> command to notmuch’s <a href="https://notmuchmail.org/manpages/notmuch-hooks-5/">pre-new hook</a>, so that the email will be synchronized on the <code>notmuch new</code> command.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#75715e"># Create the hooks folder</span>
|
||||
<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"># Create the hooks folder</span>
|
||||
</span></span><span style="display:flex;"><span>mkdir -p ~/Mail/.notmuch/hooks
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Create the file</span>
|
||||
</span></span><span style="display:flex;"><span>cd ~/Mail/.notmuch/hooks
|
||||
</span></span><span style="display:flex;"><span>cat > pre-new <span style="color:#e6db74"><<EOF
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">#!/bin/bash
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">eval "$(conda shell.bash hook)"
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">conda activate mail
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">(cd /home/pavel/Mail/thexcloud/ && gmi sync)
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">EOF</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># Create the file</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">cd</span> ~/Mail/.notmuch/hooks
|
||||
</span></span><span style="display:flex;"><span>cat > pre-new <span style="color:#ba2121"><<EOF
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">#!/bin/bash
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">eval "$(conda shell.bash hook)"
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">conda activate mail
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">(cd /home/pavel/Mail/thexcloud/ && gmi sync)
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">EOF</span>
|
||||
</span></span><span style="display:flex;"><span>chmod +x pre-new
|
||||
</span></span></code></pre></div><p>Side note: as a hook for <code>conda</code> tends to be rather slow, I run the <code>gmi</code> command with system-wide Python as follows:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#75715e">#!/bin/bash
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>GMI<span style="color:#f92672">=</span><span style="color:#e6db74">"/home/pavel/Programs/miniconda3/envs/mail/bin/gmi"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>cd /home/pavel/Mail/thexcloud/ <span style="color:#f92672">&&</span> $GMI sync<span style="color:#f92672">)</span>
|
||||
<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/bash
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#bc7a00"></span><span style="color:#19177c">GMI</span><span style="color:#666">=</span><span style="color:#ba2121">"/home/pavel/Programs/miniconda3/envs/mail/bin/gmi"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#666">(</span><span style="color:#008000">cd</span> /home/pavel/Mail/thexcloud/ <span style="color:#666">&&</span> <span style="color:#19177c">$GMI</span> sync<span style="color:#666">)</span>
|
||||
</span></span></code></pre></div><p>Which doesn’t seem to cause any particular trouble in that case.</p>
|
||||
<h3 id="emacs">Emacs</h3>
|
||||
<p>There are plenty of different <a href="https://notmuchmail.org/frontends/">frontends</a> for notmuch (even GUI apps), but the one I’m sticking with the Emacs.</p>
|
||||
<p>Configuration for Emacs is pretty straightforward, but you probably want to use the notmuch package which came with the system package, because otherwise, you may end up with different versions of frontend and backend.</p>
|
||||
<p>That’s how it can be done with <code>use-package</code>:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package notmuch
|
||||
</span></span><span style="display:flex;"><span> :ensure <span style="color:#66d9ef">nil</span>
|
||||
</span></span><span style="display:flex;"><span> :commands (notmuch)
|
||||
</span></span><span style="display:flex;"><span> :config
|
||||
</span></span><span style="display:flex;"><span> (add-hook <span style="color:#e6db74">'notmuch-hello-mode-hook</span>
|
||||
</span></span><span style="display:flex;"><span> (lambda () (display-line-numbers-mode <span style="color:#ae81ff">0</span>))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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:#008000">:ensure</span> <span style="color:#800">nil</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">notmuch</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-hook</span> <span style="color:#19177c">'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 only notable observation here is that <code>display-line-numbers-mode</code> seems to break formatting of the <code>notmuch-hello</code> page.</p>
|
||||
<p>If you use evil-mode, you also should enable the <a href="https://github.com/emacs-evil/evil-collection/blob/master/modes/notmuch/evil-collection-notmuch.el">evil-collection mode for notmuch</a>.</p>
|
||||
<p>Now run <code>M-x notmuch</code> and the <code>notmuch-hello</code> page should appear. Running <code>notmuch-poll-and-refresh-this-buffer</code> (<code>gR</code> with evil bindings) will run the <code>notmuch new</code> command and refresh the buffer. All the syncronized messages should be present.</p>
|
||||
|
|
@ -165,7 +166,7 @@
|
|||
<h3 id="reading-mail">Reading mail</h3>
|
||||
<p><code>notmuch-search-show-thread</code> (<code>RET</code>) opens the thread under the cursor.</p>
|
||||
<p><code>notmuch-show-view-part</code> (<code>. v</code> with evil) opens an attachment with associations defined in <a href="https://linux.die.net/man/4/mailcap">.mailcap</a> file. Mine looks like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>audio/*; mpc add %s
|
||||
<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>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>
|
||||
|
|
@ -175,7 +176,7 @@
|
|||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>text/html; /usr/bin/xdg-open %s
|
||||
</span></span></code></pre></div><p>Here watch out for the last line, default version of which may be set as follows:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>text/html; /usr/bin/xdg-open %s ; copiousoutput
|
||||
<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>text/html; /usr/bin/xdg-open %s ; copiousoutput
|
||||
</span></span></code></pre></div><p>Which causes a temporary file to be deleted before it could be opened because recent versions of <code>xdg-open</code> do not block the input.</p>
|
||||
<p>As expected, Emacs mail reader does not trigger any <a href="https://www.emailprivacytester.com/">spy pixels or other tracking contents of email</a> (not any I know of, at least). However, opening an HTML email in a browser will even run embedded JavaScript. Therefore, <strong>in no case open emails you do not trust with <code>xdg-open</code></strong>. Even if you use NoScript, the browser will still load all the CSS, videos and even iframes, which can be used to track you.</p>
|
||||
<p>Even Gmail web UI is preferable to view the message in a browser, because the former blocks most of the malicious stuff and does not seem to leak your IP to the sender, for what it’s worth.</p>
|
||||
|
|
@ -184,107 +185,107 @@
|
|||
<p>After doing so, <code>C-c C-c</code> will run <code>notmuch-mua-send-and-exit</code>, which will invoke the function stated in the <code>message-send-mail-function</code> variable. The default value of the variable is <code>sendmail-query-once</code>, which will inquire the parameters and save them as custom variables.</p>
|
||||
<p>If SMTP is used, <code>send-mail-function</code> will be set to the one from the built-it <a href="https://www.emacswiki.org/emacs/SendingMail">smtpmail</a> package. SMTP parameters for Gmail are listed <a href="https://support.google.com/mail/answer/7126229?hl=en">here</a>.</p>
|
||||
<p>Authorization parameters will be saved to your <a href="https://www.emacswiki.org/emacs/GnusAuthinfo">authinfo</a> file. If you didn’t have one, the plaintext <code>.authinfo</code> will be created, so it’s reasonable to encrypt it:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cd ~
|
||||
<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></span><span style="display:flex;"><span>gpg -o .authinfo.gpg -c --cipher-algo AES256 .authinfo
|
||||
</span></span></code></pre></div><p>However, if you plan to use multiple accounts with different SMTP servers, it makes more sense to use something like <a href="https://marlam.de/msmtp/msmtp.html">MSMTP</a> to manage multiple accounts. Here are a couple of examples (<a href="https://www.reddit.com/r/emacs/comments/9piml5/a%5Ffew%5Fquick%5Femacsnotmuch%5Fquestions/e83zcck?utm%5Fsource=share&utm%5Fmedium=web2x&context=3">1</a>, <a href="https://www.reddit.com/r/emacs/comments/9piml5/a%5Ffew%5Fquick%5Femacsnotmuch%5Fquestions/e84otah?utm%5Fsource=share&utm%5Fmedium=web2x&context=3">2</a>) how to do that.</p>
|
||||
<p>Another alternative for Gmail is to use <a href="https://github.com/gauteh/lieer/wiki/GNU-Emacs-and-Lieer">lieer as sendmail program</a>. That may make sense if you don’t want to enable IMAP and SMTP on your account.</p>
|
||||
<p>There are also <a href="https://notmuchmail.org/emacstips/#index13h2">a bunch of ways</a> to set up address completion if the built-in completion based on notmuch database does not suffice.</p>
|
||||
<p>I also use <a href="https://github.com/mhayashi1120/Emacs-langtool">LanguageTool for Emacs</a> to do a spell checking of important emails (integrations like that really make Emacs shine). For some reason, developers don’t give a link to download the server on the frontpage, so <a href="https://dev.languagetool.org/http-server">here it is</a>. And here is the relevant part of my Emacs config:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package langtool
|
||||
</span></span><span style="display:flex;"><span> :straight <span style="color:#66d9ef">t</span>
|
||||
</span></span><span style="display:flex;"><span> :commands (langtool-check)
|
||||
</span></span><span style="display:flex;"><span> :config
|
||||
</span></span><span style="display:flex;"><span> (setq langtool-language-tool-server-jar <span style="color:#e6db74">"/home/pavel/Programs/LanguageTool-5.1/languagetool-server.jar"</span>)
|
||||
</span></span><span style="display:flex;"><span> (setq langtool-mother-tongue <span style="color:#e6db74">"ru"</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">langtool</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">langtool-check</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">langtool-language-tool-server-jar</span> <span style="color:#ba2121">"/home/pavel/Programs/LanguageTool-5.1/languagetool-server.jar"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">langtool-mother-tongue</span> <span style="color:#ba2121">"ru"</span>))
|
||||
</span></span></code></pre></div><p>As a last note here, to set up a signature create the <code>.signature</code> file in the <code>$HOME</code> directory. If you need more complex logic here, for instance, different signatures for different accounts, you can put an arbitrary expression to the <code>mail-signature</code> variable or apply <a href="https://notmuchmail.org/emacstips/#index16h2">this gnus-alias tip</a>.</p>
|
||||
<h2 id="another-account">Another account</h2>
|
||||
<h3 id="adding-an-account">Adding an account</h3>
|
||||
<p>Now we can send and receive mail from one account. Adding another account is also pretty easy.</p>
|
||||
<p>If another account is Gmail, the process starts the same as before:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#75715e"># Create a directory</span>
|
||||
<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"># Create a directory</span>
|
||||
</span></span><span style="display:flex;"><span>mkdir -p ~/Mail/progin6304
|
||||
</span></span><span style="display:flex;"><span>cd ~/Mail/progin6304
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># OAuth</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">cd</span> ~/Mail/progin6304
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># OAuth</span>
|
||||
</span></span><span style="display:flex;"><span>gmi init progin6304@gmail.com
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Settings</span>
|
||||
</span></span><span style="display:flex;"><span>gmi set --replace-slash-with-dot
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># Settings</span>
|
||||
</span></span><span style="display:flex;"><span>gmi <span style="color:#008000">set</span> --replace-slash-with-dot
|
||||
</span></span></code></pre></div><p>However, before running <code>gmi sync</code> for the second account, we want to make sure that we can distinguish the message from different accounts. To do that, I add the <code>main</code> for the main account and <code>progin</code> for the second account. We also don’t want these labels to be pushed:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cd ~/Mail/thexcloud
|
||||
</span></span><span style="display:flex;"><span>gmi set --ignore-tags-local new,mail,progin
|
||||
</span></span><span style="display:flex;"><span>cd ~/Mail/progin6304
|
||||
</span></span><span style="display:flex;"><span>gmi set --ignore-tags-local new,mail,progin
|
||||
<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> ~/Mail/thexcloud
|
||||
</span></span><span style="display:flex;"><span>gmi <span style="color:#008000">set</span> --ignore-tags-local new,mail,progin
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">cd</span> ~/Mail/progin6304
|
||||
</span></span><span style="display:flex;"><span>gmi <span style="color:#008000">set</span> --ignore-tags-local new,mail,progin
|
||||
</span></span></code></pre></div><p>Now we can use notmuch’s <code>post-new</code> hook to tag the messages based on their folder as follows:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cd ~/Mail/.notmuch/hooks
|
||||
</span></span><span style="display:flex;"><span>cat > post-new <span style="color:#e6db74"><<EOF
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">#!/bin/bash
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">notmuch tag +main "path:thexcloud/** AND tag:new"
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">notmuch tag +progin "path:progin6304/** AND tag:new"
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">notmuch tag -new "tag:new"
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">EOF</span>
|
||||
<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> ~/Mail/.notmuch/hooks
|
||||
</span></span><span style="display:flex;"><span>cat > post-new <span style="color:#ba2121"><<EOF
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">#!/bin/bash
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">notmuch tag +main "path:thexcloud/** AND tag:new"
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">notmuch tag +progin "path:progin6304/** AND tag:new"
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">notmuch tag -new "tag:new"
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">EOF</span>
|
||||
</span></span><span style="display:flex;"><span>chmod +x post-new
|
||||
</span></span></code></pre></div><p>Now it finally makes sense why we wanted to use the <code>new</code> tag in the first place. In principle, any kind of tagging logic can be applied here, but for the reasons I stated earlier, I prefer to set up filters in the Gmail web interface.</p>
|
||||
<p>The last thing to do is to modify the <code>pre-new</code> hook:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#75715e">#!/bin/bash
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>GMI<span style="color:#f92672">=</span><span style="color:#e6db74">"/home/pavel/Programs/miniconda3/envs/mail/bin/gmi"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>cd /home/pavel/Mail/thexcloud/ <span style="color:#f92672">&&</span> $GMI sync<span style="color:#f92672">)</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>cd /home/pavel/Mail/progin6304/ <span style="color:#f92672">&&</span> $GMI sync<span style="color:#f92672">)</span>
|
||||
<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/bash
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#bc7a00"></span><span style="color:#19177c">GMI</span><span style="color:#666">=</span><span style="color:#ba2121">"/home/pavel/Programs/miniconda3/envs/mail/bin/gmi"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#666">(</span><span style="color:#008000">cd</span> /home/pavel/Mail/thexcloud/ <span style="color:#666">&&</span> <span style="color:#19177c">$GMI</span> sync<span style="color:#666">)</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#666">(</span><span style="color:#008000">cd</span> /home/pavel/Mail/progin6304/ <span style="color:#666">&&</span> <span style="color:#19177c">$GMI</span> sync<span style="color:#666">)</span>
|
||||
</span></span></code></pre></div><p>After which we can finally tag the existing messages and download ones from the new account</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#e6db74">"path:thexcloud/**"</span>
|
||||
<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/**"</span>
|
||||
</span></span><span style="display:flex;"><span>notmuch new
|
||||
</span></span></code></pre></div><p>The obvious problem, however, is that the messages are fetched sequentially, which is rather slow. A solution is to use something like <a href="http://www.gnu.org/software/parallel/">GNU Parallel</a>:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#75715e">#!/bin/bash
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>GMI<span style="color:#f92672">=</span><span style="color:#e6db74">"/home/pavel/Programs/miniconda3/envs/mail/bin/gmi"</span>
|
||||
</span></span><span style="display:flex;"><span>parallel -j0 <span style="color:#e6db74">"(cd /home/pavel/Mail/{}/ && </span>$GMI<span style="color:#e6db74"> sync)"</span> ::: thexcloud progin6304
|
||||
<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/bash
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#bc7a00"></span><span style="color:#19177c">GMI</span><span style="color:#666">=</span><span style="color:#ba2121">"/home/pavel/Programs/miniconda3/envs/mail/bin/gmi"</span>
|
||||
</span></span><span style="display:flex;"><span>parallel -j0 <span style="color:#ba2121">"(cd /home/pavel/Mail/{}/ && </span><span style="color:#19177c">$GMI</span><span style="color:#ba2121"> sync)"</span> ::: thexcloud progin6304
|
||||
</span></span></code></pre></div><p>I haven’t encountered any trouble with that solution so far (and I don’t see anything thread-unsafe in the lieer code), but I’ll keep an eye on that.</p>
|
||||
<p>In principle, it shouldn’t be too hard to add a normal IMAP account as well with <a href="https://isync.sourceforge.io/mbsync.html">mbsync</a>, but I expect it would require something like iterating through the directory structure and assigning notmuch labels based on that. I’ll probably try that some time in the future.</p>
|
||||
<h3 id="emacs">Emacs</h3>
|
||||
<p>With that done, I also want separate entries on the start page for each of the accounts. Doing that is easy enough, just modify the <code>notmuch-saved-searches</code> variable with <code>customize-group</code> or like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq notmuch-saved-searches
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">'</span>((:name <span style="color:#e6db74">"inbox (main)"</span> :query <span style="color:#e6db74">"tag:inbox AND tag:main"</span>)
|
||||
</span></span><span style="display:flex;"><span> (:name <span style="color:#e6db74">"unread (main)"</span> :query <span style="color:#e6db74">"tag:unread AND tag:main"</span>)
|
||||
</span></span><span style="display:flex;"><span> (:name <span style="color:#e6db74">"sent (main)"</span> :query <span style="color:#e6db74">"tag:sent AND tag:main"</span>)
|
||||
</span></span><span style="display:flex;"><span> (:name <span style="color:#e6db74">"all mail (main)"</span> :query <span style="color:#e6db74">"tag:main"</span>)
|
||||
</span></span><span style="display:flex;"><span> (:name <span style="color:#e6db74">"inbox (progin)"</span> :query <span style="color:#e6db74">"tag:inbox AND tag:progin"</span>)
|
||||
</span></span><span style="display:flex;"><span> (:name <span style="color:#e6db74">"unread (progin)"</span> :query <span style="color:#e6db74">"tag:unread AND tag:progin"</span>)
|
||||
</span></span><span style="display:flex;"><span> (:name <span style="color:#e6db74">"sent (progin)"</span> :query <span style="color:#e6db74">"tag:sent AND tag:progin"</span>)
|
||||
</span></span><span style="display:flex;"><span> (:name <span style="color:#e6db74">"all main (progin)"</span> :query <span style="color:#e6db74">"tag:progin"</span>)
|
||||
</span></span><span style="display:flex;"><span> (:name <span style="color:#e6db74">"drafts"</span> :query <span style="color:#e6db74">"tag:draft"</span>)))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">"inbox (main)"</span> <span style="color:#008000">:query</span> <span style="color:#ba2121">"tag:inbox AND tag:main"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:name</span> <span style="color:#ba2121">"unread (main)"</span> <span style="color:#008000">:query</span> <span style="color:#ba2121">"tag:unread AND tag:main"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:name</span> <span style="color:#ba2121">"sent (main)"</span> <span style="color:#008000">:query</span> <span style="color:#ba2121">"tag:sent AND tag:main"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:name</span> <span style="color:#ba2121">"all mail (main)"</span> <span style="color:#008000">:query</span> <span style="color:#ba2121">"tag:main"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:name</span> <span style="color:#ba2121">"inbox (progin)"</span> <span style="color:#008000">:query</span> <span style="color:#ba2121">"tag:inbox AND tag:progin"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:name</span> <span style="color:#ba2121">"unread (progin)"</span> <span style="color:#008000">:query</span> <span style="color:#ba2121">"tag:unread AND tag:progin"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:name</span> <span style="color:#ba2121">"sent (progin)"</span> <span style="color:#008000">:query</span> <span style="color:#ba2121">"tag:sent AND tag:progin"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">:name</span> <span style="color:#ba2121">"all main (progin)"</span> <span style="color:#008000">:query</span> <span style="color:#ba2121">"tag:progin"</span>)
|
||||
</span></span><span style="display:flex;"><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></span></code></pre></div><h2 id="notification-for-new-messages">Notification for new messages</h2>
|
||||
<p>Now, we can send and receive mail, but we also probably want notifications for new emails. To do that, I wrote a simple script:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#75715e">#!/bin/bash
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e"># To run notify-send from cron</span>
|
||||
</span></span><span style="display:flex;"><span>export DISPLAY<span style="color:#f92672">=</span>:0
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># A file with last time of sync</span>
|
||||
</span></span><span style="display:flex;"><span>CHECK_FILE<span style="color:#f92672">=</span><span style="color:#e6db74">"/home/pavel/Mail/.last_check"</span>
|
||||
</span></span><span style="display:flex;"><span>QUERY<span style="color:#f92672">=</span><span style="color:#e6db74">"tag:unread"</span>
|
||||
</span></span><span style="display:flex;"><span>ALL_QUERY<span style="color:#f92672">=</span><span style="color:#e6db74">"tag:unread"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e"># If the file exists, check also the new messages from the last sync</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> -f <span style="color:#e6db74">"</span>$CHECK_FILE<span style="color:#e6db74">"</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
|
||||
</span></span><span style="display:flex;"><span> DATE<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>cat <span style="color:#e6db74">"</span>$CHECK_FILE<span style="color:#e6db74">"</span><span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span> QUERY<span style="color:#f92672">=</span><span style="color:#e6db74">"</span>$QUERY<span style="color:#e6db74"> and date:@</span>$DATE<span style="color:#e6db74">.."</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
|
||||
<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/bash
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#bc7a00"></span><span style="color:#408080;font-style:italic"># To run notify-send from cron</span>
|
||||
</span></span><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:#408080;font-style:italic"># A file with last time of sync</span>
|
||||
</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:#408080;font-style:italic"># If the file exists, check also the new messages from the last sync</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>NEW_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>notmuch count <span style="color:#e6db74">"</span>$QUERY<span style="color:#e6db74">"</span><span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span>ALL_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>notmuch count <span style="color:#e6db74">"</span>$ALL_QUERY<span style="color:#e6db74">"</span><span style="color:#66d9ef">)</span>
|
||||
</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:#75715e"># I don't really care if there are unread messages for which I've already seen a notification</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> $NEW_UNREAD -gt <span style="color:#ae81ff">0</span> <span style="color:#f92672">]</span>; <span style="color:#66d9ef">then</span>
|
||||
</span></span><span style="display:flex;"><span> MAIN_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>notmuch count <span style="color:#e6db74">"tag:unread AND tag:main"</span><span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span> PROGIN_UNREAD<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>notmuch count <span style="color:#e6db74">"tag:unread AND tag:progin"</span><span style="color:#66d9ef">)</span>
|
||||
</span></span><span style="display:flex;"><span> read -r -d <span style="color:#e6db74">''</span> NOTIFICATION <span style="color:#e6db74"><<EOM
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$NEW_UNREAD new messages
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$MAIN_UNREAD thexcloud@gmail.com
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$PROGIN_UNREAD progin6304@gmail.com
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">$ALL_UNREAD total
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">EOM</span>
|
||||
</span></span><span style="display:flex;"><span> notify-send <span style="color:#e6db74">"New Mail"</span> <span style="color:#e6db74">"</span>$NOTIFICATION<span style="color:#e6db74">"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># I don't really care if there are unread messages for which I've already seen a notification</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:#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">$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:#75715e"># Save sync timestamp</span>
|
||||
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">"</span><span style="color:#66d9ef">$(</span>date +%s<span style="color:#66d9ef">)</span><span style="color:#e6db74">"</span> > $CHECK_FILE
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic"># Save sync timestamp</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 launched with cron every 5 minutes:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>*/5 * * * * bash /home/pavel/bin/scripts/check-email
|
||||
<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>*/5 * * * * bash /home/pavel/bin/scripts/check-email
|
||||
</span></span></code></pre></div><p>Here’s how the notification looks like:
|
||||
<img src="/ox-hugo/notification.png" alt=""></p>
|
||||
<h2 id="caveats">Caveats</h2>
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
<hr>
|
||||
<div id="content">
|
||||
<div class="container">
|
||||
<h1>Replacing Jupyter Notebook with Org Mode</h1>
|
||||
<figure><img src="/ox-hugo/org-python-screenshot.png"/>
|
||||
</figure>
|
||||
|
||||
|
|
@ -88,65 +89,65 @@
|
|||
<h2 id="basic-setup">Basic setup</h2>
|
||||
<p>The core package to this whole venture is <a href="https://github.com/nnicandro/emacs-jupyter">emacs-jupyter</a> (another notable alternative <a href="https://github.com/millejoh/emacs-ipython-notebook">ein</a>, using which can help with the collaboration problem).</p>
|
||||
<p>Install it however you install packages in Emacs, here is my preferred way with <code>use-package</code> and <code>straight.el</code>:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package jupyter
|
||||
</span></span><span style="display:flex;"><span> :straight <span style="color:#66d9ef">t</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">jupyter</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
|
||||
</span></span></code></pre></div><p>Then, we have to enable languages for <code>org-babel</code>. Put the following in your org mode config section:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(org-babel-do-load-languages
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'org-babel-load-languages</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">'</span>((emacs-lisp <span style="color:#f92672">.</span> <span style="color:#66d9ef">t</span>) <span style="color:#75715e">;; Other languages</span>
|
||||
</span></span><span style="display:flex;"><span> (shell <span style="color:#f92672">.</span> <span style="color:#66d9ef">t</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; Python & Jupyter</span>
|
||||
</span></span><span style="display:flex;"><span> (python <span style="color:#f92672">.</span> <span style="color:#66d9ef">t</span>)
|
||||
</span></span><span style="display:flex;"><span> (jupyter <span style="color:#f92672">.</span> <span style="color:#66d9ef">t</span>)))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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-babel-do-load-languages</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">'org-babel-load-languages</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>((<span style="color:#19177c">emacs-lisp</span> <span style="color:#666">.</span> <span style="color:#800">t</span>) <span style="color:#408080;font-style:italic">;; Other languages</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">shell</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Python & Jupyter</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">python</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">jupyter</span> <span style="color:#666">.</span> <span style="color:#800">t</span>)))
|
||||
</span></span></code></pre></div><p>Now, you should be able to use source blocks with names like <code>jupyter-LANG</code>, e.g. <code>jupyter-python</code>. To use just <code>LANG</code> src blocks, call the following function after <code>org-babel-do-load-languages</code>:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(org-babel-jupyter-override-src-block <span style="color:#e6db74">"python"</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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-babel-jupyter-override-src-block</span> <span style="color:#ba2121">"python"</span>)
|
||||
</span></span></code></pre></div><p>That overrides the built-in <code>python</code> block with <code>jupyter-python</code>.</p>
|
||||
<p>If you use <a href="https://github.com/astahlman/ob-async">ob-async</a>, you have to set <code>jupyter-LANG</code> blocks as ignored by this package, because emacs-jupyter has async execution of its own.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq ob-async-no-async-languages-alist <span style="color:#f92672">'</span>(<span style="color:#e6db74">"python"</span> <span style="color:#e6db74">"jupyter-python"</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">ob-async-no-async-languages-alist</span> <span style="color:#666">'</span>(<span style="color:#ba2121">"python"</span> <span style="color:#ba2121">"jupyter-python"</span>))
|
||||
</span></span></code></pre></div><h2 id="environments">Environments</h2>
|
||||
<p>So, we’ve set up a basic emacs-jupyter configuration.</p>
|
||||
<p>The catch here is that Jupyter should be available on Emacs startup (at the time of evaluation of the <code>emacs-jupyter</code> package, to be precise). That means, if you are launching Emacs with something like an application launcher, global Python & Jupyter will be used.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">import</span> sys
|
||||
</span></span><span style="display:flex;"><span>sys<span style="color:#f92672">.</span>executable
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/usr/bin/python3
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">sys</span>
|
||||
</span></span><span style="display:flex;"><span>sys<span style="color:#666">.</span>executable
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/usr/bin/python3
|
||||
</span></span></code></pre></div><p>Which is probably not what we want. To resolve that, we have to make the right Python available at the required time.</p>
|
||||
<h3 id="anaconda">Anaconda</h3>
|
||||
<p>If you were using Jupyter Lab or Notebook before, there is a good chance you install it via <a href="https://anaconda.org/">Anaconda</a>. If not, in a nutshell, it is a package & environment manager, which specializes in Python & R, but also supports a whole lot of stuff like Node.js. In my opinion, it is the easiest way to manage multiple Python installations if you don’t use some advanced package manager like Guix.</p>
|
||||
<p>As one may expect, there is an Emacs package called <a href="https://github.com/necaris/conda.el">conda.el</a> to help working with conda environments in Emacs. We have to put it somewhere before the <code>emacs-jupyter</code> package and call <code>conda-env-activate</code>:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package conda
|
||||
</span></span><span style="display:flex;"><span> :straight <span style="color:#66d9ef">t</span>
|
||||
</span></span><span style="display:flex;"><span> :config
|
||||
</span></span><span style="display:flex;"><span> (setq conda-anaconda-home (<span style="color:#a6e22e">expand-file-name</span> <span style="color:#e6db74">"~/Programs/miniconda3/"</span>))
|
||||
</span></span><span style="display:flex;"><span> (setq conda-env-home-directory (<span style="color:#a6e22e">expand-file-name</span> <span style="color:#e6db74">"~/Programs/miniconda3/"</span>))
|
||||
</span></span><span style="display:flex;"><span> (setq conda-env-subdirectory <span style="color:#e6db74">"envs"</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">conda</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">conda-anaconda-home</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">"~/Programs/miniconda3/"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">conda-env-home-directory</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">"~/Programs/miniconda3/"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">conda-env-subdirectory</span> <span style="color:#ba2121">"envs"</span>))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(unless (getenv <span style="color:#e6db74">"CONDA_DEFAULT_ENV"</span>)
|
||||
</span></span><span style="display:flex;"><span> (conda-env-activate <span style="color:#e6db74">"base"</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">unless</span> (<span style="color:#19177c">getenv</span> <span style="color:#ba2121">"CONDA_DEFAULT_ENV"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">conda-env-activate</span> <span style="color:#ba2121">"base"</span>))
|
||||
</span></span></code></pre></div><p>If you have Anaconda installed on a custom path, as I do, you’d have to add these <code>setq</code> lines in the <code>:config</code> section. Also, there is no point in activating the environment if Emacs is somehow already launched in an environment.</p>
|
||||
<p>That’ll give us Jupyter from a base conda environment.</p>
|
||||
<p>If you use a plain virtual environment, you can use <a href="https://github.com/porterjamesj/virtualenvwrapper.el">virtualenvwrapper.el</a>, which is similar in its design to conda.el (or, rather, the other way round).</p>
|
||||
<h3 id="switching-an-environment">Switching an environment</h3>
|
||||
<p>However, as you will notice rather soon, <code>emacs-jupyter</code> will always use the Python kernel found on startup. So if you switch to a new environment, the code will still be running in the old one, which is not too convenient.</p>
|
||||
<p>Fortunately, to fix that we have only to force the refresh of Jupyter kernelspecs:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/jupyter-refresh-kernelspecs ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Refresh Jupyter kernelspecs"</span>
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (jupyter-available-kernelspecs <span style="color:#66d9ef">t</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/jupyter-refresh-kernelspecs</span> ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Refresh Jupyter kernelspecs"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">jupyter-available-kernelspecs</span> <span style="color:#800">t</span>))
|
||||
</span></span></code></pre></div><p>Calling <code>M-x my/jupyter-refresh-kernelspecs</code> after an environment switch will give you a new kernel. Just keep in mind that a kernelspec seems to be attached to a session, so you’d also have to change the session name to get a new kernel.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">import</span> sys
|
||||
</span></span><span style="display:flex;"><span>sys<span style="color:#f92672">.</span>executable
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/home/pavel/Programs/miniconda3/bin/python
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(conda-env-activate <span style="color:#e6db74">"ann"</span>)
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">import</span> sys
|
||||
</span></span><span style="display:flex;"><span>sys<span style="color:#f92672">.</span>executable
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/home/pavel/Programs/miniconda3/bin/python
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(my/jupyter-refresh-kernelspecs)
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">import</span> sys
|
||||
</span></span><span style="display:flex;"><span>sys<span style="color:#f92672">.</span>executable
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/home/pavel/Programs/miniconda3/envs/ann/bin/python
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">sys</span>
|
||||
</span></span><span style="display:flex;"><span>sys<span style="color:#666">.</span>executable
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/home/pavel/Programs/miniconda3/bin/python
|
||||
</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">conda-env-activate</span> <span style="color:#ba2121">"ann"</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-python" data-lang="python"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">sys</span>
|
||||
</span></span><span style="display:flex;"><span>sys<span style="color:#666">.</span>executable
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/home/pavel/Programs/miniconda3/bin/python
|
||||
</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/jupyter-refresh-kernelspecs</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-python" data-lang="python"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">sys</span>
|
||||
</span></span><span style="display:flex;"><span>sys<span style="color:#666">.</span>executable
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>/home/pavel/Programs/miniconda3/envs/ann/bin/python
|
||||
</span></span></code></pre></div><h2 id="programming">Programming</h2>
|
||||
<p>To test if everything is working correctly, run <code>M-x jupyter-run-repl</code>, which should give you a REPL with a chosen kernel. If so, we can finally start using Python in org mode.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src python :session hello :async yes
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src python :session hello :async yes
|
||||
</span></span><span style="display:flex;"><span>print('Hello, world!')
|
||||
</span></span><span style="display:flex;"><span>#+end_src
|
||||
</span></span><span style="display:flex;"><span>
|
||||
|
|
@ -154,11 +155,11 @@
|
|||
</span></span><span style="display:flex;"><span>: Hello, world!
|
||||
</span></span><span style="display:flex;"><span>#+end_src
|
||||
</span></span></code></pre></div><p>To avoid repeating similar arguments for the src block, we can set the <code>header-args</code> property at the start of the file:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+PROPERTY: header-args:python :session hello
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+PROPERTY: header-args:python :session hello
|
||||
</span></span><span style="display:flex;"><span>#+PROPERTY: header-args:python+ :async yes
|
||||
</span></span></code></pre></div><p>When a kernel is initialized, an associated REPL buffer is also created with a name like <code>*jupyter-repl[python 3.9.2]-hello*</code>.</p>
|
||||
<p>One advantage of emacs-jupyter over the standard Org source execution is that kernel requests for input are queried through the minibuffer. So, you can run a code like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src python
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src python
|
||||
</span></span><span style="display:flex;"><span>name = input('Name: ')
|
||||
</span></span><span style="display:flex;"><span>print(f'Hello, {name}!')
|
||||
</span></span><span style="display:flex;"><span>#+end_src
|
||||
|
|
@ -169,7 +170,7 @@
|
|||
<h2 id="code-output">Code output</h2>
|
||||
<h3 id="images">Images</h3>
|
||||
<p>Image output should work out of the box. Run <code>M-x org-toggle-inline-images</code> (<code>C-c C-x C-v</code>) after the execution to see the image inline.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src python
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src python
|
||||
</span></span><span style="display:flex;"><span>import matplotlib.pyplot as plt
|
||||
</span></span><span style="display:flex;"><span>fig, ax = plt.subplots()
|
||||
</span></span><span style="display:flex;"><span>ax.plot([1, 2, 3, 4], [1, 4, 2, 3])
|
||||
|
|
@ -179,9 +180,9 @@
|
|||
</span></span><span style="display:flex;"><span>#+RESULTS:
|
||||
</span></span><span style="display:flex;"><span>[[file:./.ob-jupyter/86b3c5e1bbaee95d62610e1fb9c7e755bf165190.png]]
|
||||
</span></span></code></pre></div><p>There is some room for improvement though. First, you can add the following hook if you don’t want to press this awkward keybinding every time:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-hook <span style="color:#e6db74">'org-babel-after-execute-hook</span> <span style="color:#e6db74">'org-redisplay-inline-images</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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">'org-babel-after-execute-hook</span> <span style="color:#19177c">'org-redisplay-inline-images</span>)
|
||||
</span></span></code></pre></div><p>Second, we may override the image save path like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src python :file img/hello.png
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src python :file img/hello.png
|
||||
</span></span><span style="display:flex;"><span>import matplotlib.pyplot as plt
|
||||
</span></span><span style="display:flex;"><span>fig, ax = plt.subplots()
|
||||
</span></span><span style="display:flex;"><span>ax.plot([1, 2, 3, 4], [1, 4, 2, 3])
|
||||
|
|
@ -192,15 +193,15 @@
|
|||
</span></span><span style="display:flex;"><span>[[file:img/hello.png]]
|
||||
</span></span></code></pre></div><p>That can save you a <code>savefig</code> call if the image has to be used somewhere further.</p>
|
||||
<p>Finally, by default, the image has a transparent background and a ridiculously small size. That can be fixed with some matplotlib settings:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">import</span> matplotlib <span style="color:#66d9ef">as</span> mpl
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">matplotlib</span> <span style="color:#008000;font-weight:bold">as</span> <span style="color:#00f;font-weight:bold">mpl</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>mpl<span style="color:#f92672">.</span>rcParams[<span style="color:#e6db74">'figure.dpi'</span>] <span style="color:#f92672">=</span> <span style="color:#ae81ff">200</span>
|
||||
</span></span><span style="display:flex;"><span>mpl<span style="color:#f92672">.</span>rcParams[<span style="color:#e6db74">'figure.facecolor'</span>] <span style="color:#f92672">=</span> <span style="color:#e6db74">'1'</span>
|
||||
</span></span><span style="display:flex;"><span>mpl<span style="color:#666">.</span>rcParams[<span style="color:#ba2121">'figure.dpi'</span>] <span style="color:#666">=</span> <span style="color:#666">200</span>
|
||||
</span></span><span style="display:flex;"><span>mpl<span style="color:#666">.</span>rcParams[<span style="color:#ba2121">'figure.facecolor'</span>] <span style="color:#666">=</span> <span style="color:#ba2121">'1'</span>
|
||||
</span></span></code></pre></div><p>At the same time, we can set the image width to prevent images from becoming too large. I prefer to do it inside a <code>emacs-lisp</code> code block in the same org file:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq-local org-image-actual-width <span style="color:#f92672">'</span>(<span style="color:#ae81ff">1024</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-local</span> <span style="color:#19177c">org-image-actual-width</span> <span style="color:#666">'</span>(<span style="color:#666">1024</span>))
|
||||
</span></span></code></pre></div><h3 id="basic-tables">Basic tables</h3>
|
||||
<p>If you are evaluating something like pandas DataFrame, it will be outputted in the HTML format, wrapped in the <code>begin_export</code> block. To view the data in text format, you can set <code>:display plain</code>:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src python :display plain
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src python :display plain
|
||||
</span></span><span style="display:flex;"><span>import pandas as pd
|
||||
</span></span><span style="display:flex;"><span>pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
||||
</span></span><span style="display:flex;"><span>#+end_src
|
||||
|
|
@ -210,7 +211,7 @@
|
|||
</span></span><span style="display:flex;"><span>: 0 1 3
|
||||
</span></span><span style="display:flex;"><span>: 1 2 4
|
||||
</span></span></code></pre></div><p>Another solution is to use something like the <a href="https://pypi.org/project/tabulate/">tabulate</a> package:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src python
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src python
|
||||
</span></span><span style="display:flex;"><span>import pandas as pd
|
||||
</span></span><span style="display:flex;"><span>import tabulate
|
||||
</span></span><span style="display:flex;"><span>df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
||||
|
|
@ -224,7 +225,7 @@
|
|||
</span></span><span style="display:flex;"><span>: | 1 | 2 | 4 |
|
||||
</span></span></code></pre></div><h3 id="html-and-other-rich-output">HTML & other rich output</h3>
|
||||
<p>Yet another solution is to use emacs-jupyter’s option <code>:pandoc t</code>, which invokes pandoc to convert HTML, LaTeX, and Markdown to Org. Predictably, this is slower than the options above.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src python :pandoc t
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src python :pandoc t
|
||||
</span></span><span style="display:flex;"><span>import pandas as pd
|
||||
</span></span><span style="display:flex;"><span>df = pd.DataFrame({"a": [1, 2], "b": [3, 4]})
|
||||
</span></span><span style="display:flex;"><span>df
|
||||
|
|
@ -239,24 +240,24 @@
|
|||
</span></span><span style="display:flex;"><span>:END:
|
||||
</span></span></code></pre></div><p>Also, every once in a while I have to view an actual, unconverted HTML in a browser, e.g. when using <a href="https://python-visualization.github.io/folium/">folium</a> or <a href="https://spacy.io/usage/visualizers">displaCy</a>.</p>
|
||||
<p>To do that, I’ve written a small function, which performs <code>xdg-open</code> on the HTML export block under the cursor:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq my/org-view-html-tmp-dir <span style="color:#e6db74">"/tmp/org-html-preview/"</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/org-view-html-tmp-dir</span> <span style="color:#ba2121">"/tmp/org-html-preview/"</span>)
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(use-package f
|
||||
</span></span><span style="display:flex;"><span> :straight <span style="color:#66d9ef">t</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">f</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(defun my/org-view-html ()
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (let ((elem (org-element-at-point))
|
||||
</span></span><span style="display:flex;"><span> (temp-file-path (<span style="color:#a6e22e">concat</span> my/org-view-html-tmp-dir (<span style="color:#a6e22e">number-to-string</span> (<span style="color:#a6e22e">random</span> (<span style="color:#a6e22e">expt</span> <span style="color:#ae81ff">2</span> <span style="color:#ae81ff">32</span>))) <span style="color:#e6db74">".html"</span>)))
|
||||
</span></span><span style="display:flex;"><span> (cond
|
||||
</span></span><span style="display:flex;"><span> ((not (<span style="color:#a6e22e">eq</span> <span style="color:#e6db74">'export-block</span> (<span style="color:#a6e22e">car</span> elem)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">message</span> <span style="color:#e6db74">"Not in an export block!"</span>))
|
||||
</span></span><span style="display:flex;"><span> ((not (<span style="color:#a6e22e">string-equal</span> (<span style="color:#a6e22e">plist-get</span> (<span style="color:#a6e22e">car</span> (<span style="color:#a6e22e">cdr</span> elem)) :type) <span style="color:#e6db74">"HTML"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">message</span> <span style="color:#e6db74">"Export block is not HTML!"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#66d9ef">t</span> (progn
|
||||
</span></span><span style="display:flex;"><span> (f-mkdir my/org-view-html-tmp-dir)
|
||||
</span></span><span style="display:flex;"><span> (f-write (<span style="color:#a6e22e">plist-get</span> (<span style="color:#a6e22e">car</span> (<span style="color:#a6e22e">cdr</span> elem)) :value) <span style="color:#e6db74">'utf-8</span> temp-file-path)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">start-process</span> <span style="color:#e6db74">"org-html-preview"</span> <span style="color:#66d9ef">nil</span> <span style="color:#e6db74">"xdg-open"</span> temp-file-path))))))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/org-view-html</span> ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">elem</span> (<span style="color:#19177c">org-element-at-point</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">temp-file-path</span> (<span style="color:#00f">concat</span> <span style="color:#19177c">my/org-view-html-tmp-dir</span> (<span style="color:#00f">number-to-string</span> (<span style="color:#00f">random</span> (<span style="color:#00f">expt</span> <span style="color:#666">2</span> <span style="color:#666">32</span>))) <span style="color:#ba2121">".html"</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
|
||||
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">not</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">'export-block</span> (<span style="color:#00f">car</span> <span style="color:#19177c">elem</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">"Not in an export block!"</span>))
|
||||
</span></span><span style="display:flex;"><span> ((<span style="color:#19177c">not</span> (<span style="color:#00f">string-equal</span> (<span style="color:#00f">plist-get</span> (<span style="color:#00f">car</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">elem</span>)) <span style="color:#008000">:type</span>) <span style="color:#ba2121">"HTML"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">message</span> <span style="color:#ba2121">"Export block is not HTML!"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> (<span style="color:#008000">progn</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">f-mkdir</span> <span style="color:#19177c">my/org-view-html-tmp-dir</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">f-write</span> (<span style="color:#00f">plist-get</span> (<span style="color:#00f">car</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">elem</span>)) <span style="color:#008000">:value</span>) <span style="color:#19177c">'utf-8</span> <span style="color:#19177c">temp-file-path</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">start-process</span> <span style="color:#ba2121">"org-html-preview"</span> <span style="color:#800">nil</span> <span style="color:#ba2121">"xdg-open"</span> <span style="color:#19177c">temp-file-path</span>))))))
|
||||
</span></span></code></pre></div><p><code>f.el</code> is used by a lot of packages, including the above-mentioned <code>conda.el</code>, so you probably already have it installed.</p>
|
||||
<p>Put a cursor on the <code>begin_export html</code> block and run <code>M-x my/org-view-html</code>.</p>
|
||||
<p>There also <a href="https://github.com/nnicandro/emacs-jupyter#building-the-widget-support-experimental">seems to be widgets support</a> in emacs-jupyter, but I wasn’t able to make it work.</p>
|
||||
|
|
@ -265,9 +266,9 @@
|
|||
<p>However, there are standalone packages to view dataframes. One I can point out is <a href="https://github.com/man-group/dtale">dtale</a>, which is a Flask + React app designed just for that purpose. It has a rather extensive list of features, including charting, basic statistical instruments, filters, etc. <a href="http://alphatechadmin.pythonanywhere.com/dtale/main/1">Here</a> is an online demo.</p>
|
||||
<p>The problem here is that it’s a browser app, which means it defies one of the purposes of using Org Mode in the first place. What’s more, this application is a rather huge one with lots of dependencies, and they have to be installed in the same environment as your project.</p>
|
||||
<p>So this approach has its pros and cons as well. Example usage is as follows:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">import</span> dtale
|
||||
</span></span><span style="display:flex;"><span>d <span style="color:#f92672">=</span> dtale<span style="color:#f92672">.</span>show(df)
|
||||
</span></span><span style="display:flex;"><span>d<span style="color:#f92672">.</span>open_browser() <span style="color:#75715e"># Or get an URL from d._url</span>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">dtale</span>
|
||||
</span></span><span style="display:flex;"><span>d <span style="color:#666">=</span> dtale<span style="color:#666">.</span>show(df)
|
||||
</span></span><span style="display:flex;"><span>d<span style="color:#666">.</span>open_browser() <span style="color:#408080;font-style:italic"># Or get an URL from d._url</span>
|
||||
</span></span></code></pre></div><p>Another notable alternative is <a href="https://github.com/adamerose/pandasgui">PandasGUI</a>, which, as one can guess, is a GUI (PyQt5) application, although it uses QtWebEngine inside.</p>
|
||||
<h2 id="remote-kernels">Remote kernels</h2>
|
||||
<p>There are yet some problems in the current configuration.</p>
|
||||
|
|
@ -278,128 +279,128 @@
|
|||
</ul>
|
||||
<h3 id="using-a-remote-kernel">Using a “remote” kernel</h3>
|
||||
<p>For the reasons above I sometimes prefer to use a standalone kernel. To start a Jupyter kernel, run the following command in the environment and path you need:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>jupyter kernel --kernel<span style="color:#f92672">=</span>python
|
||||
<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>jupyter kernel --kernel<span style="color:#666">=</span>python
|
||||
</span></span></code></pre></div><p>After the kernel is launched, write the path to the connection file into the <code>:session</code> header and press <code>C-c C-c</code> to refresh the setup:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+PROPERTY: header-args:python :session /home/pavel/.local/share/jupyter/runtime/kernel-e770599c-2c98-429b-b9ec-4d1ddf5fc16c.json
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+PROPERTY: header-args:python :session /home/pavel/.local/share/jupyter/runtime/kernel-e770599c-2c98-429b-b9ec-4d1ddf5fc16c.json
|
||||
</span></span></code></pre></div><p>Now python source blocks should be executed in the kernel.</p>
|
||||
<p>To open a REPL, run <code>M-x jupyter-connect-repl</code> and select the given JSON. Or launch a standalone REPL like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>jupyter qtconsole --existing kernel-e770599c-2c98-429b-b9ec-4d1ddf5fc16c.json
|
||||
<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>jupyter qtconsole --existing kernel-e770599c-2c98-429b-b9ec-4d1ddf5fc16c.json
|
||||
</span></span></code></pre></div><p>Executing a piece of code in the REPL allows proper debugging, for instance with <code>%pdb</code> magic. Also, Jupyter QtConsole generally handles large outputs better and even allows certain kinds of rich output in the REPL.</p>
|
||||
<h3 id="some-automation">Some automation</h3>
|
||||
<p>Now, I wouldn’t use Emacs if it wasn’t possible to automate at least some of the listed steps. So here are the functions I’ve written for that.</p>
|
||||
<p>First, we need to get open ports on the system:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/get-open-ports ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mapcar</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">#'string-to-number</span>
|
||||
</span></span><span style="display:flex;"><span> (split-string (shell-command-to-string <span style="color:#e6db74">"ss -tulpnH | awk '{print $5}' | sed -e 's/.*://'"</span>) <span style="color:#e6db74">"\n"</span>)))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/get-open-ports</span> ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#00f">#'string-to-number</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">split-string</span> (<span style="color:#19177c">shell-command-to-string</span> <span style="color:#ba2121">"ss -tulpnH | awk '{print $5}' | sed -e 's/.*://'"</span>) <span style="color:#ba2121">"\n"</span>)))
|
||||
</span></span></code></pre></div><p>Then, list the available kernel JSONs:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq my/jupyter-runtime-folder (<span style="color:#a6e22e">expand-file-name</span> <span style="color:#e6db74">"~/.local/share/jupyter/runtime"</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/jupyter-runtime-folder</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">"~/.local/share/jupyter/runtime"</span>))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(defun my/list-jupyter-kernel-files ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mapcar</span>
|
||||
</span></span><span style="display:flex;"><span> (lambda (file) (<span style="color:#a6e22e">cons</span> (<span style="color:#a6e22e">car</span> file) (<span style="color:#a6e22e">cdr</span> (<span style="color:#a6e22e">assq</span> <span style="color:#e6db74">'shell_port</span> (json-read-file (<span style="color:#a6e22e">car</span> file))))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">sort</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">directory-files-and-attributes</span> my/jupyter-runtime-folder <span style="color:#66d9ef">t</span> <span style="color:#e6db74">".*kernel.*json$"</span>)
|
||||
</span></span><span style="display:flex;"><span> (lambda (x y) (not (<span style="color:#a6e22e">time-less-p</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">6</span> x) (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">6</span> y)))))))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/list-jupyter-kernel-files</span> ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>) (<span style="color:#00f">cons</span> (<span style="color:#00f">car</span> <span style="color:#19177c">file</span>) (<span style="color:#00f">cdr</span> (<span style="color:#00f">assq</span> <span style="color:#19177c">'shell_port</span> (<span style="color:#19177c">json-read-file</span> (<span style="color:#00f">car</span> <span style="color:#19177c">file</span>))))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">sort</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">directory-files-and-attributes</span> <span style="color:#19177c">my/jupyter-runtime-folder</span> <span style="color:#800">t</span> <span style="color:#ba2121">".*kernel.*json$"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">x</span> <span style="color:#19177c">y</span>) (<span style="color:#19177c">not</span> (<span style="color:#00f">time-less-p</span> (<span style="color:#00f">nth</span> <span style="color:#666">6</span> <span style="color:#19177c">x</span>) (<span style="color:#00f">nth</span> <span style="color:#666">6</span> <span style="color:#19177c">y</span>)))))))
|
||||
</span></span></code></pre></div><p>And query the user for a running kernel:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/select-jupyter-kernel ()
|
||||
</span></span><span style="display:flex;"><span> (let ((ports (my/get-open-ports))
|
||||
</span></span><span style="display:flex;"><span> (files (my/list-jupyter-kernel-files)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">completing-read</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Jupyter kernels: "</span>
|
||||
</span></span><span style="display:flex;"><span> (seq-filter
|
||||
</span></span><span style="display:flex;"><span> (lambda (file)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">member</span> (<span style="color:#a6e22e">cdr</span> file) ports))
|
||||
</span></span><span style="display:flex;"><span> files))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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/select-jupyter-kernel</span> ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">ports</span> (<span style="color:#19177c">my/get-open-ports</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">files</span> (<span style="color:#19177c">my/list-jupyter-kernel-files</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">completing-read</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Jupyter kernels: "</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">member</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">file</span>) <span style="color:#19177c">ports</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">files</span>))))
|
||||
</span></span></code></pre></div><p>After which we can use the <code>my/select-jupyter-kernel</code> function however we want:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/insert-jupyter-kernel ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Insert a path to an active Jupyter kernel into the buffer"</span>
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">insert</span> (my/select-jupyter-kernel)))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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/insert-jupyter-kernel</span> ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Insert a path to an active Jupyter kernel into the buffer"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">insert</span> (<span style="color:#19177c">my/select-jupyter-kernel</span>)))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(defun my/jupyter-connect-repl ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Open emacs-jupyter REPL, connected to a Jupyter kernel"</span>
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (jupyter-connect-repl (my/select-jupyter-kernel) <span style="color:#66d9ef">nil</span> <span style="color:#66d9ef">nil</span> <span style="color:#66d9ef">nil</span> <span style="color:#66d9ef">t</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/jupyter-connect-repl</span> ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Open emacs-jupyter REPL, connected to a Jupyter kernel"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">jupyter-connect-repl</span> (<span style="color:#19177c">my/select-jupyter-kernel</span>) <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(defun my/jupyter-qtconsole ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Open Jupyter QtConsole, connected to a Jupyter kernel"</span>
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">start-process</span> <span style="color:#e6db74">"jupyter-qtconsole"</span> <span style="color:#66d9ef">nil</span> <span style="color:#e6db74">"setsid"</span> <span style="color:#e6db74">"jupyter"</span> <span style="color:#e6db74">"qtconsole"</span> <span style="color:#e6db74">"--existing"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">file-name-nondirectory</span> (my/select-jupyter-kernel))))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/jupyter-qtconsole</span> ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Open Jupyter QtConsole, connected to a Jupyter kernel"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">start-process</span> <span style="color:#ba2121">"jupyter-qtconsole"</span> <span style="color:#800">nil</span> <span style="color:#ba2121">"setsid"</span> <span style="color:#ba2121">"jupyter"</span> <span style="color:#ba2121">"qtconsole"</span> <span style="color:#ba2121">"--existing"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">file-name-nondirectory</span> (<span style="color:#19177c">my/select-jupyter-kernel</span>))))
|
||||
</span></span></code></pre></div><p>The first function, which simply inserts the path to the kernel, is meant to be used on the <code>:session</code> header. One can go even further and locate the header automatically, but that’s an idea for next time.</p>
|
||||
<p>The second one opens a REPL provided by emacs-jupyter. The <code>t</code> argument is necessary to pop up the REPL immediately.</p>
|
||||
<p>The last one launches Jupyter QtConsole. <code>setsid</code> is required to run the program in a new session, so it won’t close together with Emacs.</p>
|
||||
<h3 id="cleaning-up">Cleaning up</h3>
|
||||
<p>I’ve also noticed that there are JSON files left in the runtime folder whenever the kernel isn’t stopped correctly. So here is a cleanup function.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/jupyter-cleanup-kernels ()
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (let* ((ports (my/get-open-ports))
|
||||
</span></span><span style="display:flex;"><span> (files (my/list-jupyter-kernel-files))
|
||||
</span></span><span style="display:flex;"><span> (to-delete (seq-filter
|
||||
</span></span><span style="display:flex;"><span> (lambda (file)
|
||||
</span></span><span style="display:flex;"><span> (not (<span style="color:#a6e22e">member</span> (<span style="color:#a6e22e">cdr</span> file) ports)))
|
||||
</span></span><span style="display:flex;"><span> files)))
|
||||
</span></span><span style="display:flex;"><span> (when (and (length> to-delete <span style="color:#ae81ff">0</span>)
|
||||
</span></span><span style="display:flex;"><span> (y-or-n-p (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">"Delete %d files?"</span> (<span style="color:#a6e22e">length</span> to-delete))))
|
||||
</span></span><span style="display:flex;"><span> (dolist (file to-delete)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">delete-file</span> (<span style="color:#a6e22e">car</span> file)))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/jupyter-cleanup-kernels</span> ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">ports</span> (<span style="color:#19177c">my/get-open-ports</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">files</span> (<span style="color:#19177c">my/list-jupyter-kernel-files</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">to-delete</span> (<span style="color:#19177c">seq-filter</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">file</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#00f">member</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">file</span>) <span style="color:#19177c">ports</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">files</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">and</span> (<span style="color:#19177c">length></span> <span style="color:#19177c">to-delete</span> <span style="color:#666">0</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">y-or-n-p</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">"Delete %d files?"</span> (<span style="color:#00f">length</span> <span style="color:#19177c">to-delete</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">file</span> <span style="color:#19177c">to-delete</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">delete-file</span> (<span style="color:#00f">car</span> <span style="color:#19177c">file</span>)))))
|
||||
</span></span></code></pre></div><h2 id="export">Export</h2>
|
||||
<p>An uncountable number of articles have been written already on the subject of Org Mode export, so I will just cover my particular setup.</p>
|
||||
<h3 id="html">HTML</h3>
|
||||
<p>Export to a standalone HTML is an easy way to share the code with someone who doesn’t use Emacs, just remember that HTML may not be the only file you’d have to share if you have images in the document. Although you may use something like <a href="https://github.com/BitLooter/htmlark">htmlark</a> later to get a proper self-contained HTML.</p>
|
||||
<p>To do the export, run <code>M-x org-html-export-to-html</code>. It should work out of the box, however, we can improve the output a bit.</p>
|
||||
<p>First, we can add a custom CSS to the file. I like this one:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="https://gongzhitaao.org/orgcss/org.css"/>
|
||||
<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>#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="https://gongzhitaao.org/orgcss/org.css"/>
|
||||
</span></span></code></pre></div><p>To get a syntax highlighting, we need the <code>htmlize</code> package:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package htmlize
|
||||
</span></span><span style="display:flex;"><span> :straight <span style="color:#66d9ef">t</span>
|
||||
</span></span><span style="display:flex;"><span> :after ox
|
||||
</span></span><span style="display:flex;"><span> :config
|
||||
</span></span><span style="display:flex;"><span> (setq org-html-htmlize-output-type <span style="color:#e6db74">'css</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">htmlize</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">ox</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-html-htmlize-output-type</span> <span style="color:#19177c">'css</span>))
|
||||
</span></span></code></pre></div><p>If you use the <a href="https://github.com/Fanael/rainbow-delimiters">rainbow-delimeters</a> package, as I do, default colors for delimiters may not look good with the light theme. To fix such issues, put an HTML snippet like this in a <code>begin_export html</code> block or a CSS file:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span><<span style="color:#f92672">style</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">"text/css"</span>>
|
||||
</span></span><span style="display:flex;"><span>.<span style="color:#a6e22e">org-rainbow-delimiters-depth-1</span><span style="color:#f92672">,</span> .<span style="color:#a6e22e">org-rainbow-delimiters-depth-2</span><span style="color:#f92672">,</span> .<span style="color:#a6e22e">org-rainbow-delimiters-depth-3</span><span style="color:#f92672">,</span> .<span style="color:#a6e22e">org-rainbow-delimiters-depth-4</span> {
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">color</span>: <span style="color:#66d9ef">black</span>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span><<span style="color:#008000;font-weight:bold">style</span> <span style="color:#7d9029">type</span><span style="color:#666">=</span><span style="color:#ba2121">"text/css"</span>>
|
||||
</span></span><span style="display:flex;"><span>.<span style="color:#00f;font-weight:bold">org-rainbow-delimiters-depth-1</span><span style="color:#666">,</span> .<span style="color:#00f;font-weight:bold">org-rainbow-delimiters-depth-2</span><span style="color:#666">,</span> .<span style="color:#00f;font-weight:bold">org-rainbow-delimiters-depth-3</span><span style="color:#666">,</span> .<span style="color:#00f;font-weight:bold">org-rainbow-delimiters-depth-4</span> {
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000;font-weight:bold">color</span>: <span style="color:#008000;font-weight:bold">black</span>
|
||||
</span></span><span style="display:flex;"><span>}
|
||||
</span></span><span style="display:flex;"><span></<span style="color:#f92672">style</span>>
|
||||
</span></span><span style="display:flex;"><span></<span style="color:#008000;font-weight:bold">style</span>>
|
||||
</span></span></code></pre></div><h3 id="latex-pdf">LaTeX -> pdf</h3>
|
||||
<p>Even though I use LaTeX quite extensively, I don’t like to add another layer of complexity here and 98% of the time write plain <code>.tex</code> files. LaTeX by itself provides many good options whenever you need to write a document together with some data or source code, contrary to “traditional” text processors.</p>
|
||||
<p>Nevertheless, I want to get at least a tolerable pdf from Org, so here is a piece of my config with some inline comments.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/setup-org-latex ()
|
||||
</span></span><span style="display:flex;"><span> (setq org-latex-compiler <span style="color:#e6db74">"xelatex"</span>) <span style="color:#75715e">;; Probably not necessary</span>
|
||||
</span></span><span style="display:flex;"><span> (setq org-latex-pdf-process <span style="color:#f92672">'</span>(<span style="color:#e6db74">"latexmk -outdir=%o %f"</span>)) <span style="color:#75715e">;; Use latexmk</span>
|
||||
</span></span><span style="display:flex;"><span> (setq org-latex-listings <span style="color:#e6db74">'minted</span>) <span style="color:#75715e">;; Use minted to highlight source code</span>
|
||||
</span></span><span style="display:flex;"><span> (setq org-latex-minted-options <span style="color:#75715e">;; Some minted options I like</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">'</span>((<span style="color:#e6db74">"breaklines"</span> <span style="color:#e6db74">"true"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"tabsize"</span> <span style="color:#e6db74">"4"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"autogobble"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"linenos"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"numbersep"</span> <span style="color:#e6db74">"0.5cm"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"xleftmargin"</span> <span style="color:#e6db74">"1cm"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"frame"</span> <span style="color:#e6db74">"single"</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; Use extarticle without the default packages</span>
|
||||
</span></span><span style="display:flex;"><span> (add-to-list <span style="color:#e6db74">'org-latex-classes</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">'</span>(<span style="color:#e6db74">"org-plain-extarticle"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"\\documentclass{extarticle}
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">[NO-DEFAULT-PACKAGES]
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">[PACKAGES]
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">[EXTRA]"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"\\section{%s}"</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">"\\section*{%s}"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"\\subsection{%s}"</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">"\\subsection*{%s}"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"\\subsubsection{%s}"</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">"\\subsubsection*{%s}"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"\\paragraph{%s}"</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">"\\paragraph*{%s}"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"\\subparagraph{%s}"</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">"\\subparagraph*{%s}"</span>))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/setup-org-latex</span> ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-latex-compiler</span> <span style="color:#ba2121">"xelatex"</span>) <span style="color:#408080;font-style:italic">;; Probably not necessary</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-latex-pdf-process</span> <span style="color:#666">'</span>(<span style="color:#ba2121">"latexmk -outdir=%o %f"</span>)) <span style="color:#408080;font-style:italic">;; Use latexmk</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-latex-listings</span> <span style="color:#19177c">'minted</span>) <span style="color:#408080;font-style:italic">;; Use minted to highlight source code</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">org-latex-minted-options</span> <span style="color:#408080;font-style:italic">;; Some minted options I like</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>((<span style="color:#ba2121">"breaklines"</span> <span style="color:#ba2121">"true"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"tabsize"</span> <span style="color:#ba2121">"4"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"autogobble"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"linenos"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"numbersep"</span> <span style="color:#ba2121">"0.5cm"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"xleftmargin"</span> <span style="color:#ba2121">"1cm"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"frame"</span> <span style="color:#ba2121">"single"</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Use extarticle without the default packages</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">'org-latex-classes</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>(<span style="color:#ba2121">"org-plain-extarticle"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"\\documentclass{extarticle}
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">[NO-DEFAULT-PACKAGES]
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">[PACKAGES]
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">[EXTRA]"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"\\section{%s}"</span> <span style="color:#666">.</span> <span style="color:#ba2121">"\\section*{%s}"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"\\subsection{%s}"</span> <span style="color:#666">.</span> <span style="color:#ba2121">"\\subsection*{%s}"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"\\subsubsection{%s}"</span> <span style="color:#666">.</span> <span style="color:#ba2121">"\\subsubsection*{%s}"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"\\paragraph{%s}"</span> <span style="color:#666">.</span> <span style="color:#ba2121">"\\paragraph*{%s}"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"\\subparagraph{%s}"</span> <span style="color:#666">.</span> <span style="color:#ba2121">"\\subparagraph*{%s}"</span>))))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; Make sure to eval the function when org-latex-classes list already exists</span>
|
||||
</span></span><span style="display:flex;"><span>(with-eval-after-load <span style="color:#e6db74">'ox-latex</span>
|
||||
</span></span><span style="display:flex;"><span> (my/setup-org-latex))
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; Make sure to eval the function when org-latex-classes list already exists</span>
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">with-eval-after-load</span> <span style="color:#19177c">'ox-latex</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/setup-org-latex</span>))
|
||||
</span></span></code></pre></div><p>In the document itself, add the following headers:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+LATEX_CLASS: org-plain-extarticle
|
||||
<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>#+LATEX_CLASS: org-plain-extarticle
|
||||
</span></span><span style="display:flex;"><span>#+LATEX_CLASS_OPTIONS: [a4paper, 14pt]
|
||||
</span></span></code></pre></div><p>14pt size is required by certain state standards of ours for some reason.</p>
|
||||
<p>After which you can put whatever you want in the preamble with <code>LATEX_HEADER</code>. My workflow with LaTeX is to write a bunch of <code>.sty</code> files beforehand and import the necessary ones in the preamble. <a href="https://github.com/SqrtMinusOne/LaTeX%5Ftemplates">Here</a> is the repo with these files, although quite predictably, it’s a mess. At any rate, I have to write something like the following in the target Org file:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+LATEX_HEADER: \usepackage{styles/generalPreamble}
|
||||
<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>#+LATEX_HEADER: \usepackage{styles/generalPreamble}
|
||||
</span></span><span style="display:flex;"><span>#+LATEX_HEADER: \usepackage{styles/reportFormat}
|
||||
</span></span><span style="display:flex;"><span>#+LATEX_HEADER: \usepackage{styles/mintedSourceCode}
|
||||
</span></span><span style="display:flex;"><span>#+LATEX_HEADER: \usepackage{styles/russianLocale}
|
||||
|
|
@ -407,9 +408,9 @@
|
|||
<h3 id="ipynb">ipynb</h3>
|
||||
<p>One last export backend I want to mention is <a href="https://github.com/jkitchin/ox-ipynb">ox-ipynb</a>, which allows exporting Org documents to Jupyter notebooks. Sometimes it works, sometimes it doesn’t.</p>
|
||||
<p>Also, the package isn’t on MELPA, so you have to install it from the repo directly.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package ox-ipynb
|
||||
</span></span><span style="display:flex;"><span> :straight (:host github :repo <span style="color:#e6db74">"jkitchin/ox-ipynb"</span>)
|
||||
</span></span><span style="display:flex;"><span> :after ox)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">ox-ipynb</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> (<span style="color:#008000">:host</span> <span style="color:#19177c">github</span> <span style="color:#008000">:repo</span> <span style="color:#ba2121">"jkitchin/ox-ipynb"</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> <span style="color:#19177c">ox</span>)
|
||||
</span></span></code></pre></div><p>To (try to) do export, run <code>M-x ox-ipynb-export-org-file-ipynb-file</code>.</p>
|
||||
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
<hr>
|
||||
<div id="content">
|
||||
<div class="container">
|
||||
<h1>My EMMS and elfeed setup</h1>
|
||||
<h2 id="intro">Intro</h2>
|
||||
<figure><img src="/ox-hugo/emms-screenshot.png"/>
|
||||
</figure>
|
||||
|
|
@ -73,28 +74,28 @@
|
|||
<p><a href="https://www.musicpd.org/">MPD</a> is a server for playing music, although it is usually hosted on the local machine, i.e. the one on which you intend to listen to music. There is <a href="https://www.musicpd.org/clients/">bunch of clients</a> available (take a look at <a href="https://github.com/ncmpcpp/ncmpcpp">ncmpcpp</a> is you like terminal-based apps), but here our point of interest is its integration with EMMS.</p>
|
||||
<p>While EMMS is capable of playing music without it, MPD has the advantage of being independent of Emacs. That means it won’t close if Emacs crashes and it can be controlled more easily with other means.</p>
|
||||
<p>MPD configuration is a pretty easy process. First, install MPD and <a href="https://www.musicpd.org/clients/mpc/">mpc</a> (a minimal MPD CLI client) from your distribution’s package repository. After doing that, you’d have to create a config file at the location <code>~/.config/mpd/mpd.conf</code>. Mine looks something like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-vim" data-lang="vim"><span style="display:flex;"><span><span style="color:#a6e22e">music_directory</span> <span style="color:#e6db74">"~/Music"</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">playlist_directory</span> <span style="color:#e6db74">"~/.mpd/playlists"</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">db_file</span> <span style="color:#e6db74">"~/.mpd/database"</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">log_file</span> <span style="color:#e6db74">"~/.mpd/log"</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">pid_file</span> <span style="color:#e6db74">"~/.mpd/pid"</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">state_file</span> <span style="color:#e6db74">"~/.mpd/state"</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">sticker_file</span> <span style="color:#e6db74">"~/.mpd/sticker.sql"</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#a6e22e">audio_output</span> {<span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#a6e22e">type</span> <span style="color:#e6db74">"pulse"</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span> <span style="color:#a6e22e">name</span> <span style="color:#e6db74">"My Pulse Output"</span><span style="color:#960050;background-color:#1e0010">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span>}<span style="color:#960050;background-color:#1e0010">
|
||||
<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>music_directory <span style="color:#ba2121">"~/Music"</span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>playlist_directory <span style="color:#ba2121">"~/.mpd/playlists"</span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>db_file <span style="color:#ba2121">"~/.mpd/database"</span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>log_file <span style="color:#ba2121">"~/.mpd/log"</span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>pid_file <span style="color:#ba2121">"~/.mpd/pid"</span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>state_file <span style="color:#ba2121">"~/.mpd/state"</span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>sticker_file <span style="color:#ba2121">"~/.mpd/sticker.sql"</span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>audio_output {<span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span> type <span style="color:#ba2121">"pulse"</span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span> name <span style="color:#ba2121">"My Pulse Output"</span><span style="">
|
||||
</span></span></span><span style="display:flex;"><span><span style=""></span>}<span style="">
|
||||
</span></span></span></code></pre></div><p>Here <code>music_directory</code> is, well, a directory in which MPD will look for music files. Take a look at <a href="https://linux.die.net/man/5/mpd.conf">man mpd.conf</a> and <a href="https://github.com/MusicPlayerDaemon/MPD/blob/master/doc/mpdconf.example">the default config example</a> for more information.</p>
|
||||
<p>Because MPD is a daemon, it has to be started in order to work. The easiest way is to add <code>mpd</code> to your init system, e.g. with GNU Shepherd:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#66d9ef">define </span>mpd
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">make</span> <service>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">#</span>:provides <span style="color:#f92672">'</span>(mpd)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">#</span>:respawn? <span style="color:#66d9ef">#t</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">#</span>:start (<span style="color:#a6e22e">make-forkexec-constructor</span> <span style="color:#f92672">'</span>(<span style="color:#e6db74">"mpd"</span> <span style="color:#e6db74">"--no-daemon"</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">#</span>:stop (<span style="color:#a6e22e">make-kill-destructor</span>)))
|
||||
<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">mpd</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">make</span> <span style="color:#19177c"><service></span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">#</span><span style="color:#19177c">:provides</span> <span style="color:#666">'</span>(<span style="color:#19177c">mpd</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">#</span><span style="color:#19177c">:respawn?</span> <span style="color:#800">#t</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">#</span><span style="color:#19177c">:start</span> (<span style="color:#00f">make-forkexec-constructor</span> <span style="color:#666">'</span>(<span style="color:#ba2121">"mpd"</span> <span style="color:#ba2121">"--no-daemon"</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">#</span><span style="color:#19177c">:stop</span> (<span style="color:#00f">make-kill-destructor</span>)))
|
||||
</span></span></code></pre></div><p>You can also launch <code>mpd</code> manually, as it will daemonize itself by default. To check if MPD is working, run <code>mpc status</code>:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mpc status
|
||||
<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>mpc status
|
||||
</span></span></code></pre></div><p>Take a look at <a href="https://mpd.readthedocs.io/en/stable/user.html#configuration">the official documentation</a> for more information on this subject.</p>
|
||||
<h3 id="music-directory">Music directory</h3>
|
||||
<p>The next question after we’ve set up MPD is how to organize the music directory.</p>
|
||||
|
|
@ -103,26 +104,26 @@
|
|||
<h2 id="emms">EMMS</h2>
|
||||
<p><a href="https://www.gnu.org/software/emms/">EMMS</a> is the Emacs Multimedia System, a package that can get play stuff from various sources using various players. It is a part of Emacs, which means you can use the built-in version, but the git version has a few useful patches, so I advise using the latter.</p>
|
||||
<p>Install it however you usually install packages in Emacs; I use use-package + straight:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package emms
|
||||
</span></span><span style="display:flex;"><span> :straight <span style="color:#66d9ef">t</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">emms</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>)
|
||||
</span></span></code></pre></div><h3 id="setup-and-mpd-integration">Setup & MPD integration</h3>
|
||||
<p>Now we have to configure EMMS. The following expressions have to be executed after EMMS is loaded, which means we can add them to the <code>:config</code> section of the <code>use-package</code> expression above.</p>
|
||||
<p>First, EMMS exposes a handy function that loads all the stable EMMS features. You can take a look at its source and pick the features you need or load everything like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(require <span style="color:#e6db74">'emms-setup</span>)
|
||||
</span></span><span style="display:flex;"><span>(emms-all)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">'emms-setup</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">emms-all</span>)
|
||||
</span></span></code></pre></div><p>Then we need to set up a directory for EMMS files and the required parameters for <code>emms-player-mpd</code>. Note that <code>emms-player-mpd-music-directory</code> should be set to the same value as <code>music_directory</code> in <code>mpd.conf</code>.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq emms-source-file-default-directory (<span style="color:#a6e22e">expand-file-name</span> <span style="color:#e6db74">"~/Music/"</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">emms-source-file-default-directory</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">"~/Music/"</span>))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(setq emms-player-mpd-server-name <span style="color:#e6db74">"localhost"</span>)
|
||||
</span></span><span style="display:flex;"><span>(setq emms-player-mpd-server-port <span style="color:#e6db74">"6600"</span>)
|
||||
</span></span><span style="display:flex;"><span>(setq emms-player-mpd-music-directory <span style="color:#e6db74">"~/Music"</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">emms-player-mpd-server-name</span> <span style="color:#ba2121">"localhost"</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">emms-player-mpd-server-port</span> <span style="color:#ba2121">"6600"</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">emms-player-mpd-music-directory</span> <span style="color:#ba2121">"~/Music"</span>)
|
||||
</span></span></code></pre></div><p>Add the required functions to EMMS lists:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-to-list <span style="color:#e6db74">'emms-info-functions</span> <span style="color:#e6db74">'emms-info-mpd</span>)
|
||||
</span></span><span style="display:flex;"><span>(add-to-list <span style="color:#e6db74">'emms-player-list</span> <span style="color:#e6db74">'emms-player-mpd</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">'emms-info-functions</span> <span style="color:#19177c">'emms-info-mpd</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">'emms-player-list</span> <span style="color:#19177c">'emms-player-mpd</span>)
|
||||
</span></span></code></pre></div><p>Now we can connect EMMS to MPD. For some reason, executing this function stops the MPD playback, but it is not a big issue because it has to be executed only once.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(emms-player-mpd-connect)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">emms-player-mpd-connect</span>)
|
||||
</span></span></code></pre></div><p>The last thing we may want is to link EMMS playlist clearing to MPD playlist clearing. I’m not sure how this interacts with MPD’s own playlists because I don’t use them, so you may need to watch out here if you do.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-hook <span style="color:#e6db74">'emms-playlist-cleared-hook</span> <span style="color:#e6db74">'emms-player-mpd-clear</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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">'emms-playlist-cleared-hook</span> <span style="color:#19177c">'emms-player-mpd-clear</span>)
|
||||
</span></span></code></pre></div><h3 id="usage">Usage</h3>
|
||||
<p>One rough edge of EMMS & MPD integration is that EMMS and MPD have separate libraries and playlists.</p>
|
||||
<p>So, first we have to populate the MPD library with <code>M-x emms-player-mpd-update-all</code>. This operation is executed asynchronously by MPD and may take a few minutes for the first run. The subsequent runs are much faster. You can do the same by invoking <code>mpc update</code> from the command line.</p>
|
||||
|
|
@ -144,19 +145,19 @@
|
|||
<p>One feature of ncmpcpp I was missing here is fetching lyrics, so I’ve written a small package to do just that.</p>
|
||||
<p>Debugging the package turned out to be quite funny because apparently, there is no way around parsing HTML with this task. So I’ve chosen genius.com as the source, but the site turned out to provide different versions of itself (with different DOMs!) to different users.</p>
|
||||
<p>At any rate, I’ve processed the cases I found, and it seems to be working, at least for me. To use the package, <a href="https://genius.com/api-clients/new">get the API key</a> from Genius and install it:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package lyrics-fetcher
|
||||
</span></span><span style="display:flex;"><span> :straight <span style="color:#66d9ef">t</span>
|
||||
</span></span><span style="display:flex;"><span> :after (emms)
|
||||
</span></span><span style="display:flex;"><span> :config
|
||||
</span></span><span style="display:flex;"><span> (setq lyrics-fetcher-genius-access-token
|
||||
</span></span><span style="display:flex;"><span> (password-store-get <span style="color:#e6db74">"My_Online/APIs/genius.com"</span>)))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">lyrics-fetcher</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">emms</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">lyrics-fetcher-genius-access-token</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">password-store-get</span> <span style="color:#ba2121">"My_Online/APIs/genius.com"</span>)))
|
||||
</span></span></code></pre></div><p>To fetch lyrics for the current playing EMMS song, run <code>M-x lyrics-fetcher-show-lyrics</code>. Or run <code>M-x lyrics-fetcher-emms-browser-show-at-point</code> to fetch data for the current point in the EMMS browser. See <a href="https://github.com/SqrtMinusOne/lyrics-fetcher.el">the package homepage</a> for more information.</p>
|
||||
<h3 id="album-covers">Album covers</h3>
|
||||
<p>I’ve mentioned above that EMMS supports displaying album covers.</p>
|
||||
<p>For this to work, it is necessary to have one album per one folder. By default the cover image should be saved to images named <code>cover_small</code> (100x100 recommended), <code>cover_medium</code> (200x200 recommended) and <code>cover_large</code>. The small version is to be displayed in the EMMS browser, the medium one in the playlist.</p>
|
||||
<p>It’s not required for images to be exactly of these sizes, but they definitely should be of one size across different albums to look nice in the interface.</p>
|
||||
<p>You can resize images with ImageMagick with commands like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>convert cover.jpg -resize 100x100^ -gravity Center -extent 100x100 cover_small.jpg
|
||||
<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>convert cover.jpg -resize 100x100^ -gravity Center -extent 100x100 cover_small.jpg
|
||||
</span></span><span style="display:flex;"><span>convert cover.jpg -resize 200x200^ -gravity Center -extent 200x200 cover_medium.jpg
|
||||
</span></span></code></pre></div><p><code>lyrics-fetcher</code> can (try to) do this automatically by downloading the cover from genius.com with <code>M-x lyrics-fetcher-emms-browser-fetch-covers-at-point</code> in EMMS browser.</p>
|
||||
<h2 id="mpv-and-youtube">MPV and YouTube</h2>
|
||||
|
|
@ -164,129 +165,129 @@
|
|||
<h3 id="mpv-and-youtube-dl">MPV and youtube-dl</h3>
|
||||
<p>First, install both <code>mpv</code> and <code>youtube-dl</code> from your distribution’s package repository.</p>
|
||||
<p>Then we can add another player to the list:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-to-list <span style="color:#e6db74">'emms-player-list</span> <span style="color:#e6db74">'emms-player-mpv</span> <span style="color:#66d9ef">t</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">'emms-player-list</span> <span style="color:#19177c">'emms-player-mpv</span> <span style="color:#800">t</span>)
|
||||
</span></span></code></pre></div><p>EMMS determines which player to use by a regexp. <code>emms-player-mpd</code> sets the default regexp from MPD’s diagnostic output so that regex opens basically everything, including videos, HTTPS links, etc. That is fine if MPD is the only player in EMMS, but as we want to use MPV as well, we need to override the regexes.</p>
|
||||
<p>MPD regexp can look like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(emms-player-set emms-player-mpd
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'regex</span>
|
||||
</span></span><span style="display:flex;"><span> (emms-player-simple-regexp
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"m3u"</span> <span style="color:#e6db74">"ogg"</span> <span style="color:#e6db74">"flac"</span> <span style="color:#e6db74">"mp3"</span> <span style="color:#e6db74">"wav"</span> <span style="color:#e6db74">"mod"</span> <span style="color:#e6db74">"au"</span> <span style="color:#e6db74">"aiff"</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">emms-player-set</span> <span style="color:#19177c">emms-player-mpd</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">'regex</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">emms-player-simple-regexp</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"m3u"</span> <span style="color:#ba2121">"ogg"</span> <span style="color:#ba2121">"flac"</span> <span style="color:#ba2121">"mp3"</span> <span style="color:#ba2121">"wav"</span> <span style="color:#ba2121">"mod"</span> <span style="color:#ba2121">"au"</span> <span style="color:#ba2121">"aiff"</span>))
|
||||
</span></span></code></pre></div><p>And a regexp for MPV to open videos and youtube URLs:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(emms-player-set emms-player-mpv
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'regex</span>
|
||||
</span></span><span style="display:flex;"><span> (rx (or (<span style="color:#f92672">:</span> <span style="color:#e6db74">"https://"</span> (<span style="color:#a6e22e">*</span> nonl) <span style="color:#e6db74">"youtube.com"</span> (<span style="color:#a6e22e">*</span> nonl))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">+</span> (<span style="color:#e6db74">? </span>(or <span style="color:#e6db74">"https://"</span> <span style="color:#e6db74">"http://"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">*</span> nonl)
|
||||
</span></span><span style="display:flex;"><span> (regexp (<span style="color:#a6e22e">eval</span> (emms-player-simple-regexp
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"mp4"</span> <span style="color:#e6db74">"mov"</span> <span style="color:#e6db74">"wmv"</span> <span style="color:#e6db74">"webm"</span> <span style="color:#e6db74">"flv"</span> <span style="color:#e6db74">"avi"</span> <span style="color:#e6db74">"mkv"</span>)))))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">emms-player-set</span> <span style="color:#19177c">emms-player-mpv</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">'regex</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">rx</span> (<span style="color:#008000">or</span> (<span style="color:#666">:</span> <span style="color:#ba2121">"https://"</span> (<span style="color:#00f">*</span> <span style="color:#19177c">nonl</span>) <span style="color:#ba2121">"youtube.com"</span> (<span style="color:#00f">*</span> <span style="color:#19177c">nonl</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">+</span> (<span style="color:#ba2121">? </span>(<span style="color:#008000">or</span> <span style="color:#ba2121">"https://"</span> <span style="color:#ba2121">"http://"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">*</span> <span style="color:#19177c">nonl</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">regexp</span> (<span style="color:#00f">eval</span> (<span style="color:#19177c">emms-player-simple-regexp</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"mp4"</span> <span style="color:#ba2121">"mov"</span> <span style="color:#ba2121">"wmv"</span> <span style="color:#ba2121">"webm"</span> <span style="color:#ba2121">"flv"</span> <span style="color:#ba2121">"avi"</span> <span style="color:#ba2121">"mkv"</span>)))))))
|
||||
</span></span></code></pre></div><p>Then, by default youtube-dl plays the video in the best possible quality, which may be pretty high. To have some control over it, we can modify the <code>--ytdl-format</code> key in the <code>emms-player-mpv-parameters</code> variable. I’ve come up with the following solution:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq my/youtube-dl-quality-list
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">'</span>(<span style="color:#e6db74">"bestvideo[height<=720]+bestaudio/best[height<=720]"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"bestvideo[height<=480]+bestaudio/best[height<=480]"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"bestvideo[height<=1080]+bestaudio/best[height<=1080]"</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/youtube-dl-quality-list</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>(<span style="color:#ba2121">"bestvideo[height<=720]+bestaudio/best[height<=720]"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"bestvideo[height<=480]+bestaudio/best[height<=480]"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"bestvideo[height<=1080]+bestaudio/best[height<=1080]"</span>))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(setq my/default-emms-player-mpv-parameters
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">'</span>(<span style="color:#e6db74">"--quiet"</span> <span style="color:#e6db74">"--really-quiet"</span> <span style="color:#e6db74">"--no-audio-display"</span>))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/default-emms-player-mpv-parameters</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>(<span style="color:#ba2121">"--quiet"</span> <span style="color:#ba2121">"--really-quiet"</span> <span style="color:#ba2121">"--no-audio-display"</span>))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(defun my/set-emms-mpd-youtube-quality (quality)
|
||||
</span></span><span style="display:flex;"><span> (interactive <span style="color:#e6db74">"P"</span>)
|
||||
</span></span><span style="display:flex;"><span> (unless quality
|
||||
</span></span><span style="display:flex;"><span> (setq quality (<span style="color:#a6e22e">completing-read</span> <span style="color:#e6db74">"Quality: "</span> my/youtube-dl-quality-list <span style="color:#66d9ef">nil</span> <span style="color:#66d9ef">t</span>)))
|
||||
</span></span><span style="display:flex;"><span> (setq emms-player-mpv-parameters
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">`</span>(<span style="color:#f92672">,@</span>my/default-emms-player-mpv-parameters <span style="color:#f92672">,</span>(<span style="color:#a6e22e">format</span> <span style="color:#e6db74">"--ytdl-format=%s"</span> quality))))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/set-emms-mpd-youtube-quality</span> (<span style="color:#19177c">quality</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span> <span style="color:#ba2121">"P"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">quality</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">quality</span> (<span style="color:#00f">completing-read</span> <span style="color:#ba2121">"Quality: "</span> <span style="color:#19177c">my/youtube-dl-quality-list</span> <span style="color:#800">nil</span> <span style="color:#800">t</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">emms-player-mpv-parameters</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,@</span><span style="color:#19177c">my/default-emms-player-mpv-parameters</span> <span style="color:#666">,</span>(<span style="color:#00f">format</span> <span style="color:#ba2121">"--ytdl-format=%s"</span> <span style="color:#19177c">quality</span>))))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(my/set-emms-mpd-youtube-quality (<span style="color:#a6e22e">car</span> my/youtube-dl-quality-list))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">my/set-emms-mpd-youtube-quality</span> (<span style="color:#00f">car</span> <span style="color:#19177c">my/youtube-dl-quality-list</span>))
|
||||
</span></span></code></pre></div><p>Run <code>M-x my/set-emms-mpd-youtube-quality</code> to pick the required quality. Take a look at <a href="https://github.com/ytdl-org/youtube-dl/blob/master/README.md#format-selection">youtube-dl docs</a> for more information about the format selection.</p>
|
||||
<p>Now <code>M-x emms-add-url</code> should work on YouTube URLs just fine. Just keep in mind that it will only add the URL to the playlist, not play it right away.</p>
|
||||
<h3 id="cleanup-emms-cache">Cleanup EMMS cache</h3>
|
||||
<p>All the added URLs stay in the EMMS cache after being played. We probably don’t want them to remain there, so here is a function to remove URLs from the EMMS cache.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/emms-cleanup-urls ()
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (let ((keys-to-delete <span style="color:#f92672">'</span>()))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">maphash</span> (lambda (key value)
|
||||
</span></span><span style="display:flex;"><span> (when (<span style="color:#a6e22e">eq</span> (<span style="color:#a6e22e">cdr</span> (<span style="color:#a6e22e">assoc</span> <span style="color:#e6db74">'type</span> value)) <span style="color:#e6db74">'url</span>)
|
||||
</span></span><span style="display:flex;"><span> (add-to-list <span style="color:#e6db74">'keys-to-delete</span> key)))
|
||||
</span></span><span style="display:flex;"><span> emms-cache-db)
|
||||
</span></span><span style="display:flex;"><span> (dolist (key keys-to-delete)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">remhash</span> key emms-cache-db)))
|
||||
</span></span><span style="display:flex;"><span> (setq emms-cache-dirty <span style="color:#66d9ef">t</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/emms-cleanup-urls</span> ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">keys-to-delete</span> <span style="color:#666">'</span>()))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">maphash</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">key</span> <span style="color:#19177c">value</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">eq</span> (<span style="color:#00f">cdr</span> (<span style="color:#00f">assoc</span> <span style="color:#19177c">'type</span> <span style="color:#19177c">value</span>)) <span style="color:#19177c">'url</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span> <span style="color:#19177c">'keys-to-delete</span> <span style="color:#19177c">key</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">emms-cache-db</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">key</span> <span style="color:#19177c">keys-to-delete</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">remhash</span> <span style="color:#19177c">key</span> <span style="color:#19177c">emms-cache-db</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">emms-cache-dirty</span> <span style="color:#800">t</span>))
|
||||
</span></span></code></pre></div><h2 id="youtube-rss">YouTube RSS</h2>
|
||||
<h3 id="where-to-get-urls">Where to get URLs?</h3>
|
||||
<p>So, we are able to watch YouTube videos by URLs, but where to get URLs from? A natural solution is to use <a href="https://github.com/skeeto/elfeed">elfeed</a> and RSS feeds.</p>
|
||||
<p>I’ve tried a bunch of options to get feeds for YouTube channels. The first one is <a href="https://api.invidious.io/">Invidious</a>, a FOSS YouTube frontend. The problem here is that various instances I tried weren’t particularly stable (at least when I was using them) and hosting the thing by myself would be overkill. And switching instances is causing duplicate entries in the Elfeed DB.</p>
|
||||
<p>The second option is to use YouTube’s own RSS. The feed URL looks like <code>https://www.youtube.com/feeds/videos.xml?channel_id=<CHANNEL_ID>=</code>. <a href="https://stackoverflow.com/questions/14366648/how-can-i-get-a-channel-id-from-youtube">Here are</a> a couple of options of figuring out <code>CHANNEL_ID</code> in case it’s not easily available. The problem with YouTube RSS is that it uses fields that are not supported by elfeed, so the feed entry lacks a preview and description.</p>
|
||||
<p>As my workaround, I’ve written a small <a href="https://github.com/SqrtMinusOne/yt-rss">web-server</a> which converts an RSS feed from YouTube to an elfeed-compatible Atom feed. It doesn’t do much, so you can just download the thing and launch it:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git clone https://github.com/SqrtMinusOne/yt-rss.git
|
||||
</span></span><span style="display:flex;"><span>cd ./yt-rss
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git clone https://github.com/SqrtMinusOne/yt-rss.git
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000">cd</span> ./yt-rss
|
||||
</span></span><span style="display:flex;"><span>pip install -r requirements.txt
|
||||
</span></span><span style="display:flex;"><span>gunicorn main:app
|
||||
</span></span></code></pre></div><p>A feed for a particular channel will be available at</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>http://localhost:8000/<channel_id>?token=<token>
|
||||
<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>http://localhost:8000/<channel_id>?token=<token>
|
||||
</span></span></code></pre></div><p>where <code><token></code> is set in <code>.env</code> file to the default value of <code>12345</code>.</p>
|
||||
<h3 id="elfeed">Elfeed</h3>
|
||||
<p><a href="https://github.com/skeeto/elfeed">Elfeed</a> is an Emacs Atom & RSS reader. It’s a pretty popular package with lots of information written over the years, so I’ll cover just my particular setup.</p>
|
||||
<p>My elfeed config, sans keybindings, looks like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package elfeed
|
||||
</span></span><span style="display:flex;"><span> :straight <span style="color:#66d9ef">t</span>
|
||||
</span></span><span style="display:flex;"><span> :commands (elfeed)
|
||||
</span></span><span style="display:flex;"><span> :config
|
||||
</span></span><span style="display:flex;"><span> (setq elfeed-db-directory <span style="color:#e6db74">"~/.elfeed"</span>)
|
||||
</span></span><span style="display:flex;"><span> (setq elfeed-enclosure-default-dir (<span style="color:#a6e22e">expand-file-name</span> <span style="color:#e6db74">"~/Downloads"</span>))
|
||||
</span></span><span style="display:flex;"><span> (advice-add <span style="color:#a6e22e">#'</span>elfeed-insert-html
|
||||
</span></span><span style="display:flex;"><span> :around
|
||||
</span></span><span style="display:flex;"><span> (lambda (fun <span style="color:#66d9ef">&rest</span> r)
|
||||
</span></span><span style="display:flex;"><span> (let ((shr-use-fonts <span style="color:#66d9ef">nil</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">apply</span> fun r)))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">elfeed</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">elfeed</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">elfeed-db-directory</span> <span style="color:#ba2121">"~/.elfeed"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">elfeed-enclosure-default-dir</span> (<span style="color:#00f">expand-file-name</span> <span style="color:#ba2121">"~/Downloads"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">advice-add</span> <span style="color:#00f">#'</span><span style="color:#19177c">elfeed-insert-html</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:around</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">fun</span> <span style="color:#008000">&rest</span> <span style="color:#19177c">r</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">shr-use-fonts</span> <span style="color:#800">nil</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</span> <span style="color:#19177c">fun</span> <span style="color:#19177c">r</span>)))))
|
||||
</span></span></code></pre></div><p>The advice there forces elfeed to use monospace fonts in the show buffer.</p>
|
||||
<p>I also use <a href="https://github.com/remyhonig/elfeed-org">elfeed-org</a>, which gives an option to store the feed config in an <code>.org</code> file instead of a variable:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package elfeed-org
|
||||
</span></span><span style="display:flex;"><span> :straight <span style="color:#66d9ef">t</span>
|
||||
</span></span><span style="display:flex;"><span> :after (elfeed)
|
||||
</span></span><span style="display:flex;"><span> :config
|
||||
</span></span><span style="display:flex;"><span> (setq rmh-elfeed-org-files <span style="color:#f92672">'</span>(<span style="color:#e6db74">"~/.emacs.d/elfeed.org"</span>))
|
||||
</span></span><span style="display:flex;"><span> (elfeed-org))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">elfeed-org</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:after</span> (<span style="color:#19177c">elfeed</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:config</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">rmh-elfeed-org-files</span> <span style="color:#666">'</span>(<span style="color:#ba2121">"~/.emacs.d/elfeed.org"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-org</span>))
|
||||
</span></span></code></pre></div><p>So, however you’ve got URLs for YouTube channels, put them into elfeed.</p>
|
||||
<p>To fetch the feeds, open elfeed with <code>M-x elfeed</code> and run <code>M-x elfeed-search-fetch</code> in the search buffer. And as usual, take a look at <a href="https://github.com/skeeto/elfeed">the package documentation</a> for more information.</p>
|
||||
<p>To help with navigating through the long list of entries, I’ve made the following function to narrow the search buffer to the feed of the entry under cursor:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/elfeed-search-filter-source (entry)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Filter elfeed search buffer by the feed under cursor."</span>
|
||||
</span></span><span style="display:flex;"><span> (interactive (<span style="color:#a6e22e">list</span> (elfeed-search-selected :ignore-region)))
|
||||
</span></span><span style="display:flex;"><span> (when (elfeed-entry-p entry)
|
||||
</span></span><span style="display:flex;"><span> (elfeed-search-set-filter
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">concat</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"@6-months-ago "</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"+unread "</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"="</span>
|
||||
</span></span><span style="display:flex;"><span> (replace-regexp-in-string
|
||||
</span></span><span style="display:flex;"><span> (rx <span style="color:#e6db74">"?"</span> (<span style="color:#a6e22e">*</span> not-newline) eos)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">""</span>
|
||||
</span></span><span style="display:flex;"><span> (elfeed-feed-url (elfeed-entry-feed entry)))))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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 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>So I mostly alternate between <code>M-x my/elfeed-search-filter-source</code> and <code>M-x elfeed-search-clear-filter</code>. I tag the entries which I want to watch later with <code>+later</code>, and add the ones I want to watch right now to the playlist.</p>
|
||||
<h3 id="integrating-with-emms">Integrating with EMMS</h3>
|
||||
<p>Finally, here’s the solution I came up with to add an entry from elfeed to the EMMS playlist. First, we’ve got to get a URL:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/get-youtube-url (link)
|
||||
</span></span><span style="display:flex;"><span> (let ((watch-id (cadr
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">assoc</span> <span style="color:#e6db74">"watch?v"</span>
|
||||
</span></span><span style="display:flex;"><span> (url-parse-query-string
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">substring</span>
|
||||
</span></span><span style="display:flex;"><span> (url-filename
|
||||
</span></span><span style="display:flex;"><span> (url-generic-parse-url link))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ae81ff">1</span>))))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">"https://www.youtube.com/watch?v="</span> watch-id)))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/get-youtube-url</span> (<span style="color:#19177c">link</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">watch-id</span> (<span style="color:#19177c">cadr</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">assoc</span> <span style="color:#ba2121">"watch?v"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url-parse-query-string</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url-filename</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">url-generic-parse-url</span> <span style="color:#19177c">link</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">1</span>))))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> <span style="color:#ba2121">"https://www.youtube.com/watch?v="</span> <span style="color:#19177c">watch-id</span>)))
|
||||
</span></span></code></pre></div><p>This function is intended to work with both Invidious and YouTube RSS feeds. Of course, it will require some adaptation if you want to watch channels from something like PeerTube or Odysee.</p>
|
||||
<p>The easiest way to put the URL to the playlist is to define a new source for EMMS:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(define-emms-source elfeed (entry)
|
||||
</span></span><span style="display:flex;"><span> (let ((track (emms-track
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'url</span> (my/get-youtube-url (elfeed-entry-link entry)))))
|
||||
</span></span><span style="display:flex;"><span> (emms-track-set track <span style="color:#e6db74">'info-title</span> (elfeed-entry-title entry))
|
||||
</span></span><span style="display:flex;"><span> (emms-playlist-insert-track track)))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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">define-emms-source</span> <span style="color:#19177c">elfeed</span> (<span style="color:#19177c">entry</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">track</span> (<span style="color:#19177c">emms-track</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">'url</span> (<span style="color:#19177c">my/get-youtube-url</span> (<span style="color:#19177c">elfeed-entry-link</span> <span style="color:#19177c">entry</span>)))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">emms-track-set</span> <span style="color:#19177c">track</span> <span style="color:#19177c">'info-title</span> (<span style="color:#19177c">elfeed-entry-title</span> <span style="color:#19177c">entry</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">emms-playlist-insert-track</span> <span style="color:#19177c">track</span>)))
|
||||
</span></span></code></pre></div><p>Because <code>define-emms-source</code> is an EMMS macro, the code block above has to be evaluated with EMMS loaded. E.g. you can wrap it into <code>(with-eval-after-load 'emms ...)</code> or put in the <code>:config</code> section.</p>
|
||||
<p>The macro defines a bunch of functions to work with the source, which we can use in another function:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/elfeed-add-emms-youtube ()
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (emms-add-elfeed elfeed-show-entry)
|
||||
</span></span><span style="display:flex;"><span> (elfeed-tag elfeed-show-entry <span style="color:#e6db74">'watched</span>)
|
||||
</span></span><span style="display:flex;"><span> (elfeed-show-refresh))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-add-emms-youtube</span> ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">emms-add-elfeed</span> <span style="color:#19177c">elfeed-show-entry</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-tag</span> <span style="color:#19177c">elfeed-show-entry</span> <span style="color:#19177c">'watched</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">elfeed-show-refresh</span>))
|
||||
</span></span></code></pre></div><p>Now, calling <code>M-x my/elfeed-add-emms-youtube</code> in the <code>*elfeed-show*</code> buffer will add the correct URL to the playlist and tag the entry with <code>+watched</code>. I’ve bound the function to <code>gm</code>.</p>
|
||||
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
<hr>
|
||||
<div id="content">
|
||||
<div class="container">
|
||||
<h1>Getting a consistent set of keybindings between i3 and Emacs</h1>
|
||||
<h2 id="intro">Intro</h2>
|
||||
<p>One advantage of EXWM for an Emacs user is that EXWM gives one set of keybindings to manage both Emacs windows and X windows. In every other WM, like my preferred <a href="https://i3wm.org">i3wm</a>, two orthogonal keymaps seem to be necessary. But, as both programs are quite customizable, I want to see whether I can replicate at least some part of the EXWM goodness in i3.</p>
|
||||
<p>But why not just use EXWM? One key reason is that to my taste (and perhaps on my hardware) EXWM didn’t feel snappy enough. Also, I really like i3’s tree-based layout structure; I feel like it fits my workflow much better than anything else I tried, including the master/stack paradigm of <a href="https://xmonad.org/">XMonad</a>, for instance.</p>
|
||||
|
|
@ -73,42 +74,42 @@
|
|||
<p>This may seem like a lot of overhead, but I didn’t feel it even in the worst case (i3 -> Emacs -> i3), so at least in that regard, the interaction feels seamless. The only concern is that this command flow is vulnerable to Emacs getting stuck, but it is still much less of a problem than with EXWM.</p>
|
||||
<p>One interesting observation here is that Emacs windows and X windows are sort of one-level entities, so I can talk just about “windows”.</p>
|
||||
<p>At any rate, we need a script to do the i3 -> Emacs part:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#66d9ef">if</span> <span style="color:#f92672">[[</span> <span style="color:#66d9ef">$(</span>xdotool getactivewindow getwindowname<span style="color:#66d9ef">)</span> <span style="color:#f92672">=</span>~ ^emacs<span style="color:#f92672">(</span>:.*<span style="color:#f92672">)</span>?@.* <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
|
||||
</span></span><span style="display:flex;"><span> command<span style="color:#f92672">=</span><span style="color:#e6db74">"(my/emacs-i3-integration \"</span>$@<span style="color:#e6db74">\")"</span>
|
||||
</span></span><span style="display:flex;"><span> emacsclient -e <span style="color:#e6db74">"</span>$command<span style="color:#e6db74">"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
|
||||
</span></span><span style="display:flex;"><span> i3-msg $@
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">if</span> <span style="color:#666">[[</span> <span style="color:#008000;font-weight:bold">$(</span>xdotool getactivewindow getwindowname<span style="color:#008000;font-weight:bold">)</span> <span style="color:#666">=</span>~ ^emacs<span style="color:#666">(</span>:.*<span style="color:#666">)</span>?@.* <span style="color:#666">]]</span>; <span style="color:#008000;font-weight:bold">then</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">command</span><span style="color:#666">=</span><span style="color:#ba2121">"(my/emacs-i3-integration \"</span><span style="color:#19177c">$@</span><span style="color:#ba2121">\")"</span>
|
||||
</span></span><span style="display:flex;"><span> emacsclient -e <span style="color:#ba2121">"</span><span style="color:#19177c">$command</span><span style="color:#ba2121">"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">else</span>
|
||||
</span></span><span style="display:flex;"><span> i3-msg <span style="color:#19177c">$@</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span></code></pre></div><p>My <a href="https://sqrtminusone.xyz/configs/emacs/#custom-frame-title">Emacs frame title is set</a> to <code>emacs[:<projectile-project-name>]@<hostname></code>, hence the regex. The script is saved to an executable called <code>emacs-i3-integration</code>.</p>
|
||||
<p>For this to work, we need to make sure that Emacs starts a server, so here is an expression to do just that:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-hook <span style="color:#e6db74">'after-init-hook</span> <span style="color:#a6e22e">#'</span>server-start)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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">'after-init-hook</span> <span style="color:#00f">#'</span><span style="color:#19177c">server-start</span>)
|
||||
</span></span></code></pre></div><p>The function <code>my/emacs-i3-integration</code>, which is an entrypoint for the i3 integration, will be defined a bit later.</p>
|
||||
<p>And here is a simple macro to do the Emacs -> i3 part:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defmacro i3-msg (<span style="color:#66d9ef">&rest</span> args)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">`</span>(<span style="color:#a6e22e">start-process</span> <span style="color:#e6db74">"emacs-i3-windmove"</span> <span style="color:#66d9ef">nil</span> <span style="color:#e6db74">"i3-msg"</span> <span style="color:#f92672">,@</span>args))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defmacro</span> <span style="color:#19177c">i3-msg</span> (<span style="color:#008000">&rest</span> <span style="color:#19177c">args</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#00f">start-process</span> <span style="color:#ba2121">"emacs-i3-windmove"</span> <span style="color:#800">nil</span> <span style="color:#ba2121">"i3-msg"</span> <span style="color:#666">,@</span><span style="color:#19177c">args</span>))
|
||||
</span></span></code></pre></div><h2 id="handling-i3-commands">Handling i3 commands</h2>
|
||||
<p>Now we have to handle the required set of i3 commands. It is worth noting here that I’m not trying to implement a general mechanism to apply i3 commands to Emacs, rather I’m implementing a small subset that I use in my i3 configuration and that maps reasonably to the Emacs concepts.</p>
|
||||
<p>Also, I use <a href="https://github.com/emacs-evil/evil">evil-mode</a> and generally configure the software to have vim-style bindings where possible. So if you don’t use evil-mode you’d have to detangle the given functions from evil, but then, I guess, you do not use super+hjkl to manage windows either.</p>
|
||||
<h3 id="focus"><code>focus</code></h3>
|
||||
<p>First, for the <code>focus</code> command I want to move to an Emacs window in the given direction if there is one, otherwise move to an X window in the same direction. Fortunately, i3 and <code>windmove</code> have the same names for directions, so the function is rather straightforward.</p>
|
||||
<p>One caveat here is that the minibuffer is always the bottom-most Emacs window, so it is necessary to check for that as well.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/emacs-i3-windmove (dir)
|
||||
</span></span><span style="display:flex;"><span> (let ((other-window (windmove-find-other-window dir)))
|
||||
</span></span><span style="display:flex;"><span> (if (or (<span style="color:#a6e22e">null</span> other-window) (<span style="color:#a6e22e">window-minibuffer-p</span> other-window))
|
||||
</span></span><span style="display:flex;"><span> (i3-msg <span style="color:#e6db74">"focus"</span> (<span style="color:#a6e22e">symbol-name</span> dir))
|
||||
</span></span><span style="display:flex;"><span> (windmove-do-window-select dir))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/emacs-i3-windmove</span> (<span style="color:#19177c">dir</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">other-window</span> (<span style="color:#19177c">windmove-find-other-window</span> <span style="color:#19177c">dir</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">or</span> (<span style="color:#00f">null</span> <span style="color:#19177c">other-window</span>) (<span style="color:#00f">window-minibuffer-p</span> <span style="color:#19177c">other-window</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">i3-msg</span> <span style="color:#ba2121">"focus"</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">dir</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">windmove-do-window-select</span> <span style="color:#19177c">dir</span>))))
|
||||
</span></span></code></pre></div><p>The relevant section of the i3 config looks like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>bindsym $mod+h exec emacs-i3-integration focus left
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+j exec emacs-i3-integration focus down
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+k exec emacs-i3-integration focus up
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+l exec emacs-i3-integration focus right
|
||||
<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>bindsym <span style="color:#19177c">$mod</span>+h <span style="color:#008000">exec</span> emacs-i3-integration focus left
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+j <span style="color:#008000">exec</span> emacs-i3-integration focus down
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+k <span style="color:#008000">exec</span> emacs-i3-integration focus up
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+l <span style="color:#008000">exec</span> emacs-i3-integration focus right
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+Left exec emacs-i3-integration focus left
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+Down exec emacs-i3-integration focus down
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+Up exec emacs-i3-integration focus up
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+Right exec emacs-i3-integration focus right
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+Left <span style="color:#008000">exec</span> emacs-i3-integration focus left
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+Down <span style="color:#008000">exec</span> emacs-i3-integration focus down
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+Up <span style="color:#008000">exec</span> emacs-i3-integration focus up
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+Right <span style="color:#008000">exec</span> emacs-i3-integration focus right
|
||||
</span></span></code></pre></div><p>The Emacs function has to be called like that:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(my/emacs-i3-windmove <span style="color:#e6db74">'right</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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/emacs-i3-windmove</span> <span style="color:#19177c">'right</span>)
|
||||
</span></span></code></pre></div><h3 id="move"><code>move</code></h3>
|
||||
<p>For the <code>move</code> command I want the following behavior:</p>
|
||||
<ul>
|
||||
|
|
@ -119,133 +120,133 @@
|
|||
<p>For the first part, <code>window-swap-states</code> with <code>windmove-find-other-window</code> do well enough.</p>
|
||||
<p><code>evil-move-window</code> works well for the second part. By itself it doesn’t behave quite like i3, for instance, <code>(evil-move-window 'right)</code> in a three-column split would move the window from the far left side to the far right side (bypassing center). Hence the combination as described here.</p>
|
||||
<p>So here is a simple predicate which checks whether there is space in the given direction.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/emacs-i3-direction-exists-p (dir)
|
||||
</span></span><span style="display:flex;"><span> (some (lambda (dir)
|
||||
</span></span><span style="display:flex;"><span> (let ((win (windmove-find-other-window dir)))
|
||||
</span></span><span style="display:flex;"><span> (and win (not (<span style="color:#a6e22e">window-minibuffer-p</span> win)))))
|
||||
</span></span><span style="display:flex;"><span> (pcase dir
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'width</span> <span style="color:#f92672">'</span>(left right))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'height</span> <span style="color:#f92672">'</span>(up down)))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/emacs-i3-direction-exists-p</span> (<span style="color:#19177c">dir</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">some</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">dir</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">win</span> (<span style="color:#19177c">windmove-find-other-window</span> <span style="color:#19177c">dir</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span> <span style="color:#19177c">win</span> (<span style="color:#19177c">not</span> (<span style="color:#00f">window-minibuffer-p</span> <span style="color:#19177c">win</span>)))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">dir</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'width</span> <span style="color:#666">'</span>(<span style="color:#19177c">left</span> <span style="color:#19177c">right</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'height</span> <span style="color:#666">'</span>(<span style="color:#19177c">up</span> <span style="color:#19177c">down</span>)))))
|
||||
</span></span></code></pre></div><p>And the implementation of the move command.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/emacs-i3-move-window (dir)
|
||||
</span></span><span style="display:flex;"><span> (let ((other-window (windmove-find-other-window dir))
|
||||
</span></span><span style="display:flex;"><span> (other-direction (my/emacs-i3-direction-exists-p
|
||||
</span></span><span style="display:flex;"><span> (pcase dir
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'up</span> <span style="color:#e6db74">'width</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'down</span> <span style="color:#e6db74">'width</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'left</span> <span style="color:#e6db74">'height</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'right</span> <span style="color:#e6db74">'height</span>)))))
|
||||
</span></span><span style="display:flex;"><span> (cond
|
||||
</span></span><span style="display:flex;"><span> ((and other-window (not (<span style="color:#a6e22e">window-minibuffer-p</span> other-window)))
|
||||
</span></span><span style="display:flex;"><span> (window-swap-states (<span style="color:#a6e22e">selected-window</span>) other-window))
|
||||
</span></span><span style="display:flex;"><span> (other-direction
|
||||
</span></span><span style="display:flex;"><span> (evil-move-window dir))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#66d9ef">t</span> (i3-msg <span style="color:#e6db74">"move"</span> (<span style="color:#a6e22e">symbol-name</span> dir))))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/emacs-i3-move-window</span> (<span style="color:#19177c">dir</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">other-window</span> (<span style="color:#19177c">windmove-find-other-window</span> <span style="color:#19177c">dir</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">other-direction</span> (<span style="color:#19177c">my/emacs-i3-direction-exists-p</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">dir</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'up</span> <span style="color:#19177c">'width</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'down</span> <span style="color:#19177c">'width</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'left</span> <span style="color:#19177c">'height</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'right</span> <span style="color:#19177c">'height</span>)))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
|
||||
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">and</span> <span style="color:#19177c">other-window</span> (<span style="color:#19177c">not</span> (<span style="color:#00f">window-minibuffer-p</span> <span style="color:#19177c">other-window</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">window-swap-states</span> (<span style="color:#00f">selected-window</span>) <span style="color:#19177c">other-window</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">other-direction</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-move-window</span> <span style="color:#19177c">dir</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#800">t</span> (<span style="color:#19177c">i3-msg</span> <span style="color:#ba2121">"move"</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">dir</span>))))))
|
||||
</span></span></code></pre></div><p>The relevant section of the i3 config:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>bindsym $mod+Shift+h exec emacs-i3-integration move left
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+Shift+j exec emacs-i3-integration move down
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+Shift+k exec emacs-i3-integration move up
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+Shift+l exec emacs-i3-integration move right
|
||||
<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>bindsym <span style="color:#19177c">$mod</span>+Shift+h <span style="color:#008000">exec</span> emacs-i3-integration move left
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+Shift+j <span style="color:#008000">exec</span> emacs-i3-integration move down
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+Shift+k <span style="color:#008000">exec</span> emacs-i3-integration move up
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+Shift+l <span style="color:#008000">exec</span> emacs-i3-integration move right
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+Shift+Left exec emacs-i3-integration move left
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+Shift+Down exec emacs-i3-integration move down
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+Shift+Up exec emacs-i3-integration move up
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+Shift+Right exec emacs-i3-integration move right
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+Shift+Left <span style="color:#008000">exec</span> emacs-i3-integration move left
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+Shift+Down <span style="color:#008000">exec</span> emacs-i3-integration move down
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+Shift+Up <span style="color:#008000">exec</span> emacs-i3-integration move up
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+Shift+Right <span style="color:#008000">exec</span> emacs-i3-integration move right
|
||||
</span></span></code></pre></div><h3 id="resize-and-balance-windows"><code>resize</code> and balance windows</h3>
|
||||
<p>Next on the line are <code>resize grow</code> and <code>resize shrink</code>. <code>evil-window-</code> functions do nicely for this task.</p>
|
||||
<p>This function also checks whether there is space to resize in the given direction with the help of the predicate defined above. The command is forwarded back to i3 if there is not.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/emacs-i3-resize-window (dir kind value)
|
||||
</span></span><span style="display:flex;"><span> (if (or (one-window-p)
|
||||
</span></span><span style="display:flex;"><span> (not (my/emacs-i3-direction-exists-p dir)))
|
||||
</span></span><span style="display:flex;"><span> (i3-msg <span style="color:#e6db74">"resize"</span> (<span style="color:#a6e22e">symbol-name</span> kind) (<span style="color:#a6e22e">symbol-name</span> dir)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">"%s px or %s ppt"</span> value value))
|
||||
</span></span><span style="display:flex;"><span> (setq value (<span style="color:#a6e22e">/</span> value <span style="color:#ae81ff">2</span>))
|
||||
</span></span><span style="display:flex;"><span> (pcase kind
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'shrink</span>
|
||||
</span></span><span style="display:flex;"><span> (pcase dir
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'width</span>
|
||||
</span></span><span style="display:flex;"><span> (evil-window-decrease-width value))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'height</span>
|
||||
</span></span><span style="display:flex;"><span> (evil-window-decrease-height value))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'grow</span>
|
||||
</span></span><span style="display:flex;"><span> (pcase dir
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'width</span>
|
||||
</span></span><span style="display:flex;"><span> (evil-window-increase-width value))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'height</span>
|
||||
</span></span><span style="display:flex;"><span> (evil-window-increase-height value)))))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/emacs-i3-resize-window</span> (<span style="color:#19177c">dir</span> <span style="color:#19177c">kind</span> <span style="color:#19177c">value</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">or</span> (<span style="color:#19177c">one-window-p</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">my/emacs-i3-direction-exists-p</span> <span style="color:#19177c">dir</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">i3-msg</span> <span style="color:#ba2121">"resize"</span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">kind</span>) (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">dir</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">"%s px or %s ppt"</span> <span style="color:#19177c">value</span> <span style="color:#19177c">value</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">value</span> (<span style="color:#00f">/</span> <span style="color:#19177c">value</span> <span style="color:#666">2</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">kind</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'shrink</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">dir</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'width</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-window-decrease-width</span> <span style="color:#19177c">value</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'height</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-window-decrease-height</span> <span style="color:#19177c">value</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'grow</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">dir</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'width</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-window-increase-width</span> <span style="color:#19177c">value</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'height</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-window-increase-height</span> <span style="color:#19177c">value</span>)))))))
|
||||
</span></span></code></pre></div><p>Here I’m following the default configuration of i3, which creates a “submode” to resize windows.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mode <span style="color:#e6db74">"resize"</span> <span style="color:#f92672">{</span>
|
||||
<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>mode <span style="color:#ba2121">"resize"</span> <span style="color:#666">{</span>
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> bindsym h exec emacs-i3-integration resize shrink width <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym j exec emacs-i3-integration resize grow height <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym k exec emacs-i3-integration resize shrink height <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym l exec emacs-i3-integration resize grow width <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym h <span style="color:#008000">exec</span> emacs-i3-integration resize shrink width <span style="color:#666">10</span> px or <span style="color:#666">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym j <span style="color:#008000">exec</span> emacs-i3-integration resize grow height <span style="color:#666">10</span> px or <span style="color:#666">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym k <span style="color:#008000">exec</span> emacs-i3-integration resize shrink height <span style="color:#666">10</span> px or <span style="color:#666">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym l <span style="color:#008000">exec</span> emacs-i3-integration resize grow width <span style="color:#666">10</span> px or <span style="color:#666">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+h exec emacs-i3-integration resize shrink width <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+j exec emacs-i3-integration resize grow height <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+k exec emacs-i3-integration resize shrink height <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+l exec emacs-i3-integration resize grow width <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+h <span style="color:#008000">exec</span> emacs-i3-integration resize shrink width <span style="color:#666">100</span> px or <span style="color:#666">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+j <span style="color:#008000">exec</span> emacs-i3-integration resize grow height <span style="color:#666">100</span> px or <span style="color:#666">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+k <span style="color:#008000">exec</span> emacs-i3-integration resize shrink height <span style="color:#666">100</span> px or <span style="color:#666">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+l <span style="color:#008000">exec</span> emacs-i3-integration resize grow width <span style="color:#666">100</span> px or <span style="color:#666">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e"># same bindings, but for the arrow keys</span>
|
||||
</span></span><span style="display:flex;"><span> bindsym Left exec emacs-i3-integration resize shrink width <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Down exec emacs-i3-integration resize grow height <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Up exec emacs-i3-integration resize shrink height <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Right exec emacs-i3-integration resize grow width <span style="color:#ae81ff">10</span> px or <span style="color:#ae81ff">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic"># same bindings, but for the arrow keys</span>
|
||||
</span></span><span style="display:flex;"><span> bindsym Left <span style="color:#008000">exec</span> emacs-i3-integration resize shrink width <span style="color:#666">10</span> px or <span style="color:#666">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Down <span style="color:#008000">exec</span> emacs-i3-integration resize grow height <span style="color:#666">10</span> px or <span style="color:#666">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Up <span style="color:#008000">exec</span> emacs-i3-integration resize shrink height <span style="color:#666">10</span> px or <span style="color:#666">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Right <span style="color:#008000">exec</span> emacs-i3-integration resize grow width <span style="color:#666">10</span> px or <span style="color:#666">10</span> ppt
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+Left exec emacs-i3-integration resize shrink width <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+Down exec emacs-i3-integration resize grow height <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+Up exec emacs-i3-integration resize shrink height <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+Right exec emacs-i3-integration resize grow width <span style="color:#ae81ff">100</span> px or <span style="color:#ae81ff">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+Left <span style="color:#008000">exec</span> emacs-i3-integration resize shrink width <span style="color:#666">100</span> px or <span style="color:#666">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+Down <span style="color:#008000">exec</span> emacs-i3-integration resize grow height <span style="color:#666">100</span> px or <span style="color:#666">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+Up <span style="color:#008000">exec</span> emacs-i3-integration resize shrink height <span style="color:#666">100</span> px or <span style="color:#666">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span> bindsym Shift+Right <span style="color:#008000">exec</span> emacs-i3-integration resize grow width <span style="color:#666">100</span> px or <span style="color:#666">100</span> ppt
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> bindsym equal exec i3-emacs-balance-windows
|
||||
</span></span><span style="display:flex;"><span> bindsym equal <span style="color:#008000">exec</span> i3-emacs-balance-windows
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e"># back to normal: Enter or Escape</span>
|
||||
</span></span><span style="display:flex;"><span> bindsym Return mode <span style="color:#e6db74">"default"</span>
|
||||
</span></span><span style="display:flex;"><span> bindsym Escape mode <span style="color:#e6db74">"default"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic"># back to normal: Enter or Escape</span>
|
||||
</span></span><span style="display:flex;"><span> bindsym Return mode <span style="color:#ba2121">"default"</span>
|
||||
</span></span><span style="display:flex;"><span> bindsym Escape mode <span style="color:#ba2121">"default"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#666">}</span>
|
||||
</span></span></code></pre></div><p>Next, Emacs has a built-in function called <code>balance-windows</code>, but i3 doesn’t. Fortunately, there is a Python package called <a href="https://github.com/atreyasha/i3-balance-workspace">i3-balance-workspace</a>, which performs a similar operation with i3’s IPC. If you use Guix as I do, I’ve written a <a href="https://github.com/SqrtMinusOne/channel-q/blob/master/i3-balance-workspace.scm">package definition</a>.</p>
|
||||
<p>So here is a small wrapper which calls <code>i3_balance_workspace</code> and <code>M-x balance-windows</code> if the current window is Emacs.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#66d9ef">if</span> <span style="color:#f92672">[[</span> <span style="color:#66d9ef">$(</span>xdotool getactivewindow getwindowname<span style="color:#66d9ef">)</span> <span style="color:#f92672">=</span>~ ^emacs<span style="color:#f92672">(</span>:.*<span style="color:#f92672">)</span>?@.* <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
|
||||
</span></span><span style="display:flex;"><span> emacsclient -e <span style="color:#e6db74">"(balance-windows)"</span> &
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">if</span> <span style="color:#666">[[</span> <span style="color:#008000;font-weight:bold">$(</span>xdotool getactivewindow getwindowname<span style="color:#008000;font-weight:bold">)</span> <span style="color:#666">=</span>~ ^emacs<span style="color:#666">(</span>:.*<span style="color:#666">)</span>?@.* <span style="color:#666">]]</span>; <span style="color:#008000;font-weight:bold">then</span>
|
||||
</span></span><span style="display:flex;"><span> emacsclient -e <span style="color:#ba2121">"(balance-windows)"</span> &
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">fi</span>
|
||||
</span></span><span style="display:flex;"><span>i3_balance_workspace
|
||||
</span></span></code></pre></div><h3 id="layout-toggle-split"><code>layout toggle split</code></h3>
|
||||
<p><a href="https://github.com/emacsorphanage/transpose-frame">transpose-frame</a> is a package to “transpose” the current Emacs windows layout, which behaves somewhat similar to the <code>layout toggle split</code> command in i3, so I’ll use it as well.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package transpose-frame
|
||||
</span></span><span style="display:flex;"><span> :straight <span style="color:#66d9ef">t</span>
|
||||
</span></span><span style="display:flex;"><span> :commands (transpose-frame))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">use-package</span> <span style="color:#19177c">transpose-frame</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:straight</span> <span style="color:#800">t</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:commands</span> (<span style="color:#19177c">transpose-frame</span>))
|
||||
</span></span></code></pre></div><p>The i3 config for this command:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>bindsym $mod+e exec emacs-i3-integration layout toggle split
|
||||
<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>bindsym <span style="color:#19177c">$mod</span>+e <span style="color:#008000">exec</span> emacs-i3-integration layout toggle split
|
||||
</span></span></code></pre></div><h3 id="the-entrypoint">The entrypoint</h3>
|
||||
<p>Finally, the entrypoint for the Emacs integration. In addition to the commands defined above, it processes <code>split</code> and <code>kill</code> commands and passes every other command back to i3.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/emacs-i3-integration (command)
|
||||
</span></span><span style="display:flex;"><span> (pcase command
|
||||
</span></span><span style="display:flex;"><span> ((rx bos <span style="color:#e6db74">"focus"</span>)
|
||||
</span></span><span style="display:flex;"><span> (my/emacs-i3-windmove
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">intern</span> (<span style="color:#a6e22e">elt</span> (split-string command) <span style="color:#ae81ff">1</span>))))
|
||||
</span></span><span style="display:flex;"><span> ((rx bos <span style="color:#e6db74">"move"</span>)
|
||||
</span></span><span style="display:flex;"><span> (my/emacs-i3-move-window
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">intern</span> (<span style="color:#a6e22e">elt</span> (split-string command) <span style="color:#ae81ff">1</span>))))
|
||||
</span></span><span style="display:flex;"><span> ((rx bos <span style="color:#e6db74">"resize"</span>)
|
||||
</span></span><span style="display:flex;"><span> (my/emacs-i3-resize-window
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">intern</span> (<span style="color:#a6e22e">elt</span> (split-string command) <span style="color:#ae81ff">2</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">intern</span> (<span style="color:#a6e22e">elt</span> (split-string command) <span style="color:#ae81ff">1</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">string-to-number</span> (<span style="color:#a6e22e">elt</span> (split-string command) <span style="color:#ae81ff">3</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"layout toggle split"</span> (transpose-frame))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"split h"</span> (evil-window-split))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"split v"</span> (evil-window-vsplit))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"kill"</span> (evil-quit))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">-</span> (i3-msg command))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/emacs-i3-integration</span> (<span style="color:#19177c">command</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">command</span>
|
||||
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">"focus"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/emacs-i3-windmove</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">intern</span> (<span style="color:#00f">elt</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">command</span>) <span style="color:#666">1</span>))))
|
||||
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">"move"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/emacs-i3-move-window</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">intern</span> (<span style="color:#00f">elt</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">command</span>) <span style="color:#666">1</span>))))
|
||||
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">rx</span> <span style="color:#19177c">bos</span> <span style="color:#ba2121">"resize"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/emacs-i3-resize-window</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">intern</span> (<span style="color:#00f">elt</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">command</span>) <span style="color:#666">2</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">intern</span> (<span style="color:#00f">elt</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">command</span>) <span style="color:#666">1</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">string-to-number</span> (<span style="color:#00f">elt</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">command</span>) <span style="color:#666">3</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"layout toggle split"</span> (<span style="color:#19177c">transpose-frame</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"split h"</span> (<span style="color:#19177c">evil-window-split</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"split v"</span> (<span style="color:#19177c">evil-window-vsplit</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"kill"</span> (<span style="color:#19177c">evil-quit</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">-</span> (<span style="color:#19177c">i3-msg</span> <span style="color:#19177c">command</span>))))
|
||||
</span></span></code></pre></div><p>The rest of the relevant i3 config to do the splits:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>bindsym $mod+s exec emacs-i3-integration split h
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+v exec emacs-i3-integration split v
|
||||
<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>bindsym <span style="color:#19177c">$mod</span>+s <span style="color:#008000">exec</span> emacs-i3-integration split h
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+v <span style="color:#008000">exec</span> emacs-i3-integration split v
|
||||
</span></span></code></pre></div><p>And to kill the window:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>bindsym $mod+Shift+q exec emacs-i3-integration kill
|
||||
<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>bindsym <span style="color:#19177c">$mod</span>+Shift+q <span style="color:#008000">exec</span> emacs-i3-integration <span style="color:#008000">kill</span>
|
||||
</span></span></code></pre></div><h3 id="switching-i3-tabs">Switching i3 tabs</h3>
|
||||
<p>As I use i3’s tabbed layout quite extensively, occasionally I want to switch out of the Emacs tab with one button, and that’s where my integration may interfere.</p>
|
||||
<p>As a workaround, I found a small Rust program called <a href="https://github.com/nikola-kocic/i3-switch-tabs">i3-switch-tabs</a>, which also communicates with i3 via its IPC to switch the top-level tab. I’ve written a <a href="https://github.com/SqrtMinusOne/channel-q/blob/master/i3-switch-tabs.scm">Guix package definition</a> for that as well.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>bindsym $mod+period exec i3-switch-tabs right
|
||||
</span></span><span style="display:flex;"><span>bindsym $mod+comma exec i3-switch-tabs left
|
||||
<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>bindsym <span style="color:#19177c">$mod</span>+period <span style="color:#008000">exec</span> i3-switch-tabs right
|
||||
</span></span><span style="display:flex;"><span>bindsym <span style="color:#19177c">$mod</span>+comma <span style="color:#008000">exec</span> i3-switch-tabs left
|
||||
</span></span></code></pre></div><h2 id="conclusion">Conclusion</h2>
|
||||
<p>So, how does all of that feel? Actually, I got used to that setup pretty quickly. Using <code><s-Q></code> to quit windows and the <code><s-r></code> submode to resize them is particularly nice. I’ve seen people making hydras in Emacs to do the latter.</p>
|
||||
<p>All of that would probably be easier to do in a WM which is configured in a programming language rather than in a self-cooked DSL, so I may try to replicate that somewhere else in an unknown time in the future. Meanwhile, it’s pretty good.</p>
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
<hr>
|
||||
<div id="content">
|
||||
<div class="container">
|
||||
<h1>Using EXWM and perspective.el on multi-monitor setup</h1>
|
||||
<p>I wrote about <a href="https://sqrtminusone.xyz/posts/2021-10-04-emacs-i3/">Emacs and i3</a> integration around two months ago. Shortly after however, I decided to give EXWM another try, mainly because my largest reservation - lack of performance - seems to have been resolved by updates to the native compilation since my first attempt. Or I may have lost some sensitivity to that issue. Regardless, the second dive into EXWM thus far feels successful, and I think it’s the right time to share some of my thoughts on the subject.</p>
|
||||
<p>Before we start though, I’ll point out that I won’t go into detail about the initial setup. I think David Wilson’s “<a href="https://systemcrafters.net/emacs-desktop-environment/">Emacs Desktop Environment</a>” series describes this part pretty well, so I don’t feel the need to repeat much of that.</p>
|
||||
<p>This post is a sort of a snapshot of the path from the baseline of <a href="https://github.com/daviwil/emacs-from-scratch/blob/master/Desktop.org">Emacs From Scratch</a> to my image of a perfect window manager, and it may or may not be coincidental that the latter resembles i3 in many aspects.</p>
|
||||
|
|
@ -73,85 +74,85 @@
|
|||
<li>Provides some additional functionality that makes use of both perspective.el and EXWM.</li>
|
||||
</ul>
|
||||
<p>So, you can install the package however you normally do so. E.g. I do that with straight.el & use-package:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package perspective-exwm
|
||||
</span></span><span style="display:flex;"><span> :straight <span style="color:#66d9ef">t</span>
|
||||
</span></span><span style="display:flex;"><span> :config
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">...</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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><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></code></pre></div><p>Then load the provided minor mode before <code>exwm-init</code>:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package exwm
|
||||
</span></span><span style="display:flex;"><span> :config
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">...</span>
|
||||
</span></span><span style="display:flex;"><span> (perspective-exwm-mode)
|
||||
</span></span><span style="display:flex;"><span> (exwm-init))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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><h3 id="initial-perspective-names">Initial perspective names</h3>
|
||||
<p>One nice thing this package can do is set up the initial perspective names for different workspaces. By default, enabling <code>perspective-exwm-mode</code> sets names like <code>main-1</code> for workspace with index 1 and so on, because otherwise different perspectives will share the same <code>*scratch*</code> buffer.</p>
|
||||
<p>But names can be overridden like that:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq perspective-exwm-override-initial-name
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">'</span>((<span style="color:#ae81ff">0</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">"misc"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ae81ff">1</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">"core"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ae81ff">2</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">"browser"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ae81ff">3</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">"comms"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ae81ff">4</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">"dev"</span>)))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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><h3 id="assigning-apps-to-workspaces-and-perspectives">Assigning apps to workspaces and perspectives</h3>
|
||||
<p>By default, a new Emacs buffer opens in the current perspective in the current workspace, but sure enough, it’s possible to change that.</p>
|
||||
<p>For EXWM windows, the <code>perspective-exwm</code> package provides a function called <code>perspective-exwm-assign-window</code>, which is intended to be used in <code>exwm-manage-finish-hook</code>, for instance:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/exwm-configure-window ()
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (pcase exwm-class-name
|
||||
</span></span><span style="display:flex;"><span> ((or <span style="color:#e6db74">"Firefox"</span> <span style="color:#e6db74">"Nightly"</span>)
|
||||
</span></span><span style="display:flex;"><span> (perspective-exwm-assign-window
|
||||
</span></span><span style="display:flex;"><span> :workspace-index <span style="color:#ae81ff">2</span>
|
||||
</span></span><span style="display:flex;"><span> :persp-name <span style="color:#e6db74">"browser"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"Alacritty"</span>
|
||||
</span></span><span style="display:flex;"><span> (perspective-exwm-assign-window
|
||||
</span></span><span style="display:flex;"><span> :persp-name <span style="color:#e6db74">"term"</span>))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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></span><span style="display:flex;"><span>(add-hook <span style="color:#e6db74">'exwm-manage-finish-hook</span> <span style="color:#a6e22e">#'</span>my/exwm-configure-window)
|
||||
</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><p>This hook is run after a new EXWM buffer is created and configured in the context of this buffer, so it seems customary to do such settings there. With this snippet, Firefox will always open in workspace 2 in the perspective named “browser”, and Alacritty will always open in the current workspace in the perspective named “term”.</p>
|
||||
<p>To pull this off for various Emacs apps, it is necessary to open the right EXWM workspace and perspective before opening the app. As I use <a href="https://github.com/noctuid/general.el">general.el</a>, I made a macro to automate that:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defmacro my/command-in-persp (command-name persp-name workspace-index <span style="color:#66d9ef">&rest</span> args)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">`'</span>((lambda ()
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (when (and <span style="color:#f92672">,</span>workspace-index (<span style="color:#a6e22e">fboundp</span> <span style="color:#a6e22e">#'</span>exwm-workspace-switch-create))
|
||||
</span></span><span style="display:flex;"><span> (exwm-workspace-switch-create <span style="color:#f92672">,</span>workspace-index))
|
||||
</span></span><span style="display:flex;"><span> (persp-switch <span style="color:#f92672">,</span>persp-name)
|
||||
</span></span><span style="display:flex;"><span> (delete-other-windows)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">,@</span>args)
|
||||
</span></span><span style="display:flex;"><span> :wk <span style="color:#f92672">,</span>command-name))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defmacro</span> <span style="color:#19177c">my/command-in-persp</span> (<span style="color:#19177c">command-name</span> <span style="color:#19177c">persp-name</span> <span style="color:#19177c">workspace-index</span> <span style="color:#008000">&rest</span> <span style="color:#19177c">args</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">`'</span>((<span style="color:#008000">lambda</span> ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">and</span> <span style="color:#666">,</span><span style="color:#19177c">workspace-index</span> (<span style="color:#00f">fboundp</span> <span style="color:#00f">#'</span><span style="color:#19177c">exwm-workspace-switch-create</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">exwm-workspace-switch-create</span> <span style="color:#666">,</span><span style="color:#19177c">workspace-index</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">persp-switch</span> <span style="color:#666">,</span><span style="color:#19177c">persp-name</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">delete-other-windows</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">,@</span><span style="color:#19177c">args</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:wk</span> <span style="color:#666">,</span><span style="color:#19177c">command-name</span>))
|
||||
</span></span></code></pre></div><p><code>fboundp</code> is meant to provide compatibility with running Emacs without EXWM. Usage of the macro is as follows:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(my-leader-def
|
||||
</span></span><span style="display:flex;"><span> :infix <span style="color:#e6db74">"as"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">""</span> <span style="color:#f92672">'</span>(:which-key <span style="color:#e6db74">"emms"</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"s"</span> (my/command-in-persp <span style="color:#e6db74">"emms"</span> <span style="color:#e6db74">"EMMS"</span> <span style="color:#ae81ff">0</span> (emms-smart-browse))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">...</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">my-leader-def</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:infix</span> <span style="color:#ba2121">"as"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">""</span> <span style="color:#666">'</span>(<span style="color:#008000">:which-key</span> <span style="color:#ba2121">"emms"</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"s"</span> (<span style="color:#19177c">my/command-in-persp</span> <span style="color:#ba2121">"emms"</span> <span style="color:#ba2121">"EMMS"</span> <span style="color:#666">0</span> (<span style="color:#19177c">emms-smart-browse</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">...</span>)
|
||||
</span></span></code></pre></div><p><code>my-leader-def</code> is a <a href="https://github.com/noctuid/general.el#creating-new-key-definers">custom definer</a>. That way the defined keybinding opens <a href="https://www.gnu.org/software/emms/">EMMS</a> in the workspace 0 in the perspective “EMMS”. I have this for several other apps, like elfeed, notmuch, dired <code>$HOME</code> and so on.</p>
|
||||
<h3 id="some-workflow-notes">Some workflow notes</h3>
|
||||
<p>As I said above, using perspectives in EXWM makes a lot of sense. Because all the EXWM workspace share the same buffer list (sans X windows), and because Emacs becomes the central program (for instance, it can’t be easily closed), it is only natural to split the buffer list.</p>
|
||||
<p>Another aspect of using EXWM is that it becomes very easy to work with code on multiple monitors. While it may signify issues with the code in question if such need arises, having that possibility is still handy and it’s not something easily replicable on other tiling WMs. <code>perspective-exwm</code> also presents some features here, for instance, <code>M-x perspective-exwm-copy-to-workspace</code> can be used to copy the current perspective to the adjacent monitor.</p>
|
||||
<p>Also, in my opinion, Emacs apps like <a href="https://www.gnu.org/software/emms/">EMMS</a> and <a href="https://github.com/skeeto/elfeed">elfeed</a> deserve to be on the same “level” as “proper” apps like a browser. On other tiling WMs, something like that can be done with Emacs daemon and multiple Emacs frames, but with EXWM and perspectives this seems natural without much extra work.</p>
|
||||
<p>As for switching between X windows and perspectives, I ended up preferring to have one perspective for all X windows in the workspace, at least if these windows are full-fledged apps. For instance, all my messengers go to the workspace 3 to the perspective “comms”, and I switch between them with <code>M-x perspective-exwm-cycle-exwm-buffers-<forward|backward></code>, bound to <code>s-[</code> and <code>s-]</code>. For switching perspectives, I’ve bound <code>s-,</code> and <code>s-.</code>:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq exwm-input-global-keys
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">`</span>(
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">...</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; Switch perspectives</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-,"</span>) <span style="color:#f92672">.</span> persp-prev)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-."</span>) <span style="color:#f92672">.</span> persp-next)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">exwm-input-global-keys</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></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Switch perspectives</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-,"</span>) <span style="color:#666">.</span> <span style="color:#19177c">persp-prev</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-."</span>) <span style="color:#666">.</span> <span style="color:#19177c">persp-next</span>)
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; EXWM buffers</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-["</span>) <span style="color:#f92672">.</span> perspective-exwm-cycle-exwm-buffers-backward)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-]"</span>) <span style="color:#f92672">.</span> perspective-exwm-cycle-exwm-buffers-forward)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">...</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; EXWM buffers</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-["</span>) <span style="color:#666">.</span> <span style="color:#19177c">perspective-exwm-cycle-exwm-buffers-backward</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-]"</span>) <span style="color:#666">.</span> <span style="color:#19177c">perspective-exwm-cycle-exwm-buffers-forward</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">...</span>)
|
||||
</span></span></code></pre></div><h2 id="workspaces-on-multiple-monitors">Workspaces on multiple monitors</h2>
|
||||
<p>Here, <code>exwm-randr</code> provides basic functionality for running EXWM on multiple monitors. For instance, with configuration like that:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(require <span style="color:#e6db74">'exwm-randr</span>)
|
||||
</span></span><span style="display:flex;"><span>(exwm-randr-enable)
|
||||
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; The script is generated by ARandR</span>
|
||||
</span></span><span style="display:flex;"><span>(start-process-shell-command <span style="color:#e6db74">"xrandr"</span> <span style="color:#66d9ef">nil</span> <span style="color:#e6db74">"~/bin/scripts/screen-layout"</span>)
|
||||
</span></span><span style="display:flex;"><span>(when (string= (<span style="color:#a6e22e">system-name</span>) <span style="color:#e6db74">"indigo"</span>)
|
||||
</span></span><span style="display:flex;"><span> (setq exwm-randr-workspace-monitor-plist <span style="color:#f92672">'</span>(<span style="color:#ae81ff">2</span> <span style="color:#e6db74">"DVI-D-0"</span> <span style="color:#ae81ff">3</span> <span style="color:#e6db74">"DVI-D-0"</span>)))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">'exwm-randr</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">exwm-randr-enable</span>)
|
||||
</span></span><span style="display:flex;"><span><span style="color:#408080;font-style:italic">;; The script is generated by ARandR</span>
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">start-process-shell-command</span> <span style="color:#ba2121">"xrandr"</span> <span style="color:#800">nil</span> <span style="color:#ba2121">"~/bin/scripts/screen-layout"</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">when</span> (<span style="color:#19177c">string=</span> (<span style="color:#00f">system-name</span>) <span style="color:#ba2121">"indigo"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">exwm-randr-workspace-monitor-plist</span> <span style="color:#666">'</span>(<span style="color:#666">2</span> <span style="color:#ba2121">"DVI-D-0"</span> <span style="color:#666">3</span> <span style="color:#ba2121">"DVI-D-0"</span>)))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#f92672">...</span>
|
||||
</span></span><span style="display:flex;"><span>(exwm-init)
|
||||
</span></span><span style="display:flex;"><span><span style="color:#666">...</span>
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">exwm-init</span>)
|
||||
</span></span></code></pre></div><p>workspaces 2 and 3 on the machine with hostname “indigo” will be displayed on the monitor <code>DVI-D-0</code>.</p>
|
||||
<p>However, some features, common in other tiling WMs, are missing in EXWM out of the box, namely:</p>
|
||||
<ul>
|
||||
|
|
@ -163,76 +164,76 @@
|
|||
<h3 id="tracking-recently-used-workspaces">Tracking recently used workspaces</h3>
|
||||
<p>First up though, we need to track the workspaces in the usage order. I’m not sure if there’s some built-in functionality in EXWM for that, but it seems simple enough to implement.</p>
|
||||
<p>Here is a snippet of code that does it:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq my/exwm-last-workspaces <span style="color:#f92672">'</span>(<span style="color:#ae81ff">1</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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/exwm-last-workspaces</span> <span style="color:#666">'</span>(<span style="color:#666">1</span>))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(defun my/exwm-store-last-workspace ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Save the last workspace to </span><span style="color:#e6db74">`my/exwm-last-workspaces'</span><span style="color:#e6db74">."</span>
|
||||
</span></span><span style="display:flex;"><span> (setq my/exwm-last-workspaces
|
||||
</span></span><span style="display:flex;"><span> (seq-uniq (<span style="color:#a6e22e">cons</span> exwm-workspace-current-index
|
||||
</span></span><span style="display:flex;"><span> my/exwm-last-workspaces))))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/exwm-store-last-workspace</span> ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Save the last workspace to </span><span style="color:#19177c">`my/exwm-last-workspaces'</span><span style="color:#ba2121">."</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/exwm-last-workspaces</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-uniq</span> (<span style="color:#00f">cons</span> <span style="color:#19177c">exwm-workspace-current-index</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/exwm-last-workspaces</span>))))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(add-hook <span style="color:#e6db74">'exwm-workspace-switch-hook</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">#'</span>my/exwm-store-last-workspace)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">'exwm-workspace-switch-hook</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#00f">#'</span><span style="color:#19177c">my/exwm-store-last-workspace</span>)
|
||||
</span></span></code></pre></div><p>The variable <code>my/exwm-last-workspaces</code> stores the workspace indices; the first item is the index of the current workspace, the second item is the index of the previous workspace, and so on.</p>
|
||||
<p>One note here is that workspaces may also disappear (e.g. after <code>M-x exwm-workspace-delete</code>), so we also need a function to clean the list:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/exwm-last-workspaces-clear ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Clean </span><span style="color:#e6db74">`my/exwm-last-workspaces'</span><span style="color:#e6db74"> from deleted workspaces."</span>
|
||||
</span></span><span style="display:flex;"><span> (setq my/exwm-last-workspaces
|
||||
</span></span><span style="display:flex;"><span> (seq-filter
|
||||
</span></span><span style="display:flex;"><span> (lambda (i) (<span style="color:#a6e22e">nth</span> i exwm-workspace--list))
|
||||
</span></span><span style="display:flex;"><span> my/exwm-last-workspaces)))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-last-workspaces-clear</span> ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Clean </span><span style="color:#19177c">`my/exwm-last-workspaces'</span><span style="color:#ba2121"> from deleted workspaces."</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">my/exwm-last-workspaces</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">i</span>) (<span style="color:#00f">nth</span> <span style="color:#19177c">i</span> <span style="color:#19177c">exwm-workspace--list</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/exwm-last-workspaces</span>)))
|
||||
</span></span></code></pre></div><h3 id="the-monitor-list">The monitor list</h3>
|
||||
<p>The second piece of the puzzle is getting the monitor list in the right order.</p>
|
||||
<p>While it is possible to retrieve the monitor list from <code>exwm-randr-workspace-output-plist</code>, this won’t scale well beyond two monitors, mainly because changing this variable may screw up the order.</p>
|
||||
<p>So the easiest way is to just define the variable like that:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq my/exwm-monitor-list
|
||||
</span></span><span style="display:flex;"><span> (pcase (<span style="color:#a6e22e">system-name</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"indigo"</span> <span style="color:#f92672">'</span>(<span style="color:#66d9ef">nil</span> <span style="color:#e6db74">"DVI-D-0"</span>))
|
||||
</span></span><span style="display:flex;"><span> (_ <span style="color:#f92672">'</span>(<span style="color:#66d9ef">nil</span>))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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/exwm-monitor-list</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> (<span style="color:#00f">system-name</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"indigo"</span> <span style="color:#666">'</span>(<span style="color:#800">nil</span> <span style="color:#ba2121">"DVI-D-0"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">_</span> <span style="color:#666">'</span>(<span style="color:#800">nil</span>))))
|
||||
</span></span></code></pre></div><p>If you are changing the RandR configuration on the fly, this variable will also need to be changed, but for now, I don’t have such a necessity.</p>
|
||||
<p>A function to get the current monitor:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/exwm-get-current-monitor ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Return the current monitor name or nil."</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">plist-get</span> exwm-randr-workspace-output-plist
|
||||
</span></span><span style="display:flex;"><span> (cl-position (<span style="color:#a6e22e">selected-frame</span>)
|
||||
</span></span><span style="display:flex;"><span> exwm-workspace--list)))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-get-current-monitor</span> ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Return the current monitor name or nil."</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">plist-get</span> <span style="color:#19177c">exwm-randr-workspace-output-plist</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-position</span> (<span style="color:#00f">selected-frame</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">exwm-workspace--list</span>)))
|
||||
</span></span></code></pre></div><p>And a function to cycle the monitor list in either direction:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/exwm-get-other-monitor (dir)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Cycle the monitor list in the direction DIR.
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">DIR is either 'left or 'right."</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">nth</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">%</span> (<span style="color:#a6e22e">+</span> (cl-position
|
||||
</span></span><span style="display:flex;"><span> (my/exwm-get-current-monitor)
|
||||
</span></span><span style="display:flex;"><span> my/exwm-monitor-list
|
||||
</span></span><span style="display:flex;"><span> :test <span style="color:#a6e22e">#'string-equal</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">length</span> my/exwm-monitor-list)
|
||||
</span></span><span style="display:flex;"><span> (pcase dir
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'right</span> <span style="color:#ae81ff">1</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'left</span> <span style="color:#ae81ff">-1</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">length</span> my/exwm-monitor-list))
|
||||
</span></span><span style="display:flex;"><span> my/exwm-monitor-list))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-get-other-monitor</span> (<span style="color:#19177c">dir</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Cycle the monitor list in the direction DIR.
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">DIR is either 'left or 'right."</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">nth</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">%</span> (<span style="color:#00f">+</span> (<span style="color:#19177c">cl-position</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/exwm-get-current-monitor</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/exwm-monitor-list</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:test</span> <span style="color:#00f">#'string-equal</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">length</span> <span style="color:#19177c">my/exwm-monitor-list</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">dir</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'right</span> <span style="color:#666">1</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'left</span> <span style="color:#666">-1</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">length</span> <span style="color:#19177c">my/exwm-monitor-list</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">my/exwm-monitor-list</span>))
|
||||
</span></span></code></pre></div><h3 id="switch-to-another-monitor">Switch to another monitor</h3>
|
||||
<p>With the functions from the previous two sections, we can implement switching to another monitor by switching to the most recently used workspace on that monitor.</p>
|
||||
<video controls width="100%">
|
||||
<source src="/ox-hugo/exwm-workspace-switch.mp4" type="video/mp4">
|
||||
</video>
|
||||
<p>One caveat here is that on the startup the <code>my/exwm-last-workspaces</code> variable won’t have any values from other monitor(s), so this list is concatenated with the list of available workspace indices.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/exwm-switch-to-other-monitor (<span style="color:#66d9ef">&optional</span> dir)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Switch to another monitor."</span>
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (my/exwm-last-workspaces-clear)
|
||||
</span></span><span style="display:flex;"><span> (exwm-workspace-switch
|
||||
</span></span><span style="display:flex;"><span> (cl-loop with other-monitor <span style="color:#a6e22e">=</span> (my/exwm-get-other-monitor (or dir <span style="color:#e6db74">'right</span>))
|
||||
</span></span><span style="display:flex;"><span> for i in (<span style="color:#a6e22e">append</span> my/exwm-last-workspaces
|
||||
</span></span><span style="display:flex;"><span> (cl-loop for i from <span style="color:#ae81ff">0</span>
|
||||
</span></span><span style="display:flex;"><span> for _ in exwm-workspace--list
|
||||
</span></span><span style="display:flex;"><span> collect i))
|
||||
</span></span><span style="display:flex;"><span> if (if other-monitor
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">string-equal</span> (<span style="color:#a6e22e">plist-get</span> exwm-randr-workspace-output-plist i)
|
||||
</span></span><span style="display:flex;"><span> other-monitor)
|
||||
</span></span><span style="display:flex;"><span> (not (<span style="color:#a6e22e">plist-get</span> exwm-randr-workspace-output-plist i)))
|
||||
</span></span><span style="display:flex;"><span> return i)))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-switch-to-other-monitor</span> (<span style="color:#008000">&optional</span> <span style="color:#19177c">dir</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Switch to another monitor."</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/exwm-last-workspaces-clear</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">exwm-workspace-switch</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">with</span> <span style="color:#19177c">other-monitor</span> <span style="color:#00f">=</span> (<span style="color:#19177c">my/exwm-get-other-monitor</span> (<span style="color:#008000">or</span> <span style="color:#19177c">dir</span> <span style="color:#19177c">'right</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">i</span> <span style="color:#19177c">in</span> (<span style="color:#00f">append</span> <span style="color:#19177c">my/exwm-last-workspaces</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> <span style="color:#19177c">i</span> <span style="color:#19177c">from</span> <span style="color:#666">0</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">_</span> <span style="color:#19177c">in</span> <span style="color:#19177c">exwm-workspace--list</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">collect</span> <span style="color:#19177c">i</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#008000">if</span> <span style="color:#19177c">other-monitor</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">string-equal</span> (<span style="color:#00f">plist-get</span> <span style="color:#19177c">exwm-randr-workspace-output-plist</span> <span style="color:#19177c">i</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">other-monitor</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#00f">plist-get</span> <span style="color:#19177c">exwm-randr-workspace-output-plist</span> <span style="color:#19177c">i</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">return</span> <span style="color:#19177c">i</span>)))
|
||||
</span></span></code></pre></div><p>I bind this function to <code>s-q</code>, as I’m used from i3.</p>
|
||||
<h3 id="move-the-workspace-to-another-monitor">Move the workspace to another monitor</h3>
|
||||
<p>Now, moving the workspace to another monitor.</p>
|
||||
|
|
@ -240,58 +241,58 @@
|
|||
<source src="/ox-hugo/exwm-workspace-move.mp4" type="video/mp4">
|
||||
</video>
|
||||
<p>This is actually quite easy to pull off - one just has to update <code>exwm-randr-workspace-monitor-plist</code> accordingly and run <code>exwm-randr-refresh</code>. I just add another check there because I don’t want some monitor to remain without workspaces at all.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/exwm-workspace-switch-monitor ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Move the current workspace to another monitor."</span>
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (let ((new-monitor (my/exwm-get-other-monitor <span style="color:#e6db74">'right</span>))
|
||||
</span></span><span style="display:flex;"><span> (current-monitor (my/exwm-get-current-monitor)))
|
||||
</span></span><span style="display:flex;"><span> (when (and current-monitor
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">>=</span> <span style="color:#ae81ff">1</span>
|
||||
</span></span><span style="display:flex;"><span> (cl-loop for (key value) on exwm-randr-workspace-monitor-plist
|
||||
</span></span><span style="display:flex;"><span> by <span style="color:#e6db74">'cddr</span>
|
||||
</span></span><span style="display:flex;"><span> if (<span style="color:#a6e22e">string-equal</span> value current-monitor) sum <span style="color:#ae81ff">1</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">error</span> <span style="color:#e6db74">"Can't remove the last workspace on the monitor!"</span>))
|
||||
</span></span><span style="display:flex;"><span> (setq exwm-randr-workspace-monitor-plist
|
||||
</span></span><span style="display:flex;"><span> (map-delete exwm-randr-workspace-monitor-plist exwm-workspace-current-index))
|
||||
</span></span><span style="display:flex;"><span> (when new-monitor
|
||||
</span></span><span style="display:flex;"><span> (setq exwm-randr-workspace-monitor-plist
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">plist-put</span> exwm-randr-workspace-monitor-plist
|
||||
</span></span><span style="display:flex;"><span> exwm-workspace-current-index
|
||||
</span></span><span style="display:flex;"><span> new-monitor))))
|
||||
</span></span><span style="display:flex;"><span> (exwm-randr-refresh))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-workspace-switch-monitor</span> ()
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Move the current workspace to another monitor."</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">interactive</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">new-monitor</span> (<span style="color:#19177c">my/exwm-get-other-monitor</span> <span style="color:#19177c">'right</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">current-monitor</span> (<span style="color:#19177c">my/exwm-get-current-monitor</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#008000">and</span> <span style="color:#19177c">current-monitor</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">>=</span> <span style="color:#666">1</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">for</span> (<span style="color:#19177c">key</span> <span style="color:#19177c">value</span>) <span style="color:#19177c">on</span> <span style="color:#19177c">exwm-randr-workspace-monitor-plist</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">by</span> <span style="color:#19177c">'cddr</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">if</span> (<span style="color:#00f">string-equal</span> <span style="color:#19177c">value</span> <span style="color:#19177c">current-monitor</span>) <span style="color:#19177c">sum</span> <span style="color:#666">1</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">error</span> <span style="color:#ba2121">"Can't remove the last workspace on the monitor!"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">exwm-randr-workspace-monitor-plist</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">map-delete</span> <span style="color:#19177c">exwm-randr-workspace-monitor-plist</span> <span style="color:#19177c">exwm-workspace-current-index</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">new-monitor</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">exwm-randr-workspace-monitor-plist</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">plist-put</span> <span style="color:#19177c">exwm-randr-workspace-monitor-plist</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">exwm-workspace-current-index</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">new-monitor</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">exwm-randr-refresh</span>))
|
||||
</span></span></code></pre></div><p>In my configuration this is bound to <code>s-<tab></code>.</p>
|
||||
<h3 id="windmove-between-monitors">Windmove between monitors</h3>
|
||||
<p>And the final (for now) piece of the puzzle is using the same command to switch between windows and monitors. E.g. when the focus is on the right-most window on one monitor, I want the command to switch to the left-most window on the monitor to the right instead of saying “No window right from the selected window”, as <code>windmove-right</code> does.</p>
|
||||
<p>So here is my implementation of that. It always does <code>windmove-do-select-window</code> for <code>'down</code> and <code>'up</code>. For <code>'right</code> and <code>'left</code> though, the function calls the previously defined function to switch to other monitor if <code>windmove-find-other-window</code> doesn’t return anything.</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/exwm-windmove (dir)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Move to window or monitor in the direction DIR."</span>
|
||||
</span></span><span style="display:flex;"><span> (if (or (<span style="color:#a6e22e">eq</span> dir <span style="color:#e6db74">'down</span>) (<span style="color:#a6e22e">eq</span> dir <span style="color:#e6db74">'up</span>))
|
||||
</span></span><span style="display:flex;"><span> (windmove-do-window-select dir)
|
||||
</span></span><span style="display:flex;"><span> (let ((other-window (windmove-find-other-window dir))
|
||||
</span></span><span style="display:flex;"><span> (other-monitor (my/exwm-get-other-monitor dir))
|
||||
</span></span><span style="display:flex;"><span> (opposite-dir (pcase dir
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'left</span> <span style="color:#e6db74">'right</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'right</span> <span style="color:#e6db74">'left</span>))))
|
||||
</span></span><span style="display:flex;"><span> (if other-window
|
||||
</span></span><span style="display:flex;"><span> (windmove-do-window-select dir)
|
||||
</span></span><span style="display:flex;"><span> (my/exwm-switch-to-other-monitor dir)
|
||||
</span></span><span style="display:flex;"><span> (cl-loop while (windmove-find-other-window opposite-dir)
|
||||
</span></span><span style="display:flex;"><span> do (windmove-do-window-select opposite-dir))))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-windmove</span> (<span style="color:#19177c">dir</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Move to window or monitor in the direction DIR."</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> (<span style="color:#008000">or</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">dir</span> <span style="color:#19177c">'down</span>) (<span style="color:#00f">eq</span> <span style="color:#19177c">dir</span> <span style="color:#19177c">'up</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">windmove-do-window-select</span> <span style="color:#19177c">dir</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">other-window</span> (<span style="color:#19177c">windmove-find-other-window</span> <span style="color:#19177c">dir</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">other-monitor</span> (<span style="color:#19177c">my/exwm-get-other-monitor</span> <span style="color:#19177c">dir</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">opposite-dir</span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">dir</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'left</span> <span style="color:#19177c">'right</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'right</span> <span style="color:#19177c">'left</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">if</span> <span style="color:#19177c">other-window</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">windmove-do-window-select</span> <span style="color:#19177c">dir</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/exwm-switch-to-other-monitor</span> <span style="color:#19177c">dir</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#008000">while</span> (<span style="color:#19177c">windmove-find-other-window</span> <span style="color:#19177c">opposite-dir</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">do</span> (<span style="color:#19177c">windmove-do-window-select</span> <span style="color:#19177c">opposite-dir</span>))))))
|
||||
</span></span></code></pre></div><p>I bind it to the corresponding keys like that:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq exwm-input-global-keys
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">`</span>(
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">...</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; Switch windows</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-<left>"</span>) <span style="color:#f92672">.</span> (lambda () (interactive) (my/exwm-windmove <span style="color:#e6db74">'left</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-<right>"</span>) <span style="color:#f92672">.</span> (lambda () (interactive) (my/exwm-windmove <span style="color:#e6db74">'right</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-<up>"</span>) <span style="color:#f92672">.</span> (lambda () (interactive) (my/exwm-windmove <span style="color:#e6db74">'up</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-<down>"</span>) <span style="color:#f92672">.</span> (lambda () (interactive) (my/exwm-windmove <span style="color:#e6db74">'down</span>)))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">exwm-input-global-keys</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></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Switch windows</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-<left>"</span>) <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-windmove</span> <span style="color:#19177c">'left</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-<right>"</span>) <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-windmove</span> <span style="color:#19177c">'right</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-<up>"</span>) <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-windmove</span> <span style="color:#19177c">'up</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-<down>"</span>) <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-windmove</span> <span style="color:#19177c">'down</span>)))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-h"</span>) <span style="color:#f92672">.</span> (lambda () (interactive) (my/exwm-windmove <span style="color:#e6db74">'left</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-l"</span>) <span style="color:#f92672">.</span> (lambda () (interactive) (my/exwm-windmove <span style="color:#e6db74">'right</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-k"</span>) <span style="color:#f92672">.</span> (lambda () (interactive) (my/exwm-windmove <span style="color:#e6db74">'up</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-j"</span>) <span style="color:#f92672">.</span> (lambda () (interactive) (my/exwm-windmove <span style="color:#e6db74">'down</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">...</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-h"</span>) <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-windmove</span> <span style="color:#19177c">'left</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-l"</span>) <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-windmove</span> <span style="color:#19177c">'right</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-k"</span>) <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-windmove</span> <span style="color:#19177c">'up</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-j"</span>) <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-windmove</span> <span style="color:#19177c">'down</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">...</span>)
|
||||
</span></span></code></pre></div><h2 id="managing-windows">Managing windows</h2>
|
||||
<p>Another thing I want to tackle here is managing windows.</p>
|
||||
<p>This section of the post depends on <a href="https://github.com/emacs-evil/evil">evil-mode</a>, which provides a reasonable set of vim-like commands to manage windows. But a few points to improve upon remain.</p>
|
||||
|
|
@ -303,130 +304,130 @@
|
|||
</ul>
|
||||
<p>I can’t say it’s better or worse than the built-in functionality or one provided by evil, but I’m used to it and I think it fits better for managing a lot of windows.</p>
|
||||
<p>So, first, we need a predicate that checks whether there is space in the given direction:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/exwm-direction-exists-p (dir)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Check if there is space in the direction DIR.
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Does not take the minibuffer into account."</span>
|
||||
</span></span><span style="display:flex;"><span> (cl-some (lambda (dir)
|
||||
</span></span><span style="display:flex;"><span> (let ((win (windmove-find-other-window dir)))
|
||||
</span></span><span style="display:flex;"><span> (and win (not (<span style="color:#a6e22e">window-minibuffer-p</span> win)))))
|
||||
</span></span><span style="display:flex;"><span> (pcase dir
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'width</span> <span style="color:#f92672">'</span>(left right))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'height</span> <span style="color:#f92672">'</span>(up down)))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-direction-exists-p</span> (<span style="color:#19177c">dir</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Check if there is space in the direction DIR.
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">Does not take the minibuffer into account."</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-some</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">dir</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">win</span> (<span style="color:#19177c">windmove-find-other-window</span> <span style="color:#19177c">dir</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span> <span style="color:#19177c">win</span> (<span style="color:#19177c">not</span> (<span style="color:#00f">window-minibuffer-p</span> <span style="color:#19177c">win</span>)))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">dir</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'width</span> <span style="color:#666">'</span>(<span style="color:#19177c">left</span> <span style="color:#19177c">right</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'height</span> <span style="color:#666">'</span>(<span style="color:#19177c">up</span> <span style="color:#19177c">down</span>)))))
|
||||
</span></span></code></pre></div><p>And a function to implement that:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/exwm-move-window (dir)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Move the current window in the direction DIR."</span>
|
||||
</span></span><span style="display:flex;"><span> (let ((other-window (windmove-find-other-window dir))
|
||||
</span></span><span style="display:flex;"><span> (other-direction (my/exwm-direction-exists-p
|
||||
</span></span><span style="display:flex;"><span> (pcase dir
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'up</span> <span style="color:#e6db74">'width</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'down</span> <span style="color:#e6db74">'width</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'left</span> <span style="color:#e6db74">'height</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">'right</span> <span style="color:#e6db74">'height</span>)))))
|
||||
</span></span><span style="display:flex;"><span> (cond
|
||||
</span></span><span style="display:flex;"><span> ((and other-window (not (<span style="color:#a6e22e">window-minibuffer-p</span> other-window)))
|
||||
</span></span><span style="display:flex;"><span> (window-swap-states (<span style="color:#a6e22e">selected-window</span>) other-window))
|
||||
</span></span><span style="display:flex;"><span> (other-direction
|
||||
</span></span><span style="display:flex;"><span> (evil-move-window dir)))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-move-window</span> (<span style="color:#19177c">dir</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Move the current window in the direction DIR."</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">other-window</span> (<span style="color:#19177c">windmove-find-other-window</span> <span style="color:#19177c">dir</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">other-direction</span> (<span style="color:#19177c">my/exwm-direction-exists-p</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">dir</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'up</span> <span style="color:#19177c">'width</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'down</span> <span style="color:#19177c">'width</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'left</span> <span style="color:#19177c">'height</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">'right</span> <span style="color:#19177c">'height</span>)))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cond</span>
|
||||
</span></span><span style="display:flex;"><span> ((<span style="color:#008000">and</span> <span style="color:#19177c">other-window</span> (<span style="color:#19177c">not</span> (<span style="color:#00f">window-minibuffer-p</span> <span style="color:#19177c">other-window</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">window-swap-states</span> (<span style="color:#00f">selected-window</span>) <span style="color:#19177c">other-window</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">other-direction</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">evil-move-window</span> <span style="color:#19177c">dir</span>)))))
|
||||
</span></span></code></pre></div><p>My preferred keybindings for this part are, of course, <code>s-<H|J|K|L></code>:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq exwm-input-global-keys
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">`</span>(
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; Moving windows</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-H"</span>) <span style="color:#f92672">.</span> (lambda () (interactive) (my/exwm-move-window <span style="color:#e6db74">'left</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-L"</span>) <span style="color:#f92672">.</span> (lambda () (interactive) (my/exwm-move-window <span style="color:#e6db74">'right</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-K"</span>) <span style="color:#f92672">.</span> (lambda () (interactive) (my/exwm-move-window <span style="color:#e6db74">'up</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">"s-J"</span>) <span style="color:#f92672">.</span> (lambda () (interactive) (my/exwm-move-window <span style="color:#e6db74">'down</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">...</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">exwm-input-global-keys</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Moving windows</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-H"</span>) <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-move-window</span> <span style="color:#19177c">'left</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-L"</span>) <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-move-window</span> <span style="color:#19177c">'right</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-K"</span>) <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-move-window</span> <span style="color:#19177c">'up</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#666">,</span>(<span style="color:#19177c">kbd</span> <span style="color:#ba2121">"s-J"</span>) <span style="color:#666">.</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-move-window</span> <span style="color:#19177c">'down</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">...</span>))
|
||||
</span></span></code></pre></div><h3 id="resizing-windows">Resizing windows</h3>
|
||||
<p>I find this odd that there are different commands to resize tiling and floating windows.</p>
|
||||
<video controls width="100%">
|
||||
<source src="/ox-hugo/exwm-resize-hydra.mp4" type="video/mp4">
|
||||
</video>
|
||||
<p>So let’s define one command to perform both resizes depending on the context:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq my/exwm-resize-value <span style="color:#ae81ff">5</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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/exwm-resize-value</span> <span style="color:#666">5</span>)
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(defun my/exwm-resize-window (dir kind <span style="color:#66d9ef">&optional</span> value)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Resize the current window in the direction DIR.
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">DIR is either 'height or 'width, KIND is either 'shrink or
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74"> 'grow. VALUE is </span><span style="color:#e6db74">`my/exwm-resize-value'</span><span style="color:#e6db74"> by default.
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">If the window is an EXWM floating window, execute the
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">corresponding command from the exwm-layout group, execute the
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">command from the evil-window group."</span>
|
||||
</span></span><span style="display:flex;"><span> (unless value
|
||||
</span></span><span style="display:flex;"><span> (setq value my/exwm-resize-value))
|
||||
</span></span><span style="display:flex;"><span> (let* ((is-exwm-floating
|
||||
</span></span><span style="display:flex;"><span> (and (derived-mode-p <span style="color:#e6db74">'exwm-mode</span>)
|
||||
</span></span><span style="display:flex;"><span> exwm--floating-frame))
|
||||
</span></span><span style="display:flex;"><span> (func (if is-exwm-floating
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">intern</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">concat</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"exwm-layout-"</span>
|
||||
</span></span><span style="display:flex;"><span> (pcase kind (<span style="color:#e6db74">'shrink</span> <span style="color:#e6db74">"shrink"</span>) (<span style="color:#e6db74">'grow</span> <span style="color:#e6db74">"enlarge"</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"-window"</span>
|
||||
</span></span><span style="display:flex;"><span> (pcase dir (<span style="color:#e6db74">'height</span> <span style="color:#e6db74">""</span>) (<span style="color:#e6db74">'width</span> <span style="color:#e6db74">"-horizontally"</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">intern</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">concat</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"evil-window"</span>
|
||||
</span></span><span style="display:flex;"><span> (pcase kind (<span style="color:#e6db74">'shrink</span> <span style="color:#e6db74">"-decrease-"</span>) (<span style="color:#e6db74">'grow</span> <span style="color:#e6db74">"-increase-"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">symbol-name</span> dir))))))
|
||||
</span></span><span style="display:flex;"><span> (when is-exwm-floating
|
||||
</span></span><span style="display:flex;"><span> (setq value (<span style="color:#a6e22e">*</span> <span style="color:#ae81ff">5</span> value)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">funcall</span> func value)))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/exwm-resize-window</span> (<span style="color:#19177c">dir</span> <span style="color:#19177c">kind</span> <span style="color:#008000">&optional</span> <span style="color:#19177c">value</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Resize the current window in the direction DIR.
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">DIR is either 'height or 'width, KIND is either 'shrink or
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121"> 'grow. VALUE is </span><span style="color:#19177c">`my/exwm-resize-value'</span><span style="color:#ba2121"> by default.
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">If the window is an EXWM floating window, execute the
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">corresponding command from the exwm-layout group, execute the
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">command from the evil-window group."</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">unless</span> <span style="color:#19177c">value</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">value</span> <span style="color:#19177c">my/exwm-resize-value</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">is-exwm-floating</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span> (<span style="color:#19177c">derived-mode-p</span> <span style="color:#19177c">'exwm-mode</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">exwm--floating-frame</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">func</span> (<span style="color:#008000">if</span> <span style="color:#19177c">is-exwm-floating</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">intern</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"exwm-layout-"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">kind</span> (<span style="color:#19177c">'shrink</span> <span style="color:#ba2121">"shrink"</span>) (<span style="color:#19177c">'grow</span> <span style="color:#ba2121">"enlarge"</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"-window"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">dir</span> (<span style="color:#19177c">'height</span> <span style="color:#ba2121">""</span>) (<span style="color:#19177c">'width</span> <span style="color:#ba2121">"-horizontally"</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">intern</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"evil-window"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">pcase</span> <span style="color:#19177c">kind</span> (<span style="color:#19177c">'shrink</span> <span style="color:#ba2121">"-decrease-"</span>) (<span style="color:#19177c">'grow</span> <span style="color:#ba2121">"-increase-"</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">symbol-name</span> <span style="color:#19177c">dir</span>))))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">is-exwm-floating</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">value</span> (<span style="color:#00f">*</span> <span style="color:#666">5</span> <span style="color:#19177c">value</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">funcall</span> <span style="color:#19177c">func</span> <span style="color:#19177c">value</span>)))
|
||||
</span></span></code></pre></div><p>This function will call <code>exwm-layout-<shrink|grow>[-horizontally]</code> for EXWM floating window and <code>evil-window-<decrease|increase>-<width|height></code> otherwise.</p>
|
||||
<p>This function can be bound to the required keybindings directly, but I prefer a hydra to emulate the i3 submode:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defhydra my/exwm-resize-hydra (:color pink :hint <span style="color:#66d9ef">nil</span> :foreign-keys run)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">^Resize^
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">_l_: Increase width _h_: Decrease width _j_: Increase height _k_: Decrease height
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">_=_: Balance "</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"h"</span> (lambda () (interactive) (my/exwm-resize-window <span style="color:#e6db74">'width</span> <span style="color:#e6db74">'shrink</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"j"</span> (lambda () (interactive) (my/exwm-resize-window <span style="color:#e6db74">'height</span> <span style="color:#e6db74">'grow</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"k"</span> (lambda () (interactive) (my/exwm-resize-window <span style="color:#e6db74">'height</span> <span style="color:#e6db74">'shrink</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"l"</span> (lambda () (interactive) (my/exwm-resize-window <span style="color:#e6db74">'width</span> <span style="color:#e6db74">'grow</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"="</span> balance-windows)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#e6db74">"q"</span> <span style="color:#66d9ef">nil</span> <span style="color:#e6db74">"quit"</span> :color blue))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#19177c">defhydra</span> <span style="color:#19177c">my/exwm-resize-hydra</span> (<span style="color:#008000">:color</span> <span style="color:#19177c">pink</span> <span style="color:#008000">:hint</span> <span style="color:#800">nil</span> <span style="color:#008000">:foreign-keys</span> <span style="color:#19177c">run</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">^Resize^
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">_l_: Increase width _h_: Decrease width _j_: Increase height _k_: Decrease height
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">_=_: Balance "</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"h"</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-resize-window</span> <span style="color:#19177c">'width</span> <span style="color:#19177c">'shrink</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"j"</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-resize-window</span> <span style="color:#19177c">'height</span> <span style="color:#19177c">'grow</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"k"</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-resize-window</span> <span style="color:#19177c">'height</span> <span style="color:#19177c">'shrink</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"l"</span> (<span style="color:#008000">lambda</span> () (<span style="color:#008000">interactive</span>) (<span style="color:#19177c">my/exwm-resize-window</span> <span style="color:#19177c">'width</span> <span style="color:#19177c">'grow</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"="</span> <span style="color:#19177c">balance-windows</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#ba2121">"q"</span> <span style="color:#800">nil</span> <span style="color:#ba2121">"quit"</span> <span style="color:#008000">:color</span> <span style="color:#19177c">blue</span>))
|
||||
</span></span></code></pre></div><h3 id="splitting-windows">Splitting windows</h3>
|
||||
<p><code>M-x evil-window-[v]split</code> (bound to <code>C-w v</code> and <code>C-w s</code> by default) are the default evil command to do splits.</p>
|
||||
<p>One EXWM-related issue though is that by default doing such a split “copies” the current buffer to the new window. But as EXWM buffer cannot be “copied” like that, some other buffer is displayed in the split, and generally, that’s not a buffer I want.</p>
|
||||
<p>For instance, I prefer to have Chrome DevTools as a separate window. When I click “Inspect” on something, the DevTools window replaces my Ungoogled Chromium window. I press <code>C-w v</code>, and most often I have something like <code>*scratch*</code> buffer in the opened split instead of the previous Chromium window.</p>
|
||||
<p>To implement better behavior, I define the following advice:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/exwm-fill-other-window (<span style="color:#66d9ef">&rest</span> _)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"Open the most recently used buffer in the next window."</span>
|
||||
</span></span><span style="display:flex;"><span> (interactive)
|
||||
</span></span><span style="display:flex;"><span> (when (and (<span style="color:#a6e22e">eq</span> major-mode <span style="color:#e6db74">'exwm-mode</span>) (not (<span style="color:#a6e22e">eq</span> (<span style="color:#a6e22e">next-window</span>) (<span style="color:#a6e22e">get-buffer-window</span>))))
|
||||
</span></span><span style="display:flex;"><span> (let ((other-exwm-buffer
|
||||
</span></span><span style="display:flex;"><span> (cl-loop with <span style="color:#a6e22e">other-buffer</span> <span style="color:#a6e22e">=</span> (persp-other-buffer)
|
||||
</span></span><span style="display:flex;"><span> for buf in (<span style="color:#a6e22e">sort</span> (persp-current-buffers) (lambda (a _) (<span style="color:#a6e22e">eq</span> a <span style="color:#a6e22e">other-buffer</span>)))
|
||||
</span></span><span style="display:flex;"><span> with <span style="color:#a6e22e">current-buffer</span> <span style="color:#a6e22e">=</span> (<span style="color:#a6e22e">current-buffer</span>)
|
||||
</span></span><span style="display:flex;"><span> when (and (not (<span style="color:#a6e22e">eq</span> <span style="color:#a6e22e">current-buffer</span> buf))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">buffer-live-p</span> buf)
|
||||
</span></span><span style="display:flex;"><span> (not (string-match-p (persp--make-ignore-buffer-rx) (<span style="color:#a6e22e">buffer-name</span> buf)))
|
||||
</span></span><span style="display:flex;"><span> (not (<span style="color:#a6e22e">get-buffer-window</span> buf)))
|
||||
</span></span><span style="display:flex;"><span> return buf)))
|
||||
</span></span><span style="display:flex;"><span> (when other-exwm-buffer
|
||||
</span></span><span style="display:flex;"><span> (with-selected-window (<span style="color:#a6e22e">next-window</span>)
|
||||
</span></span><span style="display:flex;"><span> (switch-to-buffer other-exwm-buffer))))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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-fill-other-window</span> (<span style="color:#008000">&rest</span> <span style="color:#19177c">_</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"Open the most recently used buffer in the next 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">when</span> (<span style="color:#008000">and</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">major-mode</span> <span style="color:#19177c">'exwm-mode</span>) (<span style="color:#19177c">not</span> (<span style="color:#00f">eq</span> (<span style="color:#00f">next-window</span>) (<span style="color:#00f">get-buffer-window</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">other-exwm-buffer</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">cl-loop</span> <span style="color:#19177c">with</span> <span style="color:#00f">other-buffer</span> <span style="color:#00f">=</span> (<span style="color:#19177c">persp-other-buffer</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">for</span> <span style="color:#19177c">buf</span> <span style="color:#19177c">in</span> (<span style="color:#00f">sort</span> (<span style="color:#19177c">persp-current-buffers</span>) (<span style="color:#008000">lambda</span> (<span style="color:#19177c">a</span> <span style="color:#19177c">_</span>) (<span style="color:#00f">eq</span> <span style="color:#19177c">a</span> <span style="color:#00f">other-buffer</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">with</span> <span style="color:#00f">current-buffer</span> <span style="color:#00f">=</span> (<span style="color:#00f">current-buffer</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">when</span> (<span style="color:#008000">and</span> (<span style="color:#19177c">not</span> (<span style="color:#00f">eq</span> <span style="color:#00f">current-buffer</span> <span style="color:#19177c">buf</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">buffer-live-p</span> <span style="color:#19177c">buf</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-match-p</span> (<span style="color:#19177c">persp--make-ignore-buffer-rx</span>) (<span style="color:#00f">buffer-name</span> <span style="color:#19177c">buf</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#00f">get-buffer-window</span> <span style="color:#19177c">buf</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">return</span> <span style="color:#19177c">buf</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">other-exwm-buffer</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">with-selected-window</span> (<span style="color:#00f">next-window</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">switch-to-buffer</span> <span style="color:#19177c">other-exwm-buffer</span>))))))
|
||||
</span></span></code></pre></div><p>This is meant to be called after doing an either vertical or horizontal split, so it’s advised like that:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(advice-add <span style="color:#e6db74">'evil-window-split</span> :after <span style="color:#a6e22e">#'</span>my/exwm-fill-other-window)
|
||||
</span></span><span style="display:flex;"><span>(advice-add <span style="color:#e6db74">'evil-window-vsplit</span> :after <span style="color:#a6e22e">#'</span>my/exwm-fill-other-window)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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:#19177c">'evil-window-split</span> <span style="color:#008000">:after</span> <span style="color:#00f">#'</span><span style="color:#19177c">my/exwm-fill-other-window</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">advice-add</span> <span style="color:#19177c">'evil-window-vsplit</span> <span style="color:#008000">:after</span> <span style="color:#00f">#'</span><span style="color:#19177c">my/exwm-fill-other-window</span>)
|
||||
</span></span></code></pre></div><p>This works as follows. If the current buffer is an EXWM buffer and there are other windows open (that is, <code>(next-window)</code> is not the current window), the function tries to find another suitable buffer to be opened in the split. And that also takes the perspectives into account, so buffers are searched only within the current perspective, and the buffer returned by <code>persp-other-buffer</code> will be the top candidate.</p>
|
||||
<h2 id="notes-on-floating-windows">Notes on floating windows</h2>
|
||||
<p>Floating windows are not the most stable feature of EXWM.</p>
|
||||
<p>One story is that closing a floating window often screws up the current perspective, but that’s advised away by my <code>perspective-exwm-mode</code>.</p>
|
||||
<p>Another is that these three settings (which are reasonably <a href="https://github.com/daviwil/emacs-from-scratch/blob/5ebd390119a48cac6258843c7d5e570f4591fdd4/show-notes/Emacs-Desktop-04.org#mouse-warping">recommended</a> in the Emacs Desktop series) seem to increase chances of breaking the current EXWM session:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq exwm-workspace-warp-cursor <span style="color:#66d9ef">t</span>)
|
||||
</span></span><span style="display:flex;"><span>(setq mouse-autoselect-window <span style="color:#66d9ef">t</span>)
|
||||
</span></span><span style="display:flex;"><span>(setq focus-follows-mouse <span style="color:#66d9ef">t</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">exwm-workspace-warp-cursor</span> <span style="color:#800">t</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">mouse-autoselect-window</span> <span style="color:#800">t</span>)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">focus-follows-mouse</span> <span style="color:#800">t</span>)
|
||||
</span></span></code></pre></div><p>Occasionally they create a loop of mouse warps and focus changes. I found that disabling them just for the floating windows greatly stabilized that part:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/fix-exwm-floating-windows ()
|
||||
</span></span><span style="display:flex;"><span> (setq-local exwm-workspace-warp-cursor <span style="color:#66d9ef">nil</span>)
|
||||
</span></span><span style="display:flex;"><span> (setq-local mouse-autoselect-window <span style="color:#66d9ef">nil</span>)
|
||||
</span></span><span style="display:flex;"><span> (setq-local focus-follows-mouse <span style="color:#66d9ef">nil</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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/fix-exwm-floating-windows</span> ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">exwm-workspace-warp-cursor</span> <span style="color:#800">nil</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">mouse-autoselect-window</span> <span style="color:#800">nil</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">focus-follows-mouse</span> <span style="color:#800">nil</span>))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(add-hook <span style="color:#e6db74">'exwm-floating-setup-hook</span> <span style="color:#a6e22e">#'</span>my/fix-exwm-floating-windows)
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">'exwm-floating-setup-hook</span> <span style="color:#00f">#'</span><span style="color:#19177c">my/fix-exwm-floating-windows</span>)
|
||||
</span></span></code></pre></div><p>However, one particularly unfriendly app is the <a href="https://zoom.us/">Zoom app</a>, which proudly creates a million various popups and still manages to break the EXWM sesssion. Fortunately, it can be used from a browser, which is what I advise to do.</p>
|
||||
<h2 id="what-else-not-to-do">What else not to do</h2>
|
||||
<p>A couple of final notes to make using EXWM a somewhat better experience.</p>
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@
|
|||
<hr>
|
||||
<div id="content">
|
||||
<div class="container">
|
||||
<h1>A few cases of literate configuration</h1>
|
||||
<p>A post that arose from the discussion of literate configuration on the <a href="https://systemcrafters.net/">System Crafters</a> Discord.</p>
|
||||
<p>I am using the <a href="https://leanpub.com/lit-config">literate configuration</a> strategy (based on <a href="https://orgmode.org/">Emacs’ Org Mode</a>) to manage most of my configuration files. A piece of such a configuration can be as simple as an Org file, which is tangled to one or many plain-text configuration files, but it can be more.</p>
|
||||
<p>In my opinion, a literate configuration can be more straightforward and concise than a “normal” one, thanks to Org Mode’s capabilities of <a href="https://orgmode.org/manual/Working-with-Source-Code.html">working with source code</a>. So here I present a few examples from my configuration where I think this is the case:</p>
|
||||
|
|
@ -72,7 +73,7 @@
|
|||
<p>Let’s start with system colors.</p>
|
||||
<p>My favorite color theme is Palenight (<a href="https://github.com/JonathanSpeek/palenight-iterm2">color codes</a>), and I want to have one source of truth for these colors. Except for Emacs itself, which has <a href="https://github.com/doomemacs/themes#theme-list">doom-palenight</a> (and in which I occasionally switch to <code>doom-one-light</code>, e.g. when reading a long text), it can be done rather nicely with Org Mode.</p>
|
||||
<p>First, let’s define a table with all the color codes:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+tblname: colors
|
||||
<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>#+tblname: colors
|
||||
</span></span><span style="display:flex;"><span>| color | key | value |
|
||||
</span></span><span style="display:flex;"><span>|---------------+---------+---------|
|
||||
</span></span><span style="display:flex;"><span>| black | color0 | #292d3e |
|
||||
|
|
@ -93,7 +94,7 @@
|
|||
</span></span><span style="display:flex;"><span>| light-white | color15 | #ffffff |
|
||||
</span></span><span style="display:flex;"><span>| color-fg | | #000000 |
|
||||
</span></span></code></pre></div><p>Contents of this table can then be <a href="https://orgmode.org/manual/Environment-of-a-Code-Block.html">accessed from a code block</a>. Let’s define one to return the color code based on its name:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: get-color
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: get-color
|
||||
</span></span><span style="display:flex;"><span>#+begin_src emacs-lisp :var table=colors name="black" quote=0
|
||||
</span></span><span style="display:flex;"><span>(let ((color (seq-some (lambda (e) (and (string= name (car e)) (nth 2 e))) table)))
|
||||
</span></span><span style="display:flex;"><span> (if (> quote 0)
|
||||
|
|
@ -102,7 +103,7 @@
|
|||
</span></span><span style="display:flex;"><span>#+end_src
|
||||
</span></span></code></pre></div><p>Evaluating this block of code should return color code, corresponding to “black”.</p>
|
||||
<p>And the best part is that the results of evaluation of one code block can be included to others with <a href="https://orgmode.org/manual/Noweb-Reference-Syntax.html">noweb</a>. For instance, here’s my <a href="https://pwmt.org/projects/zathura/">zathura</a> config:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src conf-space :noweb yes :tangle .config/zathura/zathurarc
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src conf-space :noweb yes :tangle .config/zathura/zathurarc
|
||||
</span></span><span style="display:flex;"><span>set abort-clear-search false
|
||||
</span></span><span style="display:flex;"><span>set guioptions cs
|
||||
</span></span><span style="display:flex;"><span>set selection-clipboard clipboard
|
||||
|
|
@ -130,22 +131,22 @@
|
|||
</span></span><span style="display:flex;"><span>set notification-warning-fg <<get-color(name="color-fg", quote=1)>>
|
||||
</span></span><span style="display:flex;"><span>#+end_src
|
||||
</span></span></code></pre></div><p>Running <code>M-x org-babel-expand-src-block</code> (<code>C-c C-v v</code>) on this code block will open the code buffer with noweb expressions expanded, for instance the line with <code>set recolor-lightcolor</code> will look like:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>set recolor-lightcolor "#292d3e"
|
||||
<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>set recolor-lightcolor "#292d3e"
|
||||
</span></span></code></pre></div><p><code>M-x org-babel-tangle</code> (<code>C-c C-v t</code>) will also produce <code>zathurarc</code> with the colors set (given that there’s <code>:noweb yes</code> somewhere in the code block configuration).</p>
|
||||
<p>One note is that by default running these commands will require the user to confirm evaluation of each code block. To avoid that, you can set <code>org-confirm-babel-evaluate</code> to <code>nil</code>, for example:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq my/org-config-files
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">'</span>(<span style="color:#e6db74">"/home/pavel/Emacs.org"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"/home/pavel/Desktop.org"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"/home/pavel/Console.org"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"/home/pavel/Guix.org"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"/home/pavel/Mail.org"</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">setq</span> <span style="color:#19177c">my/org-config-files</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">'</span>(<span style="color:#ba2121">"/home/pavel/Emacs.org"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"/home/pavel/Desktop.org"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"/home/pavel/Console.org"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"/home/pavel/Guix.org"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"/home/pavel/Mail.org"</span>))
|
||||
</span></span><span style="display:flex;"><span>
|
||||
</span></span><span style="display:flex;"><span>(add-hook <span style="color:#e6db74">'org-mode-hook</span>
|
||||
</span></span><span style="display:flex;"><span> (lambda ()
|
||||
</span></span><span style="display:flex;"><span> (when (<span style="color:#a6e22e">member</span> (<span style="color:#a6e22e">buffer-file-name</span>) my/org-config-files)
|
||||
</span></span><span style="display:flex;"><span> (setq-local org-confirm-babel-evaluate <span style="color:#66d9ef">nil</span>))))
|
||||
</span></span><span style="display:flex;"><span>(<span style="color:#19177c">add-hook</span> <span style="color:#19177c">'org-mode-hook</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">member</span> (<span style="color:#00f">buffer-file-name</span>) <span style="color:#19177c">my/org-config-files</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq-local</span> <span style="color:#19177c">org-confirm-babel-evaluate</span> <span style="color:#800">nil</span>))))
|
||||
</span></span></code></pre></div><p>And, to close the loop on colors, let’s generate <code>.Xresources</code> from that table:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: get-xresources
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: get-xresources
|
||||
</span></span><span style="display:flex;"><span>#+begin_src emacs-lisp :var table=colors
|
||||
</span></span><span style="display:flex;"><span>(mapconcat
|
||||
</span></span><span style="display:flex;"><span> (lambda (elem)
|
||||
|
|
@ -167,19 +168,19 @@
|
|||
<h2 id="guix-dependencies">Guix dependencies</h2>
|
||||
<p>Another case I want to cover is <a href="https://guix.gnu.org/en/cookbook/en/html_node/Advanced-package-management.html#Advanced-package-management">using profiles in GNU Guix</a>.</p>
|
||||
<p>A “profile” in Guix is a way to group package installations. For instance, I have a “music” profile that has software like <a href="https://www.musicpd.org/">MPD</a>, <a href="https://github.com/ncmpcpp/ncmpcpp">ncmpcpp</a> that I’m still occasionally using because of its tag editor, etc. Corresponding to that profile, there’s a manifest named <code>music.scm</code> that looks like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#a6e22e">specifications->manifest</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">'</span>(
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"flac"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"cuetools"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"shntool"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"mpd-mpc"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"mpd-watcher"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"picard"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"ncmpcpp"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"mpd"</span>))
|
||||
<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:#ba2121">"flac"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"cuetools"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"shntool"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"mpd-mpc"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"mpd-watcher"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"picard"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"ncmpcpp"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"mpd"</span>))
|
||||
</span></span></code></pre></div><p>I could generate this file with <code>org-babel</code> as any other, but that is often not so convenient. For example, I have a <a href="https://github.com/polybar/polybar">polybar</a> module that uses <a href="https://github.com/risacher/sunwait">sunwait</a> to show sunset and sunrise times, and ideally, I want to declare <code>sunwait</code> to be in the “desktop-polybar” profile in the same section that has the polybar module definition and the bash script.</p>
|
||||
<p>So here’s an approach I came up with. The relevant section of the config looks like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>*** sun
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>*** sun
|
||||
</span></span><span style="display:flex;"><span>| Category | Guix dependency |
|
||||
</span></span><span style="display:flex;"><span>|-----------------+-----------------|
|
||||
</span></span><span style="display:flex;"><span>| desktop-polybar | sunwait |
|
||||
|
|
@ -231,79 +232,79 @@
|
|||
<li>If there is a <code>[D|d]isabled</code> column, entries that have a non-empty value in this column are filtered out.</li>
|
||||
</ul>
|
||||
<p>And here is the implementation:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/extract-guix-dependencies (<span style="color:#66d9ef">&optional</span> category)
|
||||
</span></span><span style="display:flex;"><span> (let ((dependencies <span style="color:#f92672">'</span>()))
|
||||
</span></span><span style="display:flex;"><span> (org-table-map-tables
|
||||
</span></span><span style="display:flex;"><span> (lambda ()
|
||||
</span></span><span style="display:flex;"><span> (let* ((table
|
||||
</span></span><span style="display:flex;"><span> (seq-filter
|
||||
</span></span><span style="display:flex;"><span> (lambda (q) (not (<span style="color:#a6e22e">eq</span> q <span style="color:#e6db74">'hline</span>)))
|
||||
</span></span><span style="display:flex;"><span> (org-table-to-lisp)))
|
||||
</span></span><span style="display:flex;"><span> (dep-name-index
|
||||
</span></span><span style="display:flex;"><span> (cl-position
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">nil</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mapcar</span> <span style="color:#a6e22e">#'substring-no-properties</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> table))
|
||||
</span></span><span style="display:flex;"><span> :test (lambda (_ elem)
|
||||
</span></span><span style="display:flex;"><span> (string-match-p <span style="color:#e6db74">"[G|g]uix.*dep"</span> elem))))
|
||||
</span></span><span style="display:flex;"><span> (category-name-index
|
||||
</span></span><span style="display:flex;"><span> (cl-position
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">nil</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mapcar</span> <span style="color:#a6e22e">#'substring-no-properties</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> table))
|
||||
</span></span><span style="display:flex;"><span> :test (lambda (_ elem)
|
||||
</span></span><span style="display:flex;"><span> (string-match-p <span style="color:#e6db74">".*[C|c]ategory.*"</span> elem))))
|
||||
</span></span><span style="display:flex;"><span> (disabled-name-index
|
||||
</span></span><span style="display:flex;"><span> (cl-position
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#66d9ef">nil</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mapcar</span> <span style="color:#a6e22e">#'substring-no-properties</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> table))
|
||||
</span></span><span style="display:flex;"><span> :test (lambda (_ elem)
|
||||
</span></span><span style="display:flex;"><span> (string-match-p <span style="color:#e6db74">".*[D|d]isabled.*"</span> elem)))))
|
||||
</span></span><span style="display:flex;"><span> (when dep-name-index
|
||||
</span></span><span style="display:flex;"><span> (dolist (elem (<span style="color:#a6e22e">cdr</span> table))
|
||||
</span></span><span style="display:flex;"><span> (when
|
||||
</span></span><span style="display:flex;"><span> (and
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; Category</span>
|
||||
</span></span><span style="display:flex;"><span> (or
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; Category is not set and not present in the table</span>
|
||||
</span></span><span style="display:flex;"><span> (and
|
||||
</span></span><span style="display:flex;"><span> (or (not category) (string-empty-p category))
|
||||
</span></span><span style="display:flex;"><span> (not category-name-index))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; Category is set and present in the table</span>
|
||||
</span></span><span style="display:flex;"><span> (and
|
||||
</span></span><span style="display:flex;"><span> category-name-index
|
||||
</span></span><span style="display:flex;"><span> (not (string-empty-p category))
|
||||
</span></span><span style="display:flex;"><span> (string-match-p category (<span style="color:#a6e22e">nth</span> category-name-index elem))))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#75715e">;; Not disabled</span>
|
||||
</span></span><span style="display:flex;"><span> (or
|
||||
</span></span><span style="display:flex;"><span> (not disabled-name-index)
|
||||
</span></span><span style="display:flex;"><span> (string-empty-p (<span style="color:#a6e22e">nth</span> disabled-name-index elem))))
|
||||
</span></span><span style="display:flex;"><span> (add-to-list
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'dependencies</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">substring-no-properties</span> (<span style="color:#a6e22e">nth</span> dep-name-index elem)))))))))
|
||||
</span></span><span style="display:flex;"><span> dependencies))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/extract-guix-dependencies</span> (<span style="color:#008000">&optional</span> <span style="color:#19177c">category</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">dependencies</span> <span style="color:#666">'</span>()))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-table-map-tables</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> ()
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let*</span> ((<span style="color:#19177c">table</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">q</span>) (<span style="color:#19177c">not</span> (<span style="color:#00f">eq</span> <span style="color:#19177c">q</span> <span style="color:#19177c">'hline</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">org-table-to-lisp</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">dep-name-index</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-position</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> <span style="color:#00f">#'substring-no-properties</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">table</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:test</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">_</span> <span style="color:#19177c">elem</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">"[G|g]uix.*dep"</span> <span style="color:#19177c">elem</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">category-name-index</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-position</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> <span style="color:#00f">#'substring-no-properties</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">table</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:test</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">_</span> <span style="color:#19177c">elem</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">".*[C|c]ategory.*"</span> <span style="color:#19177c">elem</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">disabled-name-index</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">cl-position</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapcar</span> <span style="color:#00f">#'substring-no-properties</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">table</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">:test</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">_</span> <span style="color:#19177c">elem</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> <span style="color:#ba2121">".*[D|d]isabled.*"</span> <span style="color:#19177c">elem</span>)))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> <span style="color:#19177c">dep-name-index</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">elem</span> (<span style="color:#00f">cdr</span> <span style="color:#19177c">table</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Category</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Category is not set and not present in the table</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span> (<span style="color:#19177c">not</span> <span style="color:#19177c">category</span>) (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">category</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> <span style="color:#19177c">category-name-index</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Category is set and present in the table</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">and</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">category-name-index</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#19177c">string-empty-p</span> <span style="color:#19177c">category</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-match-p</span> <span style="color:#19177c">category</span> (<span style="color:#00f">nth</span> <span style="color:#19177c">category-name-index</span> <span style="color:#19177c">elem</span>))))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#408080;font-style:italic">;; Not disabled</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">or</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> <span style="color:#19177c">disabled-name-index</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">string-empty-p</span> (<span style="color:#00f">nth</span> <span style="color:#19177c">disabled-name-index</span> <span style="color:#19177c">elem</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">add-to-list</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">'dependencies</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">substring-no-properties</span> (<span style="color:#00f">nth</span> <span style="color:#19177c">dep-name-index</span> <span style="color:#19177c">elem</span>)))))))))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">dependencies</span>))
|
||||
</span></span></code></pre></div><p>Let’s execute this function in the current buffer:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(my/extract-guix-dependencies <span style="color:#e6db74">"desktop-polybar"</span>)
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#e6db74">"dateutils"</span> <span style="color:#e6db74">"sunwait"</span>)
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-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/extract-guix-dependencies</span> <span style="color:#ba2121">"desktop-polybar"</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:#ba2121">"dateutils"</span> <span style="color:#ba2121">"sunwait"</span>)
|
||||
</span></span></code></pre></div><p>As expected, it found both <code>dateutils</code> and <code>sunwait</code>. To make it work in the configuration, it is necessary to format the list so that Scheme could read it:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun my/format-guix-dependencies (<span style="color:#66d9ef">&optional</span> category)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mapconcat</span>
|
||||
</span></span><span style="display:flex;"><span> (lambda (e) (<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">"\""</span> e <span style="color:#e6db74">"\""</span>))
|
||||
</span></span><span style="display:flex;"><span> (my/extract-guix-dependencies category)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"\n"</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/format-guix-dependencies</span> (<span style="color:#008000">&optional</span> <span style="color:#19177c">category</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">mapconcat</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">e</span>) (<span style="color:#00f">concat</span> <span style="color:#ba2121">"\""</span> <span style="color:#19177c">e</span> <span style="color:#ba2121">"\""</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">my/extract-guix-dependencies</span> <span style="color:#19177c">category</span>)
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"\n"</span>))
|
||||
</span></span></code></pre></div><p>And we need an Org snippet such as this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: packages
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: packages
|
||||
</span></span><span style="display:flex;"><span>#+begin_src emacs-lisp :tangle no :var category=""
|
||||
</span></span><span style="display:flex;"><span>(my/format-guix-dependencies category)
|
||||
</span></span><span style="display:flex;"><span>#+end_src
|
||||
</span></span></code></pre></div><p>Now, creating a manifest for the <code>desktop-polybar</code> profile is as simple as:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src scheme :tangle ~/.config/guix/manifests/desktop-polybar.scm :noweb yes
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src scheme :tangle ~/.config/guix/manifests/desktop-polybar.scm :noweb yes
|
||||
</span></span><span style="display:flex;"><span>(specifications->manifest
|
||||
</span></span><span style="display:flex;"><span> '(
|
||||
</span></span><span style="display:flex;"><span> <<packages("desktop-polybar")>>))
|
||||
</span></span><span style="display:flex;"><span>#+end_src
|
||||
</span></span></code></pre></div><p>There’s a newline symbol between “(” and <code><<packages("desktop-polybar")>></code> because whenever a noweb expression expands into multiple lines, for each new line noweb duplicates contents between the start of the line and the start of the expression.</p>
|
||||
<p>One reason this is so is to support languages where indentation is a part of the syntax, for instance, Python:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">TestClass</span>:
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672"><<</span>class<span style="color:#f92672">-</span>contents<span style="color:#f92672">>></span>
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">class</span> <span style="color:#00f;font-weight:bold">TestClass</span>:
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666"><<</span>class<span style="color:#666">-</span>contents<span style="color:#666">>></span>
|
||||
</span></span></code></pre></div><p>So every line of <code><<class-contents>></code> will be indented appropriately. In our case though, it is a minor inconvenience to be aware of.</p>
|
||||
<h2 id="polybar">Polybar</h2>
|
||||
<p>Now, the most <del>crazy</del> advanced case I’ve come up with so far.</p>
|
||||
|
|
@ -316,7 +317,7 @@
|
|||
</ul>
|
||||
<h3 id="colors">Colors</h3>
|
||||
<p>The “colors” part is straightforward enough. Polybar can use <code>Xresources</code>, so we just need to generate the appropriate bindings of Xresources to the polybar variables:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: get-polybar-colors
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: get-polybar-colors
|
||||
</span></span><span style="display:flex;"><span>#+begin_src emacs-lisp :var table=colors :tangle no
|
||||
</span></span><span style="display:flex;"><span>(mapconcat
|
||||
</span></span><span style="display:flex;"><span> (lambda (elem)
|
||||
|
|
@ -337,7 +338,7 @@
|
|||
</span></span></code></pre></div><h3 id="module-decorations">Module decorations</h3>
|
||||
<p>As for the module decorations though, I find it ironic that with all this fancy rendering around I have to resort to Unicode glyphs.</p>
|
||||
<p>Anyhow, the approach is to put a glyph between two blocks like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>block1 block2
|
||||
<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>block1 block2
|
||||
</span></span></code></pre></div><p>And set the foreground and background colors like that:</p>
|
||||
<table>
|
||||
<thead>
|
||||
|
|
@ -364,12 +365,12 @@
|
|||
</tbody>
|
||||
</table>
|
||||
<p>So, that’s a start. First, let’s define the glyph symbols in the polybar config:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#66d9ef">[glyph]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">gleft</span> <span style="color:#f92672">=</span> <span style="color:#e6db74"></span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">gright</span> <span style="color:#f92672">=</span> <span style="color:#e6db74"></span>
|
||||
<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">[glyph]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">gleft</span> <span style="color:#666">=</span> <span style="color:#ba2121"></span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">gright</span> <span style="color:#666">=</span> <span style="color:#ba2121"></span>
|
||||
</span></span></code></pre></div><h4 id="defining-modules">Defining modules</h4>
|
||||
<p>As we want to interweave polybar modules with these glyphs in the right order and with the right colors, it is reasonable to define a single source of truth:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: polybar_modules
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: polybar_modules
|
||||
</span></span><span style="display:flex;"><span>| Index | Module | Color | Glyph |
|
||||
</span></span><span style="display:flex;"><span>|-------+-------------+---------------+-------|
|
||||
</span></span><span style="display:flex;"><span>| 1 | pulseaudio | light-magenta | + |
|
||||
|
|
@ -386,7 +387,7 @@
|
|||
</span></span><span style="display:flex;"><span>| 13 | aw-afk | light-blue | + |
|
||||
</span></span><span style="display:flex;"><span>| 14 | date | blue | + |
|
||||
</span></span></code></pre></div><p>Also excluding some modules from certain monitors, which for now is about excluding <code>battery</code> from the monitors of my desktop PC:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: polybar_modules_exclude
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: polybar_modules_exclude
|
||||
</span></span><span style="display:flex;"><span>| Monitor | Exclude |
|
||||
</span></span><span style="display:flex;"><span>|----------+---------|
|
||||
</span></span><span style="display:flex;"><span>| DVI-D-0 | battery |
|
||||
|
|
@ -394,74 +395,74 @@
|
|||
</span></span></code></pre></div><h4 id="generating-glyphs">Generating glyphs</h4>
|
||||
<p>To generate the required set of glyphs, we need a glyph for every possible combination of adjacent colors that can occur in polybar.</p>
|
||||
<p>Most of these combinations can be inferred from the <code>polybar_modules</code> table, the rest are defined in another table:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: polybar_extra_colors
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: polybar_extra_colors
|
||||
</span></span><span style="display:flex;"><span>| Color 1 | Color 2 |
|
||||
</span></span><span style="display:flex;"><span>|------------+---------------|
|
||||
</span></span><span style="display:flex;"><span>| background | white |
|
||||
</span></span><span style="display:flex;"><span>| background | light-magenta |
|
||||
</span></span><span style="display:flex;"><span>| blue | background |
|
||||
</span></span></code></pre></div><p>There’s a definition of the source block with the required variables:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: polybar-generate-glyphs
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: polybar-generate-glyphs
|
||||
</span></span><span style="display:flex;"><span>#+begin_src emacs-lisp :var table=polybar_modules exclude-table=polybar_modules_exclude extra=polybar_extra_colors
|
||||
</span></span><span style="display:flex;"><span>...source...
|
||||
</span></span><span style="display:flex;"><span>#+end_src
|
||||
</span></span></code></pre></div><p>And there is the source block itself (because I want to have some syntax highlighting for this one in the post):</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(let* ((monitors
|
||||
</span></span><span style="display:flex;"><span> (thread-last
|
||||
</span></span><span style="display:flex;"><span> exclude-table
|
||||
</span></span><span style="display:flex;"><span> (seq-map (lambda (el) (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> el)))
|
||||
</span></span><span style="display:flex;"><span> (seq-uniq)))
|
||||
</span></span><span style="display:flex;"><span> (exclude-combinations
|
||||
</span></span><span style="display:flex;"><span> (seq-map
|
||||
</span></span><span style="display:flex;"><span> (lambda (monitor)
|
||||
</span></span><span style="display:flex;"><span> (seq-map
|
||||
</span></span><span style="display:flex;"><span> (lambda (el) (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> el))
|
||||
</span></span><span style="display:flex;"><span> (seq-filter
|
||||
</span></span><span style="display:flex;"><span> (lambda (el) (and (<span style="color:#a6e22e">string-equal</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> el) monitor)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> el)))
|
||||
</span></span><span style="display:flex;"><span> exclude-table)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">`</span>(<span style="color:#f92672">,@</span>monitors <span style="color:#e6db74">""</span>)))
|
||||
</span></span><span style="display:flex;"><span> (module-glyph-combinations
|
||||
</span></span><span style="display:flex;"><span> (thread-last
|
||||
</span></span><span style="display:flex;"><span> exclude-combinations
|
||||
</span></span><span style="display:flex;"><span> (seq-map
|
||||
</span></span><span style="display:flex;"><span> (lambda (exclude)
|
||||
</span></span><span style="display:flex;"><span> (thread-last
|
||||
</span></span><span style="display:flex;"><span> table
|
||||
</span></span><span style="display:flex;"><span> (seq-filter
|
||||
</span></span><span style="display:flex;"><span> (lambda (<span style="color:#a6e22e">elt</span>)
|
||||
</span></span><span style="display:flex;"><span> (not (or
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">member</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> <span style="color:#a6e22e">elt</span>) exclude)
|
||||
</span></span><span style="display:flex;"><span> (not (<span style="color:#a6e22e">string-equal</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">3</span> <span style="color:#a6e22e">elt</span>) <span style="color:#e6db74">"+"</span>)))))))))
|
||||
</span></span><span style="display:flex;"><span> (seq-uniq)))
|
||||
</span></span><span style="display:flex;"><span> (color-changes <span style="color:#66d9ef">nil</span>))
|
||||
</span></span><span style="display:flex;"><span> (dolist (e extra)
|
||||
</span></span><span style="display:flex;"><span> (add-to-list
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'color-changes</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">concat</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> e) <span style="color:#e6db74">"--"</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> e))))
|
||||
</span></span><span style="display:flex;"><span> (dolist (comb module-glyph-combinations)
|
||||
</span></span><span style="display:flex;"><span> (dotimes (i (<span style="color:#a6e22e">1-</span> (<span style="color:#a6e22e">length</span> comb)))
|
||||
</span></span><span style="display:flex;"><span> (add-to-list
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">'color-changes</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">concat</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">2</span> (<span style="color:#a6e22e">nth</span> i comb))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"--"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">2</span> (<span style="color:#a6e22e">nth</span> (<span style="color:#a6e22e">1+</span> i) comb))))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mapconcat</span>
|
||||
</span></span><span style="display:flex;"><span> (lambda (el)
|
||||
</span></span><span style="display:flex;"><span> (let ((colors (split-string el <span style="color:#e6db74">"--"</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">"
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">[module/glyph-%s--%s]
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">type = custom/text
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">content-background = ${colors.%s}
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">content-foreground = ${colors.%s}
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">content = ${glyph.gright}
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">content-font = 5"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> colors)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> colors)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> colors)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> colors))))
|
||||
</span></span><span style="display:flex;"><span> color-changes
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">"\n"</span>))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">monitors</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">exclude-table</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-map</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">el</span>) (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">el</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-uniq</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">exclude-combinations</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-map</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">monitor</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-map</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">el</span>) (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">el</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">el</span>) (<span style="color:#008000">and</span> (<span style="color:#00f">string-equal</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">el</span>) <span style="color:#19177c">monitor</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">el</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">exclude-table</span>)))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#666">,@</span><span style="color:#19177c">monitors</span> <span style="color:#ba2121">""</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">module-glyph-combinations</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">exclude-combinations</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-map</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">exclude</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">table</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#00f">elt</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#008000">or</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">member</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#00f">elt</span>) <span style="color:#19177c">exclude</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">not</span> (<span style="color:#00f">string-equal</span> (<span style="color:#00f">nth</span> <span style="color:#666">3</span> <span style="color:#00f">elt</span>) <span style="color:#ba2121">"+"</span>)))))))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-uniq</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">color-changes</span> <span style="color:#800">nil</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">e</span> <span style="color:#19177c">extra</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">'color-changes</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">e</span>) <span style="color:#ba2121">"--"</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">e</span>))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dolist</span> (<span style="color:#19177c">comb</span> <span style="color:#19177c">module-glyph-combinations</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">dotimes</span> (<span style="color:#19177c">i</span> (<span style="color:#00f">1-</span> (<span style="color:#00f">length</span> <span style="color:#19177c">comb</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">'color-changes</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">concat</span> (<span style="color:#00f">nth</span> <span style="color:#666">2</span> (<span style="color:#00f">nth</span> <span style="color:#19177c">i</span> <span style="color:#19177c">comb</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"--"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">nth</span> <span style="color:#666">2</span> (<span style="color:#00f">nth</span> (<span style="color:#00f">1+</span> <span style="color:#19177c">i</span>) <span style="color:#19177c">comb</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">el</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">let</span> ((<span style="color:#19177c">colors</span> (<span style="color:#19177c">split-string</span> <span style="color:#19177c">el</span> <span style="color:#ba2121">"--"</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">format</span> <span style="color:#ba2121">"
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">[module/glyph-%s--%s]
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">type = custom/text
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">content-background = ${colors.%s}
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">content-foreground = ${colors.%s}
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">content = ${glyph.gright}
|
||||
</span></span></span><span style="display:flex;"><span><span style="color:#ba2121">content-font = 5"</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">colors</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">colors</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">colors</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">colors</span>))))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">color-changes</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">"\n"</span>))
|
||||
</span></span></code></pre></div><p>Here’s a rough outline of how the code works:</p>
|
||||
<ul>
|
||||
<li><code>monitors</code> is a list of unique monitors in <code>exclude-table</code></li>
|
||||
|
|
@ -470,20 +471,20 @@
|
|||
<li><code>color-changes</code> is a list of unique adjacent colors across modules in all monitors</li>
|
||||
</ul>
|
||||
<p>Finally, <code>color-changes</code> is used to generate glyph modules that look like this:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-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:#66d9ef">[module/glyph-light-cyan--cyan]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">type</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">custom/text</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">content-background</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">${colors.light-cyan}</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">content-foreground</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">${colors.cyan}</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">content</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">${glyph.gright}</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">content-font</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">5</span>
|
||||
<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">[module/glyph-light-cyan--cyan]</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">type</span> <span style="color:#666">=</span> <span style="color:#ba2121">custom/text</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">content-background</span> <span style="color:#666">=</span> <span style="color:#ba2121">${colors.light-cyan}</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">content-foreground</span> <span style="color:#666">=</span> <span style="color:#ba2121">${colors.cyan}</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">content</span> <span style="color:#666">=</span> <span style="color:#ba2121">${glyph.gright}</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#7d9029">content-font</span> <span style="color:#666">=</span> <span style="color:#ba2121">5</span>
|
||||
</span></span></code></pre></div><p>As of now, 15 of such modules is generated.</p>
|
||||
<p>And including this in the polybar config itself:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src conf-windows :noweb yes
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src conf-windows :noweb yes
|
||||
</span></span><span style="display:flex;"><span><<polybar-generate-glyphs()>>
|
||||
</span></span><span style="display:flex;"><span>#+end_src
|
||||
</span></span></code></pre></div><h4 id="individual-modules">Individual modules</h4>
|
||||
<p>Another thing we need to do is to set the color of modules in accordance with the <code>polybar_modules</code> table. The background can be determined from the <code>Color</code> column with the following code block:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: get-polybar-bg
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: get-polybar-bg
|
||||
</span></span><span style="display:flex;"><span>#+begin_src emacs-lisp :var table=polybar_modules module="pulseaudio"
|
||||
</span></span><span style="display:flex;"><span>(format
|
||||
</span></span><span style="display:flex;"><span> "${colors.%s}"
|
||||
|
|
@ -494,7 +495,7 @@
|
|||
</span></span><span style="display:flex;"><span> table)))
|
||||
</span></span><span style="display:flex;"><span>#+end_src
|
||||
</span></span></code></pre></div><p>And that block is meant to be invoked in each module definition, e.g. for the <code>cpu</code> module:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src conf-windows :noweb yes
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+begin_src conf-windows :noweb yes
|
||||
</span></span><span style="display:flex;"><span>[module/cpu]
|
||||
</span></span><span style="display:flex;"><span>type = internal/cpu
|
||||
</span></span><span style="display:flex;"><span>format = " <label>"
|
||||
|
|
@ -504,7 +505,7 @@
|
|||
</span></span></code></pre></div><h4 id="global-polybar-configuration">Global polybar configuration</h4>
|
||||
<p>To configure polybar itself, we first need to generate a set of modules for each monitor.</p>
|
||||
<p>Here is the source block definition:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: polybar-generate-modules
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>#+NAME: polybar-generate-modules
|
||||
</span></span><span style="display:flex;"><span>#+begin_src emacs-lisp :var table=polybar_modules exclude-table=polybar_modules_exclude monitor="DVI-D-0" first-color="background" last-color="background"
|
||||
</span></span><span style="display:flex;"><span>...
|
||||
</span></span><span style="display:flex;"><span>#+end_src
|
||||
|
|
@ -515,48 +516,48 @@
|
|||
<li><code>last-color</code> - the second color of the last glyph.</li>
|
||||
</ul>
|
||||
<p>And here is the source:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(let* ((exclude-modules
|
||||
</span></span><span style="display:flex;"><span> (thread-last
|
||||
</span></span><span style="display:flex;"><span> exclude-table
|
||||
</span></span><span style="display:flex;"><span> (seq-filter (lambda (el) (<span style="color:#a6e22e">string-equal</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">0</span> el) monitor)))
|
||||
</span></span><span style="display:flex;"><span> (seq-map (lambda (el) (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> el)))))
|
||||
</span></span><span style="display:flex;"><span> (modules
|
||||
</span></span><span style="display:flex;"><span> (thread-last
|
||||
</span></span><span style="display:flex;"><span> table
|
||||
</span></span><span style="display:flex;"><span> (seq-filter (lambda (el) (not (<span style="color:#a6e22e">member</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> el) exclude-modules))))))
|
||||
</span></span><span style="display:flex;"><span> (prev-color first-color)
|
||||
</span></span><span style="display:flex;"><span> (ret <span style="color:#66d9ef">nil</span>))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">concat</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">mapconcat</span>
|
||||
</span></span><span style="display:flex;"><span> (lambda (el)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">apply</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#a6e22e">#'concat</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">list</span>
|
||||
</span></span><span style="display:flex;"><span> (when (<span style="color:#a6e22e">string-equal</span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">3</span> el) <span style="color:#e6db74">"+"</span>)
|
||||
</span></span><span style="display:flex;"><span> (setq ret (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">"glyph-%s--%s "</span> prev-color (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">2</span> el)))
|
||||
</span></span><span style="display:flex;"><span> (setq prev-color (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">2</span> el))
|
||||
</span></span><span style="display:flex;"><span> ret)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#a6e22e">nth</span> <span style="color:#ae81ff">1</span> el))))
|
||||
</span></span><span style="display:flex;"><span> modules
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#e6db74">" "</span>)
|
||||
</span></span><span style="display:flex;"><span> (unless (string-empty-p last-color) (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">" glyph-%s--%s "</span> prev-color last-color))))
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-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">exclude-modules</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">exclude-table</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">el</span>) (<span style="color:#00f">string-equal</span> (<span style="color:#00f">nth</span> <span style="color:#666">0</span> <span style="color:#19177c">el</span>) <span style="color:#19177c">monitor</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-map</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">el</span>) (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">el</span>)))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">modules</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">thread-last</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">table</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">seq-filter</span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">el</span>) (<span style="color:#19177c">not</span> (<span style="color:#00f">member</span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">el</span>) <span style="color:#19177c">exclude-modules</span>))))))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">prev-color</span> <span style="color:#19177c">first-color</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#19177c">ret</span> <span style="color:#800">nil</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">mapconcat</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">lambda</span> (<span style="color:#19177c">el</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">apply</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">list</span>
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">when</span> (<span style="color:#00f">string-equal</span> (<span style="color:#00f">nth</span> <span style="color:#666">3</span> <span style="color:#19177c">el</span>) <span style="color:#ba2121">"+"</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">ret</span> (<span style="color:#00f">format</span> <span style="color:#ba2121">"glyph-%s--%s "</span> <span style="color:#19177c">prev-color</span> (<span style="color:#00f">nth</span> <span style="color:#666">2</span> <span style="color:#19177c">el</span>)))
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#008000">setq</span> <span style="color:#19177c">prev-color</span> (<span style="color:#00f">nth</span> <span style="color:#666">2</span> <span style="color:#19177c">el</span>))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">ret</span>)
|
||||
</span></span><span style="display:flex;"><span> (<span style="color:#00f">nth</span> <span style="color:#666">1</span> <span style="color:#19177c">el</span>))))
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#19177c">modules</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#ba2121">" "</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">last-color</span>) (<span style="color:#00f">format</span> <span style="color:#ba2121">" glyph-%s--%s "</span> <span style="color:#19177c">prev-color</span> <span style="color:#19177c">last-color</span>))))
|
||||
</span></span></code></pre></div><p>Here’s how it evaluates on my current monitor:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>glyph-background--light-magenta pulseaudio glyph-light-magenta--magenta mpd glyph-magenta--cyan cpu glyph-cyan--light-green ram-memory glyph-light-green--green swap-memory glyph-green--light-red network openvpn glyph-light-red--red xkeyboard glyph-red--light-yellow weather glyph-light-yellow--yellow sun glyph-yellow--light-blue aw-afk glyph-light-blue--blue date glyph-blue--background
|
||||
<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>glyph-background--light-magenta pulseaudio glyph-light-magenta--magenta mpd glyph-magenta--cyan cpu glyph-cyan--light-green ram-memory glyph-light-green--green swap-memory glyph-green--light-red network openvpn glyph-light-red--red xkeyboard glyph-red--light-yellow weather glyph-light-yellow--yellow sun glyph-yellow--light-blue aw-afk glyph-light-blue--blue date glyph-blue--background
|
||||
</span></span></code></pre></div><p>The polybar config doesn’t support conditional statements, but it does support environment variables, so we can pass the parameters from something like a bash script. Here’s an excerpt from mine:</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>...
|
||||
</span></span><span style="display:flex;"><span>declare -A BLOCKS<span style="color:#f92672">=(</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">[</span><span style="color:#e6db74">"eDP"</span><span style="color:#f92672">]=</span><span style="color:#e6db74">"<<polybar-generate-modules(monitor="</span>eDP<span style="color:#e6db74">")>>"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">[</span><span style="color:#e6db74">"eDP-1"</span><span style="color:#f92672">]=</span><span style="color:#e6db74">"<<polybar-generate-modules(monitor="</span>eDP-1<span style="color:#e6db74">")>>"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">[</span><span style="color:#e6db74">"DVI-D-0"</span><span style="color:#f92672">]=</span><span style="color:#e6db74">"<<polybar-generate-modules(monitor="</span>DVI-D-0<span style="color:#e6db74">")>>"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#f92672">[</span><span style="color:#e6db74">"HDMI-A-0"</span><span style="color:#f92672">]=</span><span style="color:#e6db74">"<<polybar-generate-modules(monitor="</span>HDMI-A-0<span style="color:#e6db74">")>>"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#f92672">)</span>
|
||||
<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></span><span style="display:flex;"><span><span style="color:#008000">declare</span> -A <span style="color:#19177c">BLOCKS</span><span style="color:#666">=(</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">[</span><span style="color:#ba2121">"eDP"</span><span style="color:#666">]=</span><span style="color:#ba2121">"<<polybar-generate-modules(monitor="</span>eDP<span style="color:#ba2121">")>>"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">[</span><span style="color:#ba2121">"eDP-1"</span><span style="color:#666">]=</span><span style="color:#ba2121">"<<polybar-generate-modules(monitor="</span>eDP-1<span style="color:#ba2121">")>>"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">[</span><span style="color:#ba2121">"DVI-D-0"</span><span style="color:#666">]=</span><span style="color:#ba2121">"<<polybar-generate-modules(monitor="</span>DVI-D-0<span style="color:#ba2121">")>>"</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#666">[</span><span style="color:#ba2121">"HDMI-A-0"</span><span style="color:#666">]=</span><span style="color:#ba2121">"<<polybar-generate-modules(monitor="</span>HDMI-A-0<span style="color:#ba2121">")>>"</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#666">)</span>
|
||||
</span></span><span style="display:flex;"><span>...
|
||||
</span></span><span style="display:flex;"><span>pkill polybar
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> m in <span style="color:#66d9ef">$(</span>xrandr --query | grep <span style="color:#e6db74">" connected"</span> | cut -d<span style="color:#e6db74">" "</span> -f1<span style="color:#66d9ef">)</span>; <span style="color:#66d9ef">do</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">for</span> m in <span style="color:#008000;font-weight:bold">$(</span>xrandr --query | grep <span style="color:#ba2121">" connected"</span> | cut -d<span style="color:#ba2121">" "</span> -f1<span style="color:#008000;font-weight:bold">)</span>; <span style="color:#008000;font-weight:bold">do</span>
|
||||
</span></span><span style="display:flex;"><span> ...
|
||||
</span></span><span style="display:flex;"><span> export RIGHT_BLOCKS<span style="color:#f92672">=</span><span style="color:#e6db74">${</span>BLOCKS[$MONITOR]<span style="color:#e6db74">}</span>
|
||||
</span></span><span style="display:flex;"><span> <span style="color:#008000">export</span> <span style="color:#19177c">RIGHT_BLOCKS</span><span style="color:#666">=</span><span style="color:#b68;font-weight:bold">${</span><span style="color:#19177c">BLOCKS</span>[<span style="color:#19177c">$MONITOR</span>]<span style="color:#b68;font-weight:bold">}</span>
|
||||
</span></span><span style="display:flex;"><span> polybar mybar &
|
||||
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
|
||||
</span></span><span style="display:flex;"><span><span style="color:#008000;font-weight:bold">done</span>
|
||||
</span></span></code></pre></div><p>(The full script has a lot of stuff that is not relevant to this post, but you can <a href="https://github.com/SqrtMinusOne/dotfiles/blob/master/Desktop.org#launch-script-1">check here</a> if you are interested.)</p>
|
||||
<p>So, in the case of polybar, literate configuration allows for implementing a sort of logic that wouldn’t be available with the base configuration (also a promise of projects like Guix Home, by the way). Maintaining this configuration, e.g. changing the order of modules, is much easier this way than it would be if everything was hardcoded in the polybar config itself.</p>
|
||||
|
||||
|
|
|
|||
|
|
@ -59,11 +59,12 @@
|
|||
<hr>
|
||||
<div id="content">
|
||||
<div class="container">
|
||||
<h1>Hello, world!</h1>
|
||||
<h2 id="hello-world">Hello, world!</h2>
|
||||
<p>Eventually, there will be something interesting here. Or not.</p>
|
||||
<p>Regradless, I’ll check if I can write some Python here</p>
|
||||
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>print(<span style="color:#e6db74">"Hello, world"</span>)
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Hello, world
|
||||
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#008000">print</span>(<span style="color:#ba2121">"Hello, world"</span>)
|
||||
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Hello, world
|
||||
</span></span></code></pre></div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
1925
posts/index.xml
2
sass/researcher.min.css
vendored
|
|
@ -1 +1 @@
|
|||
#content a,.nav-link{color:#dc3545;text-decoration:none}#content a *,.nav-link *{color:#dc3545}#content a:hover,.nav-link:hover{color:#dc3545;text-decoration:underline}#footer a,.navbar-brand{color:#222;text-decoration:none}#footer a *,.navbar-brand *{color:#222}#footer a:hover,.navbar-brand:hover{color:#222;text-decoration:underline}#content table td,#content table th{border:1px solid #ccc;padding:6px 12px;text-align:left}*{color:#222;font-family:Inconsolata;line-height:1.2}.container{max-width:750px}.navbar-brand{font-size:2rem}#content p{margin-bottom:.6rem}#content h1,#content h2,#content h3,#content h4,#content h5,#content h6{font-size:medium;font-weight:700;margin:1rem 0 .6rem}#content h1{font-size:1.8rem}#content h2{font-size:1.6rem}#content h3{font-size:1.4rem}#content h4{font-size:1.2rem}#content img{display:block;margin:1rem auto;max-width:100%}#content .avatar>img{border-radius:50%;float:right;margin:-8px 0 0 16px;height:90px;width:90px}#content ol{counter-reset:list;list-style:none;padding-left:2rem}#content ol>li{display:table-row}#content ol>li:before{content:"[" counter(list,decimal)"] ";counter-increment:list;display:table-cell;text-align:right;padding-right:.5em}#content .container>ol,#content .footnotes>ol{padding-left:0}#content ul{list-style:inside;padding-left:2rem}#content ul>li{list-style-position:outside;margin-left:1em}#content .container>ul,#content .footnotes>ul{padding-left:0}#content table{margin:1rem auto;width:100%}#content table th{font-weight:700}#content table tr:nth-child(2n){background-color:#f8f8f8}#content blockquote{border-left:4px solid;font-style:italic;margin:1rem 0;padding:8px}#content code{color:#222;background-color:#f8f8f8;border:1px solid #ccc;border-radius:10%;padding:0 4px;font-family:inconsolata!important}#content code span{color:#f8f8f8}#content pre code{all:unset;font-size:110%}#content .highlight{margin:1rem auto}#content .highlight>pre{padding:8px}
|
||||
#content a,.nav-link{color:#dc3545;text-decoration:none}#content a *,.nav-link *{color:#dc3545}#content a:hover,.nav-link:hover{color:#dc3545;text-decoration:underline}#footer a,.navbar-brand{color:#222;text-decoration:none}#footer a *,.navbar-brand *{color:#222}#footer a:hover,.navbar-brand:hover{color:#222;text-decoration:underline}#content table td,#content table th{border:1px solid #ccc;padding:6px 12px;text-align:left}*{color:#222;font-family:Inconsolata;line-height:1.2}.container{max-width:750px}.navbar-brand{font-size:2rem}#content p{margin-bottom:.6rem}#content h1,#content h2,#content h3,#content h4,#content h5,#content h6{font-size:medium;font-weight:700;margin:1rem 0 .6rem}#content h1{font-size:1.8rem}#content h2{font-size:1.6rem}#content h3{font-size:1.4rem}#content h4{font-size:1.2rem}#content img{display:block;margin:1rem auto;max-width:100%}#content .avatar>img{border-radius:50%;float:right;margin:-8px 0 0 16px;height:90px;width:90px}#content ol{counter-reset:list;list-style:none;padding-left:2rem}#content ol>li{display:table-row}#content ol>li:before{content:"[" counter(list,decimal)"] ";counter-increment:list;display:table-cell;text-align:right;padding-right:.5em}#content .container>ol,#content .footnotes>ol{padding-left:0}#content ul{list-style:inside;padding-left:2rem}#content ul>li{list-style-position:outside;margin-left:1em}#content .container>ul,#content .footnotes>ul{padding-left:0}#content table{margin:1rem auto;width:100%}#content table th{font-weight:700}#content table tr:nth-child(2n){background-color:#f8f8f8}#content blockquote{border-left:4px solid;font-style:italic;margin:1rem 0;padding:8px}#content code{color:#222;background-color:#f8f8f8;border:1px solid #ccc;border-radius:10%;padding:0 4px;font-family:inconsolata!important}#content pre code{all:unset;font-size:110%}#content .highlight{margin:1rem auto;border:1px solid #ccc}#content .highlight>pre{padding:8px;margin-bottom:0}
|
||||
BIN
stats/all.png
|
Before Width: | Height: | Size: 121 KiB After Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 67 KiB |