<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Emacs on Thanos Apollo</title>
    <link>https://thanosapollo.org/categories/emacs/</link>
    <description>Recent content in Emacs on Thanos Apollo</description>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Sat, 04 Apr 2026 00:00:00 +0300</lastBuildDate>
    <atom:link href="https://thanosapollo.org/categories/emacs/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Bringing jabber.el Back From the Dead</title>
      <link>https://thanosapollo.org/posts/emacs-jabber-revival/</link>
      <pubDate>Sat, 04 Apr 2026 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/emacs-jabber-revival/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://xmpp.org/software/jabber-el/&#34;&gt;jabber.el&lt;/a&gt; is an XMPP client for Emacs, originally written in 2003.
Development slowed over the years, though contributors kept the package
working across Emacs releases.&lt;/p&gt;
&lt;p&gt;I took over as maintainer with the goal of modernizing the protocol
support.&lt;/p&gt;
&lt;p&gt;Now, jabber.el is &lt;strong&gt;the most XEP-complete text-based client&lt;/strong&gt; in
existence.&lt;/p&gt;
&lt;h2 id=&#34;what-changed&#34;&gt;What Changed&lt;/h2&gt;
&lt;p&gt;For those, like me, who count XEPs like Pokemon:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;OMEMO encryption&lt;/strong&gt; (XEP-0384) via a C dynamic module wrapping &lt;a href=&#34;https://codeberg.org/picomemo/picomemo&#34;&gt;picomemo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OMEMO media sharing&lt;/strong&gt; (XEP-0454)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenPGP for XMPP&lt;/strong&gt; (XEP-0373) using Emacs&amp;rsquo; built-in EPG&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stream Management&lt;/strong&gt; (XEP-0198) with session resume&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message Archive Management&lt;/strong&gt; (XEP-0313)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message Carbons&lt;/strong&gt; (XEP-0280)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delivery Receipts&lt;/strong&gt; (XEP-0184) and &lt;strong&gt;Chat Markers&lt;/strong&gt; (XEP-0333)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Message Correction&lt;/strong&gt; (XEP-0308), &lt;strong&gt;Replies&lt;/strong&gt; (XEP-0461), &lt;strong&gt;Moderation&lt;/strong&gt; (XEP-0424/0425)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chat State Notifications&lt;/strong&gt; (XEP-0085)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Client State Indication&lt;/strong&gt; (XEP-0352)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blocking Command&lt;/strong&gt; (XEP-0191)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTTP File Upload&lt;/strong&gt; (XEP-0363)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Direct TLS&lt;/strong&gt; (XEP-0368) with dual SRV lookup&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Real Time Text&lt;/strong&gt; (XEP-0301)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PubSub&lt;/strong&gt; (XEP-0060)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bookmarks&lt;/strong&gt; (XEP-0402 with XEP-0048 fallback)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQLite message storage&lt;/strong&gt; replacing flat-file history&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MUC Self-Ping&lt;/strong&gt; (XEP-0410)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Almost caught them all&lt;/em&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><a href="https://xmpp.org/software/jabber-el/">jabber.el</a> is an XMPP client for Emacs, originally written in 2003.
Development slowed over the years, though contributors kept the package
working across Emacs releases.</p>
<p>I took over as maintainer with the goal of modernizing the protocol
support.</p>
<p>Now, jabber.el is <strong>the most XEP-complete text-based client</strong> in
existence.</p>
<h2 id="what-changed">What Changed</h2>
<p>For those, like me, who count XEPs like Pokemon:</p>
<blockquote>
<ul>
<li><strong>OMEMO encryption</strong> (XEP-0384) via a C dynamic module wrapping <a href="https://codeberg.org/picomemo/picomemo">picomemo</a></li>
<li><strong>OMEMO media sharing</strong> (XEP-0454)</li>
<li><strong>OpenPGP for XMPP</strong> (XEP-0373) using Emacs&rsquo; built-in EPG</li>
<li><strong>Stream Management</strong> (XEP-0198) with session resume</li>
<li><strong>Message Archive Management</strong> (XEP-0313)</li>
<li><strong>Message Carbons</strong> (XEP-0280)</li>
<li><strong>Delivery Receipts</strong> (XEP-0184) and <strong>Chat Markers</strong> (XEP-0333)</li>
<li><strong>Message Correction</strong> (XEP-0308), <strong>Replies</strong> (XEP-0461), <strong>Moderation</strong> (XEP-0424/0425)</li>
<li><strong>Chat State Notifications</strong> (XEP-0085)</li>
<li><strong>Client State Indication</strong> (XEP-0352)</li>
<li><strong>Blocking Command</strong> (XEP-0191)</li>
<li><strong>HTTP File Upload</strong> (XEP-0363)</li>
<li><strong>Direct TLS</strong> (XEP-0368) with dual SRV lookup</li>
<li><strong>Real Time Text</strong> (XEP-0301)</li>
<li><strong>PubSub</strong> (XEP-0060)</li>
<li><strong>Bookmarks</strong> (XEP-0402 with XEP-0048 fallback)</li>
<li><strong>SQLite message storage</strong> replacing flat-file history</li>
<li><strong>MUC Self-Ping</strong> (XEP-0410)</li>
</ul>
</blockquote>
<p><em>Almost caught them all</em></p>
<p>No other text-based XMPP client has this level of protocol coverage.
jabber.el now rivals Dino and Gajim, the major graphical clients.</p>
<h2 id="omemo">OMEMO</h2>
<p>OMEMO requires a Signal Protocol implementation.  That means C.</p>
<p><code>jabber-omemo-core.c</code> is 763 lines wrapping <a href="https://github.com/mierenhoop/picomemo">picomemo</a> through Emacs'
dynamic module API.  The Elisp layer handles XMPP integration: PubSub
bundle publishing, stanza encryption, session persistence in SQLite, and
trust management.</p>
<p>It also provides AES-256-GCM for OMEMO media sharing (<a href="https://xmpp.org/extensions/xep-0454.html">XEP-0454</a>).</p>
<h2 id="why-emacs">Why Emacs</h2>
<p>Emacs is not just the editor I write jabber.el in.  It is the runtime,
the test harness, and the application.</p>
<p>I develop in the same instance where I chat.  Fix a bug, eval changes,
and the fix is live in my running session.  Seconds, not minutes.</p>
<p>Emacs provides most of what a chat client needs out of the box: SQLite
for storage, GnuTLS for encryption, EPG for OpenPGP, EWOC for list
display, Transient for menus.</p>
<p>Distribution is through <a href="https://elpa.nongnu.org/nongnu/jabber.html">NonGNU ELPA</a>, which handles everything.</p>
<p><code>jabber.el</code> is just an <code>M-x package-install RET jabber RET</code> away from
install.</p>
<h2 id="why-xmpp">Why XMPP</h2>
<p>XMPP is the only federated, open-standard messaging protocol that
works <strong>in practice</strong>.  I use it for all my daily communication.  My
friends are on WhatsApp, Discord and IRC &ndash; gateways bridge these
networks transparently.</p>
<p><strong>One client, one interface, every chat network I need.</strong></p>
<blockquote>
<p>More on the gateway setup I use in a future post.</p>
</blockquote>
<h2 id="what-s-next">What&rsquo;s Next</h2>
<ul>
<li><strong>XEP-0444 Message Reactions</strong></li>
<li><strong>OMEMO 0.8+</strong> (picomemo supports both; the C layer is ready)</li>
<li><strong>Roster rework</strong> &ndash; flat, query-based contact list sorted by activity</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Gnosis 0.10: Import Anki, Merge Everything Into One</title>
      <link>https://thanosapollo.org/posts/gnosis-8-to-10/</link>
      <pubDate>Sat, 04 Apr 2026 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/gnosis-8-to-10/</guid>
      <description>&lt;p&gt;&lt;strong&gt;You can now import Anki decks into gnosis.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The entire Anki ecosystem, thousands of community-maintained decks
across every subject, is accessible from Emacs.  I can finally keep
track of the &lt;a href=&#34;https://www.ankihub.net/step-deck&#34;&gt;AnKing&lt;/a&gt; deck changes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you can&amp;rsquo;t beat them, import them.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;anki-import&#34;&gt;Anki import&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;gnosis-anki-import&lt;/code&gt; reads &lt;code&gt;.apkg&lt;/code&gt; files and converts them into gnosis
themata.  It resolves Anki&amp;rsquo;s note type templates to extract
question/answer pairs, normalizes tags, and strips Anki system tags
like &lt;code&gt;marked&lt;/code&gt; and &lt;code&gt;leech&lt;/code&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p><strong>You can now import Anki decks into gnosis.</strong></p>
<p>The entire Anki ecosystem, thousands of community-maintained decks
across every subject, is accessible from Emacs.  I can finally keep
track of the <a href="https://www.ankihub.net/step-deck">AnKing</a> deck changes.</p>
<blockquote>
<p><em>If you can&rsquo;t beat them, import them.</em></p>
</blockquote>
<h2 id="anki-import">Anki import</h2>
<p><code>gnosis-anki-import</code> reads <code>.apkg</code> files and converts them into gnosis
themata.  It resolves Anki&rsquo;s note type templates to extract
question/answer pairs, normalizes tags, and strips Anki system tags
like <code>marked</code> and <code>leech</code>.</p>
<p>Re-importing the same deck is safe.  Each imported note keeps its
Anki GUID, so gnosis detects duplicates and skips them.  When AnKing
pushes an update, I just re-import and only the new notes come in.</p>
<blockquote>
<p><em>Tens of thousands of notes &amp; themata, managed from a text editor.</em>
<em>As it should be.</em></p>
</blockquote>
<h2 id="one-package-one-database">One package, one database</h2>
<p><code>org-gnosis</code> was merged into gnosis.  Maintaining two packages with
two databases for what is fundamentally one system was, in retrospect,
an act of bureaucratic self-harm.  Nodes, journal, and themata now
share a single <code>gnosis.db</code>.  The migration imports existing org-gnosis
data automatically.</p>
<h2 id="export-and-import">Export and import</h2>
<p>The old org-file export format is gone.  Exports are now <code>.gnosis</code>
SQLite databases.  Importing shows a diff buffer with NEW and CHANGED
entries before applying, so you see exactly what will change before
committing.</p>
<p>Combined with GUID tracking, this makes gnosis collections
maintainable over time rather than one-shot imports.  Share a deck
with a friend, they modify it, you re-import.  No data lost, no
duplicates.</p>
<h2 id="other">Other</h2>
<ul>
<li>Decks were removed.  They were a restriction, not a feature.
Existing deck names were converted into tags.</li>
<li>N+1 queries eliminated throughout the codebase.</li>
<li>Dashboard rendering is 3-4x faster via a custom <code>gnosis-tl</code> module.</li>
<li>Review dates stored as integers; due/overdue queries run in SQL.</li>
<li>Git operations are fully async.</li>
<li>Saving <code>.org.gpg</code> files no longer triggers redundant decryption.</li>
<li>Post-failure interval capped at 7 days.</li>
<li>Interval fuzz prevents review clustering.</li>
<li>Tag bulk operations: rename, regex rename, merge case duplicates.</li>
<li>Dropped emacsql for built-in sqlite.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Gnosis: Design Mistakes</title>
      <link>https://thanosapollo.org/posts/gnosis-packages-merge/</link>
      <pubDate>Sun, 08 Mar 2026 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/gnosis-packages-merge/</guid>
      <description>&lt;p&gt;The more I use gnosis, the more I notice design faults inherited from
the software I was previously using.&lt;/p&gt;
&lt;h2 id=&#34;using-decks-for-themata--flashcards-questions&#34;&gt;Using decks for themata (flashcards/questions)&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Decks will be removed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Similarly to Anki, decks provided a restriction, not a feature.  A
thema can only belong to one deck, &lt;em&gt;many-to-one&lt;/em&gt;, while tags are
&lt;em&gt;many-to-many&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Themata in gnosis are already organized based on &lt;code&gt;tags&lt;/code&gt; and you can
customize the review algorithm per tag using
&lt;code&gt;gnosis-algorithm-custom-values&lt;/code&gt;.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>The more I use gnosis, the more I notice design faults inherited from
the software I was previously using.</p>
<h2 id="using-decks-for-themata--flashcards-questions">Using decks for themata (flashcards/questions)</h2>
<blockquote>
<p>Decks will be removed.</p>
</blockquote>
<p>Similarly to Anki, decks provided a restriction, not a feature.  A
thema can only belong to one deck, <em>many-to-one</em>, while tags are
<em>many-to-many</em>.</p>
<p>Themata in gnosis are already organized based on <code>tags</code> and you can
customize the review algorithm per tag using
<code>gnosis-algorithm-custom-values</code>.</p>
<p>Exports for &ldquo;collections&rdquo; will now be based on tags.  I plan to add
tag filters for exports, e.g <code>+anatomy -clinical</code> to export all
themata tagged with anatomy, excluding clinical.</p>
<h2 id="separating-gnosis-from-org-gnosis-and-org-gnosis-ui">Separating gnosis from org-gnosis and org-gnosis-ui</h2>
<blockquote>
<p><code>org-gnosis</code> will be merged into <code>gnosis</code>, using a single unified
database.</p>
</blockquote>
<p>The idea was to have a minimal note taking system with a separate ui
package that uses the browser, recreating the workflow I had with
org-roam but with support for linking themata to nodes for
topic-specific reviews.</p>
<p>In hindsight, this separation was a design mistake:</p>
<ul>
<li>Using <code>org-gnosis</code> without <code>gnosis</code> has no real benefits.</li>
<li>A separate <code>org-gnosis-ui</code> that recreates an obsidian-style graph
in the browser provides no real benefit beyond &ldquo;visualizing&rdquo; the
collection.
<ul>
<li>Using <code>tabulated-list</code> in emacs to display nodes, their
backlinks/links and their linked themata provides actual workflow
usage.  You can start reviews for specific nodes from the
dashboard, filter for contents and view relations, all within
emacs.</li>
</ul>
</li>
<li>Maintaining two separate databases for no real value.</li>
</ul>
<h2 id="review-by-topic-algorithm">Review by topic algorithm</h2>
<p>Gnosis supports reviewing all themata linked to a specific node, which
means themata are often reviewed before they are due.  The interval
calculation now uses elapsed time as the basis, but on success keeps
the later of the computed/existing scheduled date.  The thema&rsquo;s score
and review streak are still updated, so early reviews contribute to
progression without distorting the schedule.</p>
<p>This ensures that early successful reviews cannot inflate <em>or</em> deflate
intervals.  On failure the computed interval is used directly since
early failure is genuinely informative.</p>
<h2 id="new-feature-exporting-themata-with-their-linked-nodes">[New Feature] Exporting themata with their linked nodes</h2>
<p>Gnosis exports will optionally include all the linked nodes for the
exported themata.  This means that current collections, like <a href="https://codeberg.org/thanosapollo/gnosis-unking">Unking</a>,
will provide ready-to-use collections where users can both review
themata and browse the related material.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Gnosis 0.8.0 Release Notes</title>
      <link>https://thanosapollo.org/posts/gnosis-version-0-8-0/</link>
      <pubDate>Thu, 05 Mar 2026 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/gnosis-version-0-8-0/</guid>
      <description>Gnosis 0.8.0 Release Overview</description>
      <content:encoded><![CDATA[<p>I&rsquo;m excited to announce the release of version 0.8.0 for <a href="/projects/gnosis/">gnosis</a>.</p>
<p>Finally this project is now evolving into the <em>&ldquo;all-in-one&rdquo;</em> knowledge
system I&rsquo;ve envisioned.  This version allows for viewing of linked
nodes of <code>org-gnosis</code> and their linked themata in a tabulated-list via
the <code>gnosis-dashboard</code> with excellent performance.</p>
<p>No more external browsers needed to view my collection.  This means
the <code>org-gnosis-ui</code> project should be considered deprecated.  All
functionalities can now be performed within Emacs.</p>
<p>Additionally, I&rsquo;ve published a <code>gnosis-deck</code> specifically designed for
fellow medical students, called <a href="https://codeberg.org/thanosapollo/gnosis-unking">Unking</a>, based on the <strong>last free
version</strong> of the <a href="https://www.ankihub.net/step-deck">Anking deck</a>, Anking V11.  This deck is quite
comprehensive, featuring over 40,000 themata.</p>
<p>As Gnosis already fulfills my original intentions and beyond, further
development will primarily be focused on bug fixes and general
maintenance rather than new major features.  My priority will now
shift towards using the system for my exams rather than continuing
active development.</p>
<p>It has been really fun and rewarding working on this project.  My goal
for learning to program has been to make a knowledge system and to not
rely on any 3rd parties for my studying.</p>
<p>Which I&rsquo;ve finally achieved:) This wouldn&rsquo;t be possible without all
the work that many of you have put into the Emacs ecosystem, so I just
want to I extend my heartfelt gratitude to all of you, thank you!</p>
<h2 id="new-features">New features</h2>
<ul>
<li>Auto input-method detection: gnosis detects the script of the
expected answer (Greek, Cyrillic, etc.) and activates the
appropriate input method during review.
Configured via <code>gnosis-script-input-method-alist</code>.</li>
<li>Change thema type and deck via <code>gnosis-update-thema</code>.</li>
<li>Dashboard bulk-link action for currently displayed themata.</li>
<li>Dashboard header-line with entry count and context.</li>
<li>Asynchronous deck import with <code>gnosis-import-deck-async</code>.</li>
<li>Demo deck included in <code>decks/demo.org</code>.</li>
</ul>
<h2 id="performance">Performance</h2>
<ul>
<li>New <code>gnosis-tl</code> module replaces <code>tabulated-list-print</code> for
dashboard rendering (3-4x faster).</li>
<li>Progressive async rendering for large dashboards.</li>
<li>Batch-fetch review data instead of per-thema queries.</li>
</ul>
<h2 id="bug-fixes">Bug fixes</h2>
<ul>
<li>Fix anagnosis event calculation in the algorithm.</li>
<li>Fix cloze tag removal for edge cases and mc-cloze type.</li>
<li>Fix <code>vc-pull</code> to run migrations after pull.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Gnosis 0.7.0 Release Notes</title>
      <link>https://thanosapollo.org/posts/gnosis-version-0-7-0/</link>
      <pubDate>Sun, 22 Feb 2026 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/gnosis-version-0-7-0/</guid>
      <description>&lt;p&gt;I&amp;rsquo;ve finally published Gnosis version &lt;code&gt;0.7.0&lt;/code&gt; that brings some much
needed changes and integration with &lt;a href=&#34;https://thanosapollo.org/projects/gnosis/&#34;&gt;org-gnosis&lt;/a&gt;.  You can get the
latest version of gnosis via &lt;a href=&#34;https://elpa.gnu.org/packages/gnosis.html&#34;&gt;GNU ELPA&lt;/a&gt; or directly from &lt;a href=&#34;https://git.thanosapollo.org/gnosis/&#34;&gt;upstream&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;new-features&#34;&gt;New features&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Review topic from dashboard nodes view (&lt;code&gt;r&lt;/code&gt;), with configurable
forward-link and backlink depth (&lt;code&gt;R&lt;/code&gt; or &lt;code&gt;C-u r&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gnosis-review-topic&lt;/code&gt; accepts separate forward/backlink depth to
include themata from related nodes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gnosis-save-hook&lt;/code&gt; runs after saving a thema, called with the
thema ID.&lt;/li&gt;
&lt;li&gt;Link integrity detection and repair commands
(&lt;code&gt;gnosis-links-check&lt;/code&gt;, &lt;code&gt;gnosis-links-sync&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Dashboard maintenance menu for syncing/rebuilding nodes and link
health checks.&lt;/li&gt;
&lt;li&gt;Dashboard shows themata with orphaned links.&lt;/li&gt;
&lt;li&gt;View due org-gnosis nodes linked to themata from dashboard.&lt;/li&gt;
&lt;li&gt;Bulk replace string in keimenon with org-gnosis node link.&lt;/li&gt;
&lt;li&gt;Custom &lt;code&gt;gnosis-center-content-during-review&lt;/code&gt; option.&lt;/li&gt;
&lt;li&gt;Delete action available during review.&lt;/li&gt;
&lt;li&gt;Format org-gnosis links in keimenon during review output.&lt;/li&gt;
&lt;li&gt;Export deck option to include or exclude suspended themata.&lt;/li&gt;
&lt;li&gt;Exported decks include a &lt;code&gt;#+THEMATA:&lt;/code&gt; header with thema count.&lt;/li&gt;
&lt;li&gt;Importing into an existing deck prompts for confirmation.&lt;/li&gt;
&lt;li&gt;Failed thema imports report the source file line number.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;dashboard&#34;&gt;Dashboard&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Added nodes dashboard, view org-gnosis nodes information including
backlinks and linked themata as well as start a review session.&lt;/li&gt;
&lt;li&gt;Suspend column displays &lt;code&gt;Yes&lt;/code&gt; &lt;code&gt;No&lt;/code&gt; instead of &lt;code&gt;1&lt;/code&gt; &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Flatten Actions submenu into the home menu.&lt;/li&gt;
&lt;li&gt;Separate Import/Export into its own menu column.&lt;/li&gt;
&lt;li&gt;Four-column layout: Navigate, Actions, Import/Export, Maintenance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;algorithm&#34;&gt;Algorithm&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Cap gnosis-synolon at &lt;code&gt;gnosis-algorithm-synolon-max&lt;/code&gt; (default 3.0),
floor at 1.3.&lt;/li&gt;
&lt;li&gt;Add interval fuzz to prevent review clustering.&lt;/li&gt;
&lt;li&gt;Fix lethe event: properly reduce gnosis-plus on consecutive failures.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;performance&#34;&gt;Performance&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Dashboard suspend, delete, and edit update only the affected entry
instead of refreshing the entire buffer.&lt;/li&gt;
&lt;li&gt;Dashboard nodes view uses bulk queries for link counts (2 queries
instead of 2N).&lt;/li&gt;
&lt;li&gt;Deck export uses 2 bulk queries instead of 2 per thema (N+1 eliminated).&lt;/li&gt;
&lt;li&gt;Deck export uses plain text insertion instead of per-thema buffer scans (O(n^2) eliminated).&lt;/li&gt;
&lt;li&gt;Deck import wraps all operations in a single transaction with
pre-cached IDs (10K fsyncs reduced to 1).&lt;/li&gt;
&lt;li&gt;Review updates use a single DB query.&lt;/li&gt;
&lt;li&gt;Tag output uses a single DB call.&lt;/li&gt;
&lt;li&gt;Average daily reviews computed with a single DB call.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;bug-fixes&#34;&gt;Bug fixes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Fix &lt;code&gt;gnosis-monkeytype&lt;/code&gt; hook leak (now buffer-local).&lt;/li&gt;
&lt;li&gt;Fix &lt;code&gt;vc-pull&lt;/code&gt; to reopen database properly after successful pull.&lt;/li&gt;
&lt;li&gt;Pre-load &lt;code&gt;emacsql-sqlite-builtin&lt;/code&gt; to fix &lt;code&gt;cl-generic&lt;/code&gt; dispatch crash
on Emacs 29+.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;documentation&#34;&gt;Documentation&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Update Introduction to describe the intended workflow with &lt;code&gt;org-gnosis&lt;/code&gt;
(write notes, create themata, link, review).&lt;/li&gt;
&lt;li&gt;Document the two separate databases (gnosis and org-gnosis).&lt;/li&gt;
&lt;li&gt;Update dashboard section for new menu layout.&lt;/li&gt;
&lt;li&gt;Add Import &amp;amp; Export section with export options and import behavior.&lt;/li&gt;
&lt;/ul&gt;</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve finally published Gnosis version <code>0.7.0</code> that brings some much
needed changes and integration with <a href="/projects/gnosis/">org-gnosis</a>.  You can get the
latest version of gnosis via <a href="https://elpa.gnu.org/packages/gnosis.html">GNU ELPA</a> or directly from <a href="https://git.thanosapollo.org/gnosis/">upstream</a>.</p>
<h2 id="new-features">New features</h2>
<ul>
<li>Review topic from dashboard nodes view (<code>r</code>), with configurable
forward-link and backlink depth (<code>R</code> or <code>C-u r</code>).</li>
<li><code>gnosis-review-topic</code> accepts separate forward/backlink depth to
include themata from related nodes.</li>
<li><code>gnosis-save-hook</code> runs after saving a thema, called with the
thema ID.</li>
<li>Link integrity detection and repair commands
(<code>gnosis-links-check</code>, <code>gnosis-links-sync</code>).</li>
<li>Dashboard maintenance menu for syncing/rebuilding nodes and link
health checks.</li>
<li>Dashboard shows themata with orphaned links.</li>
<li>View due org-gnosis nodes linked to themata from dashboard.</li>
<li>Bulk replace string in keimenon with org-gnosis node link.</li>
<li>Custom <code>gnosis-center-content-during-review</code> option.</li>
<li>Delete action available during review.</li>
<li>Format org-gnosis links in keimenon during review output.</li>
<li>Export deck option to include or exclude suspended themata.</li>
<li>Exported decks include a <code>#+THEMATA:</code> header with thema count.</li>
<li>Importing into an existing deck prompts for confirmation.</li>
<li>Failed thema imports report the source file line number.</li>
</ul>
<h2 id="dashboard">Dashboard</h2>
<ul>
<li>Added nodes dashboard, view org-gnosis nodes information including
backlinks and linked themata as well as start a review session.</li>
<li>Suspend column displays <code>Yes</code> <code>No</code> instead of <code>1</code> <code>0</code>.</li>
<li>Flatten Actions submenu into the home menu.</li>
<li>Separate Import/Export into its own menu column.</li>
<li>Four-column layout: Navigate, Actions, Import/Export, Maintenance.</li>
</ul>
<h2 id="algorithm">Algorithm</h2>
<ul>
<li>Cap gnosis-synolon at <code>gnosis-algorithm-synolon-max</code> (default 3.0),
floor at 1.3.</li>
<li>Add interval fuzz to prevent review clustering.</li>
<li>Fix lethe event: properly reduce gnosis-plus on consecutive failures.</li>
</ul>
<h2 id="performance">Performance</h2>
<ul>
<li>Dashboard suspend, delete, and edit update only the affected entry
instead of refreshing the entire buffer.</li>
<li>Dashboard nodes view uses bulk queries for link counts (2 queries
instead of 2N).</li>
<li>Deck export uses 2 bulk queries instead of 2 per thema (N+1 eliminated).</li>
<li>Deck export uses plain text insertion instead of per-thema buffer scans (O(n^2) eliminated).</li>
<li>Deck import wraps all operations in a single transaction with
pre-cached IDs (10K fsyncs reduced to 1).</li>
<li>Review updates use a single DB query.</li>
<li>Tag output uses a single DB call.</li>
<li>Average daily reviews computed with a single DB call.</li>
</ul>
<h2 id="bug-fixes">Bug fixes</h2>
<ul>
<li>Fix <code>gnosis-monkeytype</code> hook leak (now buffer-local).</li>
<li>Fix <code>vc-pull</code> to reopen database properly after successful pull.</li>
<li>Pre-load <code>emacsql-sqlite-builtin</code> to fix <code>cl-generic</code> dispatch crash
on Emacs 29+.</li>
</ul>
<h2 id="documentation">Documentation</h2>
<ul>
<li>Update Introduction to describe the intended workflow with <code>org-gnosis</code>
(write notes, create themata, link, review).</li>
<li>Document the two separate databases (gnosis and org-gnosis).</li>
<li>Update dashboard section for new menu layout.</li>
<li>Add Import &amp; Export section with export options and import behavior.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Org Gnosis 0.2.0 Release Notes</title>
      <link>https://thanosapollo.org/posts/org-gnosis-version-0.2.0/</link>
      <pubDate>Sun, 22 Feb 2026 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/org-gnosis-version-0.2.0/</guid>
      <description>&lt;p&gt;I just pushed a new version for &lt;a href=&#34;https://thanosapollo.org/projects/gnosis/&#34;&gt;org-gnosis&lt;/a&gt;, the note taking module of
&lt;a href=&#34;https://thanosapollo.org/projects/gnosis/&#34;&gt;gnosis&lt;/a&gt;, which you can find &lt;a href=&#34;https://git.thanosapollo.org/org-gnosis/&#34;&gt;here&lt;/a&gt;.  The update should be available to
all users via &lt;a href=&#34;https://elpa.gnu.org/packages/org-gnosis.html&#34;&gt;GNU ELPA&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;important-changes&#34;&gt;Important Changes&lt;/h2&gt;
&lt;h3 id=&#34;database-changes&#34;&gt;Database Changes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Database version bumped to 3, tracking &lt;code&gt;mtime&lt;/code&gt; and &lt;code&gt;hash&lt;/code&gt; for both
nodes and journal files.&lt;/li&gt;
&lt;li&gt;Automatic database migration prompts when schema is outdated.&lt;/li&gt;
&lt;li&gt;Lazy database initialization - database connections are created only
when needed, improving startup time.&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;org-gnosis-database-file&lt;/code&gt; custom variable to specify custom
database file location.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;performance-improvements&#34;&gt;Performance Improvements&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Major performance improvements for &lt;code&gt;org-gnosis-db-sync&lt;/code&gt; with GC
optimization during sync.&lt;/li&gt;
&lt;li&gt;Two-tier incremental sync: fast &lt;code&gt;mtime&lt;/code&gt; check, then accurate &lt;code&gt;hash&lt;/code&gt;
comparison.
&lt;ul&gt;
&lt;li&gt;Only processes files where both modification time and content have
changed.&lt;/li&gt;
&lt;li&gt;Dramatically improves performance for .gpg encrypted files and
large repositories.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Both node files and journal files now use incremental sync with
progress reporting showing changed/total file counts.&lt;/li&gt;
&lt;li&gt;To force full resync, call &lt;code&gt;org-gnosis-db-sync&lt;/code&gt; with prefix arg
&lt;code&gt;C-u&lt;/code&gt;. e.g &lt;code&gt;C-u M-x org-gnosis-db-sync RET&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;journaling&#34;&gt;Journaling&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;By default, today&amp;rsquo;s journal entries are created in
&lt;code&gt;org-gnosis-journal-file&lt;/code&gt; as level 1 headings.
&lt;ul&gt;
&lt;li&gt;When set to &lt;code&gt;nil&lt;/code&gt;, creates separate files for each date entry.&lt;/li&gt;
&lt;li&gt;Creating new entries (e.g., via &lt;code&gt;org-gnosis-journal-find&lt;/code&gt; for an
event, non-date) creates separate files in &lt;code&gt;org-gnosis-journal-dir&lt;/code&gt;
regardless of this setting.&lt;/li&gt;
&lt;li&gt;Single journal file is only used for today&amp;rsquo;s date entries.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;org-gnosis-journal-as-gpg&lt;/code&gt; that when non-nil journal files
will be created as &lt;code&gt;gpg&lt;/code&gt; encrypted files.&lt;/li&gt;
&lt;li&gt;Journal todos now only retrieve checkboxes from today&amp;rsquo;s heading when
using a single journal file, improving performance.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;tag-management&#34;&gt;Tag Management&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Automatic cleanup of orphaned tags (tags with no associated nodes)
when updating files.&lt;/li&gt;
&lt;li&gt;Improved tag-based node selection with dedicated functions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;improvements&#34;&gt;Improvements&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Simplified parsing algorithm for better performance and
maintainability.&lt;/li&gt;
&lt;li&gt;Better handling of topic titles - only includes parent headings when
they have IDs.&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;org-gnosis-get-nodes-data&lt;/code&gt; for retrieving node information
with backlink counts.&lt;/li&gt;
&lt;li&gt;Improved test coverage for parsing, title processing, and journal
todos.&lt;/li&gt;
&lt;/ul&gt;</description>
      <content:encoded><![CDATA[<p>I just pushed a new version for <a href="/projects/gnosis/">org-gnosis</a>, the note taking module of
<a href="/projects/gnosis/">gnosis</a>, which you can find <a href="https://git.thanosapollo.org/org-gnosis/">here</a>.  The update should be available to
all users via <a href="https://elpa.gnu.org/packages/org-gnosis.html">GNU ELPA</a>.</p>
<h2 id="important-changes">Important Changes</h2>
<h3 id="database-changes">Database Changes</h3>
<ul>
<li>Database version bumped to 3, tracking <code>mtime</code> and <code>hash</code> for both
nodes and journal files.</li>
<li>Automatic database migration prompts when schema is outdated.</li>
<li>Lazy database initialization - database connections are created only
when needed, improving startup time.</li>
<li>Added <code>org-gnosis-database-file</code> custom variable to specify custom
database file location.</li>
</ul>
<h3 id="performance-improvements">Performance Improvements</h3>
<ul>
<li>Major performance improvements for <code>org-gnosis-db-sync</code> with GC
optimization during sync.</li>
<li>Two-tier incremental sync: fast <code>mtime</code> check, then accurate <code>hash</code>
comparison.
<ul>
<li>Only processes files where both modification time and content have
changed.</li>
<li>Dramatically improves performance for .gpg encrypted files and
large repositories.</li>
</ul>
</li>
<li>Both node files and journal files now use incremental sync with
progress reporting showing changed/total file counts.</li>
<li>To force full resync, call <code>org-gnosis-db-sync</code> with prefix arg
<code>C-u</code>. e.g <code>C-u M-x org-gnosis-db-sync RET</code>.</li>
</ul>
<h3 id="journaling">Journaling</h3>
<ul>
<li>By default, today&rsquo;s journal entries are created in
<code>org-gnosis-journal-file</code> as level 1 headings.
<ul>
<li>When set to <code>nil</code>, creates separate files for each date entry.</li>
<li>Creating new entries (e.g., via <code>org-gnosis-journal-find</code> for an
event, non-date) creates separate files in <code>org-gnosis-journal-dir</code>
regardless of this setting.</li>
<li>Single journal file is only used for today&rsquo;s date entries.</li>
</ul>
</li>
<li>Added <code>org-gnosis-journal-as-gpg</code> that when non-nil journal files
will be created as <code>gpg</code> encrypted files.</li>
<li>Journal todos now only retrieve checkboxes from today&rsquo;s heading when
using a single journal file, improving performance.</li>
</ul>
<h3 id="tag-management">Tag Management</h3>
<ul>
<li>Automatic cleanup of orphaned tags (tags with no associated nodes)
when updating files.</li>
<li>Improved tag-based node selection with dedicated functions.</li>
</ul>
<h2 id="improvements">Improvements</h2>
<ul>
<li>Simplified parsing algorithm for better performance and
maintainability.</li>
<li>Better handling of topic titles - only includes parent headings when
they have IDs.</li>
<li>Added <code>org-gnosis-get-nodes-data</code> for retrieving node information
with backlink counts.</li>
<li>Improved test coverage for parsing, title processing, and journal
todos.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>(Video) Contributing to Git Projects with Magit: PRs, Patches &amp; Agit workflow</title>
      <link>https://thanosapollo.org/posts/video-contributing-with-git-guide/</link>
      <pubDate>Fri, 06 Feb 2026 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/video-contributing-with-git-guide/</guid>
      <description>&lt;center&gt;
&lt;p&gt;&lt;i&gt;Contributing to Git Projects with Magit: PRs, Patches &amp; Agit workflow&lt;/i&gt;&lt;p&gt;
&lt;iframe width=&#34;560&#34; height=&#34;315&#34; src=&#34;https://www.youtube.com/embed/qSHw7D_88-0?si=v248FB_QuJLrabyu&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/center&gt;
&lt;p&gt;Quick video guide on contributing to git projects using Magit.
Showing an overview of the 3 most commonly used workflows&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Pull Requests&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Agit Workflow&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Git patches&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Video notes:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;I&amp;rsquo;m creating this as a tutorial video on how to contribute to
&lt;a href=&#34;https://codeberg.org/bebliotheca/bebliotheca&#34;&gt;bebliotheca&lt;/a&gt;, a &lt;em&gt;digital recreation&lt;/em&gt; of the Library of Constantinople to
host texts that would have been found there during the Greco-Roman
Empire.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<center>
<p><i>Contributing to Git Projects with Magit: PRs, Patches & Agit workflow</i><p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/qSHw7D_88-0?si=v248FB_QuJLrabyu" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</center>
<p>Quick video guide on contributing to git projects using Magit.
Showing an overview of the 3 most commonly used workflows</p>
<ul>
<li>
<p>Pull Requests</p>
</li>
<li>
<p>Agit Workflow</p>
</li>
<li>
<p>Git patches</p>
<blockquote>
<p>Video notes:</p>
</blockquote>
</li>
</ul>
<h2 id="introduction">Introduction</h2>
<blockquote>
<p>I&rsquo;m creating this as a tutorial video on how to contribute to
<a href="https://codeberg.org/bebliotheca/bebliotheca">bebliotheca</a>, a <em>digital recreation</em> of the Library of Constantinople to
host texts that would have been found there during the Greco-Roman
Empire.</p>
<p>The steps demonstrated here are applicable to any project.</p>
</blockquote>
<p>This is a video guide on contributing to git projects, using Emacs and
Magit (<em>the magical Git client</em>).  <code>Magit</code> provides the best
experience out of the box for a text based interface to git, which
makes <code>magit</code> an emacs&rsquo; killer feature.</p>
<p>In this video we will start from an example Emacs configuration,
adding a theme and installing Magit.  Afterwards we will see how to
contribute to git projects in 3 ways:</p>
<ul>
<li>Pull Requests</li>
<li><a href="https://forgejo.org/docs/latest/user/agit-support/">Agit Workflow Pull Requests</a>
<ul>
<li>Supported in forgejo instances, such as <code>codeberg</code></li>
</ul>
</li>
<li>Git Patches</li>
</ul>
<blockquote>
<p>I personally use <code>vc</code>, a built-in module.  But that&rsquo;s because I enjoy
tinkering and writing my own scripts for it.  Magit does by default a
lot more that even my ~300 line vc config can do.</p>
</blockquote>
<h2 id="requirements">Requirements</h2>
<p>You will need the following software installed:</p>
<ul>
<li><a href="https://git-scm.com/">git</a></li>
<li><a href="https://www.gnu.org/software/emacs/download.html">GNU Emacs</a> <em>(version &gt;=29.2)</em></li>
</ul>
<p><em>Additionally</em>, ensure you have a pair of <strong>SSH keys</strong> already generated and
set up for your forge.</p>
<h2 id="emacs-configuration-i-will-be-using">Emacs Configuration I will be using</h2>
<p>Example <code>init.el</code> file that I will be using:</p>
<ul>
<li>Defaults locations for <code>init.el</code>, depending on your system:
<ul>
<li>GNU/Linux: <code>~/.emacs.d/init.el</code></li>
<li>Windows: <code>C:\Users\&lt;YourUsername&gt;\.emacs.d\init.el</code></li>
</ul>
</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; Init packages</span>
</span></span><span style="display:flex;"><span>(package-initialize)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;;;; Do not install keycast as well, I&#39;m only using it to share my</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;;;; keystrokes for the video.</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; (use-package keycast</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;;  :ensure t)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; Set and load custom.el</span>
</span></span><span style="display:flex;"><span>(setf custom-file (locate-user-emacs-file <span style="color:#e6db74">&#34;custom.el&#34;</span>))
</span></span><span style="display:flex;"><span>(<span style="color:#a6e22e">load</span> custom-file <span style="color:#e6db74">&#39;noerror</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; Completions</span>
</span></span><span style="display:flex;"><span>(fido-vertical-mode <span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>(electric-pair-mode <span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;;; Theming ;;;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(column-number-mode)
</span></span><span style="display:flex;"><span>(global-display-line-numbers-mode <span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>(tool-bar-mode <span style="color:#ae81ff">-1</span>)
</span></span><span style="display:flex;"><span>(tooltip-mode <span style="color:#ae81ff">-1</span>)
</span></span><span style="display:flex;"><span>(menu-bar-mode <span style="color:#ae81ff">-1</span>)
</span></span><span style="display:flex;"><span>(blink-cursor-mode <span style="color:#ae81ff">-1</span>)
</span></span><span style="display:flex;"><span>(scroll-bar-mode <span style="color:#ae81ff">-1</span>)
</span></span><span style="display:flex;"><span>(set-fringe-mode <span style="color:#ae81ff">-1</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; Add transparency</span>
</span></span><span style="display:flex;"><span>(add-to-list <span style="color:#e6db74">&#39;default-frame-alist</span> <span style="color:#f92672">&#39;</span>(alpha-background <span style="color:#f92672">.</span> <span style="color:#ae81ff">85</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; ef-themes package provides a great theme collection, made by Protesilaos.</span>
</span></span><span style="display:flex;"><span>(use-package ef-themes
</span></span><span style="display:flex;"><span>  :ensure <span style="color:#66d9ef">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(defun thanos/load-theme (<span style="color:#66d9ef">&amp;optional</span> theme)
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;Disable current theme and load a new THEME.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Emacs can load multiple themes at once.  With this function we make sure we only load one at a time&#34;</span>
</span></span><span style="display:flex;"><span>  (interactive)
</span></span><span style="display:flex;"><span>  (let ((theme (or theme (<span style="color:#a6e22e">intern</span> (<span style="color:#a6e22e">completing-read</span> <span style="color:#e6db74">&#34;Theme: &#34;</span> (custom-available-themes))))))
</span></span><span style="display:flex;"><span>    (disable-theme (<span style="color:#a6e22e">car</span> custom-enabled-themes))
</span></span><span style="display:flex;"><span>    (load-theme theme <span style="color:#66d9ef">t</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(thanos/load-theme <span style="color:#e6db74">&#39;ef-dark</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(use-package magit
</span></span><span style="display:flex;"><span>  :bind (<span style="color:#e6db74">&#34;C-x g&#34;</span> <span style="color:#f92672">.</span> magit)
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Hook flyspell for autocorrect during commit messages.</span>
</span></span><span style="display:flex;"><span>  :hook (git-commit-mode <span style="color:#f92672">.</span> flyspell-mode))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; Agitjo extends Magit with a new menu for AGit-Flow operations.</span>
</span></span><span style="display:flex;"><span>(use-package agitjo
</span></span><span style="display:flex;"><span>  :vc (:url <span style="color:#e6db74">&#34;https://codeberg.org/halvin/agitjo&#34;</span>)
</span></span><span style="display:flex;"><span>  :ensure <span style="color:#66d9ef">t</span>)
</span></span></code></pre></div><h2 id="pull-requests">Pull Requests</h2>
<ul>
<li>Require an account creation for the forge the project is hosted at.
<em>e.g Github or Codeberg.</em></li>
<li><strong>Steps to submit a PR</strong>
<ul>
<li><strong>Fork</strong> repository, <em>through a Web UI.</em></li>
<li><strong>Clone</strong> your fork</li>
<li><strong>Commit</strong> changes, <em>often in a new branch.</em></li>
<li><strong>Push</strong> your changes to your fork</li>
<li><strong>Submit</strong> a Pull Request, <em>through a Web UI.</em></li>
</ul>
</li>
</ul>
<blockquote>
<p>If you&rsquo;d rather not use a Web UI, but have to use Pull Requests,
consider using <a href="https://github.com/magit/forge">forge</a>.</p>
</blockquote>
<h2 id="agit-workflow">Agit workflow</h2>
<blockquote>
<p>Note that the <strong>agit workflow</strong> is not supported by GitHub at the time
of making this video.  To use agit workflow, you will need to utilize
a forgejo instance such as Codeberg.</p>
</blockquote>
<ul>
<li>Clone repo, <em>using ssh</em></li>
<li>Commit changes</li>
<li>Push
<ul>
<li>From the Magit status buffer, press <code>#</code></li>
<li>Specify a title using <code>-t</code>
<ul>
<li>You can use the same title to push changes to the PR.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="git-patches">Git patches</h2>
<ul>
<li>Clone repo.</li>
<li>Commit changes.</li>
<li>Format patches.</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ git format-patch -<span style="color:#f92672">{</span>NUM<span style="color:#f92672">}</span> <span style="color:#75715e"># where NUM the number of commits.</span>
</span></span></code></pre></div><ul>
<li>Send patches as attachments via email, by pressing <code>C-x C-m</code>.</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>(Video) Emacs Notmuch with Multiple Addresses &amp; Auto Encryption</title>
      <link>https://thanosapollo.org/posts/emacs-notmuch-video-guide/</link>
      <pubDate>Thu, 18 Dec 2025 00:00:00 +0000</pubDate>
      <guid>https://thanosapollo.org/posts/emacs-notmuch-video-guide/</guid>
      <description>Video guide for managing emails with Emacs, using notmuch &amp;amp; isync.</description>
      <content:encoded><![CDATA[<p>This guide provides a quick setup for configuring Notmuch with GNU
Emacs to handle multiple email addresses and enable automatic
encryption.</p>
<p>Notmuch has been incredibly useful for me over the past year, and I
hope this guide helps new users overcome initial challenges.</p>
<center>
<p><i>Emacs Notmuch with Multiple Addresses & Auto Encryption</i><p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/P42C5wEQK-Y?si=wbDx5y3zH5Wd23gE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</center>
<blockquote>
<p>Video notes:</p>
</blockquote>
<h2 id="summary">Summary</h2>
<ul>
<li>Emacs email workflow demo using <code>notmuch.el</code>.
<ul>
<li>Sending mails from multiple addresses, using <a href="%5C%2Asmtpmail">smtpmail</a>.</li>
<li>Auto encrypt emails, if a pgp key is available, using <a href="%5C%2Amml-sec">mml-sec</a>.</li>
</ul>
</li>
</ul>
<h2 id="why-notmuch">Why notmuch</h2>
<ul>
<li>Builtin Emacs support, with <code>notmuch.el</code>.
<ul>
<li>Packages such as <a href="https://github.com/tarsius/ol-notmuch">ol-notmuch</a> bring integration with the rest of
the Emacs ecosystem.</li>
</ul>
</li>
<li>Notmuch is a <code>tag based system</code>.  You do not rely on your email
provider for filter rules etc to organize your emails into separate
mailboxes.
<ul>
<li>Which is inefficient to begin with when working with thousands++ of emails.</li>
<li>This also makes moving to a new email provider easier.</li>
</ul>
</li>
<li>Locally storing mail.</li>
<li>Great performance for filtering and searching through hundred of thousand mails.</li>
</ul>
<h2 id="assumptions-that-i-make-for-this-video">Assumptions that I make for this video</h2>
<h3 id="you-have-a-working-emacs-configuration">You have a working Emacs configuration</h3>
<h3 id="your-mail-providers-has-support-for-retrieving-and-sending-mail-via-3rd-party-apps">Your mail providers has support for retrieving and sending mail via 3rd party apps</h3>
<ul>
<li>You already know how to setup <code>isync/mbsync</code> to retrieve emails from remote server.</li>
<li>Your mail provider offers <code>smtp</code> credentials to use third party applications.
<ul>
<li>I personally recommend trying out <code>purelymail.com</code> <strong>only costs 10$/year and offers good service</strong>.</li>
</ul>
</li>
</ul>
<p><em>Example isyncrc configuration</em> <code>~/.config/isyncrc</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-cfg" data-lang="cfg"><span style="display:flex;"><span><span style="color:#a6e22e">IMAPAccount gmail</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Host imap.gmail.com</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Port 993</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">User user@gmail.com # Change this to your username.</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">PassCmd &#34;pass gmail/account&#34; # Change this to a command that returns your password.</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">TLSType IMAPS</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">TLSVersions +1.2</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">CertificateFile /etc/ssl/certs/ca-certificates.crt</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">IMAPStore gmail-remote</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Account gmail</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">MaildirStore gmail-local</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Path ~/Mail/gmail/</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Inbox ~/Mail/gmail/Inbox</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Trash ~/Mail/gmail/Trash</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">SubFolders Verbatim</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Channel gmail</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Far :gmail-remote:</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Near :gmail-local:</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Patterns *</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Expunge None</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">CopyArrivalDate yes</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Sync All</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Create Both</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">SyncState *</span>
</span></span></code></pre></div><p>After adjusting the above configuration, run <code>mbsync -a</code> to sync your remote mailbox locally.</p>
<h2 id="setting-up-a-notmuch">Setting up a notmuch</h2>
<h3 id="first-time-installation">First time installation</h3>
<ul>
<li>After installing notmuch for the first time, run <code>notmuch setup</code> for an interactive setup.</li>
</ul>
<h3 id="create-dot-scripts-notmuch-hook-dot-sh">Create <code>~/.scripts/notmuch-hook.sh</code></h3>
<ul>
<li>Bash script which will filter/tag your mail</li>
</ul>
<p>Example:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e">#!/bin/sh
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>notmuch new
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Add +inbox tag to a specific alias/address</span>
</span></span><span style="display:flex;"><span>notmuch tag +inbox -- to:main@address.org
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">#Sent messages, change this to your mail addresses</span>
</span></span><span style="display:flex;"><span>notmuch tag -unread -new -inbox +sent -- from:*@mydomain.org or from:*@mydomain.com or from:user@gmail.com
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Example for Emacs-devel</span>
</span></span><span style="display:flex;"><span>notmuch tag +emacs-devel -new -inbox -- from:emacs-devel@gnu.org or to:emacs-devel@gnu.org
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Example for Github</span>
</span></span><span style="display:flex;"><span>notmuch tag +github -- from:*github.com
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Filter based on other tags, such as drafts</span>
</span></span><span style="display:flex;"><span>notmuch tag -inbox -sent -inbox -- tag:draft
</span></span></code></pre></div><h2 id="emacs-configuration">Emacs configuration</h2>
<h3 id="notmuch">Notmuch</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package notmuch
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  (defun thanos/notmuch-update--command (new-buffer)
</span></span><span style="display:flex;"><span>    (let ((default-directory <span style="color:#e6db74">&#34;~/.scripts/&#34;</span>)) <span style="color:#75715e">;; Directory where notmuch script is located.</span>
</span></span><span style="display:flex;"><span>      (async-shell-command <span style="color:#e6db74">&#34;mbsync -a; ./notmuch-hook.sh&#34;</span> new-buffer)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun thanos/notmuch-update ()
</span></span><span style="display:flex;"><span>    (interactive)
</span></span><span style="display:flex;"><span>    (let* ((buffer (generate-new-buffer <span style="color:#e6db74">&#34;*notmuch update*&#34;</span>))
</span></span><span style="display:flex;"><span>           (height (<span style="color:#a6e22e">max</span> <span style="color:#ae81ff">5</span> (<span style="color:#a6e22e">truncate</span> (<span style="color:#a6e22e">*</span> (frame-height) <span style="color:#ae81ff">0.1</span>))))
</span></span><span style="display:flex;"><span>           (window (split-window-vertically (<span style="color:#a6e22e">-</span> height))))
</span></span><span style="display:flex;"><span>      (with-selected-window window
</span></span><span style="display:flex;"><span>        (switch-to-buffer buffer)
</span></span><span style="display:flex;"><span>        (let ((proc (thanos/notmuch-update--command buffer)))
</span></span><span style="display:flex;"><span>          (<span style="color:#a6e22e">set-process-sentinel</span>
</span></span><span style="display:flex;"><span>           (<span style="color:#a6e22e">get-buffer-process</span> buffer)
</span></span><span style="display:flex;"><span>           (lambda (process event)
</span></span><span style="display:flex;"><span>             (when (<span style="color:#a6e22e">memq</span> (<span style="color:#a6e22e">process-status</span> process) <span style="color:#f92672">&#39;</span>(exit <span style="color:#a6e22e">signal</span>))
</span></span><span style="display:flex;"><span>               (delete-window (<span style="color:#a6e22e">get-buffer-window</span> (<span style="color:#a6e22e">process-buffer</span> process)))
</span></span><span style="display:flex;"><span>               (<span style="color:#a6e22e">kill-buffer</span> (<span style="color:#a6e22e">process-buffer</span> process)))))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun thanos/notmuch-search ()
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Custom notmuch-search wrapper, that makes sure we have newest mail first.&#34;</span>
</span></span><span style="display:flex;"><span>    (interactive)
</span></span><span style="display:flex;"><span>    (let ((query (notmuch-read-query <span style="color:#e6db74">&#34;Notmuch search: &#34;</span>)))
</span></span><span style="display:flex;"><span>      (notmuch-search query <span style="color:#66d9ef">nil</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Configure saved searches to your liking, here&#39;s an example:</span>
</span></span><span style="display:flex;"><span>  (setf notmuch-saved-searches
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">`</span>((:name <span style="color:#e6db74">&#34;Week&#39;s Inbox&#34;</span> :query <span style="color:#e6db74">&#34;tag:inbox date:7d..today&#34;</span> :sort-order newest-first
</span></span><span style="display:flex;"><span>                 :key <span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">&#34;i&#34;</span>))
</span></span><span style="display:flex;"><span>          (:name <span style="color:#e6db74">&#34;Inbox&#34;</span> :query <span style="color:#e6db74">&#34;tag:inbox&#34;</span> :sort-order newest-first :key <span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">&#34;I&#34;</span>))
</span></span><span style="display:flex;"><span>          (:name <span style="color:#e6db74">&#34;Unread&#34;</span> :query <span style="color:#e6db74">&#34;tag:unread&#34;</span> :sort-order newest-first :key <span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">&#34;u&#34;</span>))
</span></span><span style="display:flex;"><span>          (:name <span style="color:#e6db74">&#34;Today&#39;s message&#34;</span> :query <span style="color:#e6db74">&#34;tag:inbox date:today&#34;</span>
</span></span><span style="display:flex;"><span>                 :sort-order newest-first :key <span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">&#34;t&#34;</span>))
</span></span><span style="display:flex;"><span>          (:name <span style="color:#e6db74">&#34;sent&#34;</span> :query <span style="color:#e6db74">&#34;tag:sent&#34;</span> :sort-order newest-first :key <span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">&#34;s&#34;</span>))
</span></span><span style="display:flex;"><span>          (:name <span style="color:#e6db74">&#34;drafts&#34;</span> :query <span style="color:#e6db74">&#34;tag:draft&#34;</span> :sort-order newest-first :key <span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">&#34;d&#34;</span>))
</span></span><span style="display:flex;"><span>          (:name <span style="color:#e6db74">&#34;all mail&#34;</span> :query <span style="color:#e6db74">&#34;*&#34;</span> :sort-order oldest-first :key <span style="color:#f92672">,</span>(kbd <span style="color:#e6db74">&#34;a&#34;</span>))))
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Tag format configuration</span>
</span></span><span style="display:flex;"><span>  (setf notmuch-tag-formats
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;unread&#34;</span> (<span style="color:#a6e22e">propertize</span> tag <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;notmuch-tag-unread</span>))))
</span></span><span style="display:flex;"><span>  :bind ((<span style="color:#e6db74">&#34;C-x m&#34;</span> <span style="color:#f92672">.</span> notmuch-hello)
</span></span><span style="display:flex;"><span>         :map notmuch-hello-mode-map
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;u&#34;</span> <span style="color:#f92672">.</span> notmuch-hello-update)
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;U&#34;</span> <span style="color:#f92672">.</span> thanos/notmuch-update)
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;s&#34;</span> <span style="color:#f92672">.</span> thanos/notmuch-search)
</span></span><span style="display:flex;"><span>         :map notmuch-search-mode-map
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;u&#34;</span> <span style="color:#f92672">.</span> notmuch-refresh-all-buffers)))
</span></span></code></pre></div><h3 id="smtpmail">smtpmail</h3>
<ul>
<li>This configuration is used to send email from multiple addresses,
make sure you have your authentication password saved in
<code>~/.authinfo.gpg</code> which emacs is going to use by default.</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package smtpmail
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Default credentials</span>
</span></span><span style="display:flex;"><span>  (setf smtpmail-smtp-user (auth-source-pass-get <span style="color:#e6db74">&#34;user&#34;</span> <span style="color:#e6db74">&#34;gmail/user&#34;</span>) <span style="color:#75715e">;; This is not your password, just the username.  Emacs will search for your pw in ~/.authinfo.gpg.</span>
</span></span><span style="display:flex;"><span>        smtpmail-smtp-server <span style="color:#e6db74">&#34;smtp.gmail.com&#34;</span>
</span></span><span style="display:flex;"><span>        smtpmail-smtp-service <span style="color:#ae81ff">465</span> <span style="color:#75715e">;; Adjust this to your mail provider port if needed</span>
</span></span><span style="display:flex;"><span>        smtpmail-stream-type <span style="color:#e6db74">&#39;ssl</span>
</span></span><span style="display:flex;"><span>        message-send-mail-function <span style="color:#e6db74">&#39;smtpmail-send-it</span>
</span></span><span style="display:flex;"><span>        message-signature <span style="color:#e6db74">&#34;My signature&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun thanos/mail-config-hook ()
</span></span><span style="display:flex;"><span>    (let ((from (mail-fetch-field <span style="color:#e6db74">&#34;From&#34;</span>))
</span></span><span style="display:flex;"><span>          (public <span style="color:#e6db74">&#34;&lt;public@thanosapollo.org&gt;&#34;</span>)
</span></span><span style="display:flex;"><span>          (gmail <span style="color:#e6db74">&#34;&lt;104111@students.mu-sofia.bg&gt;&#34;</span>))
</span></span><span style="display:flex;"><span>      (cond ((<span style="color:#a6e22e">string-match</span> public from)
</span></span><span style="display:flex;"><span>             (setf smtpmail-smtp-user (auth-source-pass-get <span style="color:#e6db74">&#34;user&#34;</span> <span style="color:#e6db74">&#34;purelymail/thanosapollo&#34;</span>)
</span></span><span style="display:flex;"><span>                   smtpmail-smtp-server <span style="color:#e6db74">&#34;smtp.purelymail.com&#34;</span>))
</span></span><span style="display:flex;"><span>            ((<span style="color:#a6e22e">string-match</span> gmail from)
</span></span><span style="display:flex;"><span>             (setf smtpmail-smtp-user <span style="color:#e6db74">&#34;104111@students.mu-sofia.bg&#34;</span>
</span></span><span style="display:flex;"><span>                   smtpmail-smtp-server <span style="color:#e6db74">&#34;smtp.gmail.com&#34;</span>)))))
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; You can use :hook instead, but I prefer add-hook under :config personally.</span>
</span></span><span style="display:flex;"><span>  (add-hook <span style="color:#e6db74">&#39;message-send-hook</span> <span style="color:#a6e22e">#&#39;</span>thanos/mail-config-hook))
</span></span></code></pre></div><h3 id="mml-sec">mml-sec</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package mml-sec
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  (defun gpg-list-emails-available ()
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;Return a list of trusted emails.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Parses output of `gpg --list-keys --with-colons&#39; command into a
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">list of emails.&#34;</span>
</span></span><span style="display:flex;"><span>  (let* ((command <span style="color:#e6db74">&#34;gpg --list-keys --with-colons&#34;</span>)
</span></span><span style="display:flex;"><span>         (output (shell-command-to-string command))
</span></span><span style="display:flex;"><span>         (lines (split-string output <span style="color:#e6db74">&#34;\n&#34;</span> <span style="color:#66d9ef">t</span>))
</span></span><span style="display:flex;"><span>         (emails <span style="color:#f92672">&#39;</span>()))
</span></span><span style="display:flex;"><span>    (dolist (line lines)
</span></span><span style="display:flex;"><span>      (when (string-prefix-p <span style="color:#e6db74">&#34;uid:&#34;</span> line)
</span></span><span style="display:flex;"><span>        (when (<span style="color:#a6e22e">string-match</span> <span style="color:#e6db74">&#34;&lt;\\([^&gt;]+\\)&gt;&#34;</span> line)
</span></span><span style="display:flex;"><span>          (let ((email (<span style="color:#a6e22e">downcase</span> (string-trim (match-string <span style="color:#ae81ff">1</span> line)))))
</span></span><span style="display:flex;"><span>            (push email emails)))))
</span></span><span style="display:flex;"><span>    (delete-dups emails)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun thanos/mail-list-recipients-from-buffer ()
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Get the list of recipients from the current email buffer.&#34;</span>
</span></span><span style="display:flex;"><span>    (save-excursion
</span></span><span style="display:flex;"><span>      (<span style="color:#a6e22e">goto-char</span> (<span style="color:#a6e22e">point-min</span>))
</span></span><span style="display:flex;"><span>      (let ((to (or (mail-fetch-field <span style="color:#e6db74">&#34;To&#34;</span>) <span style="color:#e6db74">&#34;&#34;</span>))
</span></span><span style="display:flex;"><span>            (cc (or (mail-fetch-field <span style="color:#e6db74">&#34;Cc&#34;</span>) <span style="color:#e6db74">&#34;&#34;</span>))
</span></span><span style="display:flex;"><span>            (bcc (or (mail-fetch-field <span style="color:#e6db74">&#34;Bcc&#34;</span>) <span style="color:#e6db74">&#34;&#34;</span>))
</span></span><span style="display:flex;"><span>            recipients)
</span></span><span style="display:flex;"><span>        (setq recipients (<span style="color:#a6e22e">concat</span> to <span style="color:#e6db74">&#34;, &#34;</span> cc <span style="color:#e6db74">&#34;, &#34;</span> bcc))
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">;; Remove empty strings from the result</span>
</span></span><span style="display:flex;"><span>        (<span style="color:#a6e22e">delq</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>              (<span style="color:#a6e22e">mapcar</span> (lambda (addr)
</span></span><span style="display:flex;"><span>                        (let ((clean-addr (string-trim addr)))
</span></span><span style="display:flex;"><span>                          (when (not (string-empty-p clean-addr))
</span></span><span style="display:flex;"><span>                            (<span style="color:#a6e22e">downcase</span>
</span></span><span style="display:flex;"><span>                             (if (<span style="color:#a6e22e">string-match</span> <span style="color:#e6db74">&#34;&lt;\\([^&gt;]+\\)&gt;&#34;</span> clean-addr)
</span></span><span style="display:flex;"><span>                                 (string-trim (match-string <span style="color:#ae81ff">1</span> clean-addr))
</span></span><span style="display:flex;"><span>                               clean-addr)))))
</span></span><span style="display:flex;"><span>                      (split-string recipients <span style="color:#e6db74">&#34;,&#34;</span> <span style="color:#66d9ef">t</span>))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun thanos/mail-sign-encrypt ()
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Auto-encrypt if all recipients have keys, else just sign.&#34;</span>
</span></span><span style="display:flex;"><span>    (let ((trusted-emails (gpg-list-emails-available))
</span></span><span style="display:flex;"><span>          (recipients (thanos/mail-list-recipients-from-buffer)))
</span></span><span style="display:flex;"><span>      (if (cl-every (lambda (r) (<span style="color:#a6e22e">member</span> r trusted-emails)) recipients)
</span></span><span style="display:flex;"><span>          (progn
</span></span><span style="display:flex;"><span>            (<span style="color:#a6e22e">message</span> <span style="color:#e6db74">&#34;Encrypting message.&#34;</span>)
</span></span><span style="display:flex;"><span>            (mml-secure-message-sign-encrypt))
</span></span><span style="display:flex;"><span>        (progn
</span></span><span style="display:flex;"><span>          (<span style="color:#a6e22e">message</span> <span style="color:#e6db74">&#34;Just signing message.&#34;</span>)
</span></span><span style="display:flex;"><span>          (mml-secure-message-sign)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (add-hook <span style="color:#e6db74">&#39;message-send-hook</span> <span style="color:#a6e22e">#&#39;</span>thanos/mail-sign-encrypt)
</span></span><span style="display:flex;"><span>  :custom
</span></span><span style="display:flex;"><span>  (mml-secure-openpgp-signers <span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;62B758D0F6719938BC09CECA339F736C3A720928&#34;</span>))) <span style="color:#75715e">;; Change this to your own key!</span>
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Daily Driving a Raspberry Pi 5</title>
      <link>https://thanosapollo.org/posts/daily-drive-pi5-01/</link>
      <pubDate>Fri, 31 Oct 2025 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/daily-drive-pi5-01/</guid>
      <description>Replacing my x220 laptop with a Raspberry Pi 5.</description>
      <content:encoded><![CDATA[<p>After switching from Apple devices to GNU/Linux, I&rsquo;ve enjoyed numerous
advantages. However, there&rsquo;s always been <em>one</em> thing that used to
make me look back: <em>battery life</em>, or the lack thereof.</p>
<p>Not anymore :)</p>
<p><strong>TLDR</strong>: I switched from a <a href="/images/setup-07-11-2023.jpg">thinkpad x220</a> to
a Raspberry Pi 5, which I use to access my desktop remotely.</p>
<figure>
    <img loading="lazy" src="/images/pi-monitor-back-01.png" width="80%" height="80%"/> 
</figure>

<blockquote>
<p>Raspberry Pi 5 with 3d printed custom VESA mount on Raspberry Pi Monitor</p>
</blockquote>
<h2 id="project-goals">Project Goals</h2>
<p>My aim with this &ldquo;project&rdquo; is to have a small, portable, and modular
device that I can simply toss in my bag and not worry about it&rsquo;s
battery life throughout the day.</p>
<p>The extra thing that I want, is to prove that you do not need to &ldquo;sell
your kidney&rdquo; and bow down to a corporation for the &lsquo;privilege&rsquo; to use
their hardware designed for obsolescence or their bloated software.</p>
<p>Hardware I&rsquo;m using:</p>
<ul>
<li>
<p>Things I&rsquo;ve purchased:</p>
<ul>
<li>Raspberry Pi 5 8GB</li>
<li>Raspberry Pi Monitor</li>
</ul>
</li>
<li>
<p>Things I&rsquo;ve already had:</p>
<ul>
<li>27000 mAh power bank</li>
<li>Keyboard</li>
</ul>
</li>
</ul>
<blockquote>
<p>I bought a Raspberry Pi 5 kit that came with a case fan for 100€.
The total cost for this project was 195€, for the Pi and the monitor.</p>
</blockquote>
<h3 id="battery-life">Battery Life</h3>
<p>I&rsquo;m usually out of home for over 7 hours a day for my studies, and I
enjoy studying in cafes and libraries. I&rsquo;ve missed having a device
with a battery life of 10+ hours, as my x220 barely lasts more than
4.5 hours.</p>
<p>Using a <code>27000mAh</code> power bank, I get ~15 hours of battery life.
I also carry an extra <em>&ldquo;emergency&rdquo;</em> power bank.</p>
<blockquote>
<p>With great power (and battery life) comes great productivity</p>
</blockquote>
<figure>
    <img loading="lazy" src="/images/pi-battery-usage.png" width="30%" height="30%"/> 
</figure>

<blockquote>
<p>The monitor consumes more energy than my Pi.</p>
</blockquote>
<h3 id="modularity">Modularity</h3>
<p>I strongly dislike laptop keyboards and I insist on using ones with a
trackpoint. I&rsquo;m currently using a <a href="https://tex.com.tw/products/shinobi">shinobi
keyboard</a>, which I can simply
plug into my Raspberry Pi and use just like on my desktop.</p>
<p>If I do not like something about my Pi setup, it&rsquo;d be trivial to
change, such using a new monitor, a new keyboard or another power bank.</p>
<h3 id="performance-file-synchronization">Performance &amp; File Synchronization</h3>
<p>Can the Pi outperform a modern laptop of &gt;1000€ price range? Yes and No :)</p>
<p>Now, you might be wondering; how can my Pi deliver better performance
than, say, a MacBook Air? A valid question, but as a GNU+Linux user,
I&rsquo;ve come to embrace the possibilities. Anything&rsquo;s possible with a
bit of hackery and FOSS magic.</p>
<p>I use <a href="https://github.com/neonkore/waypipe">waypipe</a>, a Wayland proxy,
to run Emacs remotely over a network. Emacs runs on my desktop, but I
access it from my Pi, great performance while seamlessly accessing all
my desktop files, such as my notes and PDFs, this also removes any
need for syncing files between devices.</p>
<blockquote>
<p>I have fiber connection, so there isn&rsquo;t any latency issues between
my devices using a wireguard VPN.</p>
</blockquote>
<figure>
    <img loading="lazy" src="/images/pi-waypipe-01.png"/> 
</figure>

<blockquote>
<p>Accessing my desktop Emacs session remotely, opening a PDF and eshell.</p>
</blockquote>
<h2 id="conclusion">Conclusion</h2>
<p>I will be using this setup for the rest of the academic year. I might
record a more detailed video with tips and tricks for others that
want to try something similar.</p>
<p>So far this has been more than an ideal setup for me, since I quite
often forget to sync my notes and projects between devices. Not
having to worry anymore about the battery life of my device is
quite relaxing as well.</p>]]></content:encoded>
    </item>
    <item>
      <title>Emacs Everywhere, even in Wayland</title>
      <link>https://thanosapollo.org/posts/use-emacs-everywhere/</link>
      <pubDate>Sat, 19 Jul 2025 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/use-emacs-everywhere/</guid>
      <description>How to use Emacs for input in any scenario in Wayland</description>
      <content:encoded><![CDATA[<p>If you are anything like me, you probably feel something is wrong
whenever you have to input text outside of Emacs. Fear not,
there&rsquo;s a solution.</p>
<p>Here&rsquo;s a simple code snippet to launch an emacs temp frame for input instead.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defun thanos/wtype-text (text)
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;Process TEXT for wtype, handling newlines properly.&#34;</span>
</span></span><span style="display:flex;"><span>  (let* ((has-final-newline (string-match-p <span style="color:#e6db74">&#34;\n$&#34;</span> text))
</span></span><span style="display:flex;"><span>         (lines (split-string text <span style="color:#e6db74">&#34;\n&#34;</span>))
</span></span><span style="display:flex;"><span>         (last-idx (<span style="color:#a6e22e">1-</span> (<span style="color:#a6e22e">length</span> lines))))
</span></span><span style="display:flex;"><span>    (string-join
</span></span><span style="display:flex;"><span>     (cl-loop for line in lines
</span></span><span style="display:flex;"><span>              for i from <span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span>              collect (cond
</span></span><span style="display:flex;"><span>                       <span style="color:#75715e">;; Last line without final newline</span>
</span></span><span style="display:flex;"><span>                       ((and (<span style="color:#a6e22e">=</span> i last-idx) (not has-final-newline))
</span></span><span style="display:flex;"><span>                        (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;wtype -s 350 \&#34;%s\&#34;&#34;</span>
</span></span><span style="display:flex;"><span>                                (replace-regexp-in-string <span style="color:#e6db74">&#34;\&#34;&#34;</span> <span style="color:#e6db74">&#34;\\\\\&#34;&#34;</span> line)))
</span></span><span style="display:flex;"><span>                       <span style="color:#75715e">;; Any other line</span>
</span></span><span style="display:flex;"><span>                       (<span style="color:#66d9ef">t</span>
</span></span><span style="display:flex;"><span>                        (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;wtype -s 350 \&#34;%s\&#34; &amp;&amp; wtype -k Return&#34;</span>
</span></span><span style="display:flex;"><span>                                (replace-regexp-in-string <span style="color:#e6db74">&#34;\&#34;&#34;</span> <span style="color:#e6db74">&#34;\\\\\&#34;&#34;</span> line)))))
</span></span><span style="display:flex;"><span>     <span style="color:#e6db74">&#34; &amp;&amp; &#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(defun thanos/type ()
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;Launch a temporary frame with a clean buffer for typing.&#34;</span>
</span></span><span style="display:flex;"><span>  (interactive)
</span></span><span style="display:flex;"><span>  (let ((frame (make-frame <span style="color:#f92672">&#39;</span>((name <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;emacs-float&#34;</span>)
</span></span><span style="display:flex;"><span>                             (fullscreen <span style="color:#f92672">.</span> <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>                             (undecorated <span style="color:#f92672">.</span> <span style="color:#66d9ef">t</span>)
</span></span><span style="display:flex;"><span>                             (width <span style="color:#f92672">.</span> <span style="color:#ae81ff">70</span>)
</span></span><span style="display:flex;"><span>                             (height <span style="color:#f92672">.</span> <span style="color:#ae81ff">20</span>))))
</span></span><span style="display:flex;"><span>        (buf (<span style="color:#a6e22e">get-buffer-create</span> <span style="color:#e6db74">&#34;emacs-float&#34;</span>)))
</span></span><span style="display:flex;"><span>    (<span style="color:#a6e22e">select-frame</span> frame)
</span></span><span style="display:flex;"><span>    (switch-to-buffer buf)
</span></span><span style="display:flex;"><span>    (<span style="color:#a6e22e">erase-buffer</span>)
</span></span><span style="display:flex;"><span>    (org-mode)
</span></span><span style="display:flex;"><span>    (setq-local header-line-format
</span></span><span style="display:flex;"><span>                (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34; %s to insert text or %s to cancel.&#34;</span>
</span></span><span style="display:flex;"><span>                        (<span style="color:#a6e22e">propertize</span> <span style="color:#e6db74">&#34;C-c C-c&#34;</span> <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;help-key-binding</span>)
</span></span><span style="display:flex;"><span>            (<span style="color:#a6e22e">propertize</span> <span style="color:#e6db74">&#34;C-c C-k&#34;</span> <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;help-key-binding</span>)))
</span></span><span style="display:flex;"><span>    (local-set-key (kbd <span style="color:#e6db74">&#34;C-c C-k&#34;</span>)
</span></span><span style="display:flex;"><span>           (lambda () (interactive)
</span></span><span style="display:flex;"><span>             (kill-new (<span style="color:#a6e22e">buffer-string</span>))
</span></span><span style="display:flex;"><span>             (<span style="color:#a6e22e">delete-frame</span>)))
</span></span><span style="display:flex;"><span>    (local-set-key (kbd <span style="color:#e6db74">&#34;C-c C-c&#34;</span>)
</span></span><span style="display:flex;"><span>           (lambda () (interactive)
</span></span><span style="display:flex;"><span>             (start-process-shell-command
</span></span><span style="display:flex;"><span>              <span style="color:#e6db74">&#34;wtype&#34;</span> <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>              (thanos/wtype-text (<span style="color:#a6e22e">buffer-string</span>)))
</span></span><span style="display:flex;"><span>             (<span style="color:#a6e22e">delete-frame</span>)))))
</span></span></code></pre></div><blockquote>
<p><em>Make sure <code>wtype</code> is installed in your system for the above snippet to work.</em></p>
</blockquote>
<p>All you have to do now is just bind <code>emacsclient --eval '(thanos/type)'</code>
to a shortcut of your liking.</p>
<p>On my Hyprland setup I&rsquo;m using the following settings</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>bind = $mainMod, j, exec, emacsclient --eval &#39;(thanos/type)&#39;
</span></span><span style="display:flex;"><span>windowrulev2 = float,class:^(emacs)$,title:^(emacs-float)$ # Launch as a floating window.
</span></span></code></pre></div><blockquote>
<p>For xorg users, you can simply rely on the <a href="https://github.com/tecosaur/emacs-everywhere">Emacs Everywhere</a>
package. <em>Unfortunately it does not support Wayland yet and I have
not tried it.</em></p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>Major update for Gnosis: 0.5.0 release</title>
      <link>https://thanosapollo.org/posts/gnosis-0-5-0-release/</link>
      <pubDate>Tue, 17 Jun 2025 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/gnosis-0-5-0-release/</guid>
      <description>Gnosis just got a major update with this new release.  With the long promised support of org-mode being added along with other major changes.</description>
      <content:encoded><![CDATA[<p>Gnosis just got a major update with this new release. With the long
promised support of <strong>org-mode</strong> being added along with support for
linking notes to
<a href="https://thanosapollo.org/projects/org-gnosis/">org-gnosis</a> nodes.</p>
<h2 id="org-mode-support">Org Mode Support</h2>
<p>After hacking on org-gnosis and gaining a better
understanding of how org-mode works, I decided to use org-mode for
creating and exporting gnosis notes.</p>
<p>Notes, no matter their note type, will now be as follows:</p>
<blockquote>
<p>Cloze type example.</p>
</blockquote>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-org" data-lang="org"><span style="display:flex;"><span>*<span style="font-weight:bold"> Thema                     </span><span style="font-style:italic"> :pharmacology:antimicrobials:penicillin:</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">:PROPERTIES:
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e">:GNOSIS_ID: NEW
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">:GNOSIS_TYPE: cloze
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e">:END:</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Keimenon
</span></span><span style="display:flex;"><span>What is the treatment for Actinomyces infection?
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Penicillin
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Hypothesis
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>drug type
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Answer
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>Penicillin
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Parathema
</span></span><span style="display:flex;"><span>Sulfonamides → Nocardia
</span></span><span style="display:flex;"><span>Actinomyces → [[<span style="color:#a6e22e">id:680ca944-8ee9-4513-92d6-25696ee01f48</span>][<span style="color:#f92672">Penicillin</span>]]
</span></span><span style="display:flex;"><span>(treatment is a SNAP)
</span></span></code></pre></div><blockquote>
<p>Note that anki-like syntax is still supported for clozes.</p>
</blockquote>
<!--quoteend-->
<blockquote>
<p>MCQ example</p>
</blockquote>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-org" data-lang="org"><span style="display:flex;"><span>*<span style="font-weight:bold"> Thema                                                           </span><span style="font-style:italic"> :clinical:</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">:PROPERTIES:
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e">:GNOSIS_ID: NEW
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">:GNOSIS_TYPE: mcq
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span><span style="color:#75715e">:END:</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Keimenon
</span></span><span style="display:flex;"><span>A 60-year-old man comes to the physician with chills, nausea, and
</span></span><span style="display:flex;"><span>diffuse muscle aches for 3 days. His niece had similar symptoms 2
</span></span><span style="display:flex;"><span>weeks ago and H3N2 influenza strain was isolated from her respiratory
</span></span><span style="display:flex;"><span>secretions. He received his influenza vaccination 2 months ago. His
</span></span><span style="display:flex;"><span>temperature is 38.5°C. A rapid influenza test is
</span></span><span style="display:flex;"><span>positive. Which of the following mechanisms best explains this
</span></span><span style="display:flex;"><span>patient&#39;s infection despite vaccination?
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Hypothesis
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>Random point mutations within viral genome
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>Complementing with functional viral proteins
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>Exchange of viral genes between chromosomes
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>Reassortment of viral RNA segments
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>Acquisition of viral surface proteins
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Answer
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">- </span>Random point mutations within viral genome
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">**</span> Parathema
</span></span><span style="display:flex;"><span>Random point mutations within the viral genome are responsible for
</span></span><span style="display:flex;"><span>antigenic drift, which creates a new virus strain.
</span></span></code></pre></div><p>Each note is a <strong>thema</strong> consisting of the following components:</p>
<ul>
<li><strong>Keimenon</strong>; The main text or question.</li>
<li><strong>Hypothesis</strong>; Assumptions/hints for the text to guide to the right answer
<ul>
<li>For example this is used as hints for cloze type or as choices in MCQs</li>
</ul>
</li>
<li><strong>Answer</strong>; The correct response or solution to the keimenon.</li>
<li><strong>Parathema</strong>; expansion of keimenon, that can include links to e.g
org-gnosis topics or even files, serving as a way to link org-gnosis
topics to current thema.</li>
</ul>
<p>Optionally, you can use also add tags for each note.</p>
<p>Notes/themas can have multiple hypotheses and answers (<em>depending on
their type</em>), separated by <code>gnosis-export-separator</code>, which defaults to
<code>&quot;\n-&quot;</code> (a new line followed by a dash).</p>
<h2 id="support-for-exporting-decks">Support for exporting decks</h2>
<p>Support for exporting decks as org files via <code>gnosis-export-deck</code> has
been added.</p>
<h2 id="support-for-org-gnosis-notes">Support for org-gnosis notes</h2>
<blockquote>
<p>With this update org-gnosis is finally part of gnosis. The goal is
not to just have a spaced repetition tool, but an all-in-one
learning tool.</p>
</blockquote>
<p>With this new update you can do reviews for specific <strong>org-gnosis</strong>
topics.</p>
<ul>
<li>Use <code>M-x gnosis-review-topic</code> to select a topic from your org-gnosis
notes to review all linked themas.</li>
<li>You can link a thema to an org-gnosis topic by adding an org id
link to either the parathema <em>(recommended)</em> or keimenon, using
<code>M-x org-gnosis-insert</code>.</li>
</ul>
<blockquote>
<p>Future versions will further expand on this functionality.</p>
</blockquote>
<h2 id="deprecated-support-for-images">Deprecated support for images</h2>
<ul>
<li>Image support will be rewritten in the next minor version
<ul>
<li>Support to display file links of images will be added.</li>
</ul>
</li>
</ul>
<h2 id="deprecated-support-for-y-or-n-notes">Deprecated support for y-or-n notes</h2>
<p>With this update your current <code>y-or-n</code> notes will be converted into MCQ
type, with &ldquo;Yes&rdquo; &amp; &ldquo;No&rdquo; choices.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Emacs Note Taking &amp; Journaling using org-gnosis [Video]</title>
      <link>https://thanosapollo.org/posts/org-gnosis-overview/</link>
      <pubDate>Mon, 03 Mar 2025 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/org-gnosis-overview/</guid>
      <description>Video overview about org-gnosis</description>
      <content:encoded><![CDATA[<center><i>Emacs Note Taking & Journaling with org-gnosis</i>
<iframe width="560" height="315" src="https://www.youtube.com/embed/5SkLa7jGjl0?si=ayncyQBxQ19NYqgV" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</center>
<h2 id="video-notes">Video notes</h2>
<h3 id="org-gnosis-overview">Org Gnosis Overview</h3>
<ul>
<li>
<p><strong>Org Gnosis</strong> <em>Organization of Gnosis (Knowledge)</em></p>
</li>
<li>
<p>Org Gnosis a a minimal org-mode parsing tool that organizes the data
of your notes as atomic nodes in an sqlite database.</p>
<ul>
<li>Org Gnosis provides a roam-like workflow, akin to Roam Research,
Logseq and org-roam, with support for journaling.</li>
</ul>
</li>
<li>
<p>In org-gnosis there are 2 types of nodes, gnosis nodes &amp; journal nodes.</p>
</li>
</ul>
<h3 id="installation-configuration">Installation &amp; Configuration</h3>
<ul>
<li><em>Refer to the project&rsquo;s
<a href="https://thanosapollo.org/projects/org-gnosis/">website</a> for the
latest installation instructions.</em></li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package org-gnosis
</span></span><span style="display:flex;"><span>  :ensure <span style="color:#66d9ef">t</span>
</span></span><span style="display:flex;"><span>  :init
</span></span><span style="display:flex;"><span>  (<span style="color:#a6e22e">define-prefix-command</span> <span style="color:#e6db74">&#39;thanos/notes-map</span>)
</span></span><span style="display:flex;"><span>  (<span style="color:#a6e22e">define-prefix-command</span> <span style="color:#e6db74">&#39;thanos/journal-map</span>)
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; I put my databse inside org-gnosis-dir to keep it in sync</span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; between machines, using git.</span>
</span></span><span style="display:flex;"><span>  (setf org-gnosis-db (emacsql-sqlite-open
</span></span><span style="display:flex;"><span>             (<span style="color:#a6e22e">expand-file-name</span> <span style="color:#e6db74">&#34;data.db&#34;</span> org-gnosis-dir)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (setf org-gnosis-dir <span style="color:#e6db74">&#34;~/Notes&#34;</span>
</span></span><span style="display:flex;"><span>  org-gnosis-node-templates
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;Default&#34;</span> (lambda () <span style="color:#e6db74">&#34;&#34;</span> <span style="color:#e6db74">&#34;#+startup: content\n&#34;</span>)))
</span></span><span style="display:flex;"><span>  org-gnosis-journal-templates
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;2050 Plan&#34;</span> journal/plan-2050)
</span></span><span style="display:flex;"><span>    (<span style="color:#e6db74">&#34;Empty&#34;</span> (lambda () <span style="color:#e6db74">&#34;&#34;</span> <span style="color:#e6db74">&#34;#+startup: content\n&#34;</span>)))
</span></span><span style="display:flex;"><span>  org-gnosis-show-tags <span style="color:#66d9ef">t</span>
</span></span><span style="display:flex;"><span>  org-gnosis-create-as-gpg <span style="color:#66d9ef">t</span>
</span></span><span style="display:flex;"><span>  org-gnosis-completing-read-func <span style="color:#a6e22e">#&#39;</span>org-completing-read)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun journal/plan-2050 ()
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;My journaling template for 2050-01-01.&#34;</span>
</span></span><span style="display:flex;"><span>    (let ((days-remaining (<span style="color:#a6e22e">-</span> (time-to-days (<span style="color:#a6e22e">encode-time</span> <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">0</span> <span style="color:#ae81ff">1</span> <span style="color:#ae81ff">1</span> <span style="color:#ae81ff">2050</span>))
</span></span><span style="display:flex;"><span>               (time-to-days (<span style="color:#a6e22e">current-time</span>)))))
</span></span><span style="display:flex;"><span>      (<span style="color:#a6e22e">format</span>
</span></span><span style="display:flex;"><span>       <span style="color:#e6db74">&#34;\nDays until 2050: *%s* \n\n* Records\n\n* Daily notes\n* Goals\n%s&#34;</span>
</span></span><span style="display:flex;"><span>       days-remaining (org-gnosis-todos))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  :bind ((<span style="color:#e6db74">&#34;C-c n&#34;</span> <span style="color:#f92672">.</span> thanos/notes-map)
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;C-c j&#34;</span> <span style="color:#f92672">.</span> thanos/journal-map)
</span></span><span style="display:flex;"><span>   :map thanos/notes-map
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;f&#34;</span> <span style="color:#f92672">.</span> org-gnosis-find)
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;i&#34;</span> <span style="color:#f92672">.</span> org-gnosis-insert)
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;t&#34;</span> <span style="color:#f92672">.</span> org-gnosis-find-by-tag)
</span></span><span style="display:flex;"><span>   :map thanos/journal-map
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;j&#34;</span> <span style="color:#f92672">.</span> org-gnosis-journal)
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;f&#34;</span> <span style="color:#f92672">.</span> org-gnosis-journal-find)
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;i&#34;</span> <span style="color:#f92672">.</span> org-gnosis-journal-insert)
</span></span><span style="display:flex;"><span>   :map org-gnosis-mode-map
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;C-c C-.&#34;</span> <span style="color:#f92672">.</span> org-gnosis-insert-tags)
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;C-c i&#34;</span> <span style="color:#f92672">.</span> org-id-get-create)
</span></span><span style="display:flex;"><span>   (<span style="color:#e6db74">&#34;C-c C-o&#34;</span> <span style="color:#f92672">.</span> thanos/org-open-at-point)))
</span></span></code></pre></div><h4 id="epa-easypgp-assistant">EPA (EasyPGP Assistant)</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package epa
</span></span><span style="display:flex;"><span>  :defer <span style="color:#66d9ef">t</span>
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  (setf epa-keys-select-method <span style="color:#e6db74">&#39;minibuffer</span>
</span></span><span style="display:flex;"><span>  epa-file-encrypt-to <span style="color:#f92672">&#39;</span>(<span style="color:#e6db74">&#34;your-pgp-key&#34;</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Do not prompt for key selection, we are only using the above key.</span>
</span></span><span style="display:flex;"><span>  epa-file-select-keys <span style="color:#e6db74">&#39;silent</span>))
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Emacs As Your Terminal Emulator [Video]</title>
      <link>https://thanosapollo.org/posts/emacs-shells-video/</link>
      <pubDate>Sat, 25 Jan 2025 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/emacs-shells-video/</guid>
      <description>Short video about Emacs shell interactions</description>
      <content:encoded><![CDATA[<center><i>Emacs As Your Terminal Emulator</i>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Qo7WQjbE2io?si=PAWUzeVw79DfBA4s" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</center>
<h3 id="emacs-as-your-terminal-emulator-video">Emacs As Your Terminal Emulator [Video]</h3>
<ul>
<li>Emacs offers an enhanced experience for interacting with shell tools
&amp; <em>may</em> be the most extensible terminal emulator available.</li>
<li>Provides seamless integration between shell tools &amp; editing
capabilities.</li>
</ul>
<h2 id="using-shell-commands-from-within-a-buffer">Using shell commands from within a buffer</h2>
<h3 id="shell-command">shell-command</h3>
<ul>
<li><code>M-! CMD &lt;RET&gt;</code></li>
<li>Run the shell command CMD and display the output.</li>
</ul>
<h3 id="async-shell-command">async-shell-command</h3>
<ul>
<li><code>M-&amp; CMD &lt;RET&gt;</code></li>
<li>Run the shell command CMD asynchronously, and display the output</li>
</ul>
<h3 id="shell-command-on-region">shell-command-on-region</h3>
<ul>
<li><code>M-| CMD &lt;RET&gt;</code></li>
<li>Run the shell command CMD with region contents as input; optionally
replace the region with the output</li>
</ul>
<h2 id="emacs-as-a-terminal-emulator">Emacs as a Terminal Emulator</h2>
<h3 id="shell">Shell</h3>
<ul>
<li><code>M-x shell</code></li>
<li>A subshell with input and output through an Emacs
buffer. You can then give commands interactively.</li>
</ul>
<h4 id="my-configuration">My configuration</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package shell
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  (defun thanos/shell (n)
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Create or switch to a shell buffer.&#34;</span>
</span></span><span style="display:flex;"><span>    (interactive <span style="color:#e6db74">&#34;P&#34;</span>)
</span></span><span style="display:flex;"><span>    (let* ((num (if n (<span style="color:#a6e22e">prefix-numeric-value</span> n) <span style="color:#66d9ef">nil</span>))
</span></span><span style="display:flex;"><span>           (buf-name (if num (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;*shell&lt;%d&gt;*&#34;</span> num) <span style="color:#e6db74">&#34;*shell*&#34;</span>)))
</span></span><span style="display:flex;"><span>      (shell buf-name)))
</span></span><span style="display:flex;"><span>  :bind ((<span style="color:#e6db74">&#34;C-c v&#34;</span> <span style="color:#f92672">.</span> thanos/shell)
</span></span><span style="display:flex;"><span>         :map shell-mode-map
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;C-l&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;comint-clear-buffer</span>))
</span></span><span style="display:flex;"><span>  :hook ((shell-mode <span style="color:#f92672">.</span> (lambda () (display-line-numbers-mode <span style="color:#ae81ff">-1</span>)))))
</span></span></code></pre></div><h3 id="eshell">Eshell</h3>
<ul>
<li><code>M-x eshell</code></li>
<li>Shell implemented entirely in Emacs Lisp</li>
</ul>
<h4 id="my-configuration-1">My configuration</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package eshell
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Prompt</span>
</span></span><span style="display:flex;"><span>  (defun eshell-git-info ()
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Return a string with git info.&#34;</span>
</span></span><span style="display:flex;"><span>    (when (<span style="color:#a6e22e">eq</span> (<span style="color:#a6e22e">call-process</span> <span style="color:#e6db74">&#34;git&#34;</span> <span style="color:#66d9ef">nil</span> <span style="color:#66d9ef">nil</span> <span style="color:#66d9ef">nil</span> <span style="color:#e6db74">&#34;rev-parse&#34;</span> <span style="color:#e6db74">&#34;--is-inside-work-tree&#34;</span>) <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>      (let* ((branch-raw (shell-command-to-string <span style="color:#e6db74">&#34;git rev-parse --abbrev-ref HEAD&#34;</span>))
</span></span><span style="display:flex;"><span>             (branch (if (or (string-match-p <span style="color:#e6db74">&#34;^fatal&#34;</span> branch-raw)
</span></span><span style="display:flex;"><span>                             (string-match-p <span style="color:#e6db74">&#34;^error&#34;</span> branch-raw))
</span></span><span style="display:flex;"><span>                         <span style="color:#e6db74">&#34;Unknown&#34;</span>
</span></span><span style="display:flex;"><span>                       (string-trim branch-raw)))
</span></span><span style="display:flex;"><span>             (dirty (not
</span></span><span style="display:flex;"><span>                     (string= <span style="color:#e6db74">&#34;&#34;</span> (string-trim (shell-command-to-string <span style="color:#e6db74">&#34;git status --porcelain&#34;</span>)))))
</span></span><span style="display:flex;"><span>             (dirty-info (if dirty <span style="color:#e6db74">&#34; ✎&#34;</span> <span style="color:#e6db74">&#34; ✔&#34;</span>)))
</span></span><span style="display:flex;"><span>        (<span style="color:#a6e22e">concat</span> (<span style="color:#a6e22e">propertize</span> <span style="color:#e6db74">&#34;⎇ &#34;</span> <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;modus-themes-fg-green-warmer</span>)
</span></span><span style="display:flex;"><span>                (<span style="color:#a6e22e">propertize</span> branch <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;modus-themes-fg-magenta-warmer</span>)
</span></span><span style="display:flex;"><span>                (<span style="color:#a6e22e">propertize</span> dirty-info <span style="color:#e6db74">&#39;face</span>
</span></span><span style="display:flex;"><span>                            (if dirty <span style="color:#e6db74">&#39;modus-themes-fg-red</span> <span style="color:#e6db74">&#39;modus-themes-fg-green</span>))))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun eshell-prompt-multiline ()
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Eshell Multiline Git prompt.&#34;</span>
</span></span><span style="display:flex;"><span>    (let ((separator (<span style="color:#a6e22e">propertize</span> <span style="color:#e6db74">&#34; | &#34;</span> <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;font-lock-comment-face</span>))
</span></span><span style="display:flex;"><span>          (hr (<span style="color:#a6e22e">propertize</span> (<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34;\n&#34;</span> (<span style="color:#a6e22e">make-string</span> (<span style="color:#a6e22e">/</span> (<span style="color:#a6e22e">window-total-width</span>) <span style="color:#ae81ff">2</span>) <span style="color:#e6db74">?─</span>) <span style="color:#e6db74">&#34;\n&#34;</span>) <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;font-lock-comment-face</span>))
</span></span><span style="display:flex;"><span>          (dir (<span style="color:#a6e22e">propertize</span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;%s&#34;</span> (abbreviate-file-name (eshell/pwd))) <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;modus-themes-fg-yellow-warmer</span>))
</span></span><span style="display:flex;"><span>          (git-info (eshell-git-info))
</span></span><span style="display:flex;"><span>          (time (<span style="color:#a6e22e">propertize</span> (<span style="color:#a6e22e">format-time-string</span> <span style="color:#e6db74">&#34;%H:%M:%S&#34;</span>) <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;font-lock-comment-face</span>))
</span></span><span style="display:flex;"><span>          (sign (if (<span style="color:#a6e22e">=</span> (<span style="color:#a6e22e">user-uid</span>) <span style="color:#ae81ff">0</span>)
</span></span><span style="display:flex;"><span>                    (<span style="color:#a6e22e">propertize</span> <span style="color:#e6db74">&#34;\n#&#34;</span> <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;modus-themes-fg-blue-intense</span>)
</span></span><span style="display:flex;"><span>                  (<span style="color:#a6e22e">propertize</span> <span style="color:#e6db74">&#34;\nλ&#34;</span> <span style="color:#e6db74">&#39;face</span> <span style="color:#e6db74">&#39;modus-themes-fg-red-warmer</span>))))
</span></span><span style="display:flex;"><span>      (<span style="color:#a6e22e">concat</span> hr dir separator git-info separator time sign <span style="color:#e6db74">&#34; &#34;</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (setf eshell-prompt-function <span style="color:#e6db74">&#39;eshell-prompt-multiline</span>
</span></span><span style="display:flex;"><span>        eshell-highlight-prompt <span style="color:#66d9ef">nil</span>)
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Aliases</span>
</span></span><span style="display:flex;"><span>  (defun eshell/o (file)
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Open FILE.&#34;</span>
</span></span><span style="display:flex;"><span>    (find-file file))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defvar thanos/aliases
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#39;</span>((ll <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;ls -lah&#34;</span>)
</span></span><span style="display:flex;"><span>      (clear <span style="color:#f92672">.</span> clear-scrollback)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun thanos/set-eshell-aliases (aliases)
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Set ALIASES as eshell aliases.&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">;; Remove aliases file</span>
</span></span><span style="display:flex;"><span>    (when (and eshell-aliases-file
</span></span><span style="display:flex;"><span>               (<span style="color:#a6e22e">file-exists-p</span> eshell-aliases-file))
</span></span><span style="display:flex;"><span>      (<span style="color:#a6e22e">delete-file</span> eshell-aliases-file))
</span></span><span style="display:flex;"><span>    (<span style="color:#a6e22e">mapc</span> (lambda (alias)
</span></span><span style="display:flex;"><span>            (let ((name (<span style="color:#a6e22e">symbol-name</span> (<span style="color:#a6e22e">car</span> alias)))
</span></span><span style="display:flex;"><span>                  (command (<span style="color:#a6e22e">cdr</span> alias)))
</span></span><span style="display:flex;"><span>              (eshell/alias name
</span></span><span style="display:flex;"><span>                            (cond
</span></span><span style="display:flex;"><span>                             ((<span style="color:#a6e22e">stringp</span> command) command)
</span></span><span style="display:flex;"><span>                             ((<span style="color:#a6e22e">symbolp</span> command) (<span style="color:#a6e22e">symbol-name</span> command))
</span></span><span style="display:flex;"><span>                             (<span style="color:#66d9ef">t</span> (<span style="color:#a6e22e">error</span> <span style="color:#e6db74">&#34;Unsupported alias command type&#34;</span>))))))
</span></span><span style="display:flex;"><span>          aliases))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Rebinds</span>
</span></span><span style="display:flex;"><span>  (defun thanos/eshell-clear ()
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Interactive call for clear-scrollback.&#34;</span>
</span></span><span style="display:flex;"><span>    (interactive)
</span></span><span style="display:flex;"><span>    (eshell/clear-scrollback))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  (defun thanos/eshell-preview-insert ()
</span></span><span style="display:flex;"><span>    (interactive)
</span></span><span style="display:flex;"><span>    (completion-preview-insert)
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">;; This funciton just deletes the extra space inserted after</span>
</span></span><span style="display:flex;"><span>    <span style="color:#75715e">;; completion.</span>
</span></span><span style="display:flex;"><span>    (<span style="color:#a6e22e">delete-char</span> <span style="color:#ae81ff">-1</span>))
</span></span><span style="display:flex;"><span>  :bind ((<span style="color:#e6db74">&#34;C-c e&#34;</span> <span style="color:#f92672">.</span> eshell)
</span></span><span style="display:flex;"><span>         :map eshell-mode-map
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;C-l&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;thanos/eshell-clear</span>)
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;&lt;tab&gt;&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;thanos/eshell-preview-insert</span>)
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;C-M-i&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;completion-at-point</span>))
</span></span><span style="display:flex;"><span>  :hook ((eshell-mode <span style="color:#f92672">.</span> (lambda ()
</span></span><span style="display:flex;"><span>                          (thanos/set-eshell-aliases thanos/aliases)
</span></span><span style="display:flex;"><span>                          (display-line-numbers-mode <span style="color:#ae81ff">-1</span>)
</span></span><span style="display:flex;"><span>                          (eshell-cmpl-mode <span style="color:#ae81ff">-1</span>)))))
</span></span></code></pre></div><h3 id="eat">Eat</h3>
<p><em><a href="https://codeberg.org/akib/emacs-eat">Emulate a terminal (Eat)</a></em></p>
<ul>
<li>xterm-like emulator, written in Emacs Lisp.</li>
<li>Although it&rsquo;s a standalone terminal for Emacs, similar to <code>term</code>,
I&rsquo;ve mostly used this package to enhance <code>eshell</code>.</li>
</ul>
<h4 id="my-configuration-2">My configuration</h4>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package eat
</span></span><span style="display:flex;"><span>  :ensure <span style="color:#66d9ef">t</span>
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  (setf eshell-visual-commands <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>        eat-term-name <span style="color:#e6db74">&#34;xterm-256color&#34;</span>)
</span></span><span style="display:flex;"><span>  :bind ((<span style="color:#e6db74">&#34;C-c V&#34;</span> <span style="color:#f92672">.</span> eat))
</span></span><span style="display:flex;"><span>  :hook ((eshell-mode <span style="color:#f92672">.</span> eat-eshell-mode)
</span></span><span style="display:flex;"><span>         (eshell-mode <span style="color:#f92672">.</span> eat-eshell-visual-command-mode)
</span></span><span style="display:flex;"><span>         (eat-mode <span style="color:#f92672">.</span> (lambda () (visual-line-mode <span style="color:#ae81ff">-1</span>)))))
</span></span></code></pre></div><h3 id="term-ansi-term">Term &amp; Ansi-Term</h3>
<ul>
<li><code>M-x term</code> | <code>M-x ansi-term</code>
<ul>
<li><strong>ansi-term</strong> is the same as term, except that it always creates a
new buffer and <code>C-x</code> is being marked as an escape-char.</li>
</ul>
</li>
<li>Runs a subshell with input and output through an Emacs buffer.</li>
</ul>
<h4 id="how-to-use">How to use</h4>
<ul>
<li>While in <code>term-mode</code> <code>C-c CHAR</code> is equivalent to <code>C-x CHAR</code>.
<ul>
<li>Example <code>C-c o</code> is the global binding <code>C-x o</code> <em>other-window</em></li>
</ul>
</li>
<li><code>C-c C-j</code> switches to <code>term-line-mode</code> <em>which allows navigation similar to shell</em></li>
<li><code>C-c C-k</code> switches back to <code>term-char-mode</code></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>Progress update on org-gnosis &amp; a graphical interface addition.</title>
      <link>https://thanosapollo.org/posts/org-gnosis-progress-1/</link>
      <pubDate>Wed, 18 Dec 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/org-gnosis-progress-1/</guid>
      <description>Progress update on org-gnosis, a roam-like note taking system.</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve been working on a &ldquo;roam-like&rdquo; note taking system, to replace &amp;
update my current <code>org-roam</code> workflow. This post is a minor update on
the current state of it&rsquo;s development.</p>
<blockquote>
<p>org-gnosis node &amp; my <a href="https://git.thanosapollo.org/org-roam-ui/">fork</a> of org-roam-ui</p>
</blockquote>
<p><strong>Project Name</strong>: <code>org-gnosis</code> | <strong>Org*anization of *Gnosis</strong></p>
<h2 id="goals">Goals</h2>
<p>The goals of <code>org-gnosis</code> are as follows:</p>
<ul>
<li>Keep it minimal, only implement parsing &amp; input data to a database.
<ul>
<li>Do not want to exceed 700 lines of code, <em>currently it&rsquo;s at 490</em>.</li>
</ul>
</li>
<li>Incorporate nodes as sources for <a href="/projects/gnosis/">gnosis</a> notes.
<ul>
<li>Having nodes as sources can replace my <em>extras</em> section.</li>
</ul>
</li>
<li>Make it easily extensible
<ul>
<li>Parsing functionality of <code>org-gnosis</code> should be easily customized to
work with other note taking tools.</li>
</ul>
</li>
<li>Separate journals from note taking</li>
</ul>
<h2 id="how-things-are-going">How things are going</h2>
<p>The goals above have been achieved, except for the incorporation with
my SRS system &amp; it&rsquo;s customization to parse non <code>org-mode</code> buffers can
be kinda tricky. Despite that, it has been a drop-in replacement for
my previous <code>org-roam</code> workflow.</p>
<p>I&rsquo;ve also created a fork of
<a href="https://git.thanosapollo.org/org-roam-ui/">org-roam-ui</a> that I&rsquo;ve
been using to visualize my notes. I will be testing this package and
<em>hopefully</em> publishing on either nongnu elpa or melpa <em>soon</em>.</p>
<p>If you are interested, try it out from this repo
<a href="https://git.thanosapollo.org/org-gnosis/">here</a>. If you find any
issues or got any questions feel free to email me.</p>]]></content:encoded>
    </item>
    <item>
      <title>Emacs 30 Built-in Completion UI &amp; Styles [Video]</title>
      <link>https://thanosapollo.org/posts/emacs-built-in-completions-video/</link>
      <pubDate>Thu, 12 Dec 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/emacs-built-in-completions-video/</guid>
      <description>Short video about Emacs 30 Built-in Completion UI &amp;amp; Styles</description>
      <content:encoded><![CDATA[<center>
<p><i>Emacs 30 Built-in Completion UI & Styles</i><p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/-ZeoGVtMLaU?si=nvEEv_8RPVa2EUij" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</center>
<h2 id="video-notes">Video notes:</h2>
<ul>
<li>When referring to &ldquo;Emacs Completions&rdquo;, I refer to Completion Styles &amp; UI</li>
<li>I&rsquo;ve often relied on third-party packages to emulate features from
other text editors. For instance, I&rsquo;ve long used <code>vertico</code>,
<code>corfu</code> and <code>orderless</code>.
<ul>
<li>While I still recommend these packages, I became curious about
using Emacs without depending on third-party options.</li>
<li>My current setup tries to emulate my workflow with the packages
mentioned above.</li>
</ul>
</li>
<li>The catalyst that pushed me to try the built-in completion is the
addition of <code>completion-preview-mode</code> in Emacs 30.</li>
</ul>
<h3 id="mini-buffer-completions">Mini-buffer completions</h3>
<ul>
<li>Emacs does not enable &ldquo;vertical&rdquo; completions for the mini-buffer by
default, but you can enable <code>fido-vertical-mode</code> which comes
built-in with Emacs.
<ul>
<li><code>fido-mode</code> is an enhanced <code>icomplete-mode</code> that emulates
<code>ido-mode</code>, also referred to as <code>fake ido-mode</code>.</li>
</ul>
</li>
</ul>
<h3 id="completion-styles">Completion Styles</h3>
<ul>
<li>Changing <code>completion-styles</code> example:</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setf completion-styles <span style="color:#f92672">&#39;</span>(basic flex))
</span></span></code></pre></div><ul>
<li>There is a plethora of completion styles, builtin styles include
<code>flex</code>, which provides &ldquo;fuzzy&rdquo; completions.</li>
</ul>
<h3 id="completion-ui-code-completions">Completion UI &amp; Code completions</h3>
<ul>
<li>Emacs built-in completions have a distinctive approach.</li>
<li>Instead of displaying a popup at point, a new <strong>Completions</strong> buffer
appears when invoking <code>completion-at-point</code>.</li>
</ul>
<p>Example configuration:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setf completion-styles <span style="color:#f92672">&#39;</span>(basic flex)
</span></span><span style="display:flex;"><span>      completion-auto-select <span style="color:#66d9ef">t</span> <span style="color:#75715e">;; Show completion on first call</span>
</span></span><span style="display:flex;"><span>      completion-auto-help <span style="color:#e6db74">&#39;visible</span> <span style="color:#75715e">;; Display *Completions* upon first request</span>
</span></span><span style="display:flex;"><span>      completions-format <span style="color:#e6db74">&#39;one-column</span> <span style="color:#75715e">;; Use only one column</span>
</span></span><span style="display:flex;"><span>      completions-sort <span style="color:#e6db74">&#39;historical</span> <span style="color:#75715e">;; Order based on minibuffer history</span>
</span></span><span style="display:flex;"><span>      completions-max-height <span style="color:#ae81ff">20</span> <span style="color:#75715e">;; Limit completions to 15 (completions start at line 5)</span>
</span></span><span style="display:flex;"><span>      completion-ignore-case <span style="color:#66d9ef">t</span>)
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>org-gnosis | Roam-like note taking system</title>
      <link>https://thanosapollo.org/posts/org-gnosis-01/</link>
      <pubDate>Thu, 21 Nov 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/org-gnosis-01/</guid>
      <description>Creating an org-roam replacement</description>
      <content:encoded><![CDATA[<p><code>org-roam</code> was my preferred tool for note taking &amp; journaling, but since
it&rsquo;s author seems to have stepped down &amp; it&rsquo;s implementation is quite
different from how I&rsquo;d approach making a zettelkasten for Emacs, I
decided to start working on a new package, named <code>org-gnosis</code>.</p>
<h2 id="goals-of-this-project">Goals of this project</h2>
<p>The primary objective is to achieve full compatibility with existing
org-roam notes while resolving current database implementation
issues. These goals were met successfully on the first day of
development.</p>
<p>Given that I plan to use this system for the next several years,
performance with large datasets is crucial. I have conducted tests on
org-gnosis with a dataset comprising 70,000 nodes, and it has
demonstrated flawless performance without any issues. Although, the
initialization can take sometime.</p>
<p>Beyond just performance, I want to keep it small and simple,
especially in terms of lines of code. The less lines of code I have
to maintain the happier I am :)</p>
<h2 id="how-to-install">How to install</h2>
<p>This project is <em>only 26 hours</em> old as of now, I have not published it on
any ELPA, but you can find it on this <a href="https://git.thanosapollo.org/org-gnosis/">git
repo</a>, feel free to clone it
and try it out.</p>
<p>Example <code>use-package</code> snippet</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package org-gnosis
</span></span><span style="display:flex;"><span>  :load-path <span style="color:#e6db74">&#34;~/Dev/emacs-lisp/org-gnosis&#34;</span>
</span></span><span style="display:flex;"><span>  :init
</span></span><span style="display:flex;"><span>  (<span style="color:#a6e22e">define-prefix-command</span> <span style="color:#e6db74">&#39;thanos/notes-map</span>)
</span></span><span style="display:flex;"><span>  (<span style="color:#a6e22e">define-prefix-command</span> <span style="color:#e6db74">&#39;thanos/journal-map</span>)
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  (setf org-gnosis-dir <span style="color:#e6db74">&#34;~/Notes&#34;</span>
</span></span><span style="display:flex;"><span>    org-gnosis-show-tags <span style="color:#66d9ef">t</span>) <span style="color:#75715e">;; Enable this if you use a completion system like vertico</span>
</span></span><span style="display:flex;"><span>  :bind ((<span style="color:#e6db74">&#34;C-c n&#34;</span> <span style="color:#f92672">.</span> thanos/notes-map)
</span></span><span style="display:flex;"><span>     (<span style="color:#e6db74">&#34;C-c j&#34;</span> <span style="color:#f92672">.</span> thanos/journal-map) <span style="color:#75715e">;; You can use &#34;C-c n j&#34; if you prefer</span>
</span></span><span style="display:flex;"><span>     :map thanos/notes-map
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;f&#34;</span> <span style="color:#f92672">.</span> org-gnosis-find)
</span></span><span style="display:flex;"><span>     (<span style="color:#e6db74">&#34;i&#34;</span> <span style="color:#f92672">.</span> org-gnosis-insert)
</span></span><span style="display:flex;"><span>     :map thanos/journal-map
</span></span><span style="display:flex;"><span>     (<span style="color:#e6db74">&#34;j&#34;</span> <span style="color:#f92672">.</span> org-gnosis-journal)
</span></span><span style="display:flex;"><span>     (<span style="color:#e6db74">&#34;f&#34;</span> <span style="color:#f92672">.</span> org-gnosis-journal-find)
</span></span><span style="display:flex;"><span>     (<span style="color:#e6db74">&#34;i&#34;</span> <span style="color:#f92672">.</span> org-gnosis-journal-insert)
</span></span><span style="display:flex;"><span>     :map org-mode-map
</span></span><span style="display:flex;"><span>     (<span style="color:#e6db74">&#34;C-c i&#34;</span> <span style="color:#f92672">.</span> org-id-get-create)))
</span></span></code></pre></div><p>After installing <code>org-gnosis</code> run <code>M-x org-gnosis-db-sync</code> to sync
your database, afterwards just use <code>org-gnosis-find</code> similarly to how
you&rsquo;d use <code>org-roam-find-node</code>.</p>
<blockquote>
<p>This package is still under development, if you encounter any bugs
feel free to email me.</p>
</blockquote>
]]></content:encoded>
    </item>
    <item>
      <title>RSS Mastery with RSS-Bridge &amp; Elfeed [Video]</title>
      <link>https://thanosapollo.org/posts/rss-video/</link>
      <pubDate>Sat, 09 Nov 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/rss-video/</guid>
      <description>Short video about RSS, RSS-Bridge &amp;amp; Elfeed</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve just published a short video covering the basics of RSS,
RSS-Bridge &amp; Elfeed, it&rsquo;s currently available on
<a href="https://www.youtube.com/watch?v=XvgChZdTvYU">YouTube</a>.</p>
<h2 id="video-notes">Video notes</h2>
<h3 id="what-is-rss">What is RSS?</h3>
<ul>
<li>XML-based web feed that allows users to access updates of
websites, without &ldquo;visiting&rdquo; the website.</li>
<li>Hacktivist including <a href="https://en.wikipedia.org/wiki/Aaron_Swartz">Aaron
Swartz</a> contributed to
the development of RSS</li>
</ul>
<h3 id="why-use-it">Why use it?</h3>
<ul>
<li>Having total control over information you consume
<ul>
<li>Filter/Prioritize content from various sources</li>
<li>Bypass algorithms</li>
<li>Ad-free reading</li>
</ul>
</li>
<li>Offline Access</li>
<li>Time saving</li>
<li>Allows creation of a <strong>personalized</strong> &amp; <strong>decentralized</strong> information hub</li>
</ul>
<h3 id="emacs-rss-elfeed">(+ Emacs RSS) ;; =&gt; &rsquo;elfeed</h3>
<p><strong>No matter what RSS reader you choose, they all get the same job done</strong></p>
<ul>
<li><a href="https://github.com/skeeto/elfeed">Elfeed</a> is a simple &amp; highly customizable RSS client for Emacs
<ul>
<li>Developed by Christopher Wellons (<a href="https://github.com/skeeto">skeeto</a>)</li>
</ul>
</li>
<li>It has a well designed database &amp; tagging system</li>
</ul>
<p><code>use-package</code> installation example:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(use-package elfeed
</span></span><span style="display:flex;"><span>  :vc (:url <span style="color:#e6db74">&#34;https://github.com/skeeto/elfeed&#34;</span>) <span style="color:#75715e">;; vc option is available on Emacs 30</span>
</span></span><span style="display:flex;"><span>  :config
</span></span><span style="display:flex;"><span>  (setf elfeed-search-filter <span style="color:#e6db74">&#34;@1-week-ago +unread&#34;</span>
</span></span><span style="display:flex;"><span>        browse-url-browser-function <span style="color:#a6e22e">#&#39;</span>browse-url-default-browser
</span></span><span style="display:flex;"><span>        elfeed-db-directory (locate-user-emacs-file <span style="color:#e6db74">&#34;elfeed-db&#34;</span>))
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Feeds Example</span>
</span></span><span style="display:flex;"><span>  (setf elfeed-feeds
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;https://hackaday.com/blog/feed/&#34;</span>
</span></span><span style="display:flex;"><span>           hackaday linux)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">;; Play videos from elfeed</span>
</span></span><span style="display:flex;"><span>  (defun elfeed-mpv (<span style="color:#66d9ef">&amp;optional</span> use-generic-p)
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;Play video link with mpv.&#34;</span>
</span></span><span style="display:flex;"><span>    (interactive <span style="color:#e6db74">&#34;P&#34;</span>)
</span></span><span style="display:flex;"><span>    (let ((entries (elfeed-search-selected)))
</span></span><span style="display:flex;"><span>      (cl-loop for entry in entries
</span></span><span style="display:flex;"><span>               do (elfeed-untag entry <span style="color:#e6db74">&#39;unread</span>)
</span></span><span style="display:flex;"><span>               when (elfeed-entry-link entry)
</span></span><span style="display:flex;"><span>               do (start-process-shell-command <span style="color:#e6db74">&#34;elfeed-video&#34;</span> <span style="color:#66d9ef">nil</span> (<span style="color:#a6e22e">format</span> <span style="color:#e6db74">&#34;mpv \&#34;%s\&#34;&#34;</span> it)))
</span></span><span style="display:flex;"><span>      (<span style="color:#a6e22e">mapc</span> <span style="color:#a6e22e">#&#39;</span>elfeed-search-update-entry entries)
</span></span><span style="display:flex;"><span>      (unless (use-region-p) (<span style="color:#a6e22e">forward-line</span>))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  :bind ((<span style="color:#e6db74">&#34;C-x f&#34;</span> <span style="color:#f92672">.</span> elfeed)
</span></span><span style="display:flex;"><span>         :map elfeed-search-mode-map
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;v&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;elfeed-mpv</span>)
</span></span><span style="display:flex;"><span>         (<span style="color:#e6db74">&#34;U&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#39;elfeed-update</span>)))
</span></span></code></pre></div><h3 id="what-to-do-with-websites-that-do-not-provide-an-rss-feed">What to do with websites that do not provide an RSS feed?</h3>
<ul>
<li>Utilize <a href="https://github.com/RSS-Bridge/rss-bridge">rss-bridge</a> to generate one.</li>
<li>RSS Bridge is easy to self host using docker</li>
</ul>
<p>Example <code>guix</code> service:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(service oci-container-service-type
</span></span><span style="display:flex;"><span>         (<span style="color:#a6e22e">list</span>
</span></span><span style="display:flex;"><span>          (oci-container-configuration
</span></span><span style="display:flex;"><span>           (image <span style="color:#e6db74">&#34;rssbridge/rss-bridge&#34;</span>)
</span></span><span style="display:flex;"><span>           (network <span style="color:#e6db74">&#34;host&#34;</span>)
</span></span><span style="display:flex;"><span>           (ports
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;3000&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;80&#34;</span>))))))
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>Why I Prefer VC Over Magit [Video]</title>
      <link>https://thanosapollo.org/posts/why-i-prefer-vc-over-magit/</link>
      <pubDate>Fri, 08 Nov 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/why-i-prefer-vc-over-magit/</guid>
      <description>Short video about VC &amp;amp; Magit</description>
      <content:encoded><![CDATA[<p>I&rsquo;ve just uploaded a short video on why I prefer VC over Magit,
alongside a quick demo workflow with VC.</p>
<p>The video is available on youtube
<a href="https://www.youtube.com/watch?v=-pPkGWIfdqM">here</a>.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Rewriting Gnosis: 0.4.0 release</title>
      <link>https://thanosapollo.org/posts/gnosis-0-4-0-release/</link>
      <pubDate>Wed, 07 Aug 2024 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/gnosis-0-4-0-release/</guid>
      <description>Gnosis (γνῶσις), a spaced repetition system implementation for GNU Emacs</description>
      <content:encoded><![CDATA[<p>What&rsquo;s the most important thing for storing knowledge?</p>
<p>I&rsquo;d say proper organization of said knowledge, such as with decks for
each subject and meaningful tags linking related concepts together across
decks, making it easily searchable and accessible.</p>
<p>As I started adding more and more notes into gnosis, I found myself
wanting to adjust the review algorithm not only for decks but for tags
as well. This led me to overhaul the underlying architecture and
reimplement key concepts.</p>
<h2 id="key-changes-made">Key Changes Made</h2>
<ul>
<li>Redesigned <code>gnosis-dashboard</code> with a <em>home-page-like</em> buffer
displaying current activity stats such as review streak and today&rsquo;s
due notes.
<img loading="lazy" src="/images/gnosis-dashboard-03.png"></li>
<li>Rewritten gnosis algorithm:
<ul>
<li>Added <strong>gnosis-score</strong>, the current knowledge score for a note.</li>
<li>Added <strong>epignosis</strong> value, that indicates the knowledge accuracy
for a given note, as well as <strong>agnoia</strong> to indicate the lack of
knowledge for a note, those values will be used in <strong>anagnosis
events</strong>. <em>The &ldquo;indication&rdquo; is the translation of those words
from greek.</em></li>
<li>Added special review events; <strong>Anagnosis</strong> &amp; <strong>Lethe</strong>
<ul>
<li><strong>Anagnosis</strong> refers to the recognition &amp; understanding of a
context, anagnosis events are triggered by either consecutive
failed or successful recalls. Depending on how it&rsquo;s triggered,
<strong>epignosis</strong> or <strong>agnoia</strong> will be applied to <strong>gnosis-score</strong></li>
<li><strong>Lethe</strong> refers to the forgetting of knowledge, it&rsquo;s triggered
by consecutive failures to recall an answer, upon this event the
next interval is set to 0</li>
</ul>
</li>
<li>Added <strong>amnesia</strong>, upon failing to recall a note, amnesia value is
used to determine the next interval.</li>
<li>Added <strong>proto</strong>, a list that consist of integers, indicating the
value for the first intervals. Proto list does not have a limit
on length.</li>
</ul>
</li>
<li>Re-implement the configuration for the above deck values, and added
the ability to do the same for tags. Tag configuration takes
priority over deck configuration.</li>
</ul>
<p><em>Example:</em></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq gnosis-custom-values
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#39;</span>((:deck <span style="color:#e6db74">&#34;demo&#34;</span> (:proto (<span style="color:#ae81ff">0</span> <span style="color:#ae81ff">1</span> <span style="color:#ae81ff">3</span>) :anagnosis <span style="color:#ae81ff">3</span> :epignosis <span style="color:#ae81ff">0.5</span> :agnoia <span style="color:#ae81ff">0.3</span> :amnesia <span style="color:#ae81ff">0.5</span> :lethe <span style="color:#ae81ff">3</span>))
</span></span><span style="display:flex;"><span>    (:tag <span style="color:#e6db74">&#34;demo-concept&#34;</span> (:proto (<span style="color:#ae81ff">1</span> <span style="color:#ae81ff">2</span>) :anagnosis <span style="color:#ae81ff">3</span> :amnesia <span style="color:#ae81ff">0.7</span>))))
</span></span></code></pre></div><p>A note under the deck <em>demo</em> tagged with <em>demo-concept</em> will have the
demo deck values with the exception of:</p>
<ul>
<li><code>proto</code> value set to <code>(1 2)</code></li>
<li><code>amnesia</code> value set to <code>0.7</code></li>
</ul>
<p>For notes that have multiple tags, the maximum value is retained for
most parameters. However, <code>anagnosis</code> and <code>lethe</code> will retain the
minimum value.</p>
<h2 id="next-features-on-the-horizon">Next features on the horizon</h2>
<ul>
<li>Org mode integration</li>
<li>Deck export &amp; import</li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Why Emacs will NEVER be popular</title>
      <link>https://thanosapollo.org/posts/emacs-will-never-be-popular/</link>
      <pubDate>Mon, 11 Mar 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/emacs-will-never-be-popular/</guid>
      <description>&lt;p&gt;Emacs is my ride or die software, where I do all my computing.  If not
for Emacs, I wouldn&amp;rsquo;t give a byte about computers.  Moved to GNU/Linux
just for Emacs. But let&amp;rsquo;s face it, Emacs will forever swim against the
current. Just like Gentoo, it&amp;rsquo;s too hardcore for the mainstream. To
vibe with it or not, that&amp;rsquo;s the 1 million dollar question.&lt;/p&gt;
&lt;h2 id=&#34;possible-solutions&#34;&gt;Possible Solutions&lt;/h2&gt;
&lt;p&gt;Emacs needs distributions to shine in this modern digital landscape
where everything should &amp;ldquo;just work&amp;rdquo; Distros like &lt;a href=&#34;https://github.com/doomemacs/doomemacs&#34;&gt;Doom Emacs&lt;/a&gt; can flex
the power of Emacs, enticing even those who can&amp;rsquo;t define it.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>Emacs is my ride or die software, where I do all my computing.  If not
for Emacs, I wouldn&rsquo;t give a byte about computers.  Moved to GNU/Linux
just for Emacs. But let&rsquo;s face it, Emacs will forever swim against the
current. Just like Gentoo, it&rsquo;s too hardcore for the mainstream. To
vibe with it or not, that&rsquo;s the 1 million dollar question.</p>
<h2 id="possible-solutions">Possible Solutions</h2>
<p>Emacs needs distributions to shine in this modern digital landscape
where everything should &ldquo;just work&rdquo; Distros like <a href="https://github.com/doomemacs/doomemacs">Doom Emacs</a> can flex
the power of Emacs, enticing even those who can&rsquo;t define it.</p>
<p>Most people start with a text editor and never bother looking for
alternatives.  Even Lisp learners typically skip Emacs as a starting
point.  If not them, then who?</p>
<p>An Emacs distribution that just works would draw newcomers or at least
be the editor that you can drop on someone to learn programming.
Possible also something finely tuned for academics &amp; wordsmiths with
org-mode.</p>
<h2 id="popularity-shmopularity">Popularity shmopularity!</h2>
<p>Popularizing Emacs goes beyond just boosting its own fame; it&rsquo;s about
spreading the gospel of the GNU philosophy &amp; Lisp programming that
Emacs embodies.</p>
<p>We&rsquo;re not just promoting a tool, but a mindset and a way of thinking
that challenges the status quo in the world.  Embracing Emacs means
embracing a hacker ethos of freedom.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Emacs Email Management | Setup Guide for mu4e &amp; isync</title>
      <link>https://thanosapollo.org/posts/mu4e-guide/</link>
      <pubDate>Mon, 29 Jan 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/mu4e-guide/</guid>
      <description>Managing emails with emacs, using mu4e &amp;amp; isync.</description>
      <content:encoded><![CDATA[<p>Email, hate it or love it, we all have to deal with it. Thankfully,
thanks to Emacs &amp; <a href="https://github.com/djcb/mu">mu4e</a> you can have a
productive and, dare I say, fun time working with emails.</p>
<h2 id="about">About</h2>
<p>In this guide I will guide you through setting up mu4e with multiple
accounts, using isync &amp; mu, as well as the basics of how to
incorporate mu4e into your workflow, plus tips &amp; tricks like using
mu4e actions to apply git patches.</p>
<p>To follow this guide, make sure to enable IMAP/SMTP access for your
email account. The steps to enable this may vary depending on your
specific email provider, so I won&rsquo;t cover that in this guide.</p>
<h2 id="why-mu4e">Why mu4e?</h2>
<p>There are multiple options available in GNU Emacs for managing emails,
such as rmail, gnus, notmuch, and mu4e.</p>
<p>Each of these options has its own complexities, depending on your
specific use case.</p>
<p>In my personal experience, I find mu4e to be preferable due to its
ease of setup, particularly when dealing with multiple accounts.</p>
<h2 id="installing-mu-isync">Installing MU &amp; isync</h2>
<p>To get started, install <strong>mu</strong> &amp; <strong>isync</strong></p>
<ul>
<li>Arch Linux</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ sudo pacman -S mu isync
</span></span></code></pre></div><ul>
<li>Gentoo</li>
</ul>
<!--listend-->
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ sudo emerge -av mu isync
</span></span></code></pre></div><p><code>NOTE</code>: Make sure you to use <code>emacs</code> USEFLAG for mu</p>
<p>If <code>mu</code> is not packaged for your distro, I recommend changing to a new
one. But if you insist, you might have success installing mu from
source, using
<a href="https://github.com/radian-software/straight.el">straight.el</a>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(straight-use-package <span style="color:#e6db74">&#39;mu4e</span>)
</span></span></code></pre></div><h2 id="setting-up-mbsync">Setting up mbsync</h2>
<p>Edit your configuration: <code>~/.mbsyncrc</code></p>
<h3 id="example-setup-for-fastmail">Example setup for Fastmail:</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>IMAPAccount fastmail
</span></span><span style="display:flex;"><span>Host imap.fastmail.com
</span></span><span style="display:flex;"><span>Port 993
</span></span><span style="display:flex;"><span>User myaccount@fastmail.com
</span></span><span style="display:flex;"><span>PassCmd &#34;emacsclient -e &#39;(password-store-get-field \&#34;fastmail.com/myaccount@fastmail.com\&#34; \&#34;smtp\)&#39;&#34;
</span></span><span style="display:flex;"><span>SSLType IMAPS
</span></span><span style="display:flex;"><span>SSLVersions TLSv1.2
</span></span><span style="display:flex;"><span>CertificateFile /etc/ssl/certs/ca-certificates.crt
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>IMAPStore fastmail-remote
</span></span><span style="display:flex;"><span>Account fastmail
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>MaildirStore fastmail-local
</span></span><span style="display:flex;"><span>Path ~/Mail/Fastmail/
</span></span><span style="display:flex;"><span>Inbox ~/Mail/Fastmail/Inbox
</span></span><span style="display:flex;"><span>Trash ~/Mail/Fastmail/Trash/
</span></span><span style="display:flex;"><span>SubFolders Verbatim
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Channel fastmail
</span></span><span style="display:flex;"><span>Far :fastmail-remote:
</span></span><span style="display:flex;"><span>Near :fastmail-local:
</span></span><span style="display:flex;"><span>Patterns *
</span></span><span style="display:flex;"><span>Expunge None
</span></span><span style="display:flex;"><span>CopyArrivalDate yes
</span></span><span style="display:flex;"><span>Sync All
</span></span><span style="display:flex;"><span>Create Both
</span></span><span style="display:flex;"><span>SyncState *
</span></span></code></pre></div><h3 id="example-setup-for-gmail">Example setup for Gmail:</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>IMAPAccount gmail
</span></span><span style="display:flex;"><span>Host imap.gmail.com
</span></span><span style="display:flex;"><span>Port 993
</span></span><span style="display:flex;"><span>User myaccount@gmail.com
</span></span><span style="display:flex;"><span>PassCmd &#34;pass google/mygmail.com&#34;
</span></span><span style="display:flex;"><span>SSLType IMAPS
</span></span><span style="display:flex;"><span>SSLVersions TLSv1.2
</span></span><span style="display:flex;"><span>CertificateFile /etc/ssl/certs/ca-certificates.crt
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>IMAPStore gmail-remote
</span></span><span style="display:flex;"><span>Account gmail
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>MaildirStore gmail-local
</span></span><span style="display:flex;"><span>Path ~/Mail/Account-GMAIL/
</span></span><span style="display:flex;"><span>SubFolders Verbatim
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Channel gmail
</span></span><span style="display:flex;"><span>Far :gmail-remote:
</span></span><span style="display:flex;"><span>Near :gmail-local:
</span></span><span style="display:flex;"><span>Patterns * ![Gmail]* &#34;[Gmail]/Sent Mail&#34; &#34;[Gmail]/Starred&#34; &#34;[Gmail]/All Mail&#34; &#34;[Gmail]/Trash&#34;
</span></span><span style="display:flex;"><span>Expunge None
</span></span><span style="display:flex;"><span>CopyArrivalDate yes
</span></span><span style="display:flex;"><span>Sync All
</span></span><span style="display:flex;"><span>Create Both
</span></span><span style="display:flex;"><span>SyncState *
</span></span><span style="display:flex;"><span>Settings you should adjust:
</span></span></code></pre></div><ul>
<li><code>PassCmd</code> this should output your account password. I personally use
pass as my password manager.</li>
</ul>
<p>In the fastmail example above I get my password with this emacs
function:</p>
<p><code>(password-store-get-field \&quot;fastmail.com/myaccount@fastmail.com\&quot; \&quot;smtp\)</code></p>
<p><code>password-store</code> is a pass front-end for Emacs.</p>
<p><code>NOTE</code>: You can instead of PassCmd, use Pass that just has your
password in plain text, but I do not recommend this for security
reasons.</p>
<ul>
<li>
<p><code>CertificateFile</code> - This location can vary based on your Linux distribution.</p>
</li>
<li>
<p><code>Patterns</code> - Defines which folders will be synced, I personally just
define my folders manually, similarly to the fastmail example.</p>
</li>
</ul>
<p>Feel free to define multiple accounts this way.</p>
<p>After configuring isync, start the initial sync by running this command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ mbsync -a
</span></span></code></pre></div><h2 id="setting-up-mu-mu4e">Setting up mu &amp; mu4e</h2>
<p>First, you have to run the initial index.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>mu init --maildir=~/Mail --my-address myaccount@fastmail.com
</span></span><span style="display:flex;"><span>mu index
</span></span></code></pre></div><p><code>NOTE</code>: You may add as many <code>--my-address</code> arguments you want.</p>
<p>Now, it&rsquo;s time to create your mu4e configuration for Emacs.</p>
<p>You may create this as a module, or just as part of your :config using use-package. I personally define variables in my init.el like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(defvar is-desktop (<span style="color:#a6e22e">equal</span> (<span style="color:#a6e22e">system-name</span>) <span style="color:#e6db74">&#34;desktop-hostname&#34;</span>)) <span style="color:#75715e">;; your $HOSTNAME</span>
</span></span><span style="display:flex;"><span>(defvar is-laptop (<span style="color:#a6e22e">equal</span> (<span style="color:#a6e22e">system-name</span>) <span style="color:#e6db74">&#34;laptop-hostname&#34;</span>))
</span></span></code></pre></div><p>Create <code>~/.emacs.d/modules/thanos-mu4e.el</code> for the mu4e module
configuration. And add this to my init.el</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-to-list <span style="color:#e6db74">&#39;load-path</span> <span style="color:#e6db74">&#34;~/.emacs.d/modules&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(when (or is-desktop is-laptop)
</span></span><span style="display:flex;"><span>  (require <span style="color:#e6db74">&#39;thanos-mu4e</span>))
</span></span></code></pre></div><p>This way I only load my mu4e configuration only when I&rsquo;m using my
laptop or desktop.</p>
<h2 id="loading-mu4e">Loading Mu4e</h2>
<p>Make sure <code>mu4e</code> is on load-path:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-to-list <span style="color:#e6db74">&#39;load-path</span> <span style="color:#e6db74">&#34;/usr/share/emacs/site-lisp/mu4e/&#34;</span>) <span style="color:#75715e">;; path to mu4e</span>
</span></span><span style="display:flex;"><span>(require <span style="color:#e6db74">&#39;mu4e</span>)
</span></span></code></pre></div><h2 id="the-essentials">The essentials</h2>
<p>This is an example configuration to get started with mu4e using multiple accounts:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setf mu4e-get-mail-command <span style="color:#e6db74">&#34;mbsync -a&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(when (and is-desktop (server-running-p))
</span></span><span style="display:flex;"><span>  (setf mu4e-update-interval (<span style="color:#a6e22e">*</span> <span style="color:#ae81ff">10</span> <span style="color:#ae81ff">60</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;; Snippet from EmacsWiki</span>
</span></span><span style="display:flex;"><span>(defun set-mu4e-context (context-name full-name mail-address signature)
</span></span><span style="display:flex;"><span>  <span style="color:#e6db74">&#34;Return a mu4e context named CONTEXT-NAME with :match-func matching
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    folder name CONTEXT-NAME in Maildir. The context&#39;s </span><span style="color:#e6db74">`user-mail-address&#39;</span><span style="color:#e6db74">,
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    </span><span style="color:#e6db74">`user-full-name&#39;</span><span style="color:#e6db74"> and </span><span style="color:#e6db74">`mu4e-compose-signature&#39;`smtpmail-smpt-server&#39;</span><span style="color:#e6db74"> is set to MAIL-ADDRESS
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    FULL-NAME SIGNATURE and SERVER respectively.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">    Special folders are set to context specific folders.&#34;</span>
</span></span><span style="display:flex;"><span>  (let ((dir-name (<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34;/&#34;</span> context-name)))
</span></span><span style="display:flex;"><span>    (make-mu4e-context
</span></span><span style="display:flex;"><span>     :name context-name
</span></span><span style="display:flex;"><span>     <span style="color:#75715e">;; we match based on the maildir of the message</span>
</span></span><span style="display:flex;"><span>     :match-func
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">`</span>(lambda (msg)
</span></span><span style="display:flex;"><span>    (when msg
</span></span><span style="display:flex;"><span>      (string-match-p
</span></span><span style="display:flex;"><span>       <span style="color:#f92672">,</span>(<span style="color:#a6e22e">concat</span> <span style="color:#e6db74">&#34;^&#34;</span> dir-name)
</span></span><span style="display:flex;"><span>       (mu4e-message-field msg :maildir))))
</span></span><span style="display:flex;"><span>     :vars
</span></span><span style="display:flex;"><span>     <span style="color:#f92672">`</span>((user-mail-address    <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>mail-address)
</span></span><span style="display:flex;"><span>       (<span style="color:#a6e22e">user-full-name</span>       <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>full-name)
</span></span><span style="display:flex;"><span>       (mu4e-sent-folder     <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>(<span style="color:#a6e22e">concat</span> dir-name <span style="color:#e6db74">&#34;/Sent&#34;</span>))
</span></span><span style="display:flex;"><span>       (mu4e-drafts-folder   <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>(<span style="color:#a6e22e">concat</span> dir-name <span style="color:#e6db74">&#34;/Drafts&#34;</span>))
</span></span><span style="display:flex;"><span>       (mu4e-trash-folder    <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>(<span style="color:#a6e22e">concat</span> dir-name <span style="color:#e6db74">&#34;/Trash&#34;</span>))
</span></span><span style="display:flex;"><span>       (mu4e-trash-folder    <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>(<span style="color:#a6e22e">concat</span> dir-name <span style="color:#e6db74">&#34;/Starred&#34;</span>))
</span></span><span style="display:flex;"><span>       (mu4e-refile-folder   <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>(<span style="color:#a6e22e">concat</span> dir-name <span style="color:#e6db74">&#34;/Archive&#34;</span>))
</span></span><span style="display:flex;"><span>       (mu4e-compose-signature <span style="color:#f92672">.</span> <span style="color:#f92672">,</span>signature)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e">;;Fixing duplicate UID errors when using mbsync and mu4e</span>
</span></span><span style="display:flex;"><span>(setf mu4e-change-filenames-when-moving <span style="color:#66d9ef">t</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(setf mu4e-maildir-shortcuts
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;/Fastmail/Inbox&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">?f</span>)
</span></span><span style="display:flex;"><span>    (<span style="color:#e6db74">&#34;/Drafts&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">?d</span>)
</span></span><span style="display:flex;"><span>    (<span style="color:#e6db74">&#34;/Sent&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">?s</span>)
</span></span><span style="display:flex;"><span>    (<span style="color:#e6db74">&#34;/Gmail-Account/[Gmail]/All Mail&#34;</span> <span style="color:#f92672">.</span> <span style="color:#e6db74">?g</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(setf mu4e-contexts
</span></span><span style="display:flex;"><span>      (<span style="color:#a6e22e">list</span>
</span></span><span style="display:flex;"><span>       (make-mu4e-context
</span></span><span style="display:flex;"><span>    :name <span style="color:#e6db74">&#34;fastmail&#34;</span>
</span></span><span style="display:flex;"><span>    :match-func
</span></span><span style="display:flex;"><span>    (lambda (msg)
</span></span><span style="display:flex;"><span>      (when msg
</span></span><span style="display:flex;"><span>        (string-prefix-p <span style="color:#e6db74">&#34;/Fastmail&#34;</span> (mu4e-message-field msg :maildir))))
</span></span><span style="display:flex;"><span>    :vars <span style="color:#f92672">&#39;</span>((user-mail-address <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;username@fastmail.com&#34;</span>)
</span></span><span style="display:flex;"><span>        (<span style="color:#a6e22e">user-full-name</span>    <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;User Name&#34;</span>)
</span></span><span style="display:flex;"><span>        (smtpmail-smtp-server <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;smtp.fastmail.com&#34;</span>)
</span></span><span style="display:flex;"><span>        (smtpmail-smtp-service <span style="color:#f92672">.</span> <span style="color:#ae81ff">465</span>)
</span></span><span style="display:flex;"><span>        (smtpmail-stream-type <span style="color:#f92672">.</span> ssl)
</span></span><span style="display:flex;"><span>        (mu4e-drafts-folder  <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;/Drafts&#34;</span>)
</span></span><span style="display:flex;"><span>        (mu4e-sent-folder  <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;/Sent&#34;</span>)
</span></span><span style="display:flex;"><span>        (mu4e-refile-folder  <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;/Archive&#34;</span>)
</span></span><span style="display:flex;"><span>        (mu4e-trash-folder  <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;/Trash&#34;</span>)))
</span></span><span style="display:flex;"><span>        <span style="color:#75715e">;; You can comment out the second account.</span>
</span></span><span style="display:flex;"><span>       (make-mu4e-context
</span></span><span style="display:flex;"><span>    :name <span style="color:#e6db74">&#34;gmail&#34;</span>
</span></span><span style="display:flex;"><span>    :match-func
</span></span><span style="display:flex;"><span>    (lambda (msg)
</span></span><span style="display:flex;"><span>      (when msg
</span></span><span style="display:flex;"><span>        (string-prefix-p <span style="color:#e6db74">&#34;/Gmail-Account&#34;</span> (mu4e-message-field msg :maildir))))
</span></span><span style="display:flex;"><span>    :vars <span style="color:#f92672">&#39;</span>((user-mail-address <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;username@gmail.com&#34;</span>)
</span></span><span style="display:flex;"><span>        (<span style="color:#a6e22e">user-full-name</span>    <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;User Name&#34;</span>)
</span></span><span style="display:flex;"><span>        (smtpmail-smtp-server <span style="color:#f92672">.</span> <span style="color:#e6db74">&#34;smtp.gmail.com&#34;</span>)
</span></span><span style="display:flex;"><span>        (smtpmail-smtp-service <span style="color:#f92672">.</span> <span style="color:#ae81ff">465</span>)
</span></span><span style="display:flex;"><span>        (smtpmail-stream-type <span style="color:#f92672">.</span> ssl)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(setf message-send-mail-function <span style="color:#e6db74">&#39;smtpmail-send-it</span>
</span></span><span style="display:flex;"><span>      mu4e-compose-signature <span style="color:#e6db74">&#34;My Signature&#34;</span>
</span></span><span style="display:flex;"><span>      mu4e-compose-context-policy <span style="color:#e6db74">&#39;ask</span>)
</span></span></code></pre></div><h2 id="extras">Extras</h2>
<h3 id="mu4e-actions">Mu4e actions</h3>
<p>Mu4e actions makes it really simple to work with git patches, this is
an example configuration you may like to use:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setf mu4e-view-actions
</span></span><span style="display:flex;"><span>      (delete-dups
</span></span><span style="display:flex;"><span>       (<span style="color:#a6e22e">append</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">&#39;</span>((<span style="color:#e6db74">&#34;gapply git patches&#34;</span> <span style="color:#f92672">.</span> mu4e-action-git-apply-patch)
</span></span><span style="display:flex;"><span>      (<span style="color:#e6db74">&#34;mgit am patch&#34;</span> <span style="color:#f92672">.</span> mu4e-action-git-apply-mbox)))))
</span></span></code></pre></div><h3 id="sign-your-emails-using-pgp">Sign your emails using pgp</h3>
<p>If you have setup your own pgp key, you may sign automatically all your emails using this hook:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-hook <span style="color:#e6db74">&#39;message-send-hook</span> <span style="color:#e6db74">&#39;mml-secure-message-sign-pgpmime</span>)
</span></span></code></pre></div><p>Take a look at the functions defined for <code>mml-mode-map</code> for more.</p>
]]></content:encoded>
    </item>
    <item>
      <title>Gnosis (γνῶσις) First Release</title>
      <link>https://thanosapollo.org/posts/gnosis-release/</link>
      <pubDate>Tue, 16 Jan 2024 00:00:00 +0200</pubDate>
      <guid>https://thanosapollo.org/posts/gnosis-release/</guid>
      <description>Gnosis (γνῶσις), a spaced repetition system implementation for GNU Emacs</description>
      <content:encoded><![CDATA[<p>Gnosis (γνῶσις) is a <a href="https://en.wikipedia.org/wiki/Spaced_repetition">spaced
repetition</a> system
(SRS) implementation for note taking and self testing, for <a href="https://www.gnu.org/software/emacs/">GNU
Emacs</a>.</p>
<p>Gnosis does not use flashcard type learning, instead it uses a binary
value to rate user input. Meaning you either know the right answer, or
you do not, no rating of your own is involved.</p>
<h2 id="about">About</h2>
<p>On my last post, <a href="http://thanosapollo.org/post/spaced-repetition-software-gripes/">Spaced Repetition Software
Gripes</a>,
I outlined a blueprint for what I consider to be the optimal design of
an SRS, that caters to <strong>my personal</strong> preferences.</p>
<p>So, I&rsquo;ve developed my own SRS, gnosis (γνῶσις), pronounced &ldquo;GNU-sis&rdquo;,
<em>meaning knowledge in Greek</em>. This SRS addresses the concerns that I
previously highlighted. Currently, I have found it to be highly
beneficial and, as a result, I decided to share it with all of you.</p>
<h3 id="differences-with-other-srs">Differences with other SRS</h3>
<p>Gnosis does not implement flashcard type review sessions where the
user rates his own answer on an arbitrary scale. Instead implements
&ldquo;note&rdquo; types that require user input. Some of these note types, like
the <code>MCQ</code> <em>multiple choice question</em>, even allow for simulating
real-life exams.</p>
<p>Unlike other SRS implementations for GNU Emacs, gnosis does not rely
on <code>org-mode</code>, which I&rsquo;ve found not to be an ideal option for a
database replacement. Instead opting for an
<a href="https://www.sqlite.org/index.html">sqlite</a> database with
<a href="https://en.wikipedia.org/wiki/Git">git</a> to track any changes made,
enabling efficient data management, manipulation and data integrity.</p>
<p>Furthermore, since Gnosis is built upon Emacs, with Emacs Lisp, it
offers a convenient and (hopefully) enjoyable experience for
customization according to your individual preferences.</p>
<p>However, one drawback of using Gnosis is that it is not currently
supported on mobile devices, as Emacs has yet to extend its
compatibility to such platforms.</p>
<h2 id="installation">Installation</h2>
<p>You can get gnosis from my personal git server
<a href="https://git.thanosapollo.org/gnosis">here</a> or using this <a href="https://git.sr.ht/~thanosapollo/gnosis">sourcehut
mirror</a>.</p>
<h3 id="straight.el">Straight.el</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(straight-use-package
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#39;</span>(gnosis :type git
</span></span><span style="display:flex;"><span>          :host <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>          :repo <span style="color:#e6db74">&#34;https://git.thanosapollo.org/gnosis&#34;</span>))
</span></span></code></pre></div><h3 id="manual">Manual</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ git clone https://git.thanosapollo.org/gnosis
</span></span></code></pre></div><p><em>Add this to your emacs configuration:</em></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-to-list <span style="color:#e6db74">&#39;load-path</span> <span style="color:#e6db74">&#34;/path/to/gnosis&#34;</span>)
</span></span><span style="display:flex;"><span>(load-file <span style="color:#e6db74">&#34;~/path/to/gnosis.el&#34;</span>)
</span></span><span style="display:flex;"><span>(require <span style="color:#e6db74">&#39;gnosis</span>)
</span></span></code></pre></div><h2 id="adding-notes">Adding notes</h2>
<p>Creating notes for gnosis can be done with a simple
<code>M-x gnosis-add-note</code></p>
<p>Everything is done through the mini-buffer. My personal workflow takes
advantage of that by not really leaving <code>gnosis-add-note</code> prompt until
I finish studying a chapter/section, using
<a href="https://github.com/vedang/pdf-tools">pdf-tools</a> or
<a href="https://depp.brause.cc/nov.el/">nov.el</a>.</p>
<p><em>I think you won&rsquo;t need much guidance on creating notes for any note type, except <code>cloze</code>.</em></p>
<h3 id="creating-cloze-type-notes">Creating cloze type notes</h3>
<p>Cloze type note questions are formatted similarly to Anki&rsquo;s syntax, like so:
&gt; {c1:Cyproheptadine} is a(n) {c2:5-HT2} receptor antagonist used to treat {c2:serotonin syndrome}</p>
<p><em>NOTE</em>: You can also format clozes like Anki if you so prefer; e.g
<code>{{c1::Cyproheptadine}}</code></p>
<ul>
<li>
<p>For each <code>cX</code>-tag there will be created a cloze type note, the above
example creates 2 cloze type notes.</p>
</li>
<li>
<p>Each <code>cX</code> tag can have multiple clozes, but each cloze must be a
<em>UNIQUE</em> word (or a unique combination of words) in given note.</p>
</li>
</ul>
<h2 id="customizing-gnosis-algorithm">Customizing gnosis algorithm</h2>
<h3 id="gnosis-algorithm-interval"><code>gnosis-algorithm-interval</code></h3>
<p>This is a list of 2 numbers, for the first 2 intervals after a
successful review. For example:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq gnosis-algorithm-interval <span style="color:#f92672">&#39;</span>(<span style="color:#ae81ff">1</span> <span style="color:#ae81ff">3</span>))
</span></span></code></pre></div><p>After first successfully reviewing a note, you will see it again
tomorrow, if you successfully review said note again, the next review
will be after 3 days.</p>
<h3 id="gnosis-algorithm-ef"><code>gnosis-algorithm-ef</code></h3>
<p>This is the value of gnosis &ldquo;easiness factor&rdquo;, it&rsquo;s basically a list
that consists of 3 items. The first item is the increase factor, used
to increase the easiness factor upon successful review. Second item
refers to the decrease factor, used to decrease the easiness factor
upon an unsuccessful review. The third item is the (starting) total
easiness factor, used to calculate the next interval.</p>
<p>The basic&rsquo;s of how this is used is that it&rsquo;s being multiplied with the
last interval, e.g if you last reviewed a note 6 days ago, and the
easiness factor (total) of this note is 2.0, your next interval would
be 6 * 2.0 &amp; the next total ef will be 2.0 + increase-factor.</p>
<p>Example configuration:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq gnosis-algorithm-ef <span style="color:#f92672">&#39;</span>(<span style="color:#ae81ff">0.3</span> <span style="color:#ae81ff">0.3</span> <span style="color:#ae81ff">1.3</span>))
</span></span></code></pre></div><h3 id="gnsois-algorithm-ff"><code>gnsois-algorithm-ff</code></h3>
<p>This is the value of gnosis forgetting factor (ff), it needs to be a
floating number below 1. This is used to calculate the next interval
upon an unsuccessful review, by being multiplied with last interval.
If for a note with a value of last-interval of 6 days and a ff of 0.5,
upon an unsuccessful review the next interval will be in 6 * 0.5 days</p>
<p>Example configuration:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(setq gnosis-algorithm-ff <span style="color:#ae81ff">0.5</span>)
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>pcomplete-yay | Extensible completions for yay in eshell</title>
      <link>https://thanosapollo.org/posts/pcomplete-yay/</link>
      <pubDate>Fri, 13 Oct 2023 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/pcomplete-yay/</guid>
      <description>Extensible completions for yay in eshell [Emacs Package]</description>
      <content:encoded><![CDATA[<p>Eshell is my favorite shell, but it&rsquo;s not as polished or well
documented for daily tasks. One such example is using completions for
package managers, like yay, to install/remove packages.</p>
<h2 id="about">About</h2>
<p>I&rsquo;m using eshell more than any other shell lately, but it&rsquo;s lacking in
terms of completions when it comes to other shells.</p>
<p>I&rsquo;ve made this simple package to provide completions for installing &amp;
removing packages using <a href="https://github.com/Jguer/yay">yay</a>.</p>
<p>Eshell provides a seamless integration with the rest of the Emacs
ecosystem &amp; thanks to the integration it has with
<a href="https://codeberg.org/akib/emacs-eat">Eat</a> it has no issue with visual
commands as of now, that previously struggled with. All it&rsquo;s missing is
decent completion features, which I believe we will see more of soon.</p>
<h2 id="installation">Installation</h2>
<p>You can get <code>pcomplete-yay</code> by following the instructions on project&rsquo;s
<a href="https://git.thanosapollo.org/pcomplete-yay/about">git repo</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Setting Firefox to use emacs keybindings</title>
      <link>https://thanosapollo.org/posts/firefox-with-emacs-keybindings/</link>
      <pubDate>Wed, 11 Oct 2023 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/firefox-with-emacs-keybindings/</guid>
      <description>Setting up firefox with emacs keybindings, using vimium.</description>
      <content:encoded><![CDATA[<p>Returning to Firefox from Nyxt, while preserving the Emacs-style workflow and
keybindings.</p>
<h2 id="about">About</h2>
<p>I love Emacs, but it&rsquo;s definitely not a viable alternative to modern
browsers like firefox. The desire to have an &rsquo;emacs-like&rsquo; browser lead
me to use <a href="https://nyxt.atlas.engineer">Nyxt</a>.</p>
<p>Although nyxt is impressive, it has some rough edges and inherent
issues. Furthermore, several websites that utilize cloudflare fail to
function properly with nyxt, leading to an unending verification loop.</p>
<p>Presently, I have chosen to use Firefox with Emacs-like keybindings
through the
<a href="https://addons.mozilla.org/en-US/firefox/addon/vimium-ff">vimiun</a>
extension.</p>
<p><em>Here is a concise guide on replicating this setup.</em></p>
<h3 id="step-i-aboutconfig">Step I: about:config</h3>
<p>First visit <code>about:config</code>.</p>
<p>To enable Emacs keybindings while editing text in Firefox, make the
following changes:</p>
<ul>
<li>Set <code>ui.key.accelKey</code> to <code>18</code></li>
<li>Set <code>ui.key.chromeAccess</code> to <code>0</code></li>
<li>Set <code>devtools.editor.keymap</code> to <code>emacs</code></li>
</ul>
<h3 id="step-ii-gtk-key-theme">Step II: gtk-key-theme</h3>
<p>Now, adjust <code>.config/gtk-3.0/settings.ini</code>, make sure you&rsquo;ve added
<code>gtk-key-theme-name = Emacs</code> It should look something like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>[Settings]
</span></span><span style="display:flex;"><span>.....
</span></span><span style="display:flex;"><span>gtk-key-theme-name = Emacs
</span></span></code></pre></div><h3 id="step-iii-vimium">Step III: Vimium</h3>
<p>Install <a href="https://addons.mozilla.org/en-US/firefox/addon/vimium-ff">vimium</a>.</p>
<p>Go on Vimium&rsquo;s Options page to, <em>by clicking the addon</em>, and adjust
<code>Custom Key Mappings</code>, here&rsquo;s an example setup for Emacs.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>unmapAll # use emacs-style bindings only
</span></span><span style="display:flex;"><span>map &lt;c-n&gt; scrollDown
</span></span><span style="display:flex;"><span>map &lt;c-p&gt; scrollUp
</span></span><span style="display:flex;"><span>map &lt;c-b&gt; goBack
</span></span><span style="display:flex;"><span>map &lt;c-f&gt; goForward
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;. scrollToTop
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;, scrollToBottom
</span></span><span style="display:flex;"><span>map &lt;c-V&gt; scrollFullPageUp
</span></span><span style="display:flex;"><span>map &lt;c-v&gt; scrollFullPageDown
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-r&gt; reload
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;k removeTab
</span></span><span style="display:flex;"><span>map &lt;c-c&gt;&lt;c-u&gt; copyCurrentUrl
</span></span><span style="display:flex;"><span>map &lt;c-c&gt;&lt;c-l&gt; LinkHints.activateModeToCopyLinkUrl
</span></span><span style="display:flex;"><span>map &lt;c-c&gt;&lt;c-o&gt; openCopiedUrlInCurrentTab
</span></span><span style="display:flex;"><span>map &lt;c-c&gt;&lt;c-O&gt; openCopiedUrlInNewTab
</span></span><span style="display:flex;"><span>map &lt;c-c&gt;&lt;c-i&gt; enterInsertMode
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-f&gt; LinkHints.activateMode
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-F&gt; LinkHints.activateModeToOpenInNewForegroundTab
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;a-f&gt; LinkHints.activateModeWithQueue
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;f LinkHints.activateModeToOpenInNewTab
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-d&gt; Vomnibar.activate
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-D&gt; Vomnibar.activateInNewTab
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;b Vomnibar.activateTabSelection
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-b&gt; Vomnibar.activateBookmarks
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-B&gt; Vomnibar.activateBookmarksInNewTab
</span></span><span style="display:flex;"><span>map &lt;c-@&gt; Marks.activateCreateMode
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;&lt;c-@&gt; Marks.activateGotoMode
</span></span><span style="display:flex;"><span>map &lt;c-s&gt; enterFindMode
</span></span><span style="display:flex;"><span>map &lt;c-S&gt; performFind
</span></span><span style="display:flex;"><span>map &lt;c-r&gt; performBackwardsFind
</span></span><span style="display:flex;"><span>map &lt;c-R&gt; performBackwardsFind
</span></span><span style="display:flex;"><span>map &lt;c-c&gt;b previousTab
</span></span><span style="display:flex;"><span>map &lt;c-c&gt;f nextTab
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;4 duplicateTab
</span></span><span style="display:flex;"><span>map &lt;c-g&gt;&lt;c-r&gt; restoreTab
</span></span><span style="display:flex;"><span>map &lt;c-x&gt;5 moveTabToNewWindow
</span></span><span style="display:flex;"><span>map &lt;c-g&gt;&lt;c-p&gt; togglePinTab
</span></span><span style="display:flex;"><span>map &lt;a-B&gt; moveTabLeft
</span></span><span style="display:flex;"><span>map &lt;a-F&gt; moveTabRight
</span></span><span style="display:flex;"><span>map &lt;c-h&gt; showHelp
</span></span></code></pre></div><p>You can find a complete vimium configuration that I&rsquo;m using in my
<a href="https://git.thanosapollo.org/dotfiles/tree/vimium-options.json">dotfiles
repo</a></p>
<h2 id="related-content">Related content</h2>
<ul>
<li><a href="https://github.com/raamdev/vimium">Raamdev vimium emacs configuration</a></li>
<li><a href="https://github.com/bwachter/emacs-keybinding">emacs-keybinding addon</a> <em>I do not recommend using this addon</em></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <title>yeetube | Emacs Front-End for YouTube (blog)</title>
      <link>https://thanosapollo.org/posts/yeetube/</link>
      <pubDate>Wed, 20 Sep 2023 00:00:00 +0300</pubDate>
      <guid>https://thanosapollo.org/posts/yeetube/</guid>
      <description>Creating a front-end to play YouTube videos with Emacs</description>
      <content:encoded><![CDATA[<p>To learn elisp I decided to work on a project that I&rsquo;ve felt was
missing on the GNU Emacs ecosystem, a direct front-end for YouTube.</p>
<p><strong>Update 2024-02-26</strong>: This is an old blog post from when I started working on this
project. Check out the <a href="/projects/yeetube/">Project&rsquo;s Page</a> for
up-to-date information.</p>
<blockquote>
<p>This package does not use any kind of an API, just parses html &amp;
json using regex.</p>
</blockquote>
<h2 id="motivation">Motivation</h2>
<p>I simple wanted to learn elisp, and decided to not watch any youtube
content unless it&rsquo;s inside emacs. This way I also saved a lot of time
that I&rsquo;d otherwise waste watching random youtube videos.</p>
<p>Watching youtube through <a href="https://youtube.com">youtube.com</a> is way too
distracting, the sites purpose is to keep you hooked with recommended
videos that do the bare minimum to keep you engaged. Not to mention
that the platform is basically proprietary spyware.</p>
<p>Despite that, many academics decide to upload their videos and even
lectures there, so other than entertainment it&rsquo;s a valuable learning
resource.</p>
<h2 id="installation-guide">Installation Guide</h2>
<p><a href="https://git.thanosapollo.org/yeetube">Project&rsquo;s repo</a></p>
<p>You can install yeetube via <a href="https://melpa.org/#/yeetube">MELPA</a></p>
<h3 id="straight.el">Straight.el</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(straight-use-package
</span></span><span style="display:flex;"><span> <span style="color:#f92672">&#39;</span>(yeetube :type git
</span></span><span style="display:flex;"><span>           :host <span style="color:#66d9ef">nil</span>
</span></span><span style="display:flex;"><span>           :repo <span style="color:#e6db74">&#34;https://git.thanosapollo.org/yeetube&#34;</span>))
</span></span></code></pre></div><h3 id="manual">Manual</h3>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-shell" data-lang="shell"><span style="display:flex;"><span>$ git clone https://git.thanosapollo.org/yeetube
</span></span></code></pre></div><p>Add this to your emacs configuration</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-emacs-lisp" data-lang="emacs-lisp"><span style="display:flex;"><span>(add-to-list <span style="color:#e6db74">&#39;load-path</span> <span style="color:#e6db74">&#34;/path/to/yeetube&#34;</span>)
</span></span><span style="display:flex;"><span>(load-file <span style="color:#e6db74">&#34;~/path/to/yeetube.el&#34;</span>)
</span></span></code></pre></div>]]></content:encoded>
    </item>
  </channel>
</rss>
