sqrtminusone.github.io/packages/index.xml
2025-04-20 21:50:25 +00:00

1859 lines
224 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

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

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Packages on SqrtMinusOne</title>
<link>https://sqrtminusone.xyz/packages/</link>
<description>Recent content in Packages on SqrtMinusOne</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Fri, 08 Mar 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://sqrtminusone.xyz/packages/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>eshell-atuin</title>
<link>https://sqrtminusone.xyz/packages/eshell-atuin/</link>
<pubDate>Fri, 08 Mar 2024 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/eshell-atuin/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/eshell-atuin&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/eshell-atuin-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;Integrate &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_mono/eshell.html&#34;&gt;eshell&lt;/a&gt; with &lt;a href=&#34;https://github.com/atuinsh/atuin&#34;&gt;atuin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;atuin&lt;/code&gt; stores shell history in a database, which allows for having the same history across multiple shells, sessions, and optionally across different machines. See the project page for the complete list of features.&lt;/p&gt;
&lt;p&gt;This package provides functionality to store and browse eshell history in &lt;code&gt;atuin&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you normally install packages, I prefer &lt;a href=&#34;https://github.com/jwiegley/use-package&#34;&gt;use-package&lt;/a&gt; and &lt;a href=&#34;https://github.com/radian-software/straight.el&#34;&gt;straight.el&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eshell-atuin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eshell&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;eshell-atuin-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alternatively, clone the repository, add it to the &lt;code&gt;load-path&lt;/code&gt;, and &lt;code&gt;require&lt;/code&gt; the package.&lt;/p&gt;
&lt;p&gt;If your version of &lt;code&gt;atuin&lt;/code&gt; is less than 18, turn off saving command durations:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eshell-atuin-save-duration&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;configuration&#34;&gt;Configuration&lt;/h2&gt;
&lt;p&gt;If your &lt;code&gt;atuin&lt;/code&gt; binary is located in a place unknown to &lt;code&gt;executable-find&lt;/code&gt;, set the &lt;code&gt;atuin-executable&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;If you are using a vertical completion system such as &lt;a href=&#34;https://github.com/abo-abo/swiper&#34;&gt;Ivy&lt;/a&gt;, &lt;a href=&#34;https://github.com/radian-software/selectrum&#34;&gt;Selectrum&lt;/a&gt;, etc., you can configure the completion interface, e.g.:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eshell-atuin-search-fields&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;time&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;duration&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;command&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eshell-atuin-history-format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;%-160c %t + %d&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The available flags are:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Flag&lt;/th&gt;
&lt;th&gt;atuin field (see &lt;code&gt;help atuin search&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;Required&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;%t&lt;/td&gt;
&lt;td&gt;&lt;code&gt;time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%c&lt;/td&gt;
&lt;td&gt;&lt;code&gt;command&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%e&lt;/td&gt;
&lt;td&gt;&lt;code&gt;exit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%d&lt;/td&gt;
&lt;td&gt;&lt;code&gt;duration&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%i&lt;/td&gt;
&lt;td&gt;&lt;code&gt;directory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%u&lt;/td&gt;
&lt;td&gt;&lt;code&gt;user&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%h&lt;/td&gt;
&lt;td&gt;&lt;code&gt;host&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;%r&lt;/td&gt;
&lt;td&gt;&lt;code&gt;relativetime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;See &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Custom-Format-Strings.html&#34;&gt;(emacs) Custom Format Strings&lt;/a&gt; for information on the general &lt;code&gt;format-spec&lt;/code&gt; syntax.&lt;/p&gt;
&lt;p&gt;I suspect the package might be slow if your history has a lot of records (I haven&amp;rsquo;t checked yet). In this case, it might be worth setting a limit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eshell-atuin-search-options&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--exit&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;--limit&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;10000&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the package ignores imported history, remove &lt;code&gt;--exit 0&lt;/code&gt; from the options (see &lt;a href=&#34;https://github.com/SqrtMinusOne/eshell-atuin/issues/9&#34;&gt;#9&lt;/a&gt;).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eshell-atuin-search-options&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;Enable &lt;code&gt;eshell-atuin-mode&lt;/code&gt; to turn on storing eshell commands in &lt;code&gt;atuin&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;eshell-atuin-history&lt;/code&gt; inside an &lt;code&gt;eshell&lt;/code&gt; buffer to browse the saved history. Accepting the completion will insert the command.&lt;/p&gt;
&lt;h3 id=&#34;filter-mode&#34;&gt;Filter mode&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;atuin&lt;/code&gt; supports 4 &lt;a href=&#34;https://docs.atuin.sh/configuration/config/#filter_mode&#34;&gt;filter modes&lt;/a&gt;: global (default), host, session, directory. Default filter mode for &lt;code&gt;eshell-atuin&lt;/code&gt; can be set as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eshell-atuin-filter-mode&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;global&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In order to switch the mode at runtime, run &lt;code&gt;M-x eshell-atuin-history&lt;/code&gt; with the prefix argument:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;C-u 0 M-x eshell-atuin-history&lt;/code&gt; for &lt;code&gt;global&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-u 1 M-x eshell-atuin-history&lt;/code&gt; for &lt;code&gt;host&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-u 2 M-x eshell-atuin-history&lt;/code&gt; for &lt;code&gt;session&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C-u 3 M-x eshell-atuin-history&lt;/code&gt; for &lt;code&gt;directory&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;implementation-notes&#34;&gt;Implementation notes&lt;/h2&gt;
&lt;p&gt;I may have overengineered the package a bit to scale on lots of records.&lt;/p&gt;
&lt;p&gt;The package caches the results of &lt;code&gt;atuin search&lt;/code&gt; in &lt;code&gt;eshell-atuin--history-cache&lt;/code&gt; (which see on the algorithm), and updates the cache incrementally. A formatted string for each entry is created at the moment of addition; entries are additionally &amp;ldquo;indexed&amp;rdquo; by a hashmap to lookup &amp;ldquo;raw&amp;rdquo; commands by their formatted versions.&lt;/p&gt;
&lt;p&gt;So, the only places I see with the computational complexity of O(N), where N is the number of unique commands in &lt;code&gt;atuin&lt;/code&gt;, are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;populating the cache at the first run of &lt;code&gt;M-x eshell-atuin-history&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;feeding the entirety of the cache to &lt;code&gt;completing-read&lt;/code&gt; on each run of &lt;code&gt;M-x eshell-atuin-history&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
</content>
</item>
<item>
<title>org-clock-agg</title>
<link>https://sqrtminusone.xyz/packages/org-clock-agg/</link>
<pubDate>Sun, 17 Dec 2023 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/org-clock-agg/</guid>
<content type="html">
&lt;p&gt;Aggregate &lt;a href=&#34;https://orgmode.org/manual/Clocking-Work-Time.html&#34;&gt;org-clock&lt;/a&gt; records and display the results in an interactive buffer. The records are grouped by predicates such as file name, their outline path in the file, etc. Each record is placed in a tree structure; each node of the tree shows the total time spent in that node and its children. The top-level node shows the total time spent in all records found by the query.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/org-clock-agg-img/screenshot.png&#34;&gt;
&lt;/figure&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package isn&amp;rsquo;t yet available anywhere but in this repository. My preferred way for such cases is &lt;a href=&#34;https://github.com/jwiegley/use-package&#34;&gt;use-package&lt;/a&gt; and &lt;a href=&#34;https://github.com/radian-software/straight.el&#34;&gt;straight.el&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-clock-agg&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;github&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:repo&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;SqrtMinusOne/org-clock-agg&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alternatively, clone the repository, add it to the &lt;code&gt;load-path&lt;/code&gt;, and &lt;code&gt;require&lt;/code&gt; the package.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;M-x org-clock-agg&lt;/code&gt; to open the interactive buffer (as depicted in the screenshot above).&lt;/p&gt;
&lt;p&gt;The interactive buffer provides the following controls:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Files&lt;/strong&gt;: Specifies the org files from which to select (defaults to &lt;a href=&#34;https://orgmode.org/manual/Agenda-Files.html&#34;&gt;org-agenda&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Date from&lt;/strong&gt; and &lt;strong&gt;To&lt;/strong&gt;: Define the date range.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Group by&lt;/strong&gt;: Determines how &lt;code&gt;org-clock&lt;/code&gt; records are grouped.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Show elements&lt;/strong&gt;: Whether to display raw &lt;code&gt;org-clock&lt;/code&gt; records in each node.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add &amp;ldquo;Ungrouped&amp;rdquo;&lt;/strong&gt;: Option to include the &amp;ldquo;Ungrouped&amp;rdquo; node. This is particularly useful with &lt;a href=&#34;#custom-grouping-predicates&#34;&gt;custom grouping predicates&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Press &lt;code&gt;[Refresh]&lt;/code&gt; to update the buffer. The initial search might take some time, but subsequent searches are generally faster due to the caching mechanism employed by &lt;a href=&#34;https://github.com/alphapapa/org-ql&#34;&gt;org-ql&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The buffer uses &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/emacs/Outline-Mode.html&#34;&gt;outline-mode&lt;/a&gt; to display the tree, so each node becomes an &lt;code&gt;outline-mode&lt;/code&gt; header. Refer to the linked manual for available commands/keybindings, or, if you use &lt;code&gt;evil-mode&lt;/code&gt;, check &lt;a href=&#34;https://github.com/emacs-evil/evil-collection/blob/master/modes/outline/evil-collection-outline.el&#34;&gt;the relevant evil-collection file&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;files&#34;&gt;Files&lt;/h3&gt;
&lt;p&gt;By default, the package selects &lt;code&gt;org-clock&lt;/code&gt; records from &lt;code&gt;(org-agenda-files)&lt;/code&gt;. Additional options can be included by customizing the &lt;code&gt;org-clock-agg-files-preset&lt;/code&gt; variable. For instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-clock-agg-files-preset&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;((&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Org Agenda + Archive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;(&lt;span style=&#34;color:#00f&#34;&gt;append&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-agenda-files&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;cl-remove-if&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;eos&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;directory-files&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-directory&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;/archive/&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Note that after updating any of these variables, you&amp;rsquo;ll need to reopen the &lt;code&gt;*org-clock-agg*&lt;/code&gt; buffer to view the changes.&lt;/p&gt;
&lt;p&gt;Alternatively, you can directly specify the list of files within the buffer by selecting &amp;ldquo;Custom list&amp;rdquo; in the &amp;ldquo;Files&amp;rdquo; control.&lt;/p&gt;
&lt;h3 id=&#34;date-range&#34;&gt;Date Range&lt;/h3&gt;
&lt;p&gt;Dates can take the following values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A number: Represents a relative number of days from the current date. E.g. the default value of &lt;code&gt;-7&lt;/code&gt; to &lt;code&gt;0&lt;/code&gt; menas the previous week up to today.&lt;/li&gt;
&lt;li&gt;A date string in the format &lt;code&gt;YYYY-MM-DD HH:mm:ss&lt;/code&gt;, with or without the time part.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By default, the interval is inclusive. For instance, specifying an interval like 2023-12-12 .. 2023-12-13 includes all records from 2023-12-12 00:00:00 to 2023-12-13 23:59:59.&lt;/p&gt;
&lt;h3 id=&#34;group-by&#34;&gt;Group By&lt;/h3&gt;
&lt;p&gt;Records are grouped based on the sequence of grouping predicates.&lt;/p&gt;
&lt;p&gt;For example, with the following content in &lt;code&gt;tasks.org&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* Tasks
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** DONE Thing 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:LOGBOOK:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CLOCK: [2023-12-13 Wed 19:01]--[2023-12-13 Wed 19:29] =&amp;gt; 0:28
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CLOCK: [2023-12-13 Wed 19:30]--[2023-12-13 Wed 19:40] =&amp;gt; 0:10
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;:END:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And predicates &amp;ldquo;Org file&amp;rdquo;, &amp;ldquo;Day&amp;rdquo;, and &amp;ldquo;Outline path&amp;rdquo;, the records for &amp;ldquo;Thing 1&amp;rdquo; will be processed as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Day&amp;rdquo; -&amp;gt; &lt;code&gt;2023-12-13&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Org file&amp;rdquo; -&amp;gt; &lt;code&gt;tasks.org&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Outline path&amp;rdquo; -&amp;gt; &lt;code&gt;Tasks&lt;/code&gt;, &lt;code&gt;Thing 1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Consequently, the node will be placed at the path &lt;code&gt;2023-12-13&lt;/code&gt; / &lt;code&gt;tasks.org&lt;/code&gt; / &lt;code&gt;Tasks&lt;/code&gt; / &lt;code&gt;Thing 1&lt;/code&gt; in the resulting tree:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* Results Root 0:38
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** 2023-12-13 Day 0:38
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** tasks.org Org File 0:38
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;**** Tasks Outline path 0:38
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;***** Thing 1 Outline path 0:38
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- [2023-12-13 Wed 19:01]--[2023-12-13 Wed 19:29] =&amp;gt; 0:28 : DONE Thing 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- [2023-12-13 Wed 19:30]--[2023-12-13 Wed 19:40] =&amp;gt; 0:10 : DONE Thing 1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The following built-in predicates are currently available:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Comment&lt;/th&gt;
&lt;th&gt;Customization variables&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Category&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Org file&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Outline path&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tags&lt;/td&gt;
&lt;td&gt;Sorted alphabetically&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Headline&lt;/td&gt;
&lt;td&gt;Last item of the outline path&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Day&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;org-clock-agg-day-format&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Week&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;org-clock-agg-week-format&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Month&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;org-clock-agg-month-format&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TODO keyword&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Is done&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Selected props&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;org-clock-agg-properties&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Ensure to use &lt;code&gt;setopt&lt;/code&gt; to set the variables; otherwise, the customization logic will not be invoked:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;setopt&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-clock-agg-properties&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;PROJECT_NAME&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Refer also to &lt;a href=&#34;#custom-grouping-predicates-1&#34;&gt;custom grouping predicates&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;commands-in-the-interactive-buffer&#34;&gt;Commands in the interactive buffer&lt;/h3&gt;
&lt;p&gt;Press &lt;code&gt;E&lt;/code&gt; (or &lt;code&gt;M-x org-clock-agg-view-elems-at-point&lt;/code&gt;) on a tree element to view the constituent headings. &lt;code&gt;org-ql&lt;/code&gt; is used to render the heading list.&lt;/p&gt;
&lt;h2 id=&#34;customization&#34;&gt;Customization&lt;/h2&gt;
&lt;h3 id=&#34;node-formatting&#34;&gt;Node Formatting&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;org-clock-agg-node-format&lt;/code&gt; variable determines the formatting of individual tree nodes. This uses a &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Custom-Format-Strings.html&#34;&gt;format string&lt;/a&gt; that with the following format specifiers avaiable:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;%t&lt;/code&gt;: Node title with the level prefix, truncated to &lt;code&gt;title-width&lt;/code&gt; characters (refer to below)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%c&lt;/code&gt;: Name of the grouping function that generated the node&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%z&lt;/code&gt;: Time spent in the node, formatted according to &lt;code&gt;org-clock-agg-duration-format&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%s&lt;/code&gt;: Time share of the node against the parent node&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%S&lt;/code&gt;: Time share of the node against the top-level node&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The default value is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;%-%(+ title-width)t %20c %8z
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Where &lt;code&gt;%(+ title-width)&lt;/code&gt; is &lt;code&gt;(- (window-width) org-clock-agg-node-title-width-delta)&lt;/code&gt;, with the default value of the latter set to &lt;code&gt;40&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Thefore, in the default configuration, the node title is truncated to &lt;code&gt;title-width&lt;/code&gt; characters, while 40 symbols are allocated for the rest of the header, i.e. &amp;quot; %20c %8z&amp;quot; (30 symbols), along with additional space for folding symbols of &lt;code&gt;outline-minor-mode&lt;/code&gt;, line numbers, etc.&lt;/p&gt;
&lt;h3 id=&#34;record-formatting&#34;&gt;Record Formatting&lt;/h3&gt;
&lt;p&gt;When the &amp;ldquo;Show records&amp;rdquo; flag is enabled, associated records for each node are displayed. The formatting of these is defined by &lt;code&gt;org-clock-agg-elem-format&lt;/code&gt;, which is also a format string with the following specifiers:
Customize the formatting of these records through &lt;code&gt;org-clock-agg-elem-format&lt;/code&gt;, which also utilizes a format string comprising the following specifiers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;%s&lt;/code&gt;: Start of the time range&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%e&lt;/code&gt;: End of the time range&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%d&lt;/code&gt;: Duration of the time range&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%t&lt;/code&gt;: Title of the record.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The default value is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- [%s]--[%e] =&amp;gt; %d : %t
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;custom-grouping-predicates-2&#34;&gt;Custom grouping predicates&lt;/h3&gt;
&lt;p&gt;It&amp;rsquo;s possible to define custom grouping predicates in addition to the default ones. In fact, it&amp;rsquo;s probably the only way to get grouping that is tailored to your particular org workflow; I haven&amp;rsquo;t included my predicates in the package because they aren&amp;rsquo;t general enough.&lt;/p&gt;
&lt;p&gt;To create new predicates, use &lt;code&gt;org-clock-agg-defgroupby&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;org-clock-agg-defgroupby&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;lt;name&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:key1&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:key2&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;value2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The available keyword arguments include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:readable-name&lt;/code&gt;: Function name for the UI.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:default-sort&lt;/code&gt;: Default sorting function.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The body binds two variables - &lt;code&gt;elem&lt;/code&gt; and &lt;code&gt;extra-params&lt;/code&gt;, and must return a list of strings.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;elem&lt;/code&gt; variable is an alist that represents one org-clock record. The keys are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:start&lt;/code&gt;: Start time in seconds since the epoch&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:end&lt;/code&gt;: End time in seconds since the epoch&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:duration&lt;/code&gt;: Duration in seconds&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:headline&lt;/code&gt;: Instance of &lt;a href=&#34;https://orgmode.org/worg/dev/org-element-api.html&#34;&gt;org-element&lt;/a&gt; for the headline&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:tags&lt;/code&gt;: List of tags&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:file&lt;/code&gt;: File name&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:outline-path&lt;/code&gt;: titles of all headlines from the root to the current headline&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:properties&lt;/code&gt;: List of properties; &lt;code&gt;org-clock-agg-properties&lt;/code&gt; sets the selection list&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:category&lt;/code&gt;: &lt;a href=&#34;https://orgmode.org/manual/Categories.html&#34;&gt;Category&lt;/a&gt; of the current headline.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;extra-params&lt;/code&gt; variable is an alist of global parameters controlling the function&amp;rsquo;s behavior. Additional parameters can be added by customizing &lt;code&gt;org-clock-agg-extra-params&lt;/code&gt;. This alist has keys as parameter names and values as &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_mono/widget.html&#34;&gt;widget.el&lt;/a&gt; expressions (applied to &lt;code&gt;widget-create&lt;/code&gt;) controlling the UI. Each widget must contain an &lt;code&gt;:extras-key&lt;/code&gt; key.&lt;/p&gt;
&lt;p&gt;For instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-clock-agg-extra-params&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Events: Offline / Online&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;checkbox&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:extras-key&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:events-online&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This adds a checkbox to the form that appears as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Events: Offline / Online [ ]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When checked, &lt;code&gt;extra-params&lt;/code&gt; takes the value &lt;code&gt;((:extras-keys . t))&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example predicate. I store meetings the following way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* Some project
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** Meetings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** Some meeting 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** Some meeting 2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* Another project
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** Meetings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** Another meeting 1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** Another meeting 2 (offline)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I want to group these meetings by title, i.e. group all instances of &amp;ldquo;Some meeting&amp;rdquo;, &amp;ldquo;Another meeting&amp;rdquo;, etc. Optionally I want to group online and offline meetings.&lt;/p&gt;
&lt;p&gt;This can be done the following way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;org-clock-agg-defgroupby&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;event&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:readable-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Event&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:default-sort&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;total&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;let*&lt;/span&gt; ((&lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-element-property&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:raw-value&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:headline&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;is-meeting&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;meeting&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;downcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-contains-p&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:tags&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;mt&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;is-offline&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-match-p&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;offline&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;downcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-contains-p&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:tags&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elem&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;offline&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;title-without-stuff&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;string-trim&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;replace-regexp-in-string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;+&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;digit&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;(offline)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;[&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;alnum&lt;/span&gt;) &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;]&amp;#34;&lt;/span&gt;) ))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;title&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;is-meeting&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;`&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Meeting&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;,@&lt;/span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;alist-get&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:events-online&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;extra-params&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;is-offline&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Offline&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Online&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;,&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;title-without-stuff&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For the following result:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* Results
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** Meetings
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** Some meeting
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*** Another meeting
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** Ungrouped
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This can be coupled with a project predicate to analyze the time spent per project in a particular kind of meeting.&lt;/p&gt;
</content>
</item>
<item>
<title>BIOME - Bountiful Interface to Open Meteo for Emacs</title>
<link>https://sqrtminusone.xyz/packages/biome/</link>
<pubDate>Sat, 22 Jul 2023 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/biome/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/biome&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/biome-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;Interface to &lt;a href=&#34;https://open-meteo.com/&#34;&gt;Open Meteo&lt;/a&gt; for Emacs. The service provides weather forecasts, historical weather data, climate change projections, and more.&lt;/p&gt;
&lt;p&gt;The service is AGPL-licensed; the hosted API is free for non-commercial use if you make less than 10000 requests per day.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/biome-img/report.png&#34;&gt;
&lt;/figure&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you normally install packages, I prefer &lt;a href=&#34;https://github.com/jwiegley/use-package&#34;&gt;use-package&lt;/a&gt; and &lt;a href=&#34;https://github.com/radian-software/straight.el&#34;&gt;straight.el&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or clone the repository, add it to &lt;code&gt;load-path&lt;/code&gt;, and &lt;code&gt;require&lt;/code&gt; the package.&lt;/p&gt;
&lt;h3 id=&#34;issues-with-termux&#34;&gt;Issues with termux?&lt;/h3&gt;
&lt;p&gt;I&amp;rsquo;ve been trying to run this package on termux and had some issues.&lt;/p&gt;
&lt;p&gt;First, for some reason &lt;code&gt;request.el&lt;/code&gt; throws a successfully parsed response as an error. Use this as a workaround:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome-api-try-parse-error-as-response&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Second, somehow &lt;code&gt;&amp;lt;tab&amp;gt;&lt;/code&gt; is not the same as &lt;code&gt;&amp;lt;TAB&amp;gt;&lt;/code&gt;. The following might be necessary:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome-query-tab-key&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;lt;TAB&amp;gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Be sure to add that before the package initialization.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;The main entry point is &lt;code&gt;M-x biome&lt;/code&gt;. Each item under &amp;ldquo;Open Meteo Data&amp;rdquo; corresponds to a particular endpoint of the service. For instance, &lt;code&gt;M-x biome ww&lt;/code&gt; is a generic weather forecast. Check out the &lt;a href=&#34;https://open-meteo.com/en/docs&#34;&gt;API docs&lt;/a&gt; for more detailed descriptions.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/biome-img/root.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Each of these items opens a query interface. A query consists of &amp;ldquo;global&amp;rdquo; variables, such as location, units, etc., and &amp;ldquo;group variables&amp;rdquo;. Groups are usually &amp;ldquo;hourly&amp;rdquo; and &amp;ldquo;daily&amp;rdquo;.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/biome-img/query.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Global variables must always include a location (section &amp;ldquo;Select Coordinates or City&amp;rdquo;). To enter a location, you can either enter latitude and longitude (Open Meteo has an &lt;a href=&#34;https://open-meteo.com/en/docs/geocoding-api&#34;&gt;API for those&lt;/a&gt; as well) or select a location from &lt;code&gt;biome-query-coords&lt;/code&gt;. Example configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome-query-coords&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Helsinki, Finland&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;60.16952&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;24.93545&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Berlin, Germany&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;52.52437&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;13.41053&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Dubai, UAE&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;25.0657&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;55.17128&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A timezone (&amp;ldquo;Settings&amp;rdquo; &amp;gt; &amp;ldquo;Timezone&amp;rdquo;) may not be required, but be sure to set it because &lt;strong&gt;the default one is UTC+0&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The current group is switched with &lt;code&gt;&amp;lt;tab&amp;gt;&lt;/code&gt;. Each group&amp;rsquo;s section has a set of variables that can be toggled on and off, such as temperature, precipitation, etc. Check out the &lt;a href=&#34;https://open-meteo.com/en/docs&#34;&gt;API docs&lt;/a&gt; if you&amp;rsquo;re interested in the meaning of more esoteric ones.&lt;/p&gt;
&lt;p&gt;Press &lt;code&gt;RET&lt;/code&gt; after you&amp;rsquo;ve configured the query to call the API. If something goes wrong, it will output an error, such as:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Open Meteo has returned an error.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Error: (error http 400)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Reason: Timezone is required
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or it will open the results table (the first screenshot).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;tabulated-list&lt;/code&gt; doesn&amp;rsquo;t support horizontal scrolling, so press &lt;code&gt;c&lt;/code&gt; to toggle columns&amp;rsquo; visibility.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/biome-img/columns.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Press &lt;code&gt;c&lt;/code&gt; or invoke &lt;code&gt;M-x biome-grid-export-csv&lt;/code&gt; to export the results in CSV format.&lt;/p&gt;
&lt;h2 id=&#34;more-configuration&#34;&gt;More configuration&lt;/h2&gt;
&lt;p&gt;To save a query for later, press &lt;code&gt;P&lt;/code&gt; in the root of the query interface. This will generate a definition like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;biome-def-preset&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome-query-preset-177&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Weather Forecast&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;hourly&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:params&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;hourly&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;windgusts_10m&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;windspeed_10m&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;cloudcover&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;surface_pressure&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;weathercode&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;snowfall&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;showers&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;rain&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;relativehumidity_2m&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;temperature_2m&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;longitude&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;24.93545&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;latitude&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;60.16952&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add this somewhere in your config after the package is loaded, e.g., in the &lt;code&gt;:config&lt;/code&gt; section of the &lt;code&gt;use-package&lt;/code&gt; form or wrapped in &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Hooks-for-Loading.html#index-with_002deval_002dafter_002dload&#34;&gt;with-eval-after-load&lt;/a&gt;. Running &lt;code&gt;M-x biome-query-preset-177&lt;/code&gt; will create a query interface with this preset.&lt;/p&gt;
&lt;p&gt;Alternatively, use the &lt;code&gt;add-to-list&lt;/code&gt; form (generated below the &lt;code&gt;biome-def-preset&lt;/code&gt; form). Presets added that way will show up in &lt;code&gt;M-x biome-presets&lt;/code&gt; or &amp;ldquo;Presets&amp;rdquo; in &lt;code&gt;M-x biome&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Table formatting can be configured with &lt;code&gt;biome-grid-format&lt;/code&gt;; check the docstring for more information. For instance, if you want to disable all gradients:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome-grid-format&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;seq-filter&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;lambda&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;) (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;eq&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;car-safe&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;nth&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;f&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;gradient&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome-grid-format&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Turn off highlighting of the current hour or day as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome-grid-highlight-current&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;nil&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;composite-queries&#34;&gt;Composite queries&lt;/h2&gt;
&lt;p&gt;The package also allows executing multiple queries at once to join their results. This can be useful for comparing weather in different locations or for viewing different reports about the same location.&lt;/p&gt;
&lt;p&gt;Run &lt;code&gt;M-x biome-multi&lt;/code&gt; to invoke the-multi query dialog.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/biome-img/multi.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;(&lt;em&gt;yes, I&amp;rsquo;ve switched to a light theme since the time of the previous screenshot&lt;/em&gt;)&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;a&lt;/code&gt; invokes the standard query dialog, where pressing &lt;code&gt;RET&lt;/code&gt; returns to the root dialog, adding the query to the list. Pressing &lt;code&gt;RET&lt;/code&gt; in the root dialog executes the queries in the list.&lt;/p&gt;
&lt;p&gt;Queries are executed concurrently. The results are shown if all queries have been successfully completed.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;P&lt;/code&gt; generates a preset defintion for the current query:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;biome-def-multi-preset&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;biome-query-preset-601&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (((&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Air Quality&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;hourly&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:params&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;hourly&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;uv_index&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;european_aqi&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;longitude&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;24.93545&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;latitude&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;60.16952&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;:name&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Weather Forecast&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:group&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;hourly&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:params&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;hourly&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;weathercode&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;snowfall&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;showers&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;rain&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;temperature_2m&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;longitude&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;24.93545&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;latitude&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;60.16952&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Just note that the macro is called &lt;code&gt;biome-def-multi-preset&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;implementation-notes&#34;&gt;Implementation notes&lt;/h2&gt;
&lt;p&gt;This isn&amp;rsquo;t the most complicated thing I&amp;rsquo;ve done, but it&amp;rsquo;s probably the most over-engineered one.&lt;/p&gt;
&lt;p&gt;As you may have guessed, the interfaces mirror the &lt;a href=&#34;https://open-meteo.com/en/docs&#34;&gt;API docs&lt;/a&gt;. I&amp;rsquo;ve implemented &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Parsing-HTML_002fXML.html&#34;&gt;parsing of these HTMLs&lt;/a&gt; in &lt;code&gt;biome-api-parse--generate&lt;/code&gt;, which generates the value of &lt;code&gt;biome-api-data&lt;/code&gt;. Initially, it downloaded the HTML pages by itself, but - imagine that - the website was migrated to Svelte after I implemented maybe 80% of the parsing logic, and the Svelte version populates the accordions via JavaScript. So, as of now, the function requires opening the website in the browser, manually toggling all the accordions, and copying the HTML from DevTools. Fortunately, the parsing is a one-off operation.&lt;/p&gt;
&lt;p&gt;Then, the interface&amp;hellip; I like &lt;a href=&#34;https://github.com/magit/transient/&#34;&gt;transient.el&lt;/a&gt;, so I wanted to make the interface generated dynamically from &lt;code&gt;biome-api-data&lt;/code&gt;, which turned out harder than I expected. I probably should&amp;rsquo;ve just used &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_mono/widget.html&#34;&gt;widget.el&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Generating sensible keys was a challenge. I&amp;rsquo;ve made an algorithm in &lt;code&gt;biome-query--unique-keys&lt;/code&gt; that sort of works well.&lt;/p&gt;
&lt;p&gt;And as for populating transient prefixes, I tried to use &lt;code&gt;:setup-children&lt;/code&gt; in a few places, but it&amp;rsquo;s not general enough, namely, it doesn&amp;rsquo;t seem to support specifying &lt;code&gt;:class&lt;/code&gt; for child groups&amp;hellip; So I ended up overriding &lt;code&gt;transient--layout&lt;/code&gt; in the prefix setup. This doesn&amp;rsquo;t seem to have any undesirable side effects.&lt;/p&gt;
&lt;p&gt;Also, the only way I found to use custom infix classes in these dynamic definitions was to eval &lt;code&gt;transient-define-infix&lt;/code&gt; for each required place. Unfortunately, that adds a lot of stuff to the interactive functions namespace.&lt;/p&gt;
&lt;p&gt;Getting to the results display, Lars Ingebrigtsen&amp;rsquo;s &lt;a href=&#34;https://lars.ingebrigtsen.no/2022/04/13/more-vtable-fun/&#34;&gt;vtable&lt;/a&gt; comes only in Emacs 29, so I used &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Tabulated-List-Mode.html&#34;&gt;tabulated-list&lt;/a&gt;. The only disadvantage of the latter is the lack of horizontal scroll support, which can be worked around by hiding columns with &lt;code&gt;biome-grid-columns&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Most variables are formatted with a gradient, colors for which were mostly inspired by &lt;a href=&#34;https://www.windy.com/&#34;&gt;Windy&lt;/a&gt;. Formatting for things like air quality variables is probably all over the place, so take the red color with a grain of salt.&lt;/p&gt;
</content>
</item>
<item>
<title>micromamba.el</title>
<link>https://sqrtminusone.xyz/packages/micromamba/</link>
<pubDate>Tue, 20 Jun 2023 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/micromamba/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/micromamba&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/micromamba-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;Emacs package for working with &lt;a href=&#34;https://mamba.readthedocs.io/en/latest/user_guide/micromamba.html&#34;&gt;micromamba&lt;/a&gt; environments.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://mamba.readthedocs.io/en/latest/index.html&#34;&gt;mamba&lt;/a&gt; is a reimplementation of the &lt;a href=&#34;https://docs.conda.io/en/latest/&#34;&gt;conda&lt;/a&gt; package manager in C++. &lt;code&gt;mamba&lt;/code&gt; is notably much faster and essentially compatible with &lt;code&gt;conda&lt;/code&gt;, so it also works with &lt;a href=&#34;https://github.com/necaris/conda.el&#34;&gt;conda.el&lt;/a&gt;. &lt;code&gt;micromamba&lt;/code&gt;, however, implements only a subset of &lt;code&gt;mamba&lt;/code&gt; commands, and as such requires a separate integration.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you normally install packages, I prefer &lt;code&gt;use-package&lt;/code&gt; and &lt;code&gt;straight&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;micromamba&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or clone the repository, add it to the &lt;code&gt;load-path&lt;/code&gt; and &lt;code&gt;require&lt;/code&gt; the package.&lt;/p&gt;
&lt;p&gt;If your &lt;code&gt;micromamba&lt;/code&gt; binary is located in some place unknown to &lt;code&gt;executable-find&lt;/code&gt;, set the &lt;code&gt;micromamba-executable&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;If you are running shells (e.g. &lt;a href=&#34;https://github.com/akermu/emacs-libvterm&#34;&gt;vterm&lt;/a&gt;) from Emacs, you probably want to set &lt;code&gt;auto_activate_base&lt;/code&gt; in your &lt;a href=&#34;https://docs.conda.io/projects/conda/en/latest/user-guide/configuration/index.html&#34;&gt;.condarc&lt;/a&gt; or &lt;a href=&#34;https://mamba.readthedocs.io/en/latest/user_guide/configuration.html&#34;&gt;.mambarc&lt;/a&gt;, because the shells are launched in the correct environment anyway.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;The package has two entrypoints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;M-x micromamba-activate&lt;/code&gt; - activate the environment&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-x micromamba-deactivate&lt;/code&gt; - deactivate the environment&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;micromamba-activate&lt;/code&gt; prompts for the environment (by parsing &lt;code&gt;micromamba env list&lt;/code&gt;). If some environments have duplicate names, these names are replaced by full paths.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve noticed that &lt;code&gt;micromamba&lt;/code&gt; also sees &lt;code&gt;conda&lt;/code&gt; environments, so migrating from &lt;code&gt;conda&lt;/code&gt; was rather painless for me.&lt;/p&gt;
&lt;h2 id=&#34;implementation-notes&#34;&gt;Implementation notes&lt;/h2&gt;
&lt;p&gt;I initially wanted to extend &lt;a href=&#34;https://github.com/necaris/conda.el&#34;&gt;conda.el&lt;/a&gt;, but decided it would be counterproductive for a few reasons.&lt;/p&gt;
&lt;p&gt;First, &lt;code&gt;conda&lt;/code&gt; is rather slow, so &lt;code&gt;conda.el&lt;/code&gt; does various tricks to avoid calling the &lt;code&gt;conda&lt;/code&gt; executable. For instance, it gets the environment list from scanning the anaconda home directory instead of running &lt;code&gt;conda env list&lt;/code&gt;. This is really not necessary with &lt;code&gt;micromamba&lt;/code&gt;, which is written in C++.&lt;/p&gt;
&lt;p&gt;Second, and more importantly, &lt;code&gt;conda.el&lt;/code&gt; relies heavily on passing &lt;code&gt;shell.posix+json&lt;/code&gt; to &lt;code&gt;conda&lt;/code&gt;. &lt;code&gt;micromamba&lt;/code&gt; doesn&amp;rsquo;t support that. It supports the &lt;code&gt;--json&lt;/code&gt; flag in some places, but not in the &lt;code&gt;activate&lt;/code&gt; command, so I have to parse the output of &lt;code&gt;micromamba shell -s bash activate&lt;/code&gt; and &lt;code&gt;micromamba shell -s bash deactivate&lt;/code&gt; to get the environment configuration.&lt;/p&gt;
&lt;p&gt;This also means the package most likely won&amp;rsquo;t work out-of-the-box on Windows.&lt;/p&gt;
</content>
</item>
<item>
<title>reverso.el</title>
<link>https://sqrtminusone.xyz/packages/reverso/</link>
<pubDate>Sun, 28 Aug 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/reverso/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/reverso&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/reverso-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;Emacs client for &lt;a href=&#34;https://www.reverso.net/&#34;&gt;Reverso&lt;/a&gt;. The implemented features are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reverso.net/text-translation&#34;&gt;Translation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://context.reverso.net/translation/&#34;&gt;Context&lt;/a&gt; (AKA bilingual concordances)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.reverso.net/spell-checker/english-spelling-grammar/&#34;&gt;Grammar check&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://synonyms.reverso.net/synonym/&#34;&gt;Synonyms search&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://conjugator.reverso.net/conjugation-english.html&#34;&gt;Conjugation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you normally install packages, e.g. with &lt;a href=&#34;https://github.com/jwiegley/use-package&#34;&gt;use-package&lt;/a&gt; and &lt;a href=&#34;https://github.com/radian-software/straight.el&#34;&gt;straight.el&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;reverso&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or &lt;a href=&#34;https://tony-zorman.com/posts/use-package-vc.html&#34;&gt;use-package with vc&lt;/a&gt;, which works on Emacs 30 out-of-the-box.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;reverso&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:vc&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:url&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;https://github.com/SqrtMinusOne/reverso.el.git&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Alternatively, clone the repository, add it to the &lt;code&gt;load-path&lt;/code&gt; and &lt;code&gt;require&lt;/code&gt; the package.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s a single entrypoint for all implemented functions: &lt;code&gt;M-x reverso&lt;/code&gt;. The UI is implemented using the excellent &lt;a href=&#34;https://github.com/magit/transient/&#34;&gt;transient.el&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;input-handling&#34;&gt;Input Handling&lt;/h3&gt;
&lt;p&gt;All commands handle input as follows:&lt;/p&gt;
&lt;p&gt;By default, the input string is empty. If a command is launched with a region selected, use the string of that region. If launched with the prefix argument (&lt;code&gt;C-u&lt;/code&gt;), use the entire buffer.&lt;/p&gt;
&lt;p&gt;Results are displayed in &lt;code&gt;reverso-result-mode&lt;/code&gt; buffers. When launched within that buffer, the command uses the input string specific to the buffer. If launched with &lt;code&gt;C-u&lt;/code&gt;, it uses the output string from that buffer (if available).&lt;/p&gt;
&lt;h3 id=&#34;translation&#34;&gt;Translation&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;M-x reverso t&lt;/code&gt; or &lt;code&gt;M-x reverso-translate&lt;/code&gt; to invoke the translation transient.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/translation-transient.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;The &amp;ldquo;Source language&amp;rdquo; and &amp;ldquo;Target language&amp;rdquo; parameters are self-explanatory. Note that not every language is compatible with every other language in the general case. &amp;ldquo;Swap languages&amp;rdquo; attempts to swap them.&lt;/p&gt;
&lt;p&gt;Enabling &amp;ldquo;Brief translation output&amp;rdquo; will display only the translated version of the string in the output buffer.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/translation-res.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Otherwise, the result buffer may contain the following sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Source text&lt;/strong&gt; and &lt;strong&gt;Translation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Corrected text&lt;/strong&gt;, if available&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Context results&lt;/strong&gt;, if available&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Context results typically appear for short strings, as seen in the example from the screenshot.&lt;/p&gt;
&lt;h3 id=&#34;context&#34;&gt;Context&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;M-x reverso c&lt;/code&gt; or &lt;code&gt;M-x reverso-context&lt;/code&gt; to invoke context search (or &lt;a href=&#34;https://en.wikipedia.org/w/index.php?title=Online_bilingual_concordance&amp;amp;redirect=no&#34;&gt;bilingual concordances&lt;/a&gt;, essentially a Rosetta stone generator).&lt;/p&gt;
&lt;p&gt;The input/output UI resembles that of the translation command.&lt;/p&gt;
&lt;p&gt;Interestingly, direct context search often yields different results than the &amp;ldquo;Context results&amp;rdquo; section of the translation command. Hence, checking both might provide more comprehensive data.&lt;/p&gt;
&lt;h3 id=&#34;synonyms&#34;&gt;Synonyms&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;M-x reverso s&lt;/code&gt; or &lt;code&gt;M-x reverso-synonyms&lt;/code&gt; to invoke the synonyms search.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/synonyms-transient.png&#34;&gt;
&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/synonyms-res.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;If necessary, results are segmented by parts of speech.&lt;/p&gt;
&lt;p&gt;Each part of speech section contains up to three subsections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Synonyms&lt;/li&gt;
&lt;li&gt;Examples&lt;/li&gt;
&lt;li&gt;Antonyms&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;conjugation&#34;&gt;Conjugation&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;M-x reverso o&lt;/code&gt; or &lt;code&gt;M-x reverso-conjugation&lt;/code&gt; to invoke verb conjugation dialog.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/conjugation-transient.png&#34;&gt;
&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/conjugation-res.png&#34;&gt;
&lt;/figure&gt;
&lt;h3 id=&#34;grammar-check&#34;&gt;Grammar check&lt;/h3&gt;
&lt;p&gt;Use &lt;code&gt;M-x reverso g&lt;/code&gt; or &lt;code&gt;M-x reverso-grammar&lt;/code&gt; to invoke the grammar check.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/grammar-transient.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Currently, only English, French, Spanish, and Italian languages are available.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/grammar-res.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;The results may contain the following sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Source text&lt;/strong&gt;, highlighting errors with &lt;code&gt;reverso-error-face&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Corrected text&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Corrections&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;grammar-check-in-buffer&#34;&gt;Grammar check in buffer&lt;/h3&gt;
&lt;p&gt;It can be convenient to apply the grammar check directly to the current buffer without displaying results in another buffer. Use &lt;code&gt;M-x reverso b&lt;/code&gt; or &lt;code&gt;M-x reverso-grammar-buffer&lt;/code&gt; for this.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/grammar-buffer-transient.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Running &lt;code&gt;e&lt;/code&gt; there (or &lt;code&gt;M-x reverso-check-buffer&lt;/code&gt;) utilizes the current buffer as input and highlights any found errors using overlays. If a region is selected, the check is confined to that region.&lt;/p&gt;
&lt;p&gt;There are a couple of caveats there. First, the service considers each linebreak as a new line, which is incompatible with &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/emacs/Filling.html&#34;&gt;filling text&lt;/a&gt;, i.e. breaking it into lines of a specified width. The &amp;ldquo;Remove linebreaks&amp;rdquo; option (&lt;code&gt;l&lt;/code&gt;) is a workaround for this.&lt;/p&gt;
&lt;p&gt;Secondly, the service usually freaks out with special syntax, for instance, Org Mode links.&lt;/p&gt;
&lt;p&gt;The third issue partly follows from the second one, as the service often finds &amp;ldquo;errors&amp;rdquo; within hidden parts of Org links. Either skip these errors or execute &lt;code&gt;M-x org-toggle-link-display&lt;/code&gt; in Org files beforehand.&lt;/p&gt;
&lt;p&gt;Lastly (and this applies to all other methods as well), the API usually restricts input size. If the service returns an error, try running the command on a smaller region of the buffer.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/reverso-img/grammar-buffer-res.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;When the cursor is placed on an error, the &amp;ldquo;Information&amp;rdquo; section provides details.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Fix error&amp;rdquo; (&lt;code&gt;f&lt;/code&gt; or &lt;code&gt;M-x reverso-check-fix-at-point&lt;/code&gt;) opens a completion interface with potential fixes. &amp;ldquo;Ignore error&amp;rdquo; (&lt;code&gt;i&lt;/code&gt; or &lt;code&gt;M-x reverso-check-ignore-error&lt;/code&gt;) simply removes the overlay and moves to the next error.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Previous error&amp;rdquo; (&lt;code&gt;p&lt;/code&gt; or &lt;code&gt;M-x reverso-check-prev-error&lt;/code&gt;), &amp;ldquo;Next error&amp;rdquo; (&lt;code&gt;n&lt;/code&gt; or &lt;code&gt;M-x reverso-check-next-error&lt;/code&gt;), &amp;ldquo;First error&amp;rdquo; (&lt;code&gt;P&lt;/code&gt; or &lt;code&gt;M-x reverso-check-first-error&lt;/code&gt;) and &amp;ldquo;Last error&amp;rdquo; (&lt;code&gt;L&lt;/code&gt; or &lt;code&gt;M-x reverso-check-last-error&lt;/code&gt;) serve to navigate the error list.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Clear&amp;rdquo; (&lt;code&gt;c&lt;/code&gt; or &lt;code&gt;M-x reverso-clear&lt;/code&gt;) removes error overlays. If a region is selected, it removes overlays only in that region; otherwise, it removes them from the entire buffer.&lt;/p&gt;
&lt;h3 id=&#34;history&#34;&gt;History&lt;/h3&gt;
&lt;p&gt;Enable &lt;code&gt;reverso-history-mode&lt;/code&gt; to keep history:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;reverso-history-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I haven&amp;rsquo;t implemented persistence yet, but I might in the future.&lt;/p&gt;
&lt;p&gt;After enabling the minor mode, &lt;code&gt;M-x reverso-history&lt;/code&gt; or &lt;code&gt;M-x reverso h&lt;/code&gt; will display recent commands. &lt;code&gt;RET&lt;/code&gt; on shows the results of each command.&lt;/p&gt;
&lt;h2 id=&#34;caveats&#34;&gt;Caveats&lt;/h2&gt;
&lt;p&gt;Before proceeding further, here are some caveats to be aware of.&lt;/p&gt;
&lt;p&gt;First, the package uses a reverse-engineered API, so all the typical consequences apply, such as sudden irreparable breakages. Although I&amp;rsquo;ve been using it for over a year, so&amp;hellip; maybe not.&lt;/p&gt;
&lt;p&gt;Second, the limit on input size has been mentioned. The obvious workaround is executing commands on a smaller region.&lt;/p&gt;
&lt;p&gt;Third, there have been reports that Reverso dispatches &lt;strong&gt;IP bans&lt;/strong&gt; to particularly enthusiastic users, so be cautious if you&amp;rsquo;re sending lots of automated queries. This is also why I didn&amp;rsquo;t implement running one command for multiple consecutive regions.&lt;/p&gt;
&lt;p&gt;Finally, exercise caution with the content sent to the service. Avoid inadvertently sharing confidential information (like passwords) or anything that could be used against you in other ways. While the service claims to be &lt;a href=&#34;https://www.reverso.net/privacy.aspx?lang=EN&#34;&gt;GDPR-compliant&lt;/a&gt;, we can&amp;rsquo;t actually check that.&lt;/p&gt;
&lt;h2 id=&#34;customization&#34;&gt;Customization&lt;/h2&gt;
&lt;p&gt;Run &lt;code&gt;M-x customize-group reverso&lt;/code&gt; to view the available parameters. Here are a few.&lt;/p&gt;
&lt;p&gt;If you don&amp;rsquo;t need all 17 languages, customize the &lt;code&gt;reverso-languages&lt;/code&gt; variable to narrow down the list:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;reverso-languages&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;english&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;german&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;russian&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the length of &lt;code&gt;reverso-languages&lt;/code&gt; exceeds &lt;code&gt;reverso-language-completing-read-threshold&lt;/code&gt;, switching a language in transient buffers will invoke &lt;code&gt;completing-read&lt;/code&gt; (minibuffer completion). Otherwise, it will simply switch to the next language available.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;reverso-max-display-lines-in-input&lt;/code&gt; controls the maximum number of lines displayed in the input section of a transient buffer.&lt;/p&gt;
&lt;p&gt;The available faces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;reverso-highlight-face&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverso-error-face&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverso-heading-face&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverso-keyword-face&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverso-definition-face&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;are inherited from the faces of &lt;code&gt;transient.el&lt;/code&gt; and &lt;code&gt;basic-faces&lt;/code&gt; to look nice.&lt;/p&gt;
&lt;h2 id=&#34;elisp-api&#34;&gt;Elisp API&lt;/h2&gt;
&lt;p&gt;In Emacs Lisp, there are four primary functions that interact with the Reverso API:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;reverso--translate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverso--get-context&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverso--get-grammar&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverso--get-context&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Refer to the docstrings for more detailed information.&lt;/p&gt;
&lt;p&gt;Each function is asynchronous, and the results are retrieved via a callback.&lt;/p&gt;
&lt;p&gt;As Reverso sometimes modifies its available languages and compatibility matrix, so if you change that, execute &lt;code&gt;reverso-verify-settings&lt;/code&gt; to check for potential errors.&lt;/p&gt;
&lt;h2 id=&#34;alternatives-and-observations&#34;&gt;Alternatives and Observations&lt;/h2&gt;
&lt;p&gt;A widely recognized translation service is &lt;a href=&#34;https://translate.google.com/&#34;&gt;Google Translate&lt;/a&gt;, so of course, there&amp;rsquo;s an &lt;a href=&#34;https://github.com/atykhonov/google-translate&#34;&gt;Emacs client&lt;/a&gt; for it.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/emacs-grammarly&#34;&gt;emacs-grammarly&lt;/a&gt; package series provides the Elisp API for &lt;a href=&#34;https://www.grammarly.com/&#34;&gt;Grammarly&lt;/a&gt; (a grammar checking service) along with multiple frontends. Unlike Reverso, Grammarly has an official API (so you don&amp;rsquo;t risk getting an IP ban), and it allows a much larger input size.&lt;/p&gt;
&lt;p&gt;Additionally, Grammarly is less bothered by Org and Markdown syntax, although it struggles with inline code blocks. It seems to do work generally better than Reverso, but it also generates a lot of false positives. For instance, it finds a lot of issues in &lt;a href=&#34;https://www.economist.com/&#34;&gt;The Economist&lt;/a&gt; articles, which, I think, have beautiful English.&lt;/p&gt;
&lt;p&gt;Another notable grammar-checking solution is &lt;a href=&#34;https://languagetool.org/&#34;&gt;LanguageTool&lt;/a&gt;, which can be &lt;a href=&#34;https://dev.languagetool.org/http-server&#34;&gt;run offline&lt;/a&gt; and used with its &lt;a href=&#34;https://github.com/mhayashi1120/Emacs-langtool&#34;&gt;Emacs package&lt;/a&gt;. This tool offers the advantage of unlimited usage and doesn&amp;rsquo;t transmit your data to a third-party server you can&amp;rsquo;t control. But it still doesn&amp;rsquo;t like markup syntaxes.&lt;/p&gt;
&lt;p&gt;Also, I&amp;rsquo;ve been pretty happy with &lt;a href=&#34;https://github.com/valentjn/ltex-ls&#34;&gt;LTeX LS&lt;/a&gt;, which is a LanguageTool-based language server explicitly designed to support markup formats like Org, Markdown, LaTeX, among others.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://www.npmjs.com/package/reverso-api&#34;&gt;reverso-api&lt;/a&gt; npm package implements the same commands in JavaScript. It also provided invaluable information for creating this package.&lt;/p&gt;
</content>
</item>
<item>
<title>elfeed-sync</title>
<link>https://sqrtminusone.xyz/packages/elfeed-sync/</link>
<pubDate>Sun, 29 May 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/elfeed-sync/</guid>
<content type="html">
&lt;p&gt;Sync read/marked status of entries between &lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed&lt;/a&gt; and &lt;a href=&#34;https://tt-rss.org/&#34;&gt;tt-rss&lt;/a&gt;. Supports &lt;a href=&#34;https://github.com/SqrtMinusOne/elfeed-summary&#34;&gt;elfeed-summary&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;DISCLAIMER: It&amp;rsquo;s still an alpha version of the package, so you may want to backup your elfeed index and tt-rss database.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/elfeed-sync-img/screenshot.png&#34;&gt;
&lt;/figure&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The project consists of the tt-rss plugin and the Emacs package.&lt;/p&gt;
&lt;p&gt;If you are using the &lt;a href=&#34;https://git.tt-rss.org/fox/ttrss-docker-compose.git/tree/README.md&#34;&gt;tt-rss docker&lt;/a&gt; setup, the steps are as follows. Change them accordingly if you are not.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Mount the &lt;code&gt;/var/www/html&lt;/code&gt; directory from the container somewhere to the filesystem as described &lt;a href=&#34;https://git.tt-rss.org/fox/ttrss-docker-compose.wiki.git/tree/Home.md#how-do-i-use-dynamic-image-for-development&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Put the repository to the &lt;code&gt;tt-rss/plugins.local/elfeed_sync&lt;/code&gt; folder:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;cd&lt;/span&gt; ./html/tt-rss/plugins.local/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/SqrtMinusOne/elfeed-sync.git elfeed_sync
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add &lt;code&gt;elfeed_sync&lt;/code&gt; to the &lt;code&gt;TTRSS_PLUGINS&lt;/code&gt; environment variable.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-dotenv&#34; data-lang=&#34;dotenv&#34;&gt;TTRSS_PLUGINS=auth_internal, auth_remote, nginx_xaccel, elfeed_sync
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Allow larger request body sizes in nginx. Add the following to the &lt;code&gt;server&lt;/code&gt; directive:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;client_max_body_size 10M;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For me, the sync payload is around 3M.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Increase the read timeout in nginx. Add the following to the php location directive:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-cfg&#34; data-lang=&#34;cfg&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#7d9029&#34;&gt;fastcgi_read_timeout 600;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Syncing the entries is usually pretty fast, but the first feed sync takes a while.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Then restart tt-rss. Check if the plugin appears in the Preferences &amp;gt; Plugins section.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enable &amp;ldquo;Allows accessing this account through the API&amp;rdquo; in the Preferences &amp;gt; Preferences. You also may want to disable &amp;ldquo;Purge unread articles&amp;rdquo;, because elfeed doesn&amp;rsquo;t do that.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Install the Emacs package however you normally install packages, I prefer use-package and straight.el. Make sure to enable &lt;code&gt;elfeed-sync-mode&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-sync&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;github&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:repo&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;SqrtMinusOne/elfeed-sync&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-sync-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then set up the following variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;elfeed-sync-tt-rss-instance&lt;/code&gt; - point that to your tt-rss instance, e.g.
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;https://example.com/tt-rss
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;(No trailing slash)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;elfeed-sync-tt-rss-login&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;elfeed-sync-tt-rss-password&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;elfeed-sync-unread-tag&lt;/code&gt; - elfeed tag to map to read status in tt-rss. &lt;code&gt;unread&lt;/code&gt; by default.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;elfeed-sync-marked-tag&lt;/code&gt; - elfeed tag to map to marked status in tt-rss. &lt;code&gt;later&lt;/code&gt; by default.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;h3 id=&#34;syncing-the-feed-list&#34;&gt;Syncing the feed list&lt;/h3&gt;
&lt;p&gt;The first thing you probably want to do is to sync the feed list.&lt;/p&gt;
&lt;p&gt;It makes little sense to sync tt-rss feeds to elfeed, because people often use projects like &lt;a href=&#34;https://github.com/remyhonig/elfeed-org&#34;&gt;elfeed-org&lt;/a&gt;. But it&amp;rsquo;s possible to sync elfeed feeds to tt-rss.&lt;/p&gt;
&lt;p&gt;The function &lt;code&gt;M-x elfeed-sync-feeds&lt;/code&gt; does exactly that. If you have &lt;a href=&#34;https://github.com/SqrtMinusOne/elfeed-summary&#34;&gt;elfeed-summary&lt;/a&gt; installed and tt-rss categories enabled, the function will recreate the elfeed-summary tree in tt-rss.&lt;/p&gt;
&lt;p&gt;The first run of the function takes a while because tt-rss has to fetch the feed at the moment of the first subscription. Which is why increasing the timeout may be necessary.&lt;/p&gt;
&lt;p&gt;However, running the function multiple times until it succeeds should also work.&lt;/p&gt;
&lt;h3 id=&#34;syncing-the-entry-list&#34;&gt;Syncing the entry list&lt;/h3&gt;
&lt;p&gt;To sync the entry list, run &lt;code&gt;M-x elfeed-sync&lt;/code&gt;. The sync usually takes a couple of seconds.&lt;/p&gt;
&lt;p&gt;The sync finishes at the &amp;ldquo;Sync complete!&amp;rdquo; message. Check the &lt;code&gt;*elfeed-log*&lt;/code&gt; buffer for statistics.&lt;/p&gt;
&lt;p&gt;Occasionally, some entries do not match. Here are the possible cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Entry exists in the elfeed database, but not in tt-rss.
Run &lt;code&gt;M-x elfeed-sync-search-missing&lt;/code&gt; to display such entries.&lt;/li&gt;
&lt;li&gt;Entry exists in the tt-rss database, but not in elfeed:
&lt;ul&gt;
&lt;li&gt;Entry appeared in the feed after the last &lt;code&gt;elfeed-update&lt;/code&gt;.
Run &lt;code&gt;M-x elfeed-update&lt;/code&gt; and then &lt;code&gt;M-x elfeed-sync&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Entry appeared and disappeared in the feed after the last &lt;code&gt;elfeed-update&lt;/code&gt;.
Such an entry will never get to the elfeed database. If you want to, run &lt;code&gt;M-x elfeed-sync&lt;/code&gt; and then &lt;code&gt;M-x elfeed-sync-read-ttrss-missing&lt;/code&gt; to mark all such entries as read.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Entry appeared in the feed before &lt;code&gt;elfeed-sync-look-back&lt;/code&gt;.
Such an entry will never be matched. This is an inconvenience if you have just set up tt-rss, it fetched old entries from the feeds and such entries remain permanently unread because they are untouched by the &lt;code&gt;M-x elfeed-sync&lt;/code&gt;.
To mark such entries as read, run &lt;code&gt;M-x elfeed-sync-read-ttrss-old&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;implementation-details&#34;&gt;Implementation details&lt;/h2&gt;
&lt;p&gt;The heavy-lifting is done on the elisp side because I ran into strange performance issues with associative arrays in PHP.&lt;/p&gt;
&lt;p&gt;Check the &lt;code&gt;elfeed-sync--do-sync&lt;/code&gt; function for the description of the synchronization algorithm. The tl;dr is to download all entries from tt-rss and match each entry against the elfeed database. In the case of discrepancy update whichever entry has the lower priority.&lt;/p&gt;
</content>
</item>
<item>
<title>avy-dired</title>
<link>https://sqrtminusone.xyz/packages/avy-dired/</link>
<pubDate>Fri, 01 Apr 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/avy-dired/</guid>
<content type="html">
&lt;p&gt;Doing some experimentation with avy &amp;amp; dired. Still somewhat flaky.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/avy-dired-img/screenshot.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;The only available command is &lt;code&gt;M-x avy-dired-goto-line&lt;/code&gt;. Use &lt;code&gt;K&lt;/code&gt; and &lt;code&gt;J&lt;/code&gt; to scroll up and down while in the avy state, &lt;code&gt;C-g&lt;/code&gt; or &lt;code&gt;q&lt;/code&gt; to quit.&lt;/p&gt;
</content>
</item>
<item>
<title>elfeed-summary</title>
<link>https://sqrtminusone.xyz/packages/elfeed-summary/</link>
<pubDate>Sat, 26 Mar 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/elfeed-summary/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/elfeed-summary&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/elfeed-summary-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;The package provides a tree-based feed summary interface for &lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed&lt;/a&gt;. The tree can include individual feeds, &lt;a href=&#34;https://github.com/skeeto/elfeed#filter-syntax&#34;&gt;searches&lt;/a&gt;, and groups. It mainly serves as an easier &amp;ldquo;jumping point&amp;rdquo; for elfeed, so to make querying a subset of the elfeed database one action away.&lt;/p&gt;
&lt;p&gt;Inspired by &lt;a href=&#34;https://github.com/newsboat/newsboat&#34;&gt;newsboat&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/elfeed-summary-img/screenshot.png&#34;&gt;
&lt;/figure&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA, so install it however you normally install packages. My preferred way is &lt;code&gt;use-package&lt;/code&gt; with &lt;code&gt;straight&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-summary&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course, you have to have &lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed&lt;/a&gt; configured.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;Running &lt;code&gt;M-x elfeed-summary&lt;/code&gt; opens up the summary buffer, as shown on the screenshot.&lt;/p&gt;
&lt;p&gt;The tree consists of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;feeds;&lt;/li&gt;
&lt;li&gt;searches;&lt;/li&gt;
&lt;li&gt;groups, that can include other groups, feeds, and searches.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Groups can also be generated automatically.&lt;/p&gt;
&lt;p&gt;Available keybindings in the summary mode:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Keybinding&lt;/th&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;elfeed-summary--action&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open thing under the cursor (a feed, search, or a group). If there is at least one unread item, it will show only unread items.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;M-RET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;elfeed-summary--action-show-read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Open thing under the cursor, but always include read items&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;q&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&amp;hellip;&lt;/td&gt;
&lt;td&gt;Quit the summary buffer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;r&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;elfeed-summary--refresh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Refresh the summary buffer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;R&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;elfeed-summary-update&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run update for elfeed feeds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;u&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;elfeed-summary-toggle-only-unread&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Toggle showing only unread entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;U&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;elfeed-summary--action-mark-read&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mark everything in the entry under the cursor as read&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The standard keybindings from &lt;a href=&#34;https://magit.vc/manual/magit.html#Sections&#34;&gt;magit-section&lt;/a&gt; are also available, for instance &lt;code&gt;TAB&lt;/code&gt; toggles the visibility of the current group. &lt;a href=&#34;https://github.com/emacs-evil/evil&#34;&gt;evil-mode&lt;/a&gt; is also supported.&lt;/p&gt;
&lt;h2 id=&#34;configuration&#34;&gt;Configuration&lt;/h2&gt;
&lt;h3 id=&#34;tree-configuration&#34;&gt;Tree configuration&lt;/h3&gt;
&lt;p&gt;The structure of the tree is determined by the &lt;code&gt;elfeed-summary-settings&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;This is a list of these possible items:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Group &lt;code&gt;(group . &amp;lt;group-params&amp;gt;)&lt;/code&gt;
Groups are used to group elements under collapsible sections.&lt;/li&gt;
&lt;li&gt;Query &lt;code&gt;(query . &amp;lt;query-params&amp;gt;)&lt;/code&gt;
Query extracts a subset of elfeed feeds based on the given criteria. Each found feed will be represented as a line.&lt;/li&gt;
&lt;li&gt;Search &lt;code&gt;(search . &amp;lt;search-params&amp;gt;)&lt;/code&gt;
Elfeed search, as defined by &lt;code&gt;elfeed-search-set-filter&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Tags tree &lt;code&gt;(auto-tags . &amp;lt;auto-tags-params&amp;gt;)&lt;/code&gt;
A tree generated automatically from the available tags.&lt;/li&gt;
&lt;li&gt;Tag groups &lt;code&gt;(tag-groups . &amp;lt;tag-group-params&amp;gt;)&lt;/code&gt;
Insert one tag as one group.&lt;/li&gt;
&lt;li&gt;a few special forms&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;group-params&amp;gt;&lt;/code&gt; is an alist with the following keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:title&lt;/code&gt; (mandatory)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:elements&lt;/code&gt; (mandatory) - elements of the group. The structure is the same as in the root definition.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:face&lt;/code&gt; - group face. The default face is &lt;code&gt;elfeed-summary-group-face&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:hide&lt;/code&gt; - if non-nil, the group is collapsed by default.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;query-params&amp;gt;&lt;/code&gt; can be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A symbol of a tag.
A feed will be matched if it has that tag.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:all&lt;/code&gt;. Will match anything.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(title . &amp;quot;string&amp;quot;)&lt;/code&gt; or &lt;code&gt;(title . &amp;lt;form&amp;gt;)&lt;/code&gt;
Match feed title with &lt;code&gt;string-match-p&lt;/code&gt;. &amp;lt;form&amp;gt; makes sense if you
want to pass something like &lt;code&gt;rx&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(author . &amp;quot;string&amp;quot;)&lt;/code&gt; or &lt;code&gt;(author . &amp;lt;form&amp;gt;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(url . &amp;quot;string&amp;quot;)&lt;/code&gt; or &lt;code&gt;(url . &amp;lt;form&amp;gt;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(and &amp;lt;q-1&amp;gt; &amp;lt;q-2&amp;gt; ... &amp;lt;q-n&amp;gt;)&lt;/code&gt;
Match if all the conditions 1, 2, &amp;hellip;, n match.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(or &amp;lt;q-1&amp;gt; &amp;lt;q-2&amp;gt; ... &amp;lt;q-n&amp;gt;)&lt;/code&gt; or &lt;code&gt;(&amp;lt;q-1&amp;gt; &amp;lt;q-2&amp;gt; ... &amp;lt;q-n&amp;gt;)&lt;/code&gt;
Match if any of the conditions 1, 2, &amp;hellip;, n match.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(not &amp;lt;query&amp;gt;)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Feed tags for the query are determined by the &lt;code&gt;elfeed-feeds&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;Query examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;(emacs lisp)&lt;/code&gt;
Return all feeds that have either &amp;ldquo;emacs&amp;rdquo; or &amp;ldquo;lisp&amp;rdquo; tags.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(and emacs lisp)&lt;/code&gt;
Return all feeds that have both &amp;ldquo;emacs&amp;rdquo; and &amp;ldquo;lisp&amp;rdquo; tags.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(and (title . &amp;quot;Emacs&amp;quot;) (not planets))&lt;/code&gt;
Return all feeds that have &amp;ldquo;Emacs&amp;rdquo; in their title and don&amp;rsquo;t have
the &amp;ldquo;planets&amp;rdquo; tag.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;search-params&amp;gt;&lt;/code&gt; is an alist with the following keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:filter&lt;/code&gt; (mandatory) filter string, as defined by
&lt;code&gt;elfeed-search-set-filter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:title&lt;/code&gt; (mandatory) title.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:tags&lt;/code&gt; - list of tags to get the face of the entry.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;auto-tags-params&amp;gt;&lt;/code&gt; is an alist with the following keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:max-level&lt;/code&gt; - maximum level of the tree (default 2)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:source&lt;/code&gt; - which feeds to use to build the tree.
Can be &lt;code&gt;:misc&lt;/code&gt; (default) or &lt;code&gt;(query . &amp;lt;query-params&amp;gt;)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:original-order&lt;/code&gt; - do not try to build a more concise tree by
putting the most frequent tags closer to the root of the tree.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:faces&lt;/code&gt; - list of faces for groups.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;tag-group-params&amp;gt;&lt;/code&gt; is an alist with the following keys:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:source&lt;/code&gt; - which feeds to use to build the tree.
Can be &lt;code&gt;:misc&lt;/code&gt; (default) or &lt;code&gt;(query . &amp;lt;query-params&amp;gt;)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:repeat-feeds&lt;/code&gt; - allow feeds to repeat. Otherwise, each feed is
assigned to group with the least amount of members.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:face&lt;/code&gt; - face for groups.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Available special forms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:misc&lt;/code&gt; - print out feeds, not found by any query above.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also keep in mind that &lt;code&gt;&#39;(key . ((values)))&lt;/code&gt; is the same as &lt;code&gt;&#39;(key (values))&lt;/code&gt;. This helps to shorten the form in many cases.&lt;/p&gt;
&lt;p&gt;Also, this variable is not validated by any means, so wrong values can produce somewhat cryptic errors. Sorry about that.&lt;/p&gt;
&lt;h3 id=&#34;example&#34;&gt;Example&lt;/h3&gt;
&lt;p&gt;Here is an excerpt from my configuration that was used to produce this screenshot:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-summary-settings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;GitHub&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;SqrtMinusOne.private.atom&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Guix packages&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;github&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;guix_packages&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:hide&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Blogs [Software]&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;software_blogs&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Blogs [People]&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;blogs&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;people&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emacs&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Emacs&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;blogs&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;people&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;emacs&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Podcasts&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;podcasts&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Videos&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Music&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;videos&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;music&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Tech&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;videos&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;tech&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;History&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;query&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;videos&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;history&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#408080;font-style:italic&#34;&gt;;; ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Miscellaneous&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Searches&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;search&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:filter&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;@6-months-ago sqrtminusone&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;About me&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;search&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:filter&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;+later&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Check later&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;group&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:title&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Ungrouped&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:elements&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:misc&lt;/span&gt;))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;automatic-generation-of-groups&#34;&gt;Automatic generation of groups&lt;/h3&gt;
&lt;h4 id=&#34;auto-tags&#34;&gt;&lt;code&gt;auto-tags&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;As described in the &lt;a href=&#34;#tree-configuration-1&#34;&gt;tree configuration&lt;/a&gt; section, there are two ways to avoid defining all the relevant groups manually, &lt;code&gt;auto-tags&lt;/code&gt; and &lt;code&gt;tag-groups&lt;/code&gt;. Both use tags that are defined in &lt;code&gt;elfeed-feeds&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;auto-tags&lt;/code&gt; tries to build the most concise tree from these tags. E.g. if we have feeds:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;feed1 tag1 tag2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;feed2 tag1 tag2
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;feed3 tag1 tag3
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;feed4 tag1 tag3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It will create the following tree:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tag1
&lt;ul&gt;
&lt;li&gt;tag2
&lt;ul&gt;
&lt;li&gt;feed1&lt;/li&gt;
&lt;li&gt;feed2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tag3
&lt;ul&gt;
&lt;li&gt;feed3&lt;/li&gt;
&lt;li&gt;feed4&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The tree is truncated by &lt;code&gt;:max-level&lt;/code&gt;, which is 2 by default.&lt;/p&gt;
&lt;p&gt;If tags don&amp;rsquo;t form this kind of hierarchy in &lt;code&gt;elfeed-feeds&lt;/code&gt;, the algorithm will still try to build the most &amp;ldquo;optimal&amp;rdquo; tree, where the most frequent tags are on the top.&lt;/p&gt;
&lt;p&gt;To avoid that you can set &lt;code&gt;(:original-order . t)&lt;/code&gt;, in which case each feed will be placed at the path &lt;code&gt;tag1 tag2 ... tagN feed&lt;/code&gt;, where the order of tags is the same as in &lt;code&gt;elfeed-feeds&lt;/code&gt;. By the way, this allows reproducing the hierarchy of &lt;a href=&#34;https://github.com/remyhonig/elfeed-org&#34;&gt;elfeed-org&lt;/a&gt;, e.g. this structure:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* tag1 :tag1:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** feed1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** feed2 :tag2:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** feed3 :tag2:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* tag3 :tag3:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** feed4 :tag2:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** feed5 :tag2:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;** feed6 :tag2:
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Will be converted to this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tag1
&lt;ul&gt;
&lt;li&gt;feed1&lt;/li&gt;
&lt;li&gt;tag2
&lt;ul&gt;
&lt;li&gt;feed2&lt;/li&gt;
&lt;li&gt;feed3&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tag3
&lt;ul&gt;
&lt;li&gt;tag2
&lt;ul&gt;
&lt;li&gt;feed4&lt;/li&gt;
&lt;li&gt;feed5&lt;/li&gt;
&lt;li&gt;feed6&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whereas without &lt;code&gt;:original-order&lt;/code&gt; the structure will be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tag1
&lt;ul&gt;
&lt;li&gt;feed1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tag2
&lt;ul&gt;
&lt;li&gt;tag1
&lt;ul&gt;
&lt;li&gt;feed2&lt;/li&gt;
&lt;li&gt;feed3&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tag3
&lt;ul&gt;
&lt;li&gt;feed4&lt;/li&gt;
&lt;li&gt;feed5&lt;/li&gt;
&lt;li&gt;feed6&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;tag-groups&#34;&gt;&lt;code&gt;tag-groups&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;The second option is &lt;code&gt;tag-groups&lt;/code&gt;, which creates a group for each tag.&lt;/p&gt;
&lt;p&gt;By default, each feed is assigned to its less frequent tag. This can be turned off by setting &lt;code&gt;(:repeat-feeds . t)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;E.g., the elfeed-org setup from the section above will be converted to this structure:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tag1
&lt;ul&gt;
&lt;li&gt;feed1&lt;/li&gt;
&lt;li&gt;feed2&lt;/li&gt;
&lt;li&gt;feed3&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tag3
&lt;ul&gt;
&lt;li&gt;feed4&lt;/li&gt;
&lt;li&gt;feed5&lt;/li&gt;
&lt;li&gt;feed6&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And with &lt;code&gt;:repeat-feeds&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tag1
&lt;ul&gt;
&lt;li&gt;feed1&lt;/li&gt;
&lt;li&gt;feed2&lt;/li&gt;
&lt;li&gt;feed3&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tag2
&lt;ul&gt;
&lt;li&gt;feed2&lt;/li&gt;
&lt;li&gt;feed3&lt;/li&gt;
&lt;li&gt;feed4&lt;/li&gt;
&lt;li&gt;feed5&lt;/li&gt;
&lt;li&gt;feed6&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;tag3
&lt;ul&gt;
&lt;li&gt;feed4&lt;/li&gt;
&lt;li&gt;feed5&lt;/li&gt;
&lt;li&gt;feed6&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;common-options&#34;&gt;Common options&lt;/h4&gt;
&lt;p&gt;Both &lt;code&gt;auto-tags&lt;/code&gt; and &lt;code&gt;tag-groups&lt;/code&gt; allow setting the &lt;code&gt;:search&lt;/code&gt; parameter.&lt;/p&gt;
&lt;p&gt;The default value is &lt;code&gt;(:search . :misc)&lt;/code&gt;, i.e. use feeds that weren&amp;rsquo;t found by other queries.&lt;/p&gt;
&lt;p&gt;Passing &lt;code&gt;(:search . (query . &amp;lt;query-params&amp;gt;))&lt;/code&gt; is another option.&lt;/p&gt;
&lt;h3 id=&#34;faces&#34;&gt;Faces&lt;/h3&gt;
&lt;p&gt;Group faces by default use the &lt;code&gt;elfeed-summary-group-faces&lt;/code&gt; variable, which serves as a list of faces for each level of the tree. Individual group faces can be overridden with the &lt;code&gt;:face&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;Feed faces by default reuse &lt;a href=&#34;https://github.com/skeeto/elfeed#custom-tag-faces&#34;&gt;the existing elfeed mechanism&lt;/a&gt;. The tags for feeds are taken from the &lt;code&gt;elfeed-feeds&lt;/code&gt; variable; if a feed has at least one unread entry, the unread tag is added to the list. This can be overridden by setting the &lt;code&gt;elfeed-summary-feed-face-fn&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;Searches are mostly the same as feeds, but tags for the search are taken from the &lt;code&gt;:tags&lt;/code&gt; attribute. This also can be overridden with &lt;code&gt;elfeed-summary-search-face-fn&lt;/code&gt; variable.&lt;/p&gt;
&lt;h3 id=&#34;opening-elfeed-search-in-other-window&#34;&gt;Opening &lt;code&gt;elfeed-search&lt;/code&gt; in other window&lt;/h3&gt;
&lt;p&gt;If you set:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-summary-other-window&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then &lt;code&gt;RET&lt;/code&gt; and &lt;code&gt;M-RET&lt;/code&gt; in the &lt;code&gt;elfeed-summary&lt;/code&gt; buffer will open the search buffer in other window.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;elfeed-summary-width&lt;/code&gt; regulates the width of the remaining summary window in this case. It is useful because the data in the search buffer is generally wider than in the summary buffer. The variable can also be set to &lt;code&gt;nil&lt;/code&gt; to disable this behavior.&lt;/p&gt;
&lt;h3 id=&#34;skipping-feeds&#34;&gt;Skipping feeds&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://tt-rss.org/&#34;&gt;tt-rss&lt;/a&gt; has a feature to disable updating a particular feed but keep it in the feed list. I also want that for elfeed.&lt;/p&gt;
&lt;p&gt;To use that, set &lt;code&gt;elfeed-summary-skip-sync-tag&lt;/code&gt; to some value:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;elfeed-summary-skip-sync-tag&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;skip&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And tag the feeds you want to skip with this tag. Then, running &lt;code&gt;M-x elfeed-summary-update&lt;/code&gt; will skip them. This won&amp;rsquo;t affect &lt;code&gt;M-x elfeed-update&lt;/code&gt; unless you:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;advice-add&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-update&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:override&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-summary-update&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also watch out if you use &lt;a href=&#34;https://github.com/remyhonig/elfeed-org&#34;&gt;elfeed-org&lt;/a&gt; and want to use the &lt;code&gt;ignore&lt;/code&gt; tag, because this package omits feeds with this tag altogether (configurable by &lt;code&gt;rmh-elfeed-org-ignore-tag&lt;/code&gt;).&lt;/p&gt;
&lt;h3 id=&#34;other-options&#34;&gt;Other options&lt;/h3&gt;
&lt;p&gt;Also take a look at &lt;code&gt;M-x customize-group elfeed-summary&lt;/code&gt; for the rest of available options.&lt;/p&gt;
&lt;h2 id=&#34;ideas-and-alternatives&#34;&gt;Ideas and alternatives&lt;/h2&gt;
&lt;p&gt;The default interface of elfeed is just a list of all entries. Naturally, it gets hard to navigate when there are a lot of sources with varying frequencies of posts.&lt;/p&gt;
&lt;p&gt;Elfeed itself provides one solution, which is using &lt;a href=&#34;https://github.com/skeeto/elfeed#bookmarks&#34;&gt;bookmarks&lt;/a&gt; to save individual &lt;a href=&#34;https://github.com/skeeto/elfeed#filter-syntax&#34;&gt;searches&lt;/a&gt;. This can work, but it can be somewhat cumbersome.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/sp1ff/elfeed-score&#34;&gt;elfeed-score&lt;/a&gt; is another solution, which introduces scoring rules for entries. Thus, with proper rules set, the most important entries should be on the top of the list. You can take a look at &lt;a href=&#34;https://www.youtube.com/watch?v=rvWbUGx9U5E&#34;&gt;this video by John Kitchin&lt;/a&gt; to see how this can work.&lt;/p&gt;
&lt;p&gt;However, I mostly had &lt;code&gt;elfeed-score&lt;/code&gt; to group entries to sets with equal scores, and I then processed one such set or the other. This is why I decided this package is a better fit for my workflow.&lt;/p&gt;
&lt;p&gt;Another idea I used often before that is this function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/elfeed-search-filter-source&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Filter elfeed search buffer by the feed under the cursor.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-search-selected&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:ignore-region&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-p&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-search-set-filter&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;@6-months-ago &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;+unread &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;=&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;replace-regexp-in-string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;rx&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;?&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;not-newline&lt;/span&gt;) &lt;span style=&#34;color:#19177c&#34;&gt;eos&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-feed-url&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;elfeed-entry-feed&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;entry&lt;/span&gt;)))))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;rsquo;ve bound it to &lt;code&gt;o&lt;/code&gt;, so I would open &lt;code&gt;elfeed&lt;/code&gt;, press &lt;code&gt;o&lt;/code&gt;, and only see unread entries from a particular feed. Then I cleaned the filter and switched to the next feed. Once again, a tree with feeds is obviously a better tool for such a workflow.&lt;/p&gt;
&lt;p&gt;The last solution I want to mention is &lt;a href=&#34;https://github.com/manojm321/elfeed-dashboard&#34;&gt;elfeed-dashboard&lt;/a&gt;, although I didn&amp;rsquo;t test this one. It looks similar to this package but seems to require much more fine-tuning, for instance, it doesn&amp;rsquo;t allow to list all the feeds with a certain tag in a group.&lt;/p&gt;
</content>
</item>
<item>
<title>password-store-completion</title>
<link>https://sqrtminusone.xyz/packages/password-store-completion/</link>
<pubDate>Sun, 13 Feb 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/password-store-completion/</guid>
<content type="html">
&lt;p&gt;A completion-based pass frontend inspired by &lt;a href=&#34;https://github.com/carnager/rofi-pass&#34;&gt;rofi-pass&lt;/a&gt;. Integrates with &lt;a href=&#34;https://github.com/abo-abo/swiper&#34;&gt;Ivy&lt;/a&gt; or &lt;a href=&#34;https://github.com/oantolin/embark&#34;&gt;Embark&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The main purpose is typing passwords with &lt;code&gt;xdotool&lt;/code&gt; (useful in &lt;a href=&#34;https://github.com/emacs-exwm/exwm&#34;&gt;EXWM&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Also take a look at Nicolas Petton&amp;rsquo;s &lt;a href=&#34;https://github.com/NicolasPetton/pass&#34;&gt;pass&lt;/a&gt;. &lt;code&gt;password-store-completion&lt;/code&gt; is designed as complementary to Nicolas&amp;rsquo; package.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;As the package isn&amp;rsquo;t yet available anywhere but in this repository, you can clone the repository, add it to the load-path, and require the package. My preferred way is &lt;code&gt;use-package&lt;/code&gt; with &lt;code&gt;straight&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;password-store-completion&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;:host&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;github&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:repo&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;SqrtMinusOne/password-store-completion&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;xdotool&lt;/code&gt; has to be available in &lt;code&gt;$PATH&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For Ivy integration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;password-store-ivy&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also be sure to load the main package before Ivy.&lt;/p&gt;
&lt;p&gt;For Embark integration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;password-store-embark&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;password-store-embark-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;Emacs&amp;rsquo; built-in &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/auth/The-Unix-password-store.html&#34;&gt;password store&lt;/a&gt; integration has to be set up.&lt;/p&gt;
&lt;p&gt;For Ivy integration, the command is &lt;code&gt;M-x password-store-ivy&lt;/code&gt;, which invokes Ivy to select an entry from the pass database. Available commands in the selection buffer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;M-a&lt;/code&gt;: Perform autotype&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-p&lt;/code&gt;: Type password&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-u&lt;/code&gt;: Type username&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-U&lt;/code&gt;: Type URL&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-f&lt;/code&gt;: Select a field to type&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For other completion frameworks, run &lt;code&gt;M-x password-store-completion&lt;/code&gt;. If Embark integration is enabled, the same actions are added.&lt;/p&gt;
&lt;h2 id=&#34;customization&#34;&gt;Customization&lt;/h2&gt;
&lt;p&gt;The following parameters control delays:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;password-store-completion-initial-wait&lt;/code&gt; controls the initial delay before starting to type a sequence (in milliseconds)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;password-store-completion-delay&lt;/code&gt; controls the delay between typing characters (in milliseconds)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;password-store-completion-sequences&lt;/code&gt; determines the steps of sequences. It is an alist; the keys correspond to the default sequences:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;autotype&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;password&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;username&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;url&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The values are lists of the following elements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;wait&lt;/code&gt;: Wait for &lt;code&gt;password-store-completion-initial-wait&lt;/code&gt; milliseconds&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(wait &amp;lt;milliseconds&amp;gt;)&lt;/code&gt;: Wait for &lt;code&gt;&amp;lt;milliseconds&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(key &amp;lt;key&amp;gt;)&lt;/code&gt;: Type &lt;code&gt;&amp;lt;key&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(field &amp;lt;field&amp;gt;)&lt;/code&gt;: Type &lt;code&gt;&amp;lt;field&amp;gt;&lt;/code&gt; of entry&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The default value is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#19177c&#34;&gt;autotype&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;wait&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;field&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Tab&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;field&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;secret&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Return&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;password&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;wait&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;field&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;secret&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;username&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;wait&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;field&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;wait&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;field&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;url&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Sequences can also be overridden in a particular entry with a field called &lt;code&gt;sequence-&amp;lt;name&amp;gt;&lt;/code&gt;, where &lt;code&gt;&amp;lt;name&amp;gt;&lt;/code&gt; is a key of &lt;code&gt;password-store-completion-sequences&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For example, to press &lt;code&gt;Tab&lt;/code&gt; twice in the &lt;code&gt;autotype&lt;/code&gt; sequence:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;pass&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;username: thexcloud@gmail.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;url: &amp;lt;url&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sequence-autotype: (wait (field . &amp;#34;username&amp;#34;) (key . &amp;#34;Tab&amp;#34;) (key . &amp;#34;Tab&amp;#34;) (field . secret) (key . &amp;#34;Return&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or, create a custom sequence:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;pass&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;username: thexcloud@gmail.com
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;url: &amp;lt;url&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sequence-doubletab: (wait (field . &amp;#34;username&amp;#34;) (key . &amp;#34;Tab&amp;#34;) (key . &amp;#34;Tab&amp;#34;) (field . secret) (key . &amp;#34;Return&amp;#34;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Custom sequences can be run in the field selection interface (&lt;code&gt;M-f&lt;/code&gt; in Ivy, &lt;code&gt;M-x embark-act f&lt;/code&gt; in Embark).&lt;/p&gt;
</content>
</item>
<item>
<title>org-journal-tags</title>
<link>https://sqrtminusone.xyz/packages/org-journal-tags/</link>
<pubDate>Sun, 06 Feb 2022 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/org-journal-tags/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/org-journal-tags&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/org-journal-tags-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;A package to make sense of &lt;del&gt;my life&lt;/del&gt; &lt;a href=&#34;https://github.com/bastibe/org-journal&#34;&gt;org-journal&lt;/a&gt; records.&lt;/p&gt;
&lt;p&gt;The package adds the &lt;code&gt;org-journal:&lt;/code&gt; link type to Org Mode. When placed in an org-journal file, the link serves as a &amp;ldquo;tag&amp;rdquo; that references one or many paragraphs of the journal or the entire section. These tags are aggregated in the database that can be queried in various ways.&lt;/p&gt;
&lt;h2 id=&#34;rationale&#34;&gt;Rationale&lt;/h2&gt;
&lt;p&gt;Journal files, by their very nature, are weakly structured. A single journal note can reference multiple entities (or none) and can itself be composed of multiple parts that have in common only the date and time when they were written. Needless to say, it&amp;rsquo;s hard to find anything in such records.&lt;/p&gt;
&lt;p&gt;This package attempts to improve the accessibility of the journal by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Taking advantage of temporal data, e.g. allowing to query entries in some date range.&lt;/li&gt;
&lt;li&gt;Allowing to extract (and reference) only certain parts of a particular journal entry.&lt;/li&gt;
&lt;li&gt;Compensating weak structure by with more advanced query engine.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For instance, when I&amp;rsquo;m writing down the progress on a job project, I can leave a tag like &lt;code&gt;job.&amp;lt;project-name&amp;gt;&lt;/code&gt; in the paragraph(s) related to that project. Later, I can query only those paragraphs that are referenced by this particular tag. The query results can then be narrowed, for instance, to include the word &amp;ldquo;backend&amp;rdquo;, or extended with some other tag.&lt;/p&gt;
&lt;p&gt;If no tag matches the subject matter, the journal can be queried with a regular expression, e.g. by searching some regex within a specific time frame. Subsequent searches are also significantly faster than the built-in &lt;code&gt;org-journal&lt;/code&gt; search functionality due to the to caching mechanism.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you normally install packages, my preferred way is &lt;code&gt;use-package&lt;/code&gt; with &lt;code&gt;straight&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-journal-tags&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-journal&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-journal-tags-autosync-mode&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;basic-usage&#34;&gt;Basic usage&lt;/h2&gt;
&lt;h3 id=&#34;adding-tags&#34;&gt;Adding tags&lt;/h3&gt;
&lt;p&gt;To add an inline tag, you can manually create a link of the following format:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[org-journal:&amp;lt;tag-name&amp;gt;][&amp;lt;tag-description&amp;gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or run &lt;code&gt;M-x org-journal-tags-insert-tag&lt;/code&gt; to insert a tag with a completion interface. The description is not aggregated and thus optional. Also, &lt;code&gt;&amp;lt;tag-name&amp;gt;&lt;/code&gt; cannot contain &lt;code&gt;:&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The link will reference the current Org Mode paragraph. If you want to reference more paragraphs, you can set the number of paragraphs like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[org-journal:&amp;lt;tag-name&amp;gt;::&amp;lt;number-of-paragraphs&amp;gt;][&amp;lt;tag-description&amp;gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Run &lt;code&gt;M-x org-journal-tags-link-get-region-at-point&lt;/code&gt; to select the referenced region of the buffer.&lt;/p&gt;
&lt;p&gt;To add a tag to the entire section, run &lt;code&gt;M-x org-journal-tags-prop-set&lt;/code&gt;, which will create or update the &lt;code&gt;Tags&lt;/code&gt; property in the property drawer of the current time section. This command features a notmuch-like UI, i.e. completing read for multiple entries, where &lt;code&gt;+&amp;lt;tag&amp;gt;&lt;/code&gt; adds a tag and &lt;code&gt;-&amp;lt;tag&amp;gt;&lt;/code&gt; deletes a tag.&lt;/p&gt;
&lt;p&gt;If you decide to rename a tag, there&amp;rsquo;s &lt;code&gt;M-x org-journal-tags-refactor&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;tag-kinds&#34;&gt;Tag kinds&lt;/h3&gt;
&lt;p&gt;Tag kind is a predefined class of tag with some extra functionality. The link format fo such tags is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[org-journal:&amp;lt;kind&amp;gt;:&amp;lt;tag-name&amp;gt;][&amp;lt;tag-description&amp;gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[[org-journal:&amp;lt;kind&amp;gt;:&amp;lt;tag-name&amp;gt;::&amp;lt;number-of-paragraphs&amp;gt;][&amp;lt;tag-description&amp;gt;]]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If &lt;code&gt;&amp;lt;kind&amp;gt;&lt;/code&gt; is omitted, a tag is considered &amp;ldquo;normal&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Running &lt;code&gt;C-u M-x org-journal-tags-insert-tag&lt;/code&gt; will first prompt for the tag kind and then for the tag itself from the set of already used tags of that kind.&lt;/p&gt;
&lt;p&gt;Running &lt;code&gt;C-u C-u M-x org-journal-tags-insert-tag&lt;/code&gt; will also first prompt for the tag kind, but then will try to invoke the kind-specific tag selection logic, if such is available. For instance, the &lt;code&gt;contact&lt;/code&gt; kind will prompt the &lt;code&gt;org-contacts&lt;/code&gt; database.&lt;/p&gt;
&lt;p&gt;For now, the only available tag kind is &lt;a href=&#34;https://repo.or.cz/org-contacts.git&#34;&gt;org-contacts&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;adding-timestamps&#34;&gt;Adding timestamps&lt;/h3&gt;
&lt;p&gt;In addition to tags, the package also aggregates inline timestamps, i.e. timestamps that are left in the text like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;This is a text. This is a text with &amp;lt;2022-04-07 Thu&amp;gt; a timestamp. This is a text again.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A timestamp will reference just the current paragraph.&lt;/p&gt;
&lt;p&gt;Other forms of timestamps (&lt;code&gt;SCHEDULED&lt;/code&gt;, &lt;code&gt;DEADLINE&lt;/code&gt;, etc.) are not supported at the moment, because this functionality is implemented well enough by &lt;a href=&#34;https://orgmode.org/manual/Agenda-Views.html&#34;&gt;org-agenda&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The envisioned use case for this functionality to leave references for the future to be seen at a particular date.&lt;/p&gt;
&lt;h3 id=&#34;database&#34;&gt;Database&lt;/h3&gt;
&lt;p&gt;The package stores tags and references to these tags in a database.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;org-journal-tags-autosync-mode&lt;/code&gt; enables synchronizing the database at the moment of saving of the org-journal buffer. You can also run the synchronization manually:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;M-x org-journal-tags-process-buffer&lt;/code&gt; to process the current buffer.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;M-x org-journal-tags-db-sync&lt;/code&gt; to sync changed org-journal files in the filesystem.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The same mode enables saving the database on killing Emacs, but you can always run &lt;code&gt;M-x org-journal-tags-db-save&lt;/code&gt; manually.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;M-x org-journal-tags-db-unload&lt;/code&gt; saves and unloads the database from the memory, &lt;code&gt;M-x org-journal-tags-db-reset&lt;/code&gt; creates a new database.&lt;/p&gt;
&lt;h3 id=&#34;status-buffer&#34;&gt;Status buffer&lt;/h3&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/org-journal-tags-img/status.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;em&gt;(I replaced tag names with &amp;ldquo;X&amp;rdquo; just for the screenshot)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;M-x org-journal-tags-status&lt;/code&gt; opens the status buffer with some statistics about the journal and tags. Press &lt;code&gt;?&lt;/code&gt; to see the available keybindings.&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;RET&lt;/code&gt; on a tag name in the &amp;ldquo;All tags&amp;rdquo; section should open a query buffer set to return all references for this tag.&lt;/p&gt;
&lt;h3 id=&#34;query-constructor&#34;&gt;Query constructor&lt;/h3&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/org-journal-tags-img/query.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Pressing &lt;code&gt;s&lt;/code&gt; in the status buffer or running &lt;code&gt;M-x org-journal-tags-transient-query&lt;/code&gt; opens a &lt;a href=&#34;https://magit.vc/manual/transient/&#34;&gt;transient.el&lt;/a&gt; buffer with query settings.&lt;/p&gt;
&lt;p&gt;The options are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Include tags&lt;/strong&gt; filters the references so that each reference had at least one of these tags.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Exclude tags&lt;/strong&gt; filters the references so that each reference didn&amp;rsquo;t have any of these tags.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Include children&lt;/strong&gt; includes child tags to the previous two lists.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tag location&lt;/strong&gt; can filter only section tags on inline tags.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Start date&lt;/strong&gt; and &lt;strong&gt;End date&lt;/strong&gt; filter the references by date.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filter timestamps&lt;/strong&gt; filters the references so that they include a timestamp.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timestamp start date&lt;/strong&gt; and &lt;strong&gt;Timestamp end date&lt;/strong&gt; filter
timestamps by their date.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Regex&lt;/strong&gt; filter the references by a regular expression. It can be a string or &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/elisp/Rx-Notation.html&#34;&gt;rx&lt;/a&gt; expression (it just has to start with &lt;code&gt;(rx&lt;/code&gt; in this case).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Narrow to regex&lt;/strong&gt; makes it so that each reference had only paragraphs that have a regex match.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sort&lt;/strong&gt; sorts the result in ascending order. It&amp;rsquo;s descending by default.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pressing &lt;code&gt;RET&lt;/code&gt; or &lt;code&gt;e&lt;/code&gt; executes the query. Journal files are cached, so subsequent queries within one session are much faster.&lt;/p&gt;
&lt;h3 id=&#34;query-results&#34;&gt;Query results&lt;/h3&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/org-journal-tags-img/query-results.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;After the query completes, the package opens the results buffer. Press &lt;code&gt;?&lt;/code&gt; to see the available keybindings there.&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;RET&lt;/code&gt; opens the corresponding org-journal entry.&lt;/p&gt;
&lt;p&gt;Pressing &lt;code&gt;s&lt;/code&gt; opens the query constructor buffer. If opened from inside the query results, the query constructor has 4 additional options:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Set operation&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Union&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;old new&lt;/td&gt;
&lt;td&gt;Add records of the new query to the displayed records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Intersection&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;old ∩ new&lt;/td&gt;
&lt;td&gt;Leave only those records that are both displayed and in the new query&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Difference from current&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;old \ new&lt;/td&gt;
&lt;td&gt;Exclude records of the new query from the displayed records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Difference to current&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;new \ old&lt;/td&gt;
&lt;td&gt;Exclude displayed records from ones of the new query&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Thus it is possible to make any query that can be described as a sequence of such set operations.&lt;/p&gt;
&lt;h2 id=&#34;advanced-usage&#34;&gt;Advanced usage&lt;/h2&gt;
&lt;h3 id=&#34;automatic-tagging&#34;&gt;Automatic tagging&lt;/h3&gt;
&lt;p&gt;org-journal provides a hook to automatically add information to the journal entries.&lt;/p&gt;
&lt;p&gt;It can be used to automatically assign tags, for instance, based on hostname. Here&amp;rsquo;s an excerpt from my configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/set-journal-header&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-journal-tags-prop-apply-delta&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:add&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;host.%s&amp;#34;&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;system-name&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;when&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;boundp&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;my/loc-tag&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;org-journal-tags-prop-apply-delta&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:add&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;list&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/loc-tag&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;org-journal-after-entry-create-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;my/set-journal-header&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;encryption&#34;&gt;Encryption&lt;/h3&gt;
&lt;p&gt;There are two ways how org-journal can be encrypted:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;With &lt;a href=&#34;https://orgmode.org/manual/Org-Crypt.html&#34;&gt;org-crypt&lt;/a&gt;, by setting &lt;code&gt;org-journal-enable-encryption&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;With &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/epa/Encrypting_002fdecrypting-gpg-files.html&#34;&gt;epa&lt;/a&gt;, by setting &lt;code&gt;org-journal-encrypt-journal&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both ways are supported by this package (I use the first). The decryption of entries takes some time, but this is alleviated by caching.&lt;/p&gt;
&lt;p&gt;The cache is stored in the &lt;code&gt;org-journal-tags--files-cache&lt;/code&gt; variable, so in principle, someone could come to your computer and inspect the value of this variable (who would ever do that?). If that&amp;rsquo;s an issue, you can do something like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;run-with-idle-timer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;60&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;15&lt;/span&gt;) &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;org-journal-tags-cache-reset&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To clear the cache on Emacs being idle after 15 minutes.&lt;/p&gt;
&lt;p&gt;Also, as said above, &lt;code&gt;org-journal-tags&lt;/code&gt; uses its own database, which is more like persistent cache for tags and references. You can encrypt it as well with &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_node/epa/Encrypting_002fdecrypting-gpg-files.html&#34;&gt;epa&lt;/a&gt; by adding &lt;code&gt;.gpg&lt;/code&gt; to the &lt;code&gt;org-journal-tags-db-file&lt;/code&gt; variable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;org-journal-tags-db-file&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;concat&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;user-emacs-directory&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;var/org-journal-tags/index.gpg&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The database is also stored in memory in &lt;code&gt;org-journal-tags-db&lt;/code&gt; variable, so once again, someone could inspect the value of the variable or just run &lt;code&gt;M-x org-journal-tags-status&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To avoid that, you can manually run &lt;code&gt;M-x org-journal-tags-db-unload&lt;/code&gt; or add it to &lt;code&gt;run-with-idle-timer&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;run-with-idle-timer&lt;/span&gt; (&lt;span style=&#34;color:#00f&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;60&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;15&lt;/span&gt;) &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;org-journal-tags-db-unload&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you have everything set up correctly, encrypting a file shouldn&amp;rsquo;t ask for a passphrase, so this function can be run automatically.&lt;/p&gt;
&lt;h3 id=&#34;advanced-querying&#34;&gt;Advanced querying&lt;/h3&gt;
&lt;p&gt;This package provides an API for doing queries from the Lisp code.&lt;/p&gt;
&lt;p&gt;The central function there &lt;code&gt;org-journal-tags-query&lt;/code&gt;, which has an interface corresponding to the flags in the query constructor. Take a look at its docstring for more info.&lt;/p&gt;
&lt;p&gt;Also, you can use some of the following operations on the set of journal references:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;org-journal-tags--query-union-refs&lt;/code&gt; - union&lt;/li&gt;
&lt;li&gt;&lt;code&gt;org-journal-tags--query-diff-refs&lt;/code&gt; - difference&lt;/li&gt;
&lt;li&gt;&lt;code&gt;org-journal-tags--query-intersect-refs&lt;/code&gt; - intersection&lt;/li&gt;
&lt;li&gt;&lt;code&gt;org-journal-tags--query-merge-refs&lt;/code&gt; - merge intersecting references within one set&lt;/li&gt;
&lt;li&gt;&lt;code&gt;org-journal-tags--query-sort-refs&lt;/code&gt; - order references by date&lt;/li&gt;
&lt;li&gt;&lt;code&gt;org-journal-tags--string-extract-refs&lt;/code&gt; - collect strings corresponding to references&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;final-notes&#34;&gt;Final notes&lt;/h2&gt;
&lt;p&gt;This package turned out to be almost as long and complex as &lt;a href=&#34;https://github.com/bastibe/org-journal&#34;&gt;org-journal&lt;/a&gt; itself, and it also introduces some new dependencies. Hence I decided it would be better off as a separate package.&lt;/p&gt;
&lt;p&gt;Also, I want to list some sources of inspiration. The database logic is heavily inspired by &lt;a href=&#34;https://github.com/skeeto/elfeed&#34;&gt;elfeed&lt;/a&gt;. The UI with &lt;a href=&#34;https://www.gnu.org/software/emacs/manual/html_mono/widget.html&#34;&gt;Emacs widgets&lt;/a&gt; for tags &amp;amp; &lt;code&gt;completing-read-multiple&lt;/code&gt; and the tagging system in general is inspired by &lt;a href=&#34;https://notmuchmail.org/&#34;&gt;notmuch&lt;/a&gt;. Finally, &lt;a href=&#34;https://github.com/magit/transient&#34;&gt;transient.el&lt;/a&gt; and &lt;a href=&#34;https://magit.vc/manual/magit-section.html&#34;&gt;magit-section&lt;/a&gt; are the UI packages that made this one possible, or at least much easier to implement.&lt;/p&gt;
</content>
</item>
<item>
<title>exwm-modeline</title>
<link>https://sqrtminusone.xyz/packages/exwm-modeline/</link>
<pubDate>Wed, 22 Dec 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/exwm-modeline/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/exwm-modeline&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/exwm-modeline-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;A modeline segment to display exwm workspaces.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s how it looks near the list of &lt;a href=&#34;https://github.com/nex3/perspective-el&#34;&gt;perspectives&lt;/a&gt; (the segment of the current package is to the left):
&lt;img src=&#34;https://sqrtminusone.xyz/exwm-modeline-img/screenshot.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;workspaces 0 and 5 do not have any X windows&lt;/li&gt;
&lt;li&gt;workspace 1 is the current workspace&lt;/li&gt;
&lt;li&gt;workspace 2 has at least one X window.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Supports &lt;code&gt;exwm-randr&lt;/code&gt; to display only workspaces related to the current monitor.&lt;/li&gt;
&lt;li&gt;Numbers are clickable.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you usually install packages, I use &lt;a href=&#34;https://github.com/jwiegley/use-package&#34;&gt;use-package&lt;/a&gt; and &lt;a href=&#34;https://github.com/raxod502/straight.el&#34;&gt;straight.el&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-modeline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;exwm&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then put a call to &lt;code&gt;exwm-modeline-mode&lt;/code&gt; somewhere after the moment when EXWM has been initialized, for instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exwm-init-hook&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;exwm-modeline-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;customization&#34;&gt;Customization&lt;/h2&gt;
&lt;p&gt;Set &lt;code&gt;exwm-modeline-randr&lt;/code&gt; to nil to turn off filtering of workspaces by monitor.&lt;/p&gt;
&lt;p&gt;Set &lt;code&gt;exwm-modeline-short&lt;/code&gt; to &lt;code&gt;t&lt;/code&gt; display only the current workspace in the modeline.&lt;/p&gt;
&lt;p&gt;Set &lt;code&gt;exwm-modeline-display-urgent&lt;/code&gt; to nil to turn off displaying whether a workspace has an urgent window. This will significantly decrease the number of modeline updates, which may help with performance issues.&lt;/p&gt;
&lt;h2 id=&#34;credits&#34;&gt;Credits&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/nex3/perspective-el&#34;&gt;perspective.el&lt;/a&gt; by &lt;a href=&#34;https://github.com/nex3&#34;&gt;@nex3&lt;/a&gt; was extremely instructive on how to make a modeline segment individual to a particular frame and avoid recalculating it too often.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/elken/doom-modeline-exwm&#34;&gt;doom-modeline-exwm&lt;/a&gt; by &lt;a href=&#34;https://github.com/elken&#34;&gt;@elken&lt;/a&gt; also was a source of inspiration.&lt;/p&gt;
</content>
</item>
<item>
<title>perspective-exwm</title>
<link>https://sqrtminusone.xyz/packages/perspective-exwm/</link>
<pubDate>Wed, 01 Dec 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/perspective-exwm/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/perspective-exwm&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/perspective-exwm-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;A couple of tricks and fixes to make using &lt;a href=&#34;https://github.com/ch11ng/exwm&#34;&gt;EXWM&lt;/a&gt; and &lt;a href=&#34;https://github.com/nex3/perspective-el&#34;&gt;perspective.el&lt;/a&gt; a better experience.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;This package is available on MELPA. Install it however you usually install packages, I use &lt;a href=&#34;https://github.com/jwiegley/use-package&#34;&gt;use-package&lt;/a&gt; and &lt;a href=&#34;https://github.com/raxod502/straight.el&#34;&gt;straight.el&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or clone the repository, add the package to the &lt;code&gt;load-path&lt;/code&gt; and load it with &lt;code&gt;require&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The package provides a minor mode, &lt;code&gt;perspective-exwm-mode&lt;/code&gt;, which is meant to be loaded before &lt;code&gt;exwm-init&lt;/code&gt;. For instance, if you use &lt;code&gt;use-package&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-mode&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;exwm-init&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;usage-and-details&#34;&gt;Usage and details&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;perspective-exwm-mode&lt;/code&gt;&lt;br /&gt;
The mode does a couple of things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;advises away a bug with half-killing the current perspective when closing a floating window. &lt;del&gt;I haven&amp;rsquo;t tested this as thoroughly&lt;/del&gt; I haven&amp;rsquo;t run into this issue for nearly a month, so it seems to be fixed. But there&amp;rsquo;s &lt;code&gt;M-x perspective-exwm-revive-perspectives&lt;/code&gt; if the problem arises anyway.&lt;/li&gt;
&lt;li&gt;fixes a bug with running &lt;code&gt;persp-set-buffer&lt;/code&gt; on an EXWM buffer that was moved between workspaces by advising &lt;code&gt;persp-buffer-in-other-p&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;fixes a bug with &lt;code&gt;persp-set-buffer&lt;/code&gt; copying all the perspectives from other workspaces to the current one.&lt;/li&gt;
&lt;li&gt;adjusts the name of the initial perspective in the new workspace. It tries to get the name from the &lt;code&gt;perspective-exwm-override-initial-name&lt;/code&gt; variable and fallbacks to &lt;code&gt;main-&amp;lt;index&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For the last point, I have the following in my configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-override-initial-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#666&#34;&gt;&amp;#39;&lt;/span&gt;((&lt;span style=&#34;color:#666&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;misc&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;core&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;browser&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;comms&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#666&#34;&gt;4&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;dev&amp;#34;&lt;/span&gt;)))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Having distinct perspective names between frames also serves a purpose, because otherwise there are issues with multiple perspectives sharing the same scratch buffer.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x perspective-exwm-cycle-exwm-buffers-forward&lt;/code&gt;, &lt;code&gt;perspective-exwm-cycle-exwm-buffers-backward&lt;/code&gt;&lt;br /&gt;
Cycle EXWM buffers in the current perspective.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/perspective-exwm-img/cycle-buffers.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;The buffer highlighted in yellow is the current one, the buffer highlighted in blue is shown in another window of the perspective so it will be omitted from the cycle.&lt;/p&gt;
&lt;p&gt;Set &lt;code&gt;perspective-exwm-get-exwm-buffer-name&lt;/code&gt; to customize the displayed name, by default it&amp;rsquo;s &lt;code&gt;exwm-class-name&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x perspective-exwm-cycle-all-buffers-forward&lt;/code&gt;, &lt;code&gt;perspective-exwm-cycle-exwm-all-backward&lt;/code&gt;&lt;br /&gt;
The same as above, but not restricted to EXWM buffers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x perspective-exwm-switch-perspective&lt;/code&gt;&lt;br /&gt;
Select a perspective from the list of all perspectives on all workspaces.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/perspective-exwm-img/switch-perspective.png&#34;&gt;
&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x perspective-exwm-copy-to-workspace&lt;/code&gt;&lt;br /&gt;
Copy the current perspective to another EXWM workspace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x perspective-exwm-move-to-workspace&lt;/code&gt;&lt;br /&gt;
Move the current perspective to another EXWM workspace.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;perspective-exwm-assign-windows&lt;/code&gt;&lt;br /&gt;
A handy function to move the current window to a given workspace and/or perspective. Example usage:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;defun&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-configure-window&lt;/span&gt; ()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;interactive&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#008000&#34;&gt;pcase&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;exwm-class-name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Firefox&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Nightly&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-assign-window&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:workspace-index&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:persp-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;browser&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Alacritty&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-assign-window&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:persp-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;term&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ((&lt;span style=&#34;color:#008000&#34;&gt;or&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;VK&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Slack&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;Discord&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;TelegramDesktop&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;perspective-exwm-assign-window&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:workspace-index&lt;/span&gt; &lt;span style=&#34;color:#666&#34;&gt;3&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:persp-name&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;comms&amp;#34;&lt;/span&gt;))))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;exwm-manage-finish-hook&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;my/exwm-configure-window&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;known-issues&#34;&gt;Known issues&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;perspective-exwm-move-to-workspace&lt;/code&gt; kills X windows in the perspective it tries to move. Have no idea how to fix this at the moment.&lt;/li&gt;
&lt;/ul&gt;
</content>
</item>
<item>
<title>pomm.el</title>
<link>https://sqrtminusone.xyz/packages/pomm/</link>
<pubDate>Fri, 05 Nov 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/pomm/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/pomm&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/pomm-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;Implementation of &lt;a href=&#34;https://en.wikipedia.org/wiki/Pomodoro_Technique&#34;&gt;Pomodoro&lt;/a&gt; and &lt;a href=&#34;https://www.lesswrong.com/posts/RWu8eZqbwgB9zaerh/third-time-a-better-way-to-work&#34;&gt;Third Time&lt;/a&gt; techniques for Emacs.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/pomm-img/screenshot.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Managing the timer with the excellent &lt;a href=&#34;https://github.com/magit/transient/blob/master/lisp/transient.el&#34;&gt;transient.el&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Persistent state between Emacs sessions.
The timer state isn&amp;rsquo;t reset if you close Emacs. If necessary, the state file can be synchronized between machines.&lt;/li&gt;
&lt;li&gt;History.
History of the timer can be stored in a CSV file. Eventually, I want to join this with &lt;a href=&#34;https://activitywatch.net/&#34;&gt;other activity data&lt;/a&gt; to see if the state of the timer changes how I use the computer.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you usually install Emacs packages, e.g.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;M-x package-install pomm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;My preferred way is &lt;code&gt;use-package&lt;/code&gt; with &lt;code&gt;straight.el&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;pomm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:commands&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;pomm&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;pomm-third-time&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or you can clone the repository, add the package to the &lt;code&gt;load-path&lt;/code&gt; and load it with &lt;code&gt;require&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;pomm&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The package requires Emacs 27.1 because the time API of the previous versions is kinda crazy and 27.1 has &lt;code&gt;time-convert&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;h3 id=&#34;pomodoro&#34;&gt;Pomodoro&lt;/h3&gt;
&lt;p&gt;Run &lt;code&gt;M-x pomm&lt;/code&gt; to open the transient buffer.&lt;/p&gt;
&lt;p&gt;The listed commands are self-descriptive and match the Pomodoro ideology.&lt;/p&gt;
&lt;p&gt;The timer can have 3 states:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stopped&lt;/strong&gt;. Can be started with &amp;ldquo;s&amp;rdquo; or &lt;code&gt;M-x pomm-start&lt;/code&gt;. A new iteration of the timer will be started.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Paused&lt;/strong&gt;. Can be continued with &amp;ldquo;s&amp;rdquo; / &lt;code&gt;M-x pomm-start&lt;/code&gt; or stopped completely with &amp;ldquo;S&amp;rdquo; / &lt;code&gt;M-x pomm-stop&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Running&lt;/strong&gt;. Can be paused with &amp;ldquo;p&amp;rdquo; / &lt;code&gt;M-x pomm-pause&lt;/code&gt; or stopped with &amp;ldquo;S&amp;rdquo; / &lt;code&gt;M-x pomm-stop&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The state of the timer can be reset with &amp;ldquo;R&amp;rdquo; or &lt;code&gt;M-x pomm-reset&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;u&amp;rdquo; updates the transient buffer. The update is manual because I didn&amp;rsquo;t figure out how to automate this, and I think this is not &lt;em&gt;really&lt;/em&gt; necessary.&lt;/p&gt;
&lt;p&gt;With &amp;ldquo;r&amp;rdquo; or &lt;code&gt;M-x pomm-set-context&lt;/code&gt; you can set the current &amp;ldquo;context&amp;rdquo;, that is some description of the task you are currently working on. This description will show up in history and in the CSV file. Also, &lt;code&gt;M-x pomm-start-with-context&lt;/code&gt; will prompt for the context and then start the timer.&lt;/p&gt;
&lt;h3 id=&#34;third-time&#34;&gt;Third Time&lt;/h3&gt;
&lt;p&gt;Run &lt;code&gt;M-x pomm-third-time&lt;/code&gt; to open the transient buffer for the Third Time technique.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/pomm-img/screenshot-tt.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;Essentially, the technique is designed around the formula:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Time of break = 1/3 x Time of work.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I.e., you work as long as you want or need, and then take a break with the maximum duration of &lt;code&gt;1/3&lt;/code&gt; of the time worked. If you take a shorter break, the remaining break time is saved and added to the next break within the same session. &lt;a href=&#34;https://www.lesswrong.com/posts/RWu8eZqbwgB9zaerh/third-time-a-better-way-to-work&#34;&gt;Here is a more detailed explanation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Third Time timer can have 2 states:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stopped&lt;/strong&gt;. Can be started with &amp;ldquo;s&amp;rdquo; or &lt;code&gt;M-x pomm-third-time-start&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Running&lt;/strong&gt;. Can be stopped with &amp;ldquo;S&amp;rdquo; or &lt;code&gt;M-x pomm-third-time-stop&lt;/code&gt;. This resets the accumulated break time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Use &amp;ldquo;b&amp;rdquo; or &lt;code&gt;M-x pomm-third-time-switch&lt;/code&gt; to switch the current period type (work or break). If the break time runs out, the timer automatically switches to work.&lt;/p&gt;
&lt;h2 id=&#34;customization&#34;&gt;Customization&lt;/h2&gt;
&lt;p&gt;Some settings are available in the transient buffer, but you can customize the relevant variables to make them permanent. Check &lt;code&gt;M-x customize-group&lt;/code&gt; &lt;code&gt;pomm&lt;/code&gt; and &lt;code&gt;M-x customize-group pomm-third-time&lt;/code&gt; for more information.&lt;/p&gt;
&lt;h3 id=&#34;alerts&#34;&gt;Alerts&lt;/h3&gt;
&lt;p&gt;The package sends alerts via &lt;code&gt;alert.el&lt;/code&gt;. The default style of alert is a plain &lt;code&gt;message&lt;/code&gt;, but if you want an actual notification, set &lt;code&gt;alert-default-style&lt;/code&gt; accordingly:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;alert-default-style&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;libnotify&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;sounds&#34;&gt;Sounds&lt;/h3&gt;
&lt;p&gt;By default, sounds are disabled. Set &lt;code&gt;pomm-audio-enabled&lt;/code&gt; to &lt;code&gt;t&lt;/code&gt; to toggle them. Set &lt;code&gt;pomm-audio-tick-enabled&lt;/code&gt; to &lt;code&gt;t&lt;/code&gt; if you want the ticking sound.&lt;/p&gt;
&lt;p&gt;This functionality needs &lt;code&gt;pomm-audio-player-executable&lt;/code&gt; to be set so that the program could be invoked like: &lt;code&gt;&amp;lt;executable&amp;gt; /path/to/sound.wav&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The package ships with some built-it sounds, which you can replace by customizing the &lt;code&gt;pomm-audio-files&lt;/code&gt; variable.&lt;/p&gt;
&lt;h3 id=&#34;modeline&#34;&gt;Modeline&lt;/h3&gt;
&lt;p&gt;If you want the timer to display in the modeline, activate the &lt;code&gt;pomm-mode-line-mode&lt;/code&gt; minor mode.&lt;/p&gt;
&lt;h3 id=&#34;polybar-module&#34;&gt;Polybar module&lt;/h3&gt;
&lt;p&gt;If you want to display the Pomodoro status in something like polybar, you can add the following lines to your config:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;pomm-on-tick-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;pomm-update-mode-line-string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;pomm-on-status-changed-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;pomm-update-mode-line-string&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Create a script like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;if&lt;/span&gt; ps -e | grep emacs &amp;gt;&amp;gt; /dev/null; &lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; emacsclient --eval &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;(if (boundp &amp;#39;pomm-current-mode-line-string) pomm-current-mode-line-string \&amp;#34;\&amp;#34;) &amp;#34;&lt;/span&gt; | xargs &lt;span style=&#34;color:#008000&#34;&gt;echo&lt;/span&gt; -e
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000;font-weight:bold&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And add a polybar module definition to your polybar config:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-conf-windows&#34; data-lang=&#34;conf-windows&#34;&gt;[module/pomm]
type = custom/script
exec = /home/pavel/bin/polybar/pomm.sh
interval = 1
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;state-file-location&#34;&gt;State file location&lt;/h3&gt;
&lt;p&gt;To implement persistence between Emacs sessions, the package stores its state in the following files:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pomm-state-file-location&lt;/code&gt;, &lt;code&gt;.emacs.d/pomm&lt;/code&gt; by default&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pomm-third-time-state-file-location&lt;/code&gt;, &lt;code&gt;/.emacs.d/pomm-third-time&lt;/code&gt; by default&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Set these paths however like.&lt;/p&gt;
&lt;h3 id=&#34;history&#34;&gt;History&lt;/h3&gt;
&lt;p&gt;If you set the &lt;code&gt;pomm-csv-history-file&lt;/code&gt; (and/or &lt;code&gt;pomm-third-time-csv-history-file&lt;/code&gt;) variable, the package will log its history in CSV format. Just keep in mind that the parent directory has to exist.&lt;/p&gt;
&lt;p&gt;The file for the Pomodoro technique has the following columns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;timestamp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;status&lt;/code&gt; (&lt;code&gt;stopped&lt;/code&gt;, &lt;code&gt;paused&lt;/code&gt; or &lt;code&gt;running&lt;/code&gt;, according to the &lt;a href=&#34;#usage-1&#34;&gt;usage&lt;/a&gt; section)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kind&lt;/code&gt; (&lt;code&gt;work&lt;/code&gt;, &lt;code&gt;short-break&lt;/code&gt;, &lt;code&gt;long-break&lt;/code&gt; or &lt;code&gt;nil&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;iteration&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;context&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The one for the Third Time technique has an extra column called &lt;code&gt;break-time-remaining&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A new entry is written after a particular state of the timer comes into being.&lt;/p&gt;
&lt;p&gt;To customize timestamp, set the &lt;code&gt;pomm-csv-history-file-timestamp-format&lt;/code&gt; variable. For example, for traditional &lt;code&gt;YYYY-MM-DD HH:mm:ss&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;pomm-csv-history-file-timestamp-format&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;%F %T&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The format is the same as in &lt;code&gt;format-time-string&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&#34;usage-with-org-clock&#34;&gt;Usage with &lt;code&gt;org-clock&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The package can be used with &lt;a href=&#34;https://orgmode.org/manual/Clocking-commands.html&#34;&gt;org-clock&lt;/a&gt; in the following way. Set up these two hooks:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;pomm-on-status-changed-hook&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;pomm--sync-org-clock&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;add-hook&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;pomm-third-time-on-status-changed-hook&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;#&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#19177c&#34;&gt;pomm-third-time--sync-org-clock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then, start the timer (either &lt;code&gt;pomm&lt;/code&gt; or &lt;code&gt;pomm-third-time&lt;/code&gt;) and &lt;code&gt;org-clock-in&lt;/code&gt;, in whichever order. The package will call &lt;code&gt;org-clock-out&lt;/code&gt; when a break starts and &lt;code&gt;org-clock-in-last&lt;/code&gt; when it ends.&lt;/p&gt;
&lt;p&gt;Setting &lt;code&gt;pomm-org-clock-in-immediately&lt;/code&gt; to &lt;code&gt;nil&lt;/code&gt; &amp;ldquo;defers&amp;rdquo; calling &lt;code&gt;org-clock-in-last&lt;/code&gt; until after any command from the user (via &lt;code&gt;post-command-hook&lt;/code&gt;). I&amp;rsquo;ve added this because I occasionally return to my PC a few minutes after the break ends, so I don&amp;rsquo;t want these minutes to show up in &lt;code&gt;org-clock&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Also see &lt;a href=&#34;https://github.com/SqrtMinusOne/pomm.el/issues/13#issuecomment-2216868331&#34;&gt;this comment&lt;/a&gt; (&lt;a href=&#34;https://github.com/SqrtMinusOne/pomm.el/issues/13&#34;&gt;#13&lt;/a&gt;) for an alternative approach.&lt;/p&gt;
&lt;h2 id=&#34;alternatives&#34;&gt;Alternatives&lt;/h2&gt;
&lt;p&gt;There is a number of packages with a similar purpose, here is a rough comparison of features:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;3rd party integrations&lt;/th&gt;
&lt;th&gt;Control method (1)&lt;/th&gt;
&lt;th&gt;Persistent history&lt;/th&gt;
&lt;th&gt;Persistent state&lt;/th&gt;
&lt;th&gt;Notifications&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://github.com/SqrtMinusOne/pomm.el&#34;&gt;pomm.el&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;transient.el&lt;/td&gt;
&lt;td&gt;CSV&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;alert.el + sounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://github.com/marcinkoziej/org-pomodoro/tree/master&#34;&gt;org-pomodoro&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Org Mode!&lt;/td&gt;
&lt;td&gt;via Org commands&lt;/td&gt;
&lt;td&gt;via Org mode&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;alert.el + sounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://github.com/TatriX/pomidor/&#34;&gt;pomidor&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;self-cooked interactive buffer&lt;/td&gt;
&lt;td&gt;custom delimited format?&lt;/td&gt;
&lt;td&gt;+, but saving on-demand&lt;/td&gt;
&lt;td&gt;alert.el + sounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://github.com/baudtack/pomodoro.el/&#34;&gt;pomodoro.el&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;notifications.el + sounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://github.com/konr/tomatinho/&#34;&gt;tomatinho&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;self-cooked interactive buffer&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;message + sounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://github.com/ferfebles/redtick&#34;&gt;redtick&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;mode-line icon&lt;/td&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;sounds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&#34;https://github.com/abo-abo/gtk-pomodoro-indicator&#34;&gt;gtk-pomodoro-indicator&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;GTK panel&lt;/td&gt;
&lt;td&gt;CLI&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-, but the program is independent of Emacs&lt;/td&gt;
&lt;td&gt;GTK notifications&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Be sure to check those out if this one doesn&amp;rsquo;t quite fit your workflow!&lt;/p&gt;
&lt;p&gt;(1) Means of timer control with exception to Emacs interactive commands&lt;/p&gt;
&lt;p&gt;Also take a look at &lt;a href=&#34;https://github.com/telotortium/org-pomodoro-third-time&#34;&gt;org-pomodoro-third-time&lt;/a&gt;, which adapts &lt;code&gt;org-pomodoro&lt;/code&gt; for the Third Time technique.&lt;/p&gt;
&lt;h2 id=&#34;p-dot-s-dot&#34;&gt;P.S.&lt;/h2&gt;
&lt;p&gt;The package name is not an abbreviation. I just hope it doesn&amp;rsquo;t mean something horrible in some language I don&amp;rsquo;t know.&lt;/p&gt;
&lt;p&gt;The sounds are made by Mike Koening under &lt;a href=&#34;https://creativecommons.org/licenses/by/3.0/legalcode&#34;&gt;CC BY 3.0&lt;/a&gt;.&lt;/p&gt;
</content>
</item>
<item>
<title>lyrics-fetcher.el</title>
<link>https://sqrtminusone.xyz/packages/lyrics-fetcher/</link>
<pubDate>Sat, 14 Aug 2021 00:00:00 +0000</pubDate>
<guid>https://sqrtminusone.xyz/packages/lyrics-fetcher/</guid>
<content type="html">
&lt;figure&gt;&lt;a href=&#34;https://melpa.org/#/lyrics-fetcher&#34;&gt;&lt;img src=&#34;https://melpa.org/packages/lyrics-fetcher-badge.svg&#34;&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;p&gt;A package to fetch song lyrics and album covers. Integrates with EMMS.&lt;/p&gt;
&lt;figure&gt;&lt;img src=&#34;https://sqrtminusone.xyz/lyrics-fetcher-img/screenshot.png&#34;&gt;
&lt;/figure&gt;
&lt;p&gt;The available backends are &lt;a href=&#34;https://genius.com&#34;&gt;genius.com&lt;/a&gt; and &lt;a href=&#34;https://music.163.com/&#34;&gt;music.163.com&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;installation&#34;&gt;Installation&lt;/h2&gt;
&lt;p&gt;The package is available on MELPA. Install it however you normally install packages, I prefer &lt;code&gt;use-package&lt;/code&gt; with &lt;code&gt;straight&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;use-package&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;lyrics-fetcher&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:straight&lt;/span&gt; &lt;span style=&#34;color:#800&#34;&gt;t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;:after&lt;/span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;emms&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Install &lt;a href=&#34;https://imagemagick.org/index.php&#34;&gt;imagemagick&lt;/a&gt; if you want to download covers.&lt;/p&gt;
&lt;p&gt;If you want to use the genius backend, you have to set &lt;a href=&#34;https://docs.genius.com/&#34;&gt;genius.com&lt;/a&gt; client access token. To do that, &lt;a href=&#34;https://genius.com/api-clients/new&#34;&gt;create a new client,&lt;/a&gt; click &amp;ldquo;Generate Access Token&amp;rdquo; and put the result to the &lt;code&gt;lyrics-fetcher-genius-access-token&lt;/code&gt; variable. I do this with password-store:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#008000&#34;&gt;setq&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;lyrics-fetcher-genius-access-token&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; (&lt;span style=&#34;color:#19177c&#34;&gt;password-store-get&lt;/span&gt; &lt;span style=&#34;color:#ba2121&#34;&gt;&amp;#34;My_Online/APIs/genius.com&amp;#34;&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;But of course, you can just hardcode the string.&lt;/p&gt;
&lt;h2 id=&#34;usage&#34;&gt;Usage&lt;/h2&gt;
&lt;p&gt;Available commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x lyrics-fetcher-show-lyrics&lt;/code&gt; - show lyrics for the current playing track.&lt;/p&gt;
&lt;p&gt;The resulting lyric files are saved to the &lt;code&gt;lyrics-fetcher-lyrics-folder&lt;/code&gt; and have the &lt;code&gt;lyrics-fetcher-lyrics-file-extension&lt;/code&gt; extension. The folder will be created if it doesn&amp;rsquo;t exist.&lt;/p&gt;
&lt;p&gt;By default, the function opens an already saved lyrics file if one exists, otherwise tries to fetch the lyrics.&lt;/p&gt;
&lt;p&gt;If called with &lt;code&gt;C-u&lt;/code&gt;, then tries to fetch the text regardless of the latter.&lt;/p&gt;
&lt;p&gt;If called with &lt;code&gt;C-u C-u&lt;/code&gt;, prompts the user to select a matching song. That is helpful when there are multiple songs with similar names, and the top one isn&amp;rsquo;t the right one.&lt;/p&gt;
&lt;p&gt;If called with &lt;code&gt;C-u C-u C-u&lt;/code&gt;, edit the search query in minibuffer before sending. This is helpful when there is extra information in the song title which prevents the API from finding the song.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x lyrics-fetcher-show-lyrics-query&lt;/code&gt; - fetch lyrics by a text query.&lt;/p&gt;
&lt;p&gt;Modified by &lt;code&gt;C-u&lt;/code&gt; the same way as &lt;code&gt;lyrics-fetcher-show-lyrics&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x lyrics-fetcher-use-backend&lt;/code&gt; - select a backend to use.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;EMMS integration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x lyrics-fetcher-emms-browser-show-at-point&lt;/code&gt; - fetch data for the current point in EMMS browser.&lt;/p&gt;
&lt;p&gt;If the point contains just one song, it will be fetched the usual way and lyrics will be shown upon successful completion.&lt;/p&gt;
&lt;p&gt;If the point contains many songs (e.g. it&amp;rsquo;s an album), the lyrics will be fetched consequentially for every song. The process then will stop at the first failure.&lt;/p&gt;
&lt;p&gt;Modified by &lt;code&gt;C-u&lt;/code&gt; the same way as &lt;code&gt;lyrics-fetcher-show-lyrics&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x lyrics-fetcher-emms-browser-fetch-covers-at-point&lt;/code&gt; - fetch album covers for the current point in the EMMS browser.&lt;/p&gt;
&lt;p&gt;This functionality requires songs&amp;rsquo; directories to be grouped by albums, i.e. one album per one folder.&lt;/p&gt;
&lt;p&gt;The files will be saved to the folder with names like &amp;ldquo;cover_small.jpg&amp;rdquo;, &amp;ldquo;cover_med.jpg&amp;rdquo;, &amp;ldquo;cover_large.jpg&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;You can customize the sizes via the &lt;code&gt;lyrics-fetcher-small-cover-size&lt;/code&gt; and &lt;code&gt;lyrics-fetcher-medium-cover-size&lt;/code&gt; variables.&lt;/p&gt;
&lt;p&gt;Modified by &lt;code&gt;C-u&lt;/code&gt; the same way as &lt;code&gt;lyrics-fetcher-show-lyrics&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x lyrics-fetcher-emms-browser-open-large-cover-at-point&lt;/code&gt; - open large_cover for the current point in EMMS browser.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;M-x lyrics-fetcher-lyrics-catchup&lt;/code&gt; - feed the LRC file for the current track to EMMS.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lyric view mode keybindings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;q&lt;/code&gt; - close the lyrics buffer&lt;/li&gt;
&lt;li&gt;&lt;code&gt;r&lt;/code&gt; - refetch the lyrics in the buffer&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;available-backends&#34;&gt;Available backends&lt;/h2&gt;
&lt;p&gt;As of now, the available backends are &lt;code&gt;genius&lt;/code&gt; and &lt;code&gt;neteasecloud&lt;/code&gt; (thanks &lt;a href=&#34;https://github.com/Elilif&#34;&gt;@Elilif&lt;/a&gt;). Backends can be switched with &lt;code&gt;M-x lyrics-fetcher-use-backend&lt;/code&gt;, or from the Lisp code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-emacs-lisp&#34; data-lang=&#34;emacs-lisp&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(&lt;span style=&#34;color:#19177c&#34;&gt;lyrics-fetcher-use-backend&lt;/span&gt; &lt;span style=&#34;color:#19177c&#34;&gt;&amp;#39;neteasecloud&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;genius&lt;/code&gt; backend fetches lyrics in a simple text format.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;neteasecloud&lt;/code&gt; fetches in the &lt;a href=&#34;https://en.wikipedia.org/wiki/LRC_(file_format)&#34;&gt;LRC&lt;/a&gt; format, which contains timestamps for each line of the lyrics text.&lt;/p&gt;
&lt;p&gt;LRC files can also be read by &lt;code&gt;emms-lyrics&lt;/code&gt;. &lt;code&gt;lyrics-fetcher-use-backend&lt;/code&gt; sets up &lt;code&gt;lyrics-fetcher&lt;/code&gt; and EMMS variables so that EMMS could see the lyrics, downloaded by &lt;code&gt;lyrics-fetcher&lt;/code&gt;. Running &lt;code&gt;M-x emms-lyrics&lt;/code&gt; then should enable lyric display for newly played tracks, or you can run &lt;code&gt;M-x lyrics-fetcher-lyrics-catchup&lt;/code&gt; to manually feed the current LRC file to EMMS.&lt;/p&gt;
&lt;h2 id=&#34;customization-and-extension&#34;&gt;Customization and extension&lt;/h2&gt;
&lt;h3 id=&#34;lyrics-file-naming-and-location&#34;&gt;Lyrics file naming and location&lt;/h3&gt;
&lt;p&gt;As was outlined above, lyrics files are saved to &lt;code&gt;lyrics-fetcher-lyrics-folder&lt;/code&gt; and have an extension set in &lt;code&gt;lyrics-fetcher-lyrics-file-extension&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Take a look at the &lt;code&gt;lyrics-fetcher-format-song-name-method&lt;/code&gt; and &lt;code&gt;lyrics-fetcher-format-file-name-method&lt;/code&gt; variables if you want to customize the lyrics buffer and file naming.&lt;/p&gt;
&lt;p&gt;Also note that integration with &lt;code&gt;emms-lyrics&lt;/code&gt; requires these variables to be set with &lt;code&gt;lyrics-fetcher-use-backend&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;using-other-player-than-emms&#34;&gt;Using other player than EMMS&lt;/h3&gt;
&lt;p&gt;To use another player, customize &lt;code&gt;lyrics-fetcher-current-track-method&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This variable contains a function that returns the current playing track. The return format has to be either a string or (recommended) an EMMS-like alist, which has to have the following fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;info-artist&lt;/code&gt; or &lt;code&gt;info-albumartist&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;info-title&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;adding-another-backend&#34;&gt;Adding another backend&lt;/h3&gt;
&lt;p&gt;A function to perform the lyric fetching is set in &lt;code&gt;lyrics-fetcher-fetch-method&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The function has to receive 3 arguments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;track&lt;/code&gt; - a string or alist, as outlined &lt;a href=&#34;#using-other-player-than-emms-1&#34;&gt;above&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; - the function which has to be called with the resulting lyrics string&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sync&lt;/code&gt; - if non-nil, inquire the user about the possible choices. This is called &lt;code&gt;sync&lt;/code&gt; because then it is reasonable to perform the request synchronously, as otherwise, it won&amp;rsquo;t be nice to suddenly throw a prompt at the user.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The album cover fetching is similar. The corresponding function is set in &lt;code&gt;lyrics-fetcher-download-cover-method&lt;/code&gt; and has to receive the following parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;track&lt;/code&gt; - as above&lt;/li&gt;
&lt;li&gt;&lt;code&gt;callback&lt;/code&gt; - has to be called with the path to the resulting file. This file should be named &lt;code&gt;cover_large.&amp;lt;extension&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;folder&lt;/code&gt; - where the file has to be put&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sync&lt;/code&gt; - as above.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first argument is &lt;code&gt;track&lt;/code&gt; because in EMMS all the required information is stored in tracks, and album data is deduced from tracks. So this package just takes a sample track in the album.&lt;/p&gt;
&lt;h2 id=&#34;troubleshooting&#34;&gt;Troubleshooting&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve noticed that Genius can give pages with different DOMs to different people. If you have an empty buffer instead of lyrics, please attach the &lt;code&gt;curl-cookie-jar&lt;/code&gt; file to the issue. It usually resides in &lt;code&gt;.emacs.d/request&lt;/code&gt;.&lt;/p&gt;
</content>
</item>
</channel>
</rss>