mirror of
https://github.com/SqrtMinusOne/sqrtminusone.github.io.git
synced 2025-12-10 15:53:03 +03:00
627 lines
64 KiB
HTML
627 lines
64 KiB
HTML
<!DOCTYPE html>
|
|
<html lang=""><head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
|
|
<title>A few cases of literate configuration</title>
|
|
<meta name="description" content="Freedom is a state of mind">
|
|
<meta name="author" content='SqrtMinusOne'>
|
|
|
|
<link href="https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous">
|
|
|
|
|
|
<link rel="stylesheet" href="/sass/researcher.min.css">
|
|
|
|
|
|
<link rel="icon" type="image/ico" href="https://sqrtminusone.xyz/favicon.ico">
|
|
|
|
|
|
<script defer data-domain="sqrtminusone.xyz" src="https://plausible.sqrtminusone.xyz/js/plausible.js"></script>
|
|
|
|
</head>
|
|
|
|
<body><div class="container mt-5">
|
|
<nav class="navbar navbar-expand-sm flex-column flex-sm-row text-nowrap p-0">
|
|
<a class="navbar-brand mx-0 mr-sm-auto" href="https://sqrtminusone.xyz/" title="SqrtMinusOne">
|
|
|
|
SqrtMinusOne
|
|
</a>
|
|
<div class="navbar-nav flex-row flex-wrap justify-content-center">
|
|
|
|
|
|
|
|
<a class="nav-item nav-link" href="/" title="Index">
|
|
Index
|
|
</a>
|
|
|
|
<span class="nav-item navbar-text mx-1">/</span>
|
|
|
|
|
|
<a class="nav-item nav-link" href="/posts/" title="Posts">
|
|
Posts
|
|
</a>
|
|
|
|
<span class="nav-item navbar-text mx-1">/</span>
|
|
|
|
|
|
<a class="nav-item nav-link" href="/configs/readme" title="Configs">
|
|
Configs
|
|
</a>
|
|
|
|
<span class="nav-item navbar-text mx-1">/</span>
|
|
|
|
|
|
<a class="nav-item nav-link" href="/emacs-packages/" title="Emacs packages">
|
|
Emacs packages
|
|
</a>
|
|
|
|
|
|
|
|
</div>
|
|
</nav>
|
|
</div>
|
|
<hr>
|
|
<div id="content">
|
|
<script defer language="javascript" type="text/javascript" src="/js/dynamic-toc.js"></script>
|
|
|
|
<div class="root">
|
|
<h1 id="title-small-screen">A few cases of literate configuration</h1>
|
|
<div class="container" id="actual-content">
|
|
<h1 id="title-large-screen">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>
|
|
<ul>
|
|
<li>Managing system colors</li>
|
|
<li>Managing manifests for Guix profiles</li>
|
|
<li>Configuring modules in polybar</li>
|
|
</ul>
|
|
<p>I hope you find something interesting here!</p>
|
|
<h2 id="colors">Colors</h2>
|
|
<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=";-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 |
|
|
</span></span><span style="display:flex;"><span>| red | color1 | #f07178 |
|
|
</span></span><span style="display:flex;"><span>| green | color2 | #c3e88d |
|
|
</span></span><span style="display:flex;"><span>| yellow | color3 | #ffcb6b |
|
|
</span></span><span style="display:flex;"><span>| blue | color4 | #82aaff |
|
|
</span></span><span style="display:flex;"><span>| magenta | color5 | #c792ea |
|
|
</span></span><span style="display:flex;"><span>| cyan | color6 | #89ddff |
|
|
</span></span><span style="display:flex;"><span>| white | color7 | #d0d0d0 |
|
|
</span></span><span style="display:flex;"><span>| light-black | color8 | #434758 |
|
|
</span></span><span style="display:flex;"><span>| light-red | color9 | #ff8b92 |
|
|
</span></span><span style="display:flex;"><span>| light-green | color10 | #ddffa7 |
|
|
</span></span><span style="display:flex;"><span>| light-yellow | color11 | #ffe585 |
|
|
</span></span><span style="display:flex;"><span>| light-blue | color12 | #9cc4ff |
|
|
</span></span><span style="display:flex;"><span>| light-magenta | color13 | #e1acff |
|
|
</span></span><span style="display:flex;"><span>| light-cyan | color14 | #a3f7ff |
|
|
</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=";-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)
|
|
</span></span><span style="display:flex;"><span> (concat "\"" color "\"")
|
|
</span></span><span style="display:flex;"><span> color))
|
|
</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=";-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
|
|
</span></span><span style="display:flex;"><span>set recolor true
|
|
</span></span><span style="display:flex;"><span>map <C-r> set recolor false
|
|
</span></span><span style="display:flex;"><span>map <C-R> set recolor true
|
|
</span></span><span style="display:flex;"><span>
|
|
</span></span><span style="display:flex;"><span>set recolor-lightcolor <<get-color(name="black", quote=1)>>
|
|
</span></span><span style="display:flex;"><span>
|
|
</span></span><span style="display:flex;"><span>set completion-bg <<get-color(name="black", quote=1)>>
|
|
</span></span><span style="display:flex;"><span>set completion-fg <<get-color(name="white", quote=1)>>
|
|
</span></span><span style="display:flex;"><span>set completion-group-bg <<get-color(name="light-black", quote=1)>>
|
|
</span></span><span style="display:flex;"><span>set completion-group-fg <<get-color(name="white", quote=1)>>
|
|
</span></span><span style="display:flex;"><span>set completion-highlight-bg <<get-color(name="magenta", quote=1)>>
|
|
</span></span><span style="display:flex;"><span>set completion-highlight-fg <<get-color(name="black", quote=1)>>
|
|
</span></span><span style="display:flex;"><span>
|
|
</span></span><span style="display:flex;"><span>set inputbar-bg <<get-color(name="black", quote=1)>>
|
|
</span></span><span style="display:flex;"><span>set inputbar-fg <<get-color(name="light-magenta", quote=1)>>
|
|
</span></span><span style="display:flex;"><span>set statusbar-bg <<get-color(name="black", quote=1)>>
|
|
</span></span><span style="display:flex;"><span>set statusbar-fg <<get-color(name="light-magenta", quote=1)>>
|
|
</span></span><span style="display:flex;"><span>
|
|
</span></span><span style="display:flex;"><span>set notification-error-bg <<get-color(name="red", quote=1)>>
|
|
</span></span><span style="display:flex;"><span>set notification-error-fg <<get-color(name="color-fg", quote=1)>>
|
|
</span></span><span style="display:flex;"><span>set notification-warning-bg <<get-color(name="yellow", quote=1)>>
|
|
</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=";-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=";-moz-tab-size:4;-o-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>(<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=";-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)
|
|
</span></span><span style="display:flex;"><span> (concat "*" (nth 1 elem) ": " (nth 2 elem)))
|
|
</span></span><span style="display:flex;"><span> (seq-filter
|
|
</span></span><span style="display:flex;"><span> (lambda (elem) (and (nth 1 elem)
|
|
</span></span><span style="display:flex;"><span> (not (string-empty-p (nth 1 elem)))))
|
|
</span></span><span style="display:flex;"><span> table)
|
|
</span></span><span style="display:flex;"><span> "\n")
|
|
</span></span><span style="display:flex;"><span>#+end_src
|
|
</span></span><span style="display:flex;"><span>
|
|
</span></span><span style="display:flex;"><span>#+begin_src conf-xdefaults :noweb yes :tangle ~/.Xresources
|
|
</span></span><span style="display:flex;"><span><<get-xresources()>>
|
|
</span></span><span style="display:flex;"><span>
|
|
</span></span><span style="display:flex;"><span>*background: <<get-color(name="black")>>
|
|
</span></span><span style="display:flex;"><span>*foreground: <<get-color(name="white")>>
|
|
</span></span><span style="display:flex;"><span>#+end_src
|
|
</span></span></code></pre></div><p>So, whenever a program is capable of reading <code>.Xresources</code>, it will get colors from there, otherwise, it will get colors from noweb expressions in the literate config. Thus, in both cases, the color is set in a single Org Mode table.</p>
|
|
<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=";-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=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>*** sun
|
|
</span></span><span style="display:flex;"><span>| Category | Guix dependency |
|
|
</span></span><span style="display:flex;"><span>|-----------------+-----------------|
|
|
</span></span><span style="display:flex;"><span>| desktop-polybar | sunwait |
|
|
</span></span><span style="display:flex;"><span>
|
|
</span></span><span style="display:flex;"><span>Prints out the time of sunrise/sunset. Uses [[https://github.com/risacher/sunwait][sunwait]]
|
|
</span></span><span style="display:flex;"><span>
|
|
</span></span><span style="display:flex;"><span>#+begin_src bash :tangle ./bin/polybar/sun.sh :noweb yes
|
|
</span></span><span style="display:flex;"><span>...script...
|
|
</span></span><span style="display:flex;"><span>#+end_src
|
|
</span></span><span style="display:flex;"><span>
|
|
</span></span><span style="display:flex;"><span>#+begin_src conf-windows :noweb yes
|
|
</span></span><span style="display:flex;"><span>...polybar module definition...
|
|
</span></span><span style="display:flex;"><span>#+end_src
|
|
</span></span></code></pre></div><p><code>sunwait</code> is declared in an Org table that looks like that:</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Category</th>
|
|
<th>Guix dependency</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>desktop-polybar</td>
|
|
<td>sunwait</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>Such tables are spread through my <code>Desktop.org</code>, for instance, here is another one for a polybar module that depends on dateutils:</p>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Category</th>
|
|
<th>Guix dependency</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>desktop-polybar</td>
|
|
<td>dateutils</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<p>Thus I made a function that extracts packages from all such tables from the current Org buffer. The rules are as follows:</p>
|
|
<ul>
|
|
<li>If a column name matches <code>[G|g]uix.*dep</code>, its contents are added to the result.</li>
|
|
<li>If <code>CATEGORY</code> is passed, a column with name <code>[C|c]ategory</code> is used to filter results. That way, one Org file can be used to produce multiple manifests.</li>
|
|
<li>If <code>CATEGORY</code> is not passed, entries with the non-empty category are filtered out</li>
|
|
<li>If there is a <code>[D|d]isabled</code> column, entries that have a non-empty value in this column are filtered out.</li>
|
|
</ul>
|
|
<p>And here is the implementation:</p>
|
|
<div class="highlight"><pre tabindex="0" style=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(<span style="color:#008000">defun</span> <span style="color:#19177c">my/extract-guix-dependencies</span> (<span style="color:#008000">&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=";-moz-tab-size:4;-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=";-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code 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=";-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=";-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=";-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>
|
|
<p>Basically, here is how my <a href="https://github.com/polybar/polybar">polybar</a> currently looks:
|
|
<img src="/images/literate--polybar.png" alt=""></p>
|
|
<p>It has:</p>
|
|
<ul>
|
|
<li>colors from the general color theme;</li>
|
|
<li>powerline-ish decorations between modules.</li>
|
|
</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=";-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)
|
|
</span></span><span style="display:flex;"><span> (format "%s = ${xrdb:%s}" (nth 0 elem) (nth 1 elem)))
|
|
</span></span><span style="display:flex;"><span> (seq-filter
|
|
</span></span><span style="display:flex;"><span> (lambda (elem) (when-let (name (nth 1 elem))
|
|
</span></span><span style="display:flex;"><span> (not (string-empty-p name))))
|
|
</span></span><span style="display:flex;"><span> table)
|
|
</span></span><span style="display:flex;"><span> "\n")
|
|
</span></span><span style="display:flex;"><span>#+end_src
|
|
</span></span><span style="display:flex;"><span>
|
|
</span></span><span style="display:flex;"><span>#+begin_src conf-windows :noweb yes
|
|
</span></span><span style="display:flex;"><span>[colors]
|
|
</span></span><span style="display:flex;"><span><<get-polybar-colors()>>
|
|
</span></span><span style="display:flex;"><span>
|
|
</span></span><span style="display:flex;"><span>background = ${xrdb:background}
|
|
</span></span><span style="display:flex;"><span>#+end_src
|
|
</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=";-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>
|
|
<tr>
|
|
<th></th>
|
|
<th>block1</th>
|
|
<th>glyph</th>
|
|
<th>block2</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>foreground</td>
|
|
<td>F1</td>
|
|
<td>B2</td>
|
|
<td>F2</td>
|
|
</tr>
|
|
<tr>
|
|
<td>background</td>
|
|
<td>B1</td>
|
|
<td>B1</td>
|
|
<td>B2</td>
|
|
</tr>
|
|
</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=";-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=";-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 | + |
|
|
</span></span><span style="display:flex;"><span>| 2 | mpd | magenta | + |
|
|
</span></span><span style="display:flex;"><span>| 9 | battery | light-cyan | + |
|
|
</span></span><span style="display:flex;"><span>| 3 | cpu | cyan | + |
|
|
</span></span><span style="display:flex;"><span>| 4 | ram-memory | light-green | + |
|
|
</span></span><span style="display:flex;"><span>| 5 | swap-memory | green | + |
|
|
</span></span><span style="display:flex;"><span>| 6 | network | light-red | + |
|
|
</span></span><span style="display:flex;"><span>| 7 | openvpn | light-red | |
|
|
</span></span><span style="display:flex;"><span>| 8 | xkeyboard | red | + |
|
|
</span></span><span style="display:flex;"><span>| 10 | weather | light-yellow | + |
|
|
</span></span><span style="display:flex;"><span>| 12 | sun | yellow | + |
|
|
</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=";-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 |
|
|
</span></span><span style="display:flex;"><span>| HDMI-A-0 | battery |
|
|
</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=";-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=";-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=";-moz-tab-size:4;-o-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>
|
|
<li><code>exclude-combilnations</code> is a list of lists of module names to be excluded for each monitor</li>
|
|
<li><code>module-glyphs-combinations</code> is a list of lists of actual modules for each monitor</li>
|
|
<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=";-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=";-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=";-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}"
|
|
</span></span><span style="display:flex;"><span> (nth
|
|
</span></span><span style="display:flex;"><span> 2
|
|
</span></span><span style="display:flex;"><span> (seq-find
|
|
</span></span><span style="display:flex;"><span> (lambda (el) (string-equal (nth 1 el) module))
|
|
</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=";-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>"
|
|
</span></span><span style="display:flex;"><span>label = %percentage%%
|
|
</span></span><span style="display:flex;"><span>format-background = <<get-polybar-bg(module="cpu")>>
|
|
</span></span><span style="display:flex;"><span>#+end_src
|
|
</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=";-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
|
|
</span></span></code></pre></div><p>The parameters here, excluding the two required tables, are:</p>
|
|
<ul>
|
|
<li><code>monitor</code> - the current monitor on which to filter out the blocks by the <code>polybar_modules_exclude</code> table,</li>
|
|
<li><code>first-color</code> - the first color of the first glyph,</li>
|
|
<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=";-moz-tab-size:4;-o-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=";-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=";-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:#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> <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:#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>
|
|
|
|
</div>
|
|
<div class="table-of-contents">
|
|
<div class="table-of-contents-text">
|
|
<b><a href="#">Table of Contents</a></b>
|
|
<nav id="TableOfContents">
|
|
<ul>
|
|
<li><a href="#colors">Colors</a></li>
|
|
<li><a href="#guix-dependencies">Guix dependencies</a></li>
|
|
<li><a href="#polybar">Polybar</a>
|
|
<ul>
|
|
<li><a href="#colors">Colors</a></li>
|
|
<li><a href="#module-decorations">Module decorations</a>
|
|
<ul>
|
|
<li><a href="#defining-modules">Defining modules</a></li>
|
|
<li><a href="#generating-glyphs">Generating glyphs</a></li>
|
|
<li><a href="#individual-modules">Individual modules</a></li>
|
|
<li><a href="#global-polybar-configuration">Global polybar configuration</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
<a id="unhide-all-button" class="hidden"><Expand></a>
|
|
<a id="hide-all-button" class="hidden"><Collapse></a>
|
|
</div>
|
|
</div>
|
|
|
|
</div><div id="footer" class="mb-5">
|
|
<hr>
|
|
<div class="container text-center">
|
|
|
|
</div>
|
|
|
|
<div class="container text-center">
|
|
|
|
|
|
<a href="https://creativecommons.org/licenses/by/4.0/legalcode" title="Licensed under CC-BY 4.0"><small>Licensed under CC-BY 4.0</small></a>
|
|
|
|
|
|
|
|
|
|
|
<a href="https://plausible.io/" title="Uses Plausible Analytics"><small>Uses Plausible Analytics</small></a>
|
|
|
|
|
|
<br>
|
|
|
|
<a href="https://sqrtminusone.xyz/" title="Pavel Korytov, 2024"><small>Pavel Korytov, 2024</small></a>
|
|
</div>
|
|
|
|
</div>
|
|
</body>
|
|
</html>
|