<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
        <title><![CDATA[Rahul's Blog | Emacs | RSS Feed]]></title>
        <description><![CDATA[Welcome to Rahul's Blog Emacs posts!]]></description>
        <link>https://rahuljuliato.com</link>
        <image>
            <url>https://avatars.githubusercontent.com/u/16169950?s=400&amp;u=e79b2220a9b9edfe6bd2a92e709d63d7bf97be72</url>
            <title>Rahul&apos;s Blog | Emacs | RSS Feed</title>
            <link>https://rahuljuliato.com</link>
        </image>
        <generator>RSS for Node</generator>
        <lastBuildDate>Fri, 24 Apr 2026 23:31:54 GMT</lastBuildDate>
        <atom:link href="https://rahuljuliato.com/rss-emacs.xml" rel="self" type="application/rss+xml"/>
        <pubDate>Fri, 24 Apr 2026 23:31:43 GMT</pubDate>
        <copyright><![CDATA[All rights reserved 2026]]></copyright>
        <item>
            <title><![CDATA[Getting Emacs proced.el to Show CPU and Memory on macOS]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>I have used the <code>proced.el</code> package in Emacs on Linux for years. It is
my go-to "ps as a buffer". A nicely formatted, colorized listing of
every running process, with auto-update and tree view. I use it far
more often than <code>top</code>, <code>htop</code>, or similar tools.</p>
<p>But on macOS I noticed something important is missing: no CPU or
memory columns.</p>
<p>The reason lives in Emacs itself, since <code>proced.el</code> does asks the C
function <code>system_process_attributes</code> in <code>src/sysdep.c</code> for a plist of
fields per PID. On Linux that function pulls <code>%CPU</code> and <code>%Mem</code> out of
<code>/proc/*/stat</code>. On the BSDs and Windows it computes them from the
native APIs. On Darwin, though, the implementation simply never fills
in <code>pcpu</code> or <code>pmem</code>, even though it already calls <code>proc_pidinfo</code> for
things like <code>vsize</code> and <code>rss</code>. The data is reachable through
<code>proc_pid_rusage</code>, <code>task_info</code>, and <code>sysctl hw.memsize</code>, it just is
not wired up. So <code>proced</code> has nothing to show in those columns. Maybe
a patch idea for later? (Edit: I did proposed one possible solution
for this problem, hopefully done the "right way":
<a href="https://debbugs.gnu.org/cgi/bugreport.cgi?bug=80898">here</a>).</p>
<p>I wanted to figure it out if I could somehow fix it on the lisp side
of the equation. It turned out to be a fun Emacs Lisp exercise.</p>
<p>I am sharing this walk-through for <strong>educational purposes</strong>. The point
of breaking the code down step by step is to show how the pieces fit
together. Reading and dissecting code like this is one of the best
ways to learn Emacs Lisp. And even if the Darwin gap eventually gets
patched upstream, this exercise still stands on its own if you want to
understand a bit more about how Emacs works under the hood.</p>
<hr>
<h2>What we aim to achieve</h2>
<p>After this setup, our <code>proced</code> buffer on macOS looks a bit more like
it does on Linux:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown"> PID    %CPU    %Mem    COMMAND
 712     2.4     1.3    /Applications/Safari...
 438     0.8     0.9    /usr/bin/emacs...
  86     0.3     0.2    /Applications/Podman Desktop...</code></pre></div>
<p>The <code>%CPU</code> and <code>%Mem</code> values come from running <code>ps</code> on the system,
cached and refreshed every couple of seconds, all from within Emacs.
Let me walk you through how it works.</p>
<hr>
<h2>My base configuration</h2>
<p>This is my normal <code>proced</code> setup, nothing unusual at all:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> proced
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">nil</span>
  <span class="token lisp-property property">:defer</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:custom</span>
  <span class="token punctuation">(</span><span class="token car">proced-enable-color-flag</span> <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">proced-tree-flag</span> <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">proced-auto-update-flag</span> <span class="token quoted-symbol variable symbol">'visible</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">proced-auto-update-interval</span> <span class="token number">1</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">proced-descend</span> <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">proced-format</span> <span class="token quoted-symbol variable symbol">'medium</span><span class="token punctuation">)</span> <span class="token comment">;; can be changed interactively with `F'</span>
  <span class="token punctuation">(</span><span class="token car">proced-filter</span> <span class="token quoted-symbol variable symbol">'user</span><span class="token punctuation">)</span><span class="token punctuation">)</span>  <span class="token comment">;; can be changed interactively with `f'</span>
</code></pre></div>
<p>This gives me an auto-updating, colorized, tree-view <code>proced</code>. On
Linux it shows <code>%CPU</code> and <code>%Mem</code> out of the box. On macOS the same
config is identical, except for those missing columns.</p>
<hr>
<h2>The core idea</h2>
<p>The approach is straightforward, and I like keeping a clear mental
model of what is going on:</p>
<p>→ Run <code>ps -axo pid=,%cpu=,%mem=</code> to grab the process info.</p>
<p>→ Parse the output and stash it in a hash table keyed by PID.</p>
<p>→ Hook two new attributes (<code>pcpu</code> and <code>pmem</code>) into
<code>proced-custom-attributes</code>.</p>
<p>→ Periodically refresh the hash table with a timer.</p>
<p>It is a bit unorthodox, pulling data externally and caching it by
hand, but it works. And it teaches you a lot about Emacs along the
way, which is our main goal.</p>
<hr>
<h3>Running <code>ps</code> in the background</h3>
<p>We use <code>make-process</code> to run <code>ps</code> asynchronously. The key pieces:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token car">eq</span> system-type <span class="token quoted-symbol variable symbol">'darwin</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defvar</span> <span class="token variable">emacs-solo--proced-ps-cache</span></span> <span class="token punctuation">(</span><span class="token car">make-hash-table</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defvar</span> <span class="token variable">emacs-solo--proced-ps-timer</span></span> <span class="token boolean">nil</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo--proced-ps-do-refresh</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
	<span class="token punctuation">(</span><span class="token car">make-process</span>
	 <span class="token lisp-property property">:name</span> <span class="token string">"proced-ps-refresh"</span>
	 <span class="token lisp-property property">:buffer</span> <span class="token punctuation">(</span><span class="token car">generate-new-buffer</span> <span class="token string">" *proced-ps-temp*"</span><span class="token punctuation">)</span>
	 <span class="token lisp-property property">:command</span> <span class="token punctuation">'(</span><span class="token string">"env"</span> <span class="token string">"LC_ALL=C"</span> <span class="token string">"ps"</span> <span class="token string">"-axo"</span> <span class="token string">"pid=,%cpu=,%mem="</span><span class="token punctuation">)</span>
	 <span class="token lisp-property property">:noquery</span> <span class="token boolean">t</span>
	 <span class="token lisp-property property">:sentinel</span>
	 <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">proc</span> <span class="token argument variable">_event</span></span><span class="token punctuation">)</span></span>
	   <span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token car">eq</span> <span class="token punctuation">(</span><span class="token car">process-status</span> proc<span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'exit</span><span class="token punctuation">)</span>
		 <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">new-cache</span> <span class="token punctuation">(</span><span class="token car">make-hash-table</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">with-current-buffer</span> <span class="token punctuation">(</span><span class="token car">process-buffer</span> proc<span class="token punctuation">)</span>
			 <span class="token punctuation">(</span><span class="token car">goto-char</span> <span class="token punctuation">(</span><span class="token car">point-min</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			 <span class="token punctuation">(</span><span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token keyword">not</span> <span class="token punctuation">(</span><span class="token car">eobp</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			   <span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token car">looking-at</span>
					  <span class="token punctuation">(</span><span class="token car">rx</span> <span class="token punctuation">(</span><span class="token car">*</span> blank<span class="token punctuation">)</span>
						  <span class="token punctuation">(</span><span class="token car">group</span> <span class="token punctuation">(</span><span class="token car">+</span> digit<span class="token punctuation">)</span><span class="token punctuation">)</span>
						  <span class="token punctuation">(</span><span class="token car">+</span> blank<span class="token punctuation">)</span>
						  <span class="token punctuation">(</span><span class="token car">group</span> <span class="token punctuation">(</span><span class="token car">+</span> <span class="token punctuation">(</span><span class="token car">any</span> digit ?.<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
						  <span class="token punctuation">(</span><span class="token car">+</span> blank<span class="token punctuation">)</span>
						  <span class="token punctuation">(</span><span class="token car">group</span> <span class="token punctuation">(</span><span class="token car">+</span> <span class="token punctuation">(</span><span class="token car">any</span> digit ?.<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				 <span class="token punctuation">(</span><span class="token car">puthash</span>
				  <span class="token punctuation">(</span><span class="token car">string-to-number</span> <span class="token punctuation">(</span><span class="token car">match-string</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token keyword">cons</span> <span class="token punctuation">(</span><span class="token car">string-to-number</span>
						 <span class="token punctuation">(</span><span class="token car">match-string</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
						<span class="token punctuation">(</span><span class="token car">string-to-number</span>
						 <span class="token punctuation">(</span><span class="token car">match-string</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				  new-cache<span class="token punctuation">)</span><span class="token punctuation">)</span>
			   <span class="token punctuation">(</span><span class="token car">forward-line</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">kill-buffer</span> <span class="token punctuation">(</span><span class="token car">process-buffer</span> proc<span class="token punctuation">)</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token keyword">setq</span> emacs-solo--proced-ps-cache new-cache<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		   <span class="token comment">;; ...</span>
</code></pre></div>
<p>A few things to note:</p>
<p>→ <strong><code>LC_ALL=C</code></strong> can affect how <code>ps</code> formats its output. Forcing a <code>C</code>
locale keeps it predictable.</p>
<p>→ <strong>The <code>sentinel</code></strong> only runs once the process has exited. That is
when we know the buffer contains the full output.</p>
<p>→ <strong>The <code>rx</code> regex</strong> I use extended regex for cleaner matching.  There
are three groups: PID (integer), <code>%CPU</code> (float), <code>%Mem</code>
(float). They land in <code>match-string 1</code>, <code>2</code>, and <code>3</code>.</p>
<p>→ <strong><code>puthash</code></strong> stores a cons of CPU and memory as the value,
keyed by the PID.</p>
<p>Why a hash table? Because the <code>proced</code> package calls our custom
attributes per process. A hash lookup by PID is fast, even when you
have hundreds of processes listed.</p>
<hr>
<h3>Simple lookup helpers</h3>
<p>Trivial functions that pull from the cached hash. These are what
<code>proced-custom-attributes</code> will call:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo--proced-pcpu</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">pid</span></span><span class="token punctuation">)</span></span>
  <span class="token punctuation">(</span><span class="token car">car</span> <span class="token punctuation">(</span><span class="token car">gethash</span> pid emacs-solo--proced-ps-cache<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo--proced-pmem</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">pid</span></span><span class="token punctuation">)</span></span>
  <span class="token punctuation">(</span><span class="token car">cdr</span> <span class="token punctuation">(</span><span class="token car">gethash</span> pid emacs-solo--proced-ps-cache<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>That is all they do. <code>car</code> for CPU, <code>cdr</code> for memory.</p>
<hr>
<h3>Hooking it into <code>proced</code></h3>
<p>This is the part that connected everything. The <code>proced</code> package
supports <em>custom attributes</em>, which are lambdas that receive each
row's data and return an additional property.</p>
<p>We also guard every branch with <code>file-remote-p</code> on <code>default-directory</code>.
When <code>proced-show-remote-processes</code> is non-nil and the buffer is
pointing at a remote host, our local <code>ps</code> data is meaningless (and
worse, the cached local PIDs could collide with remote ones). So the
timer does not run, and the custom attributes return nothing:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token car">add-hook</span> <span class="token quoted-symbol variable symbol">'proced-mode-hook</span>
		  <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
			<span class="token punctuation">(</span><span class="token keyword">unless</span> <span class="token punctuation">(</span><span class="token car">file-remote-p</span> default-directory<span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token keyword">setq</span> emacs-solo--proced-ps-timer
					<span class="token punctuation">(</span><span class="token car">run-with-timer</span> <span class="token number">0</span> <span class="token number">2</span>
									<span class="token quoted-symbol variable symbol">#'emacs-solo--proced-ps-do-refresh</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token punctuation">(</span><span class="token keyword">setq</span> proced-custom-attributes
	  <span class="token punctuation">(</span><span class="token car">list</span>
	   <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">attrs</span></span><span class="token punctuation">)</span></span>
		 <span class="token punctuation">(</span><span class="token keyword">unless</span> <span class="token punctuation">(</span><span class="token car">file-remote-p</span> default-directory<span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">when-let*</span>
			   <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">pid</span> <span class="token punctuation">(</span><span class="token car">cdr</span> <span class="token punctuation">(</span><span class="token car">assq</span> <span class="token quoted-symbol variable symbol">'pid</span> attrs<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">v</span> <span class="token punctuation">(</span><span class="token car">emacs-solo--proced-pcpu</span> pid<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			 <span class="token punctuation">(</span><span class="token keyword">cons</span> <span class="token quoted-symbol variable symbol">'pcpu</span> v<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	   <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">attrs</span></span><span class="token punctuation">)</span></span>
		 <span class="token punctuation">(</span><span class="token keyword">unless</span> <span class="token punctuation">(</span><span class="token car">file-remote-p</span> default-directory<span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">when-let*</span>
			   <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">pid</span> <span class="token punctuation">(</span><span class="token car">cdr</span> <span class="token punctuation">(</span><span class="token car">assq</span> <span class="token quoted-symbol variable symbol">'pid</span> attrs<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">v</span> <span class="token punctuation">(</span><span class="token car">emacs-solo--proced-pmem</span> pid<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			 <span class="token punctuation">(</span><span class="token keyword">cons</span> <span class="token quoted-symbol variable symbol">'pmem</span> v<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Two lambdas, one for CPU and one for memory. Each one:</p>
<ol>
<li>Bails out if the buffer is remote.</li>
<li>Extracts the PID from <code>proced</code>'s attribute list (<code>attrs</code>).</li>
<li>Looks up the value in our hash table.</li>
<li>Returns a cons <code>(keyword . value)</code>. That is what tells <code>proced</code>
to add the column.</li>
</ol>
<p>The timer runs every 2 seconds to keep the data fresh. I put the
timer start inside <code>proced-mode-hook</code> because it only makes sense
when the <code>proced</code> buffer is present and local.</p>
<hr>
<h3>Cleaning up</h3>
<p>We do not want to leave timers dangling when the buffer is killed:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token car">add-hook</span> <span class="token quoted-symbol variable symbol">'kill-buffer-hook</span>
			<span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
			  <span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token car">derived-mode-p</span> <span class="token quoted-symbol variable symbol">'proced-mode</span><span class="token punctuation">)</span>
						 <span class="token punctuation">(</span><span class="token car">timerp</span> emacs-solo--proced-ps-timer<span class="token punctuation">)</span><span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">cancel-timer</span> emacs-solo--proced-ps-timer<span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token keyword">setq</span> emacs-solo--proced-ps-timer <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Simple. Cancel the timer when the <code>proced</code> buffer is killed. The guard
checks that the buffer is in <code>proced-mode</code> and that the variable holds
an actual timer to avoid errors on first load.</p>
<hr>
<h2>What we've covered</h2>
<p>Summarizing:</p>
<p>→ <strong><code>proced-custom-attributes</code></strong> is a list of lambdas called per row.
Each lambda receives the row's attributes and returns
<code>(keyword . value)</code>, which then becomes a new column.</p>
<p>→ <strong><code>proced-mode-hook</code></strong> is the right place to hook things that need
to start when the <code>proced</code> buffer appears.</p>
<p>→ <strong><code>run-with-timer</code></strong> is the standard way to do periodic updates in
Emacs. Unlike <code>run-at-time</code>, it returns a timer object you can
cancel.</p>
<p>→ <strong><code>make-process</code></strong> with a <code>sentinel</code> is the idiomatic way to
handle async external commands. The sentinel fires when the
process state changes. In our case we only care about the <code>'exit</code>
state.</p>
<p>→ <strong><code>file-remote-p</code></strong> on <code>default-directory</code> is how you detect that
a buffer is operating on a TRAMP host. Useful whenever your local
hack should not leak into a remote context.</p>
<hr>
<h2>The complete code</h2>
<p>Here is the full block you can copy and paste directly:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> proced
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">nil</span>
  <span class="token lisp-property property">:defer</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:custom</span>
  <span class="token punctuation">(</span><span class="token car">proced-enable-color-flag</span> <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">proced-tree-flag</span> <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">proced-auto-update-flag</span> <span class="token quoted-symbol variable symbol">'visible</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">proced-auto-update-interval</span> <span class="token number">1</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">proced-descend</span> <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">proced-format</span> <span class="token quoted-symbol variable symbol">'medium</span><span class="token punctuation">)</span> <span class="token comment">;; can be changed interactively with `F'</span>
  <span class="token punctuation">(</span><span class="token car">proced-filter</span> <span class="token quoted-symbol variable symbol">'user</span><span class="token punctuation">)</span>   <span class="token comment">;; can be changed interactively with `f'</span>
  <span class="token lisp-property property">:config</span>
  <span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token car">eq</span> system-type <span class="token quoted-symbol variable symbol">'darwin</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defvar</span> <span class="token variable">emacs-solo--proced-ps-cache</span></span> <span class="token punctuation">(</span><span class="token car">make-hash-table</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defvar</span> <span class="token variable">emacs-solo--proced-ps-timer</span></span> <span class="token boolean">nil</span><span class="token punctuation">)</span>

	<span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo--proced-ps-do-refresh</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
	  <span class="token punctuation">(</span><span class="token car">make-process</span>
	   <span class="token lisp-property property">:name</span> <span class="token string">"proced-ps-refresh"</span>
	   <span class="token lisp-property property">:buffer</span> <span class="token punctuation">(</span><span class="token car">generate-new-buffer</span> <span class="token string">" *proced-ps-temp*"</span><span class="token punctuation">)</span>
	   <span class="token lisp-property property">:command</span> <span class="token punctuation">'(</span><span class="token string">"env"</span> <span class="token string">"LC_ALL=C"</span> <span class="token string">"ps"</span> <span class="token string">"-axo"</span>
				  <span class="token string">"pid=,%cpu=,%mem="</span><span class="token punctuation">)</span>
	   <span class="token lisp-property property">:noquery</span> <span class="token boolean">t</span>
	   <span class="token lisp-property property">:sentinel</span>
	   <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">proc</span> <span class="token argument variable">_event</span></span><span class="token punctuation">)</span></span>
		 <span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token car">eq</span> <span class="token punctuation">(</span><span class="token car">process-status</span> proc<span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'exit</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">new-cache</span> <span class="token punctuation">(</span><span class="token car">make-hash-table</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			 <span class="token punctuation">(</span><span class="token car">with-current-buffer</span> <span class="token punctuation">(</span><span class="token car">process-buffer</span> proc<span class="token punctuation">)</span>
			   <span class="token punctuation">(</span><span class="token car">goto-char</span> <span class="token punctuation">(</span><span class="token car">point-min</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			   <span class="token punctuation">(</span><span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token keyword">not</span> <span class="token punctuation">(</span><span class="token car">eobp</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				 <span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token car">looking-at</span>
						<span class="token punctuation">(</span><span class="token car">rx</span> <span class="token punctuation">(</span><span class="token car">*</span> blank<span class="token punctuation">)</span>
							<span class="token punctuation">(</span><span class="token car">group</span> <span class="token punctuation">(</span><span class="token car">+</span> digit<span class="token punctuation">)</span><span class="token punctuation">)</span>
							<span class="token punctuation">(</span><span class="token car">+</span> blank<span class="token punctuation">)</span>
							<span class="token punctuation">(</span><span class="token car">group</span> <span class="token punctuation">(</span><span class="token car">+</span> <span class="token punctuation">(</span><span class="token car">any</span> digit ?.<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
							<span class="token punctuation">(</span><span class="token car">+</span> blank<span class="token punctuation">)</span>
							<span class="token punctuation">(</span><span class="token car">group</span> <span class="token punctuation">(</span><span class="token car">+</span> <span class="token punctuation">(</span><span class="token car">any</span> digit ?.<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				   <span class="token punctuation">(</span><span class="token car">puthash</span>
					<span class="token punctuation">(</span><span class="token car">string-to-number</span> <span class="token punctuation">(</span><span class="token car">match-string</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token keyword">cons</span> <span class="token punctuation">(</span><span class="token car">string-to-number</span>
						   <span class="token punctuation">(</span><span class="token car">match-string</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
						  <span class="token punctuation">(</span><span class="token car">string-to-number</span>
						   <span class="token punctuation">(</span><span class="token car">match-string</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
					new-cache<span class="token punctuation">)</span><span class="token punctuation">)</span>
				 <span class="token punctuation">(</span><span class="token car">forward-line</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			 <span class="token punctuation">(</span><span class="token car">kill-buffer</span> <span class="token punctuation">(</span><span class="token car">process-buffer</span> proc<span class="token punctuation">)</span><span class="token punctuation">)</span>
			 <span class="token punctuation">(</span><span class="token keyword">setq</span> emacs-solo--proced-ps-cache new-cache<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

	<span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo--proced-pcpu</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">pid</span></span><span class="token punctuation">)</span></span>
	  <span class="token punctuation">(</span><span class="token car">car</span> <span class="token punctuation">(</span><span class="token car">gethash</span> pid emacs-solo--proced-ps-cache<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

	<span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo--proced-pmem</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">pid</span></span><span class="token punctuation">)</span></span>
	  <span class="token punctuation">(</span><span class="token car">cdr</span> <span class="token punctuation">(</span><span class="token car">gethash</span> pid emacs-solo--proced-ps-cache<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

	<span class="token punctuation">(</span><span class="token car">add-hook</span> <span class="token quoted-symbol variable symbol">'proced-mode-hook</span>
			  <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
				<span class="token punctuation">(</span><span class="token keyword">unless</span> <span class="token punctuation">(</span><span class="token car">file-remote-p</span> default-directory<span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token keyword">setq</span> emacs-solo--proced-ps-timer
						<span class="token punctuation">(</span><span class="token car">run-with-timer</span> <span class="token number">0</span> <span class="token number">2</span>
										<span class="token quoted-symbol variable symbol">#'emacs-solo--proced-ps-do-refresh</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

	<span class="token punctuation">(</span><span class="token car">add-hook</span> <span class="token quoted-symbol variable symbol">'kill-buffer-hook</span>
			  <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
				<span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token car">derived-mode-p</span> <span class="token quoted-symbol variable symbol">'proced-mode</span><span class="token punctuation">)</span>
						   <span class="token punctuation">(</span><span class="token car">timerp</span> emacs-solo--proced-ps-timer<span class="token punctuation">)</span><span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token car">cancel-timer</span> emacs-solo--proced-ps-timer<span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token keyword">setq</span> emacs-solo--proced-ps-timer <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

	<span class="token punctuation">(</span><span class="token keyword">setq</span> proced-custom-attributes
		  <span class="token punctuation">(</span><span class="token car">list</span>
		   <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">attrs</span></span><span class="token punctuation">)</span></span>
			 <span class="token punctuation">(</span><span class="token keyword">unless</span> <span class="token punctuation">(</span><span class="token car">file-remote-p</span> default-directory<span class="token punctuation">)</span>
			   <span class="token punctuation">(</span><span class="token car">when-let*</span>
				   <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">pid</span> <span class="token punctuation">(</span><span class="token car">cdr</span> <span class="token punctuation">(</span><span class="token car">assq</span> <span class="token quoted-symbol variable symbol">'pid</span> attrs<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token car">v</span> <span class="token punctuation">(</span><span class="token car">emacs-solo--proced-pcpu</span> pid<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				 <span class="token punctuation">(</span><span class="token keyword">cons</span> <span class="token quoted-symbol variable symbol">'pcpu</span> v<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">attrs</span></span><span class="token punctuation">)</span></span>
			 <span class="token punctuation">(</span><span class="token keyword">unless</span> <span class="token punctuation">(</span><span class="token car">file-remote-p</span> default-directory<span class="token punctuation">)</span>
			   <span class="token punctuation">(</span><span class="token car">when-let*</span>
				   <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">pid</span> <span class="token punctuation">(</span><span class="token car">cdr</span> <span class="token punctuation">(</span><span class="token car">assq</span> <span class="token quoted-symbol variable symbol">'pid</span> attrs<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token car">v</span> <span class="token punctuation">(</span><span class="token car">emacs-solo--proced-pmem</span> pid<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				 <span class="token punctuation">(</span><span class="token keyword">cons</span> <span class="token quoted-symbol variable symbol">'pmem</span> v<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>If you end up doing something similar, I would love to hear about it.
What kind of hacks have you built in Emacs?</p>
<hr>
<h2>Other Resources</h2>
<p>If you'd like to learn more about <code>proced.el</code>:</p>
<p>→ <a href="https://laurencewarne.github.io/emacs/programming/2022/12/26/exploring-proced.html">https://laurencewarne.github.io/emacs/programming/2022/12/26/exploring-proced.html</a></p>
<p>→ <a href="https://www.masteringemacs.org/article/displaying-interacting-processes-proced">https://www.masteringemacs.org/article/displaying-interacting-processes-proced</a></p>
<p>→ <a href="https://github.com/emacs-mirror/emacs/blob/master/lisp/proced.el">https://github.com/emacs-mirror/emacs/blob/master/lisp/proced.el</a></p>
<p>If you'd like to learn more about <code>emacs lisp</code>:</p>
<p>→ <a href="https://www.gnu.org/software/emacs/manual/elisp.html">https://www.gnu.org/software/emacs/manual/elisp.html</a></p>
<p>→ <a href="https://protesilaos.com/emacs/emacs-lisp-elements">https://protesilaos.com/emacs/emacs-lisp-elements</a></p>
<hr>
<h3>Edit</h3>
<p><strong>2026-04-24:</strong> Removed useless call to <code>proced-toggle-auto-update</code> as
it is not needed. As noted by <code>the_cecep</code> on reddit.</p>
<p><strong>2026-04-24:</strong> Fixed typo on variable name <code>proced-descend</code> thanks to
<code>Stéphane Marks</code> and <code>morganw</code> for pointing it.</p>
<p><strong>2026-04-24:</strong> Added
<a href="https://debbugs.gnu.org/cgi/bugreport.cgi?bug=80898">https://debbugs.gnu.org/cgi/bugreport.cgi?bug=80898</a> reference.</p>
<p><strong>2026-04-24:</strong> Guarded the Darwin <code>ps</code> timer and the
<code>proced-custom-attributes</code> lambdas with <code>file-remote-p</code> on
<code>default-directory</code>, so they do not run (and do not leak local PID
data) when <code>proced-show-remote-processes</code> is non-nil and the buffer
is on a remote host. Thanks to <code>Stéphane Marks</code> for the suggestion.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/proced-macos</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/proced-macos</guid>
            <pubDate>Thu, 23 Apr 2026 12:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Two Years of Emacs Solo: 35 Modules, Zero External Packages, and a Full Refactor]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>I've been maintaining <a href="https://github.com/LionyxML/emacs-solo">Emacs Solo</a>
for a while now, and I think it's time to talk about what happened in
this latest cycle as the project reaches its two-year mark.</p>
<p>For those who haven't seen it before, Emacs Solo is my daily-driver
Emacs configuration with one strict rule: <strong>no external packages</strong>.
Everything is either built into Emacs or written from scratch by me in
the <code>lisp/</code> directory. No <code>package-install</code>, no <code>straight.el</code>, no
<code>use-package :ensure t</code> pointing at ELPA or MELPA. Just Emacs and
Elisp. I'm keeping this post text only, but if you'd like to check how
<code>Emacs Solo</code> looks and feels, the repository has screenshots and more
details.</p>
<p>Why? Partly because I wanted to understand what Emacs <em>actually</em> gives
you out of the box. Partly because I wanted my config to survive
without breakage across Emacs releases. Partly because I was tired of
dealing with package repositories, mirrors going down in the middle of
the workday, native compilation hiccups, and the inevitable downtime
when something changed somewhere upstream and my job suddenly became
debugging my very long (at the time) config instead of doing actual
work. And partly, honestly, because it's a lot of fun!</p>
<p>This post covers the recent refactor, walks through every section of
the core config, introduces all 35 self-contained extra modules I've
written, and shares some thoughts on what I've learned.</p>
<p>Now, I'll be the first to admit: this config is <em>long</em>. But there's a
principle behind it. I only add features when they are not already in
Emacs core, and when I do, I try to build them myself. That means the
code is sketchy sometimes, sure, but it's <strong>in my control</strong>. I wrote
it, I understand it, and when it breaks, I know exactly where to look.
The refactor I'm about to describe makes this distinction crystal
clear: what is "Emacs core being tweaked" versus what is "a really
hacky outsider I built in because I didn't want to live without it".</p>
<hr>
<h2>The Refactor: Core vs. Extras</h2>
<p>The single biggest change in this cycle was <strong>architectural</strong>. Emacs
Solo used to be one big <code>init.el</code> with everything crammed
together. That worked, but it had problems:</p>
<p>— It was hard to navigate (even with <code>outline-mode</code>)</p>
<p>— If someone wanted just one piece, say my Eshell config or my VC
extensions, they had to dig through thousands of lines</p>
<p>— It was difficult to tell where "configuring built-in Emacs" ended
and "my own hacky reimplementations" began</p>
<p>The solution was clean and simple: <strong>split the config into two layers</strong>.</p>
<h3>Layer 1: <code>init.el</code> (Emacs core configuration)</h3>
<p>This file configures <em>only</em> built-in Emacs packages and features. Every
<code>use-package</code> block in here has <code>:ensure nil</code>, because it's pointing
at something that ships with Emacs. This is pure, standard Emacs
customization.</p>
<p>The idea is that <strong>anyone can read <code>init.el</code>, find a section they like, and
copy-paste it directly into their own config</strong>. No dependencies. No
setup. It just works, because it's configuring things Emacs already
has.</p>
<h3>Layer 2: <code>lisp/</code> (Self-contained extra modules)</h3>
<p>These are my own implementations: replacements for popular external
packages, reimagined as small, focused Elisp files. Each one is a
proper <code>provide</code>/<code>require</code> module. They live under <code>lisp/</code> and are
loaded at the bottom of <code>init.el</code> via a simple block:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token car">add-to-list</span> <span class="token quoted-symbol variable symbol">'load-path</span> <span class="token punctuation">(</span><span class="token car">expand-file-name</span> <span class="token string">"lisp"</span> user-emacs-directory<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">(</span><span class="token keyword">require</span> <span class="token quoted-symbol variable symbol">'emacs-solo-themes</span><span class="token punctuation">)</span>
<span class="token punctuation">(</span><span class="token keyword">require</span> <span class="token quoted-symbol variable symbol">'emacs-solo-movements</span><span class="token punctuation">)</span>
<span class="token punctuation">(</span><span class="token keyword">require</span> <span class="token quoted-symbol variable symbol">'emacs-solo-formatter</span><span class="token punctuation">)</span>
<span class="token comment">;; ... and so on</span>
</code></pre></div>
<p>If you don't want one of them, just comment out the <code>require</code> line.
If you want to use one in your own config, just copy the <code>.el</code> file
into your own <code>lisp/</code> directory and <code>require</code> it. That's it.</p>
<p>This separation made the whole project dramatically easier to
maintain, understand, and share.</p>
<hr>
<h2>The Core: What init.el Configures</h2>
<p>The <code>init.el</code> file is organized into clearly labeled sections (using
outline-mode-friendly headers, so you can fold and navigate them
inside Emacs). Here's every built-in package and feature it touches,
and <em>why</em>.</p>
<h3>General Emacs Settings</h3>
<p>The <code>emacs</code> use-package block is the largest single section. It sets
up sensible defaults that most people would want:</p>
<p>— Key rebindings: <code>M-o</code> for <code>other-window</code>, <code>M-j</code> for
<code>duplicate-dwim</code>, <code>C-x ;</code> for <code>comment-line</code>, <code>C-x C-b</code> for
<code>ibuffer</code></p>
<p>— Window layout commands bound under <code>C-x w</code> (these are upcoming
<strong>Emacs 31</strong> features: <code>window-layout-transpose</code>,
<code>window-layout-rotate-clockwise</code>, <code>window-layout-flip-leftright</code>,
<code>window-layout-flip-topdown</code>)</p>
<p>— Named frames: <code>C-x 5 l</code> to <code>select-frame-by-name</code>, <code>C-x 5 s</code> to
<code>set-frame-name</code>, great for multi-frame workflows</p>
<p>— Disabling <code>C-z</code> (suspend) because accidentally suspending Emacs in
a terminal is never fun</p>
<p>— Sensible file handling: backups and auto-saves in a <code>cache/</code>
directory, <code>recentf</code> for recent files, clean buffer naming with
<code>uniquify</code></p>
<p>— Tree-sitter auto-install and auto-mode (<code>treesit-auto-install-grammar t</code> and <code>treesit-enabled-modes t</code>, both Emacs 31)</p>
<p>— <code>delete-pair-push-mark</code>, <code>kill-region-dwim</code>, <code>ibuffer-human-readable-size</code>, all the small quality-of-life settings coming in Emacs 31</p>
<h3>Abbrev</h3>
<p>A full abbrev-mode setup with a custom placeholder system. You
define abbreviations with <code>###1###</code>, <code>###2###</code> markers, and when the
abbreviation expands, it prompts you to fill in each placeholder
interactively. The <code>###@###</code> marker tells it where to leave point
after expansion. I wrote a <a href="https://www.rahuljuliato.com/posts/abbrev-mode">whole article about it</a>.</p>
<h3>Auth-Source</h3>
<p>Configures <code>auth-source</code> to use <code>~/.authinfo.gpg</code> for credential
storage. Simple but essential if you use Gnus, ERC, or any
network-facing Emacs feature.</p>
<h3>Auto-Revert</h3>
<p>Makes buffers automatically refresh when files change on disk.
Essential for any Git workflow.</p>
<h3>Conf / Compilation</h3>
<p>Configuration file mode settings and a <code>compilation-mode</code> setup
with ANSI color support, so compiler output actually looks readable.</p>
<h3>Window</h3>
<p>Custom window management beyond the defaults, because Emacs window
management out of the box is <em>powerful</em> but needs a little nudging.</p>
<h3>Tab-Bar</h3>
<p>Tab-bar configuration for workspace management. Emacs has had tabs
since version 27, and they're genuinely useful once you configure
them properly.</p>
<h3>RCIRC and ERC</h3>
<p>Two IRC clients, both built into Emacs, both configured. ERC gets
the bigger treatment: logging, scrolltobottom, fill, match
highlighting, and even inline image support (via one of the extra
modules). The Emacs 31 cycle brought nice improvements here too,
including a fix for the scrolltobottom/fill-wrap dependency issue.</p>
<h3>Icomplete</h3>
<p>This is where Emacs Solo's completion story lives. Instead of
reaching for Vertico, Consult, or Helm, I use <code>icomplete-vertical-mode</code>,
which is built into Emacs. With the right settings it's surprisingly
capable:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-delay-completions-threshold <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-compute-delay <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-show-matches-on-no-input <span class="token boolean">t</span><span class="token punctuation">)</span>
<span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-scroll <span class="token boolean">t</span><span class="token punctuation">)</span>
</code></pre></div>
<p>I've also been contributing patches upstream to improve icomplete's
vertical rendering with prefix indicators. Some of those features
are already landing in Emacs 31, which means the polyfill code I
carry today will eventually become unnecessary.</p>
<h3>Dired</h3>
<p>A heavily customized Dired setup. Custom listing switches, human
readable sizes, integration with system openers (<code>open</code> on macOS,
<code>xdg-open</code> on Linux), and the <code>dired-hide-details-hide-absolute-location</code>
option from Emacs 31.</p>
<h3>WDired</h3>
<p>Writable Dired, so you can rename files by editing the buffer
directly.</p>
<h3>Eshell</h3>
<p>This one I'm particularly proud of. Emacs Solo's Eshell
configuration includes:</p>
<p>— <strong>Shared history across all Eshell buffers</strong>: Every Eshell instance
reads from and writes to a merged history, so you never lose a
command just because you ran it in a different buffer</p>
<p>— <strong>Custom prompts</strong>: Multiple prompt styles you can toggle between
with <code>C-c t</code> (full vs. minimal) and <code>C-c T</code> (lighter vs. heavier
full prompt)</p>
<p>— A custom <strong>welcome banner</strong> with keybinding hints</p>
<p>— History size of 100,000 entries with deduplication</p>
<h3>Isearch</h3>
<p>Enhanced incremental search with sensible defaults.</p>
<h3>VC (Version Control)</h3>
<p>This is one of the largest sections and one I'm most invested in.
Emacs's built-in <code>vc</code> is an incredible piece of software that most
people overlook in favor of Magit. I'm not saying it replaces Magit
entirely, but with the right configuration it covers 95% of daily
Git operations:</p>
<p>— <strong>Git add/reset from vc-dir</strong>: <code>S</code> to stage, <code>U</code> to unstage,
directly in the <code>vc-dir</code> buffer. Admittedly, I almost never use this
because I'm now used to the Emacs-style VC workflow: <code>C-x v D</code> or <code>C-x v =</code>, then killing what I don’t want, splitting what isn’t ready yet,
and finishing with <code>C-c C-c</code>. Amending with <code>C-c C-e</code> is
awesome. Still useful once or twice a semester.</p>
<p>— <strong>Git reflog viewer</strong>: A custom <code>emacs-solo/vc-git-reflog</code> command
with ANSI color rendering and navigation keybindings</p>
<p>— <strong>Browse remote</strong>: <code>C-x v B</code> opens your repository on GitHub/GitLab
in a browser; with a prefix argument it jumps to the current
file and line</p>
<p>— <strong>Jump to current hunk</strong>: <code>C-x v =</code> opens the diff buffer scrolled
to the hunk containing your current line</p>
<p>— <strong>Switch between modified files</strong>: <code>C-x C-g</code> lets you
<code>completing-read</code> through all modified/untracked files in the
current repo</p>
<p>— <strong>Pull current branch</strong>: A dedicated command for <code>git pull origin &#x3C;current-branch></code></p>
<p>— Emacs 31 settings: <code>vc-auto-revert-mode</code>,
<code>vc-allow-rewriting-published-history</code>,
<code>vc-dir-hide-up-to-date-on-revert</code></p>
<h3>Smerge / Diff / Ediff</h3>
<p>Merge conflict resolution and diff viewing. Ediff configured to
split windows sanely (side by side, not in a new frame).</p>
<h3>Eldoc</h3>
<p>Documentation at point, with <code>eldoc-help-at-pt</code> (Emacs 31) for
showing docs automatically.</p>
<h3>Eglot</h3>
<p>The LSP client that ships with Emacs. Configured with:</p>
<p>— Auto-shutdown of unused servers</p>
<p>— No event buffer logging (for performance)</p>
<p>— Custom server programs, including <strong>rassumfrassum</strong> for
multiplexing TypeScript + ESLint + Tailwind (I wrote <a href="https://www.rahuljuliato.com/posts/eglot-rass">a whole post
about that</a>)</p>
<p>— Keybindings under <code>C-c l</code> for code actions, rename, format, and
inlay hints</p>
<p>— Automatic enabling for all <code>prog-mode</code> buffers except
<code>emacs-lisp-mode</code> and <code>lisp-mode</code></p>
<h3>Flymake / Flyspell / Whitespace</h3>
<p>Diagnostics, spell checking, and whitespace visualization. All
built-in, all configured.</p>
<h3>Gnus</h3>
<p>The Emacs newsreader and email client. Configured for IMAP/SMTP
usage.</p>
<h3>Man</h3>
<p>Manual page viewer settings.</p>
<h3>Minibuffer</h3>
<p>Fine-tuned minibuffer behavior, including <code>completion-eager-update</code>
from Emacs 31 for faster feedback during completion.</p>
<h3>Newsticker</h3>
<p>RSS/Atom feed reader built into Emacs. Customized with some extras I
build my self for dealing with youtube feeds: thumbnail, transcripts,
sending to AI for a quick summary, and so on.</p>
<h3>Electric-Pair / Paren</h3>
<p>Auto-closing brackets and parenthesis highlighting.</p>
<h3>Proced</h3>
<p>Process manager (like <code>top</code>, but inside Emacs).</p>
<h3>Org</h3>
<p>Org-mode configuration, because of course.</p>
<h3>Speedbar</h3>
<p>File tree navigation in a side window. With Emacs 31, speedbar
gained <code>speedbar-window</code> support, so it can live inside your
existing frame instead of spawning a new one.</p>
<h3>Time</h3>
<p>World clock with multiple time zones, sorted by ISO timestamp
(Emacs 31).</p>
<h3>Uniquify</h3>
<p>Buffer name disambiguation when you have multiple files with the
same name open.</p>
<h3>Which-Key</h3>
<p>Key discovery. Built into Emacs since version 30.</p>
<h3>Webjump</h3>
<p>Quick web searches from the minibuffer. Configured with useful
search engines.</p>
<h3>Language Modes</h3>
<p>Specific configurations for every language I work with, organized
into three areas:</p>
<p><strong>Common Lisp</strong>: <code>inferior-lisp</code> and <code>lisp-mode</code> with custom REPL
interaction, evaluation commands, and a poor man's SLIME/SLY setup
that actually works quite well for basic Common Lisp development.</p>
<p><strong>Non-Tree-sitter</strong>: <code>sass-mode</code> for when tree-sitter grammars
aren't available.</p>
<p><strong>Tree-sitter modes</strong>: <code>ruby-ts-mode</code>, <code>js-ts-mode</code>,
<code>json-ts-mode</code>, <code>typescript-ts-mode</code>, <code>bash-ts-mode</code>,
<code>rust-ts-mode</code>, <code>toml-ts-mode</code>, <code>markdown-ts-mode</code> (Emacs 31),
<code>yaml-ts-mode</code>, <code>dockerfile-ts-mode</code>, <code>go-ts-mode</code>. Each one
configured with tree-sitter grammar sources (which Emacs 31 is
starting to define internally, so those definitions will eventually
become unnecessary).</p>
<hr>
<h2>The Extras: 35 Self-Contained Modules</h2>
<p>This is where the fun really is. Each of these is a complete,
standalone Elisp file that reimplements functionality you'd
normally get from an external package. They're all in <code>lisp/</code> and
can be used independently.</p>
<p>I call them "hacky reimplementations" in the spirit of Emacs Solo:
they're not trying to be feature-complete replacements for their
MELPA counterparts. They're trying to be <strong>small, understandable,
and good enough</strong> for daily use while keeping the config
self-contained.</p>
<h3>emacs-solo-themes</h3>
<p><strong>Custom color themes based on Modus.</strong> Provides several theme
variants: Catppuccin Mocha, Crafters (the default), Matrix, and
GITS. All built on top of Emacs's built-in Modus themes by overriding
faces, so you get the accessibility and completeness of Modus with
different aesthetics.</p>
<h3>emacs-solo-mode-line</h3>
<p><strong>Custom mode-line format and configuration.</strong> A hand-crafted
mode-line that shows exactly what I want: buffer state indicators,
file name, major mode, Git branch, line/column, and nothing else.
No <code>doom-modeline</code>, no <code>telephone-line</code>, just format strings and
faces.</p>
<h3>emacs-solo-movements</h3>
<p><strong>Enhanced navigation and window movement commands.</strong> Extra
commands for moving between windows, resizing splits, and
navigating buffers more efficiently.</p>
<h3>emacs-solo-formatter</h3>
<p><strong>Configurable format-on-save with a formatter registry.</strong> You
register formatters by file extension (e.g., <code>prettier</code> for <code>.tsx</code>,
<code>black</code> for <code>.py</code>), and the module automatically hooks into
<code>after-save-hook</code> to format the buffer. All controllable via a
<code>defcustom</code>, so you can toggle it on and off globally.</p>
<h3>emacs-solo-transparency</h3>
<p><strong>Frame transparency for GUI and terminal.</strong> Toggle transparency on
your Emacs frame. Works on both graphical and terminal Emacs, using
the appropriate mechanism for each.</p>
<h3>emacs-solo-exec-path-from-shell</h3>
<p><strong>Sync shell PATH into Emacs.</strong> The classic macOS problem: GUI Emacs
doesn't inherit your shell's <code>PATH</code>. This module solves it the same
way <code>exec-path-from-shell</code> does, but in about 20 lines instead of a
full package.</p>
<h3>emacs-solo-rainbow-delimiters</h3>
<p><strong>Rainbow coloring for matching delimiters.</strong> Colorizes nested
parentheses, brackets, and braces in different colors so you can
visually match nesting levels. Essential for any Lisp, and helpful
everywhere else.</p>
<h3>emacs-solo-project-select</h3>
<p><strong>Interactive project finder and switcher.</strong> A <code>completing-read</code>
interface for finding and switching between projects, building on
Emacs's built-in <code>project.el</code>.</p>
<h3>emacs-solo-viper-extensions</h3>
<p><strong>Vim-like keybindings and text objects for Viper.</strong> If you use
Emacs's built-in <code>viper-mode</code> (the Vim emulation layer), this
extends it with text objects and additional Vim-like commands. No
Evil needed.</p>
<h3>emacs-solo-highlight-keywords</h3>
<p><strong>Highlight TODO and similar keywords in comments.</strong> Makes <code>TODO</code>,
<code>FIXME</code>, <code>HACK</code>, <code>NOTE</code>, and similar keywords stand out in source
code comments with distinctive faces. A small thing that makes a
big difference.</p>
<h3>emacs-solo-gutter</h3>
<p><strong>Git diff gutter indicators in buffers.</strong> Shows added, modified,
and deleted line indicators in the margin, like <code>diff-hl</code> or
<code>git-gutter</code>. Pure Elisp, using <code>vc-git</code> under the hood.</p>
<h3>emacs-solo-ace-window</h3>
<p><strong>Quick window switching with labels.</strong> When you have three or more
windows, this overlays single-character labels on each window so
you can jump to any one with a single keystroke. A minimal
reimplementation of the popular <code>ace-window</code> package.</p>
<h3>emacs-solo-olivetti</h3>
<p><strong>Centered document layout mode.</strong> Centers your text in the window
with wide margins, like <code>olivetti-mode</code>. Great for prose writing,
Org documents, or any time you want a distraction-free centered
layout.</p>
<h3>emacs-solo-0x0</h3>
<p><strong>Upload text and files to 0x0.st.</strong> Select a region or a file and
upload it to the <a href="https://0x0.st">0x0.st</a> paste service. The URL
is copied to your kill ring. Quick and useful for sharing snippets.</p>
<h3>emacs-solo-sudo-edit</h3>
<p><strong>Edit files as root via TRAMP.</strong> Reopen the current file with root
privileges using TRAMP's <code>/sudo::</code> prefix. A reimplementation of the
<code>sudo-edit</code> package.</p>
<h3>emacs-solo-replace-as-diff</h3>
<p><strong>Multi-file regexp replace with diff preview.</strong> Perform a
search-and-replace across multiple files and see the changes as a
diff before applying them. This one turned out to be more useful
than I expected.</p>
<h3>emacs-solo-weather</h3>
<p><strong>Weather forecast from wttr.in.</strong> Fetches weather data from
<a href="https://wttr.in">wttr.in</a> and displays it in an Emacs buffer.
Because checking the weather shouldn't require leaving Emacs.</p>
<h3>emacs-solo-rate</h3>
<p><strong>Cryptocurrency and fiat exchange rate viewer.</strong> Query exchange
rates and display them inside Emacs. For when you need to know how
much a bitcoin is worth but refuse to open a browser tab.</p>
<h3>emacs-solo-how-in</h3>
<p><strong>Query cheat.sh for programming answers.</strong> Ask "how do I do X in
language Y?" and get an answer from <a href="https://cheat.sh">cheat.sh</a>
displayed right in Emacs. Like <code>howdoi</code> but simpler.</p>
<h3>emacs-solo-ai</h3>
<p><strong>AI assistant integration (Ollama, Gemini, Claude).</strong> Send prompts
to AI models directly from Emacs. Supports multiple backends:
local Ollama, Google Gemini, and Anthropic Claude. The response
streams into a buffer. No <code>gptel</code>, no <code>ellama</code>, just
<code>url-retrieve</code> and some JSON parsing.</p>
<h3>emacs-solo-dired-gutter</h3>
<p><strong>Git status indicators in Dired buffers.</strong> Shows Git status
(modified, added, untracked) next to file names in Dired, using
colored indicators in the margin. Think <code>diff-hl-dired-mode</code> but
self-contained.</p>
<h3>emacs-solo-dired-mpv</h3>
<p><strong>Audio player for Dired using mpv.</strong> Mark audio files in Dired,
hit <code>C-c m</code>, and play them through mpv. You get a persistent mpv
session you can control from anywhere with <code>C-c m</code>. A mini music
player that lives inside your file manager.</p>
<h3>emacs-solo-icons</h3>
<p><strong>File type icon definitions for Emacs Solo.</strong> The icon registry
that maps file extensions and major modes to Unicode/Nerd Font
icons. This is the foundation that the next three modules build on.</p>
<h3>emacs-solo-icons-dired</h3>
<p><strong>File type icons for Dired buffers.</strong> Displays file type icons
next to file names in Dired. Uses Nerd Font glyphs.</p>
<h3>emacs-solo-icons-eshell</h3>
<p><strong>File type icons for Eshell listings.</strong> Same as above but for
Eshell's <code>ls</code> output.</p>
<h3>emacs-solo-icons-ibuffer</h3>
<p><strong>File type icons for ibuffer.</strong> And again for the buffer list.</p>
<h3>emacs-solo-container</h3>
<p><strong>Container management UI for Docker and Podman.</strong> A full
<code>tabulated-list-mode</code> interface for managing containers: list,
start, stop, restart, remove, inspect, view logs, open a shell.
Works with both Docker and Podman. This one started small and grew
into a genuinely useful tool.</p>
<h3>emacs-solo-m3u</h3>
<p><strong>M3U playlist viewer and online radio player.</strong> Open <code>.m3u</code>
playlist files, browse the entries, and play them with mpv. <code>RET</code> to
play, <code>x</code> to stop. Great for online radio streams.</p>
<h3>emacs-solo-clipboard</h3>
<p><strong>System clipboard integration for terminals.</strong> Makes copy/paste
work correctly between Emacs running in a terminal and the system
clipboard. Solves the eternal terminal Emacs clipboard problem.</p>
<h3>emacs-solo-eldoc-box</h3>
<p><strong>Eldoc documentation in a child frame.</strong> Shows eldoc
documentation in a floating child frame near point instead of the
echo area. A reimplementation of the <code>eldoc-box</code> package.</p>
<h3>emacs-solo-khard</h3>
<p><strong>Khard contacts browser.</strong> Browse and search your
<a href="https://github.com/lucc/khard">khard</a> address book from inside
Emacs. Niche, but if you use khard for contact management, this
is handy.</p>
<h3>emacs-solo-flymake-eslint</h3>
<p><strong>Flymake backend for ESLint.</strong> Runs ESLint as a Flymake checker
for JavaScript/TypeScript files. Disabled by default now that LSP
servers handle ESLint natively, but still available if you prefer
the standalone approach.</p>
<h3>emacs-solo-erc-image</h3>
<p><strong>Inline images in ERC chat buffers.</strong> When someone posts an image
URL in IRC, this fetches and displays the image inline in the ERC
buffer. A small luxury that makes IRC feel more modern.</p>
<h3>emacs-solo-yt</h3>
<p><strong>YouTube search and playback with yt-dlp and mpv.</strong> Search
YouTube from Emacs, browse results, and play videos (or just
audio) through mpv. Because sometimes you need background music
and YouTube is right there.</p>
<h3>emacs-solo-gh</h3>
<p><strong>GitHub CLI interface with transient menu.</strong> A transient-based
menu for the <code>gh</code> CLI tool. Browse issues, pull requests, run
actions, all from a structured Emacs interface without memorizing
<code>gh</code> subcommands.</p>
<hr>
<h2>Emacs 31: Looking Forward</h2>
<p>Throughout the config you'll see comments tagged <code>; EMACS-31</code>
marking features that are coming (or already available on the
development branch). Some highlights:</p>
<p>— <strong>Window layout commands</strong>: <code>window-layout-transpose</code>,
<code>window-layout-rotate-clockwise</code>, and flip commands. Finally,
first-class support for rearranging window layouts</p>
<p>— <strong>Tree-sitter grammar sources defined in modes</strong>: No more
manually specifying <code>treesit-language-source-alist</code> entries for
every language</p>
<p>— <strong><code>markdown-ts-mode</code></strong>: Tree-sitter powered Markdown, built-in</p>
<p>— <strong>Icomplete improvements</strong>: In-buffer adjustment, prefix
indicators, and better vertical rendering</p>
<p>— <strong>Speedbar in-frame</strong>: <code>speedbar-window</code> lets the speedbar live
inside your frame as a normal window</p>
<p>— <strong>VC enhancements</strong>: <code>vc-dir-hide-up-to-date-on-revert</code>,
<code>vc-auto-revert-mode</code>, <code>vc-allow-rewriting-published-history</code></p>
<p>— <strong>ERC fixes</strong>: The scrolltobottom/fill-wrap dependency is finally
resolved</p>
<p>— <strong><code>native-comp-async-on-battery-power</code></strong>: Don't waste battery
on native compilation</p>
<p>— <strong><code>kill-region-dwim</code></strong>: Smart kill-region behavior</p>
<p>— <strong><code>delete-pair-push-mark</code></strong>: Better delete-pair with mark
pushing</p>
<p>— <strong>World clock sorting</strong>: <code>world-clock-sort-order</code> for sensible
timezone display</p>
<p>I tag these not just for my own reference, but so that anyone
reading the config can see exactly which parts will become cleaner
or unnecessary as Emacs 31 stabilizes. Some of the polyfill code
I carry today, particularly around icomplete, exists specifically
because those features haven't landed in a stable release yet.</p>
<hr>
<h2>What I've Learned</h2>
<p>This latest cycle of working on Emacs Solo taught me a few things
worth sharing.</p>
<p><strong>Emacs gives you more than you think.</strong> Every time I set out to
"reimplement" something, I discovered that Emacs already had 70% of
it built in. <code>vc</code> is far more capable than most people realize.
<code>icomplete-vertical-mode</code> is genuinely good. <code>tab-bar-mode</code> is a
real workspace manager. <code>proced</code> is a real process manager. The gap
between "built-in Emacs" and "Emacs with 50 packages" is smaller
than the community often assumes.</p>
<p><strong>Writing your own packages is the best way to learn Elisp.</strong> I
learned more about Emacs Lisp writing <code>emacs-solo-gutter</code> and
<code>emacs-solo-container</code> than I did in years of tweaking other
people's configs. When you have to implement something from
scratch, you're forced to understand <code>overlays</code>, <code>process filters</code>, <code>tabulated-list-mode</code>, <code>transient</code>, <code>child frames</code>,
and all the machinery that packages usually hide from you.</p>
<p><strong>Small is beautiful.</strong> Most of the modules in <code>lisp/</code> are under
200 lines. Some are under 50. They don't try to handle every edge
case. They handle <em>my</em> edge cases, and that's enough. If someone
else needs something different, the code is simple enough to fork
and modify.</p>
<p><strong>Contributing upstream is worth it.</strong> Some of the things I
built as workarounds (like the icomplete vertical prefix indicators)
turned into upstream patches. When you're deep enough in a feature
to build a workaround, you're deep enough to propose a fix.</p>
<hr>
<h2>Conclusion</h2>
<p>Emacs Solo started as a personal challenge: can I have a productive,
modern Emacs setup without installing a single external package?</p>
<p>The answer, after this cycle, is a definitive <strong>yes</strong>.</p>
<p>Is it for everyone? Absolutely not. If you're happy with Doom Emacs or
Spacemacs or your own carefully curated package list, that's
great. Those are excellent choices.</p>
<p>But if you're curious about what Emacs can do on its own, if
you want a config where you understand every line, if you want
something you can hand to someone and say "just drop this into
<code>~/.emacs.d/</code> and it works", then maybe Emacs Solo is worth a
look.</p>
<p>The repository is here:
<a href="https://github.com/LionyxML/emacs-solo">https://github.com/LionyxML/emacs-solo</a></p>
<p>It's been a lot of fun. I learned more in this cycle than in any
previous one. And if anyone out there finds even a single module or
config snippet useful, I'd be happy.</p>
<p>That's the whole point, really. Sharing what works.</p>
<hr>
<h2>Acknowledgements</h2>
<p>None of this exists in a vacuum, and I want to give proper thanks.</p>
<p>First and foremost, to the <strong>Emacs core team</strong>. The people who
maintain and develop GNU Emacs are doing extraordinary work, often
quietly, often thanklessly. Every built-in feature I configure in
<code>init.el</code> is the result of decades of careful engineering. The fact
that Emacs 31 keeps making things <em>better</em> in ways that matter
(tree-sitter integration, icomplete improvements, VC enhancements,
window layout commands) is a testament to how alive this project
is.</p>
<p>While working on Emacs Solo I also had the opportunity to contribute
directly to Emacs itself. I originally wrote <code>markdown-ts-mode</code>,
which was later improved and integrated with the help and review of
Emacs maintainers. I also contributed changes such as aligning
<code>icomplete</code> candidates with point in the buffer (similar to Corfu or
Company) and a few fixes to <code>newsticker</code>.</p>
<p>I'm very grateful for the help, reviews, patience, and guidance from
people like <strong>Eli Zaretskii</strong>, <strong>Yuan Fu</strong>, <strong>Stéphane Marks</strong>, <strong>João
Távora</strong>, and others on the mailing lists.</p>
<p>To the <strong>authors of every package that inspired a module in
<code>lisp/</code></strong>. Even though Emacs Solo doesn't install external
packages, it is deeply influenced by them. <code>diff-hl</code>, <code>ace-window</code>,
<code>olivetti</code>, <code>doom-modeline</code>, <code>exec-path-from-shell</code>, <code>eldoc-box</code>,
<code>rainbow-delimiters</code>, <code>sudo-edit</code>, and many others showed me what
was possible and set the bar for what a good Emacs experience looks
like. Where specific credit is due, it's noted in the source code
itself.</p>
<p>A special thanks to <strong>David Wilson (daviwil) and the System Crafters
community</strong>. David's streams and videos were foundational for me in
understanding how to build an Emacs config from scratch, and the
System Crafters community has been an incredibly welcoming and
knowledgeable group of people. The "Crafters" theme variant in
Emacs Solo exists as a direct nod to that influence.</p>
<p>To <strong>Protesilaos Stavrou (Prot)</strong>, whose work on Modus themes, Denote,
and his thoughtful writing about Emacs philosophy has shaped how I
think about software defaults, accessibility, and keeping things
simple. The fact that Emacs Solo's themes are built on top of Modus
is no coincidence.</p>
<p>And to <strong>Gopar (goparism)</strong>, whose Emacs content and enthusiasm for
exploring Emacs from the ground up resonated deeply with the spirit
of this project. It's encouraging to see others who believe in
understanding the tools we use.</p>
<p>To everyone who I probably forgot to mention, who has opened issues,
suggested features, or just tried Emacs Solo and told me about it:
thank you. Open source is a conversation, and every bit of feedback
makes the project better.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/emacs-solo-two-years</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/emacs-solo-two-years</guid>
            <pubDate>Sun, 08 Mar 2026 12:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Eglot with multiple LSP servers per buffer using rassumfrassum]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>I'll start by admitting something upfront: for a long time, I was
<strong>very vocal about not recommending Eglot</strong> if you were working with a
modern web development stack, especially things like React,
TypeScript, ESLint, Tailwind, Vue, etc. I even said so publicly in
GitHub issues and discussions.</p>
<p>That said, I always <em>liked</em> Eglot.</p>
<p>More than liked, actually. Eglot always felt <strong>closer to Emacs
itself</strong>. So much so that it eventually became part of Emacs core. Its
design philosophy: minimalistic, protocol-driven, no magic UI layers
is very close to my way to tackle Emacs.  In contrast, <code>lsp-mode</code> +
<code>lsp-ui</code> behaves much more like a full-blown IDE, and yes, nothing
wrong with that approach, you can use <code>lsp-mode</code> without the <code>lsp-ui</code>
package, but you know, if I could, I'd rather stay within Emacs
provided capabilities.</p>
<p>The real problem for me was simple:
<strong>I couldn't use all the LSP servers I needed at the same time.</strong></p>
<p>And in modern web development with Eglot, that's not optional anymore 😄.</p>
<hr>
<h2>Intro</h2>
<p>It's been a few years now since LSP servers started absorbing
responsibilities that once belonged exclusively to <em>linters</em>.</p>
<p>Linting today is faster, more precise, and far more
interactive. Diagnostics, quick fixes, refactors, formatting, and even
architectural hints are now part of the LSP ecosystem. Servers can
recommend actions, explain problems, and react to changes in real
time.</p>
<p>Because of that, there's less and less reason to:</p>
<p>• wrap a linter's API into a Flymake backend</p>
<p>• parse CLI output while developing</p>
<p>• reinvent glue code for every tool</p>
<p>The LSP protocol is well documented, standardized, and, at least in
theory, every server speaks the same "language".</p>
<p>As time went on, something else became clear: some linters stopped
being maintained as standalone tools, while <strong>new ones started life as
LSP servers first</strong>. In some ecosystems, the <em>only</em> supported
interface is LSP.</p>
<p>This imposed a brick wall for Eglot usage.</p>
<p>Eglot supports <strong>one server per buffer</strong>. That was fine when "one
server did everything". But today, we often want:</p>
<p>• a language server for semantics and completion</p>
<p>• a linter server for diagnostics and code actions</p>
<p>• a (or some) framework-specific server(s) (Tailwind, Vue, Angular, etc.)</p>
<hr>
<h2>Solutions</h2>
<p>For a long time, João (Eglot's maintainer) collected feedback around
this limitation. Multiple issues, discussions, and experiments circled
around the same idea:</p>
<blockquote>
<p>"How do we support multiple LSP servers per buffer <strong>without turning Eglot into something it isn't</strong>?"</p>
</blockquote>
<p>One important constraint was clear: <strong>Eglot itself should not be overhauled to manage multiple servers internally</strong>.</p>
<p>The proposed solution was elegant: an <strong>external multiplexer</strong>, a tool that looks like <em>one</em> LSP server to the client, but actually
talks to many servers behind the scenes, merging and routing messages
appropriately.</p>
<p>I'll admit that having designed hardware-level mux/demuxes in the past
made me like this "software" idea.</p>
<p>One implementation which came from these discussions is <code>lspx</code>. I
tested it before, and while promising, it wasn't quite mature enough
for my daily workflow at the time.</p>
<p>So João did what he had been suggesting for some time.</p>
<p>He stepped in and built it himself.</p>
<hr>
<h2>What is Rassumfrassum</h2>
<p><code>rassumfrassum</code> is an <strong>LSP multiplexer</strong>, you can check its
repository here:
<a href="https://github.com/joaotavora/rassumfrassum/">https://github.com/joaotavora/rassumfrassum/</a></p>
<p>From the client's perspective (Eglot, Neovim, anything), it behaves
like a single stdio LSP server. Internally, it spawns and manages
<strong>multiple real LSP servers</strong>, routing requests and merging responses.</p>
<p>You start it like this:</p>
<div class="remark-highlight"><pre class="language-sh"><code class="language-sh">rass -- server-a <span class="token punctuation">[</span>params-a<span class="token punctuation">]</span> -- server-b <span class="token punctuation">[</span>params-b<span class="token punctuation">]</span> -- server-c <span class="token punctuation">[</span>params-c<span class="token punctuation">]</span>
</code></pre></div>
<p>Or, using presets, like:</p>
<div class="remark-highlight"><pre class="language-sh"><code class="language-sh">rass python
</code></pre></div>
<p>Behind the scenes, Rassumfrassum:</p>
<p>• forwards requests to all relevant servers</p>
<p>• aggregates diagnostics</p>
<p>• merges code actions and completions</p>
<p>• handles timing, delays, and late responses</p>
<p>• optionally streams diagnostics incrementally</p>
<p>All of this is implemented in Python, with a clear separation between:</p>
<p>• JSON-RPC plumbing</p>
<p>• LSP semantics</p>
<p>• server-specific logic</p>
<p>This is also where Rassumfrassum introduces a <strong>non-standard but
optional streaming diagnostics extension</strong>, which allows multiple
diagnostic sources to coexist without stomping on each other.</p>
<p>See it in action from João's screencapture:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Feglot-rass-01.gif&w=3840&q=75" alt="rassumfrassum"></p>
<hr>
<h2>Bringing it to my React Web Dev workflow</h2>
<p>My day job often involves a lot of <strong>React web development</strong>, from
different repo sizes and ages, and this is where Rassumfrassum becomes
a <em>killer feature</em> for me.</p>
<p>Let's take an example, a typical modern React stack needs, at
minimum (as suggested by NextJS framework I'll present in a example below):</p>
<p>• <code>typescript-language-server</code> (types, navigation, refactors)</p>
<p>• <code>ESLint</code> (diagnostics, fixes)</p>
<p>• <code>tailwindcss-language-server</code> (class completion, validation)</p>
<p>Before this, with Eglot, you had to choose <em>one</em>.</p>
<p>To properly test this, I created a minimal but realistic example
repository you can clone:</p>
<div class="remark-highlight"><pre class="language-sh"><code class="language-sh"><span class="token comment"># **demo_react_ts_eslint_tailwind_app_for_lsp_debug**</span>
<span class="token function">git</span> clone https://github.com/LionyxML/demo_react_ts_eslint_tailwind_app_for_lsp_debug
</code></pre></div>
<p>It's basically this so-called "default" modern React setup:
TypeScript, ESLint, Tailwind.</p>
<p>To make this post not too long, I'm assuming the reader knows about
<code>npm</code>, <code>pnpm</code> and other tools related to the <code>javascript</code> world.</p>
<p>Basically you need to clone the repo and install the app with:</p>
<div class="remark-highlight"><pre class="language-sh"><code class="language-sh"><span class="token function">pnpm</span> <span class="token function">install</span>
</code></pre></div>
<p>And make sure you have the needed LSP servers installed, I did it with:</p>
<div class="remark-highlight"><pre class="language-sh"><code class="language-sh"><span class="token function">pnpm</span> <span class="token function">install</span> <span class="token parameter variable">-g</span> typescript-language-server typescript @tailwindcss/language-server eslint-lsp
</code></pre></div>
<p><strong>Note</strong>: Yep, I know about <code>vscode-eslint-language-server</code> being
newer, but still I had problems with it, <code>eslint-lsp</code> worked, and I'm happy.</p>
<p>After fixing a broken Tailwind server installation on my side (user
error 😄), this setup worked flawlessly with:</p>
<div class="remark-highlight"><pre class="language-sh"><code class="language-sh">rass -- typescript-language-server <span class="token parameter variable">--stdio</span> <span class="token punctuation">\</span>
	 -- eslint-lsp <span class="token parameter variable">--stdio</span> <span class="token punctuation">\</span>
	 -- tailwindcss-language-server <span class="token parameter variable">--stdio</span>
</code></pre></div>
<p>You don't need to run this in your terminal, instead, visit your
project file and fire up Eglot using:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">C-u M-x eglot RET
rass -- typescript-language-server --stdio -- eslint-lsp --stdio -- tailwindcss-language-server --stdio RET</code></pre></div>
<p>This project <code>README</code> provides you with directions on what is expected
from each LSP server to "see". The only relevant file is
<code>app/page.tsx</code>.</p>
<p>Well, I did all that and suddenly, everything was there:</p>
<p>• <strong>Flymake buffer</strong> listing diagnostics from <em>all servers</em></p>
<p>• <strong>Code completion</strong> from both TypeScript and Tailwind</p>
<p>• <strong>Code actions</strong></p>
<p>Fast, responsive, and clean. Here are some other screenshots:</p>
<p>• the example React code with Flymake marking diagnostics on margin
and in-buffer:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Feglot-rass-02.png&w=3840&q=75" alt="demo-02"></p>
<p>• Flymake buffer showing messages from typescript, eslint and tailwind:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Feglot-rass-03.png&w=3840&q=75" alt="demo-03"></p>
<p>• Eldoc showing typescript + eslint warnings while also providing type description:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Feglot-rass-05.png&w=3840&q=75" alt="demo-05"></p>
<p>• Typescript completion:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Feglot-rass-06.png&w=3840&q=75" alt="demo-06"></p>
<p>• Tailwind completion:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Feglot-rass-07.png&w=3840&q=75" alt="demo-07"></p>
<p>• Code actions:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Feglot-rass-04.png&w=3840&q=75" alt="demo-04"></p>
<p>It feels fast. It feels correct. And most importantly: <strong>it feels like
Emacs, not an IDE pretending to be Emacs.</strong></p>
<p>And of course, if everything works for you when firing up Eglot
manually, you can add something like this to your config:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token car">with-eval-after-load</span> <span class="token quoted-symbol variable symbol">'eglot</span>
  <span class="token punctuation">(</span><span class="token car">add-to-list</span>
   <span class="token quoted-symbol variable symbol">'eglot-server-programs</span>
   <span class="token punctuation">'(</span><span class="token punctuation">(</span><span class="token car">tsx-ts-mode</span> typescript-ts-mode<span class="token punctuation">)</span>
	 <span class="token punctuation">.</span> <span class="token punctuation">(</span><span class="token string">"rass"</span>
		<span class="token string">"--"</span>
		<span class="token string">"typescript-language-server"</span> <span class="token string">"--stdio"</span>
		<span class="token string">"--"</span>
		<span class="token string">"eslint-lsp"</span> <span class="token string">"--stdio"</span>
		<span class="token string">"--"</span>
		<span class="token string">"tailwindcss-language-server"</span> <span class="token string">"--stdio"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>A small debugging tip: you can check eglot connections with <code>M-x eglot-list-connections RET</code> and be sure it is running your custom
invocation command.</p>
<hr>
<h2>Conclusion</h2>
<p>I want to sincerely thank <strong>João Távora</strong> for his continuous work for
the Emacs community over the years.</p>
<p>Rassumfrassum solves a long-standing, real-world problem in a way that
respects both:</p>
<p>• the LSP ecosystem</p>
<p>• Eglot's design philosophy</p>
<p>This is still a young project, and there will be bugs. That's
expected. But the foundation is solid, the approach is elegant, and
the impact is huge.</p>
<p>If you were, like me, holding back on Eglot for modern web development
<strong>this changes everything.</strong></p>
<p>Please try it, report issues, and support the project.
This is not just a win for Eglot, it's a win for the entire LSP ecosystem.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/eglot-rassumfrassum</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/eglot-rassumfrassum</guid>
            <pubDate>Thu, 15 Jan 2026 20:44:55 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Composing Text in Emacs: Unicode, Emojis, and the Power of C-x 8]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>One of the things that never stops fascinating me about Emacs is how
deep the rabbit hole goes when your start
exploring... well... anything!</p>
<p>You come for a text editor.</p>
<p>You stay because it quietly turns into a laboratory and eventually the
custom <strong>interface</strong> for your entire computer experience.</p>
<p>Most people associate emojis with mobile keyboards, chat apps, or
graphical pickers. Emacs takes a completely different approach:
<strong>Unicode as a first-class citizen</strong>. And at the center of this
philosophy lives a deceptively simple prefix <code>C-x 8</code>.</p>
<p>Altough not obligatory, In order to explore this feature, try enabling
<code>which-key</code> with <code>M-x which-key-mode RET</code>, then issue <code>C-x 8</code> and wait
for the options.</p>
<p>If you've ever wondered how to <em>compose</em>, <em>combine</em>, and <em>bend
Unicode</em> inside Emacs, this post is for you.</p>
<hr>
<h2><code>C-x 8</code></h2>
<p>In Emacs, <code>C-x 8</code> is the entry point to <strong>character composition</strong>.</p>
<p>It allows you to:</p>
<p>→ Insert Unicode characters by name</p>
<p>→ Compose accented characters manually</p>
<p>→ Combine multiple code points into a single visible glyph</p>
<p>→ Create emoji sequences using <strong>Zero Width Joiners</strong></p>
<p>→ Abuse combining characters in ways that would scare typography purists</p>
<p>This is not about convenience, this is about <strong>control</strong>.</p>
<hr>
<h3>Inserting Unicode by Name</h3>
<p>The most straightforward usage is:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">C-x 8 RET</code></pre></div>
<p>This prompts you for a Unicode character name.</p>
<p>Try typing:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">LATIN SMALL LETTER A WITH ACUTE</code></pre></div>
<p>→ <code>á</code></p>
<p>Or:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">GREEK SMALL LETTER LAMBDA</code></pre></div>
<p>→ <code>λ</code></p>
<p><strong>Tip</strong>: If you have something like <code>vertico-mode</code> or
<code>icomplete-vertical-mode</code> turned ON, you get a preview of your search.</p>
<p>You can also type the code directly, even if Emacs doesn't show it as a preview, like:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">274C</code></pre></div>
<p>Returns:</p>
<p>→ <code>❌</code></p>
<hr>
<h3>Composing Accents Manually (Base + Combining Marks)</h3>
<p>Unicode doesn’t require precomposed characters like <code>á</code> or
<code>ç</code>. Instead, it allows you to build them from <strong>base characters +
combining marks</strong>.</p>
<p>This is where Emacs shines again:</p>
<h4>Using <code>M-x compose-region</code>.</h4>
<p>Start by tiping <code>a</code> and <code>'</code> for example, you'll get:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">a´</code></pre></div>
<p>Mark the region (select) with both chars then and use <code>M-x compose-region RET</code> do get:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">á</code></pre></div>
<p>And even more layered:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">c¸´</code></pre></div>
<p>Becomes:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">ḉ</code></pre></div>
<p>These are not “single characters” in the traditional sense.</p>
<p>They are <strong>Unicode sequences</strong> rendered as one glyph.</p>
<p>If you try to delete from right to left, you'll get it decomposing, like:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">ḉ
ç
c</code></pre></div>
<p><strong>Note:</strong> After I first published this post, <strong>Eli Zaretskii</strong> (Emacs
maintainer) was kind enough to share his critique of this approach.
Here are his remarks (<a href="https://www.reddit.com/r/emacs/comments/1psnudt/comment/nveavzm/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button">original here</a>):</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">The section about composing accents is, in my opinion,
misguided.  Emacs already handles this automatically by
default, without any need to invoke `compose-region`.

The reason the command appeared necessary in the earlier
example is that it used the wrong characters. It should have
used **COMBINING CEDILLA** and **COMBINING ACUTE ACCENT**
instead — which is exactly what the following section does.

I recommend staying away from `compose-region` in Emacs. It
does not fully support all display features and options
(such as bidirectional display), and it may cause problems
in certain corner cases.</code></pre></div>
<hr>
<h4>Combining Characters</h4>
<p>Let’s take a simple letter:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">Z</code></pre></div>
<p>Now, using <code>C-x 8 RET</code>, start adding combining marks:</p>
<div class="remark-highlight"><pre class="language-text"><code class="language-text">COMBINING OGONEK
COMBINING TILDE
COMBINING DOT BELOW
COMBINING CEDILLA</code></pre></div>
<p>→ …repeat as many times as your conscience allows</p>
<p>Result:</p>
<p>→ <code>Ẓ̨̧̧̧̧̧̧̧̧̧̧̧̃</code></p>
<p>This is valid Unicode.</p>
<p>It may render differently depending on font and platform, but Emacs
treats it as a perfectly legitimate text sequence. If you're not
inside Emacs, try copying it into some buffer and/or change fonts.</p>
<p>At this point, hopefully you can see how text stops being "letters"
and starts being <strong>stacked metadata</strong>.</p>
<hr>
<h3>Variation Selector-16 (U+FE0F): Forcing Emoji Presentation</h3>
<p>Not every emoji-looking thing <em>starts</em> as an emoji.</p>
<p>Many Unicode characters exist in a <strong>neutral or text presentation</strong> form.</p>
<p>Whether they render as plain text or as colorful emoji depends on an
invisible hint called a <strong>Variation Selector</strong>.</p>
<p>The most important one is:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">VARIATION SELECTOR-16 (U+FE0F)</code></pre></div>
<p>In Emacs:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">C-x 8 RET VARIATION SELECTOR-16</code></pre></div>
<p>VS16 explicitly tells the renderer:</p>
<blockquote>
<p>"Treat the previous character as an <strong>emoji</strong>, not as text."</p>
</blockquote>
<p>Let's start with this example:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">❤   (HEAVY BLACK HEART)</code></pre></div>
<p>Adding <code>VARIATION SELECTOR-16</code>, we get:</p>
<p>→ <code>❤️  (HEAVY BLACK HEART + VARIATION SELECTOR-16)</code></p>
<p>Same base character.
Different <em>semantic intent</em>.</p>
<p>VS16 doesn’t draw anything.
It <strong>changes meaning</strong>.</p>
<p>Another example, insert the digit:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">1</code></pre></div>
<p>That’s just ASCII text.</p>
<p>Now add:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">COMBINING ENCLOSING KEYCAP</code></pre></div>
<p>Result:</p>
<p>→ <code>1⃣</code></p>
<p>This <em>might</em> look like a keycap, or it might look broken. It
depends on your font.  That’s because we didn’t force emoji
presentation.</p>
<p>Now do it properly:</p>
<p>Sequence:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">1
VARIATION SELECTOR-16
COMBINING ENCLOSING KEYCAP</code></pre></div>
<p>Result:</p>
<p>→ <code>1️⃣</code></p>
<p>Important note: that is <strong>not</strong> one character.</p>
<p>It’s a sequence of <strong>three code points</strong>:</p>
<p>→ <code>1</code> (DIGIT ONE)</p>
<p>→ <code>U+FE0F</code> (VARIATION SELECTOR-16)</p>
<p>→ <code>U+20E3</code> (COMBINING ENCLOSING KEYCAP)</p>
<p>Without VS16, renderers are free to choose a text glyph.
With VS16, you get the emoji version, consistently.</p>
<hr>
<h3>Zero Width Joiner (U+200D): Emoji Glue</h3>
<p>If combining marks alter a single character by adding overlays, the
<strong>Zero Width Joiner (ZWJ)</strong> works at the sequence level, telling the
renderer to treat multiple characters as one visual unit — most notably
in emoji composition.</p>
<p>Unicode code point:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">U+200D</code></pre></div>
<p>In Emacs:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">C-x 8 RET ZERO WIDTH JOINER</code></pre></div>
<p>ZWJ tells the renderer:</p>
<blockquote>
<p>"These characters should be treated as a single semantic unit."</p>
</blockquote>
<p>Here's an example:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">❤  HEAVY BLACK HEART
❤️  HEAVY BLACK HEART + VARIATION SELECTOR 16
❤️‍🔥  HEAVY BLACK HEART + VARIATION SELECTOR 16 + ZERO WIDTH JOINER + FIRE</code></pre></div>
<p>The "flaming heart" is not a single character. It’s a sequence:</p>
<ul>
<li>❤️</li>
<li>ZWJ</li>
<li>🔥</li>
</ul>
<p>Another example is creating "Families" from "Individuals":</p>
<p>This emoji:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">👨‍👩‍👦</code></pre></div>
<p>Actually is the combination of:</p>
<ul>
<li>👨</li>
<li>ZWJ</li>
<li>👩</li>
<li>ZWJ</li>
<li>👦</li>
</ul>
<p>You can add more members to your "family" and change their appearance,
this is only limited by your "font set", meaning some fonts might not
render well an specific combination, but many will.</p>
<p><strong>Note:</strong> After I first published this post, <strong>shipmints</strong>
suggested that you can also create these sequences via <strong>Emacs Lisp</strong>
(<a href="https://www.reddit.com/r/emacs/comments/1psnudt/comment/nvd050q/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button">original
here</a>),
like:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token keyword">concat</span> <span class="token string">"\N{WOMAN}"</span>
		<span class="token string">"\N{<span class="token argument">ZERO</span> <span class="token argument">WIDTH</span> JOINER}"</span>
		<span class="token string">"\N{<span class="token argument">HEAVY</span> <span class="token argument">BLACK</span> HEART}"</span>
		<span class="token string">"\N{<span class="token argument">VARIATION</span> SELECTOR-16}"</span>
		<span class="token string">"\N{<span class="token argument">ZERO</span> <span class="token argument">WIDTH</span> JOINER}"</span>
		<span class="token string">"\N{MAN}"</span>
		<span class="token string">" "</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Result:</p>
<p>→ <code>👩‍❤️‍👨 </code></p>
<hr>
<h3>Inspecting Unicode with <code>C-x =</code> (<code>what-cursor-position</code>)</h3>
<p>Typing Unicode is only half the story.</p>
<p>Understanding <strong>what you actually typed</strong> is the another half.</p>
<p>Lucky us, Emacs users. Just place point over <em>any character</em> and
press:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">C-x =</code></pre></div>
<p>You will have a description of the char in your minibuffer, with
information like:</p>
<p>→ Character name</p>
<p>→ Unicode code point</p>
<p>→ Script</p>
<p>→ Charset</p>
<p>→ How Emacs internally represents it</p>
<p>This alone is already incredibly useful, but wait! There's more!</p>
<hr>
<h3>Deep Inspection: <code>C-u C-x =</code></h3>
<p>Now add the <code>(universal-argument)</code> prefix:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">C-u C-x =</code></pre></div>
<p>This is where things get serious.</p>
<p>For <strong>composed characters and emojis</strong>, Emacs will show:</p>
<p>→ The full Unicode sequence</p>
<p>→ Each individual code point</p>
<p>→ Combining characters</p>
<p>→ Zero Width Joiners</p>
<p>→ Text properties and composition details</p>
<p>This is essential when dealing with:</p>
<p>→ Accents built from combining marks</p>
<p>→ ZWJ emoji sequences</p>
<p>→ “Why does this look right but behave wrong?”</p>
<p>→ Copy/paste weirdness across platforms</p>
<p>Some examples:</p>
<blockquote>
<p><code>C-x =</code> on a simple accented character (<code>á</code>)</p>
</blockquote>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">Char: á (225, #o341, #xe1, file ...) point=7495 of 8976 (83%) column=43</code></pre></div>
<blockquote>
<p><code>C-u C-x =</code> on a simple accented character (<code>á</code>)</p>
</blockquote>
<div class="remark-highlight"><pre class="language-text"><code class="language-text">			 position: 7495 of 9102 (82%), column: 43
			character: á (displayed as á) (codepoint 225, #o341, #xe1)
			  charset: unicode (Unicode (ISO10646))
code point in charset: 0xE1
			   script: latin
			   syntax: w	which means: word
			 category: .:Base, L:Strong L2R, c:Chinese, j:Japanese, l:Latin, v:Viet
			 to input: type &quot;C-x 8 RET e1&quot; or &quot;C-x 8 RET LATIN SMALL LETTER A WITH ACUTE&quot;
		  buffer code: #xC3 #xA1
			file code: #xC3 #xA1 (encoded by coding system utf-8-unix)
			  display: by this font (glyph code):
	ftcrhb:-JB-JetBrainsMono Nerd Font-regular-italic-normal-*-14-*-*-*-m-0-iso10646-1 (#xA4)

Character code properties: customize what to show
  name: LATIN SMALL LETTER A WITH ACUTE
  old-name: LATIN SMALL LETTER A ACUTE
  general-category: Ll (Letter, Lowercase)
  decomposition: (97 769) (&#39;a&#39; &#39;́&#39;)
...</code></pre></div>
<p>This can be specially usefull in our emojis, let's try it on ❤️‍🔥:</p>
<div class="remark-highlight"><pre class="language-text"><code class="language-text">			 position: 8529 of 10012 (85%), column: 61
			character: ❤ (displayed as ❤) (codepoint 10084, #o23544, #x2764)
			  charset: unicode (Unicode (ISO10646))
code point in charset: 0x2764
			   script: symbol
			   syntax: w	which means: word
			 category: .:Base, 5:symbol
			 to input: type &quot;C-x 8 RET 2764&quot; or &quot;C-x 8 RET HEAVY BLACK HEART&quot;
		  buffer code: #xE2 #x9D #xA4
			file code: #xE2 #x9D #xA4 (encoded by coding system utf-8-unix)
			  display: composed to form &quot;❤️‍🔥&quot; (see below)

Composed with the following character(s) &quot;️‍🔥&quot; using this font:
  ftcrhb:-GOOG-Noto Color Emoji-regular-normal-normal-*-14-*-*-*-m-0-iso10646-1
by these glyphs:
  [0 3 10084 1537 17 0 18 13 4 nil]
with these character(s):
  ️ (#xfe0f) VARIATION SELECTOR-16
  ‍ (#x200d) ZERO WIDTH JOINER
  🔥 (#x1f525) FIRE

Character code properties: customize what to show
  name: HEAVY BLACK HEART
  general-category: So (Symbol, Other)
  decomposition: (10084) (&#39;❤&#39;)
 ...</code></pre></div>
<hr>
<h2>Fonts Matter (A Lot)</h2>
<p>One important caveat: <strong>fonts decide how far you can go</strong>.</p>
<p>Some fonts handle combining characters and emoji sequences beautifully.
Others collapse under pressure.</p>
<p>If you see:</p>
<p>→ Misaligned accents</p>
<p>→ Overlapping glyphs</p>
<p>→ Missing emoji components</p>
<p>It’s almost always a font issue, probably not Emacs, not
Unicode.</p>
<p>I'd recommend <code>JetBrainsMono Nerd Font</code> or <code>Maple Mono NF</code>. You can find a lot more fonts on <a href="https://www.nerdfonts.com/">nerd fonts
site</a>, or use my custom
installer script (<a href="/posts/nerd-fonts">post</a>,
<a href="https://github.com/LionyxML/nerd-installer">github</a>).</p>
<hr>
<h2>Final Thoughts</h2>
<p>Once you internalize <code>C-x 8</code>, unicode and emojis stop being
“special”. If you explored it with <code>which-keys</code> as I recommended at
the beginning of this post, you probably saw a lot more than <code>C-x 8 RET</code>, emojis even get the special <code>C-x 8 e e</code> sub-menu for
convenience.</p>
<p>And I hope once you use <code>C-u C-x =</code>, special characters, block non
visible (non printable with your font choice) chars stops being
mysterious.</p>
<p>Unicode is a vast and deeply technical subject, but the goal here
wasn't theory, it was to show how Emacs turns it into something you
can actually use, inspect, and enjoy.</p>
<hr>
<h2>Thanks!</h2>
<p>This is likely my final post for 2025, so it feels like a good moment to
say thank you.</p>
<p>Thank you to everyone who read these posts, sent feedback, pointed out
mistakes, shared them around, or just quietly followed along. This year
was especially fun to write: lots of small discoveries, deep dives into
Emacs internals, and many "oh wow, it already does that?" moments.</p>
<p>Happy hacking!</p>
<hr>
<h3>Edit</h3>
<p><strong>2025-12-28:</strong> Added Eli Zaretskii remarks. Added Shipmints
code suggestion, typo fix and font recommendations.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/unicode-emojis</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/unicode-emojis</guid>
            <pubDate>Sun, 21 Dec 2025 20:44:55 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Crafting Your Own Snippets with Emacs Built-In Abbrev Mode]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>In the world of text editing and programming, templating is a
<strong>superpower</strong>. It saves keystrokes, reduces errors, and lets you
focus on the bigger picture. For Emacs users, battle-tested packages
like <code>yasnippet</code> and <code>tempel</code> are often the go-to solutions, offering
powerful features and extensive libraries.</p>
<p>But what if you're in the mood for a little crafting? What if you want
a solution that's built right into Emacs, requires no third-party
installations, and can be easily copied and pasted into any
configuration?</p>
<p>The all mighty built-in <code>abbrev-mode</code> is there for all of us Emacs
users! In this post, we'll explore how you can leverage this humble,
built-in minor mode to create a powerful, progressive, and deeply
personal (for good or bad) snippet system.</p>
<h2>What is Abbrev Mode?</h2>
<p>At its core, abbrev-mode is a simple expansion system. You define an
"abbreviation" (a short string) and an "expansion" (the text it should
be replaced with). When the mode is active, it can automatically
replace the abbrev with its expansion as you type.</p>
<p>However, I prefer a more deliberate approach. Instead of having
abbrevs expand automatically, I like to trigger them manually with the
command <code>expand-abbrev</code>, which is bound to <code>C-x '</code>. This gives me full
control and avoids unintentional expansions. If you prefer the
automatic method, you can always enable it with <code>M-x abbrev-mode</code>.</p>
<h3>Level 1: Simple Text Replacements</h3>
<p>Let's start with the basics. The simplest use of abbrevs is to replace
a short string with a longer one. This is perfect for things you type
often, like symbols, emojis, or special characters.</p>
<p>Here is a minimal configuration example (full nicer code on the end of
this post):</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> abbrev
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">nil</span>
  <span class="token lisp-property property">:custom</span>
  <span class="token punctuation">(</span><span class="token car">save-abbrevs</span> <span class="token boolean">nil</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:config</span>
  <span class="token punctuation">(</span><span class="token car">define-abbrev-table</span> <span class="token quoted-symbol variable symbol">'global-abbrev-table</span>
	<span class="token punctuation">'(</span><span class="token comment">;; Arrows</span>
	  <span class="token punctuation">(</span><span class="token string">"ra"</span> <span class="token string">"→"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"la"</span> <span class="token string">"←"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"ua"</span> <span class="token string">"↑"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"da"</span> <span class="token string">"↓"</span><span class="token punctuation">)</span>

	  <span class="token comment">;; Emojis for context markers</span>
	  <span class="token punctuation">(</span><span class="token string">"todo"</span>  <span class="token string">"👷 TODO:"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"fixme"</span> <span class="token string">"🔥 FIXME:"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"note"</span>  <span class="token string">"📎 NOTE:"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"hack"</span>  <span class="token string">"👾 HACK:"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"smile"</span>  <span class="token string">"😄"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"party"</span> <span class="token string">"🎉"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"up"</span>  <span class="token string">"☝️"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"applause"</span> <span class="token string">"👏"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"manyapplauses"</span> <span class="token string">"👏👏👏👏👏👏👏👏"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"heart"</span> <span class="token string">"❤️"</span><span class="token punctuation">)</span>

	  <span class="token comment">;; NerdFonts</span>
	  <span class="token punctuation">(</span><span class="token string">"nerdfolder"</span> <span class="token string">" "</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"nerdgit"</span> <span class="token string">""</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"nerdemacs"</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>With these defined, I can type <code>ra</code> and then <code>C-x '</code> to get a <code>→</code>, or
<code>fixme</code> followed by <code>C-x '</code> to get <code>"🔥 FIXME:"</code>. It's simple, fast,
and incredibly useful.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fabbrev-mode-01.gif&w=3840&q=75" alt="abbrev-mode-01"></p>
<h3>Level 2: Running Functions</h3>
<p>What if you need more than just static text? What if you want to
position the cursor in a specific spot after the expansion? Abbrevs
can do that too, by executing an Emacs Lisp function as part of the
expansion.</p>
<p>Let's look at a common use case: creating a Markdown code block and
placing the cursor inside it.</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token comment">;; Markdown</span>
<span class="token punctuation">(</span><span class="token string">"cb"</span> <span class="token string">"```@\n\n```"</span>
 <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span> <span class="token punctuation">(</span><span class="token car">search-backward</span> <span class="token string">"@"</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">delete-char</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token comment">;; ORG</span>
<span class="token punctuation">(</span><span class="token string">"ocb"</span> <span class="token string">"#+BEGIN_<span class="token argument">SRC</span> @\n\n#+END_SRC"</span>
 <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span> <span class="token punctuation">(</span><span class="token car">search-backward</span> <span class="token string">"@"</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">delete-char</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>When I expand <code>cb</code>, it first inserts the string <code>ˋˋˋ @\n\n\ˋˋˋ</code>
. Then, it immediately runs the provided lambda function, which
searches backward for the temporary @ marker, deletes it, and leaves
the point (the cursor) right where I need it, ready to type. Or mabe
we want to do the same for org-mode? No problem, just check <code>ocb</code>.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fabbrev-mode-02.gif&w=3840&q=75" alt="abbrev-mode-02"></p>
<p>You could also make variations of these examples by adding your most
used language to the template, maybe adding comments, and whathever
else you need!</p>
<h3>Level 3: The Big Guns - Interactive Templates</h3>
<p>Now for the really powerful stuff. Simple text replacement is great,
and cursor positioning is even better, but what about true,
interactive templates with placeholders? With a simple helper function
(check for <code>emacs-solo/abbrev--replace-placeholders</code> on the full code
on the bottom of this post), we can make <code>abbrev-mode</code> do just that.</p>
<p>The core of this system is a function that searches for placeholders
like <code>###1###</code>, <code>###2###</code>, and a special cursor marker <code>###@###</code>. It
prompts you in the minibuffer for the value of each placeholder and,
at the end, places the cursor exactly where you told it to.</p>
<p>Here are a few examples that use this function:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token comment">;; part of the `global-abbrev-table'</span>
<span class="token comment">;;</span>
<span class="token comment">;; JS/TS snippets</span>
<span class="token punctuation">(</span><span class="token string">"imp"</span> <span class="token string">"import { ###1### } from '###2###';"</span>
 emacs-solo/abbrev--replace-placeholders<span class="token punctuation">)</span>
<span class="token punctuation">(</span><span class="token string">"fn"</span> <span class="token string">"function ###1### () {\n ###@### ;\n};"</span>
 emacs-solo/abbrev--replace-placeholders<span class="token punctuation">)</span>
<span class="token punctuation">(</span><span class="token string">"clog"</span> <span class="token string">"console.log(\">>> LOG:\", {###@### })"</span>
 emacs-solo/abbrev--replace-placeholders<span class="token punctuation">)</span>
<span class="token punctuation">(</span><span class="token string">"cwarn"</span> <span class="token string">"console.warn(\">>> WARN:\", {###@### })"</span>
 emacs-solo/abbrev--replace-placeholders<span class="token punctuation">)</span>
<span class="token punctuation">(</span><span class="token string">"cerr"</span> <span class="token string">"console.error(\">>> ERR:\", {###@### })"</span>
 emacs-solo/abbrev--replace-placeholders<span class="token punctuation">)</span>
</code></pre></div>
<p>When I expand <code>rfc</code> with <code>C-x '</code>, Emacs first asks me for the value of
<code>###1###</code> (the component name).  Then it asks for <code>###2###</code> (the
initial content). It replaces the placeholders with my input and
creates the full component structure in seconds.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fabbrev-mode-03.gif&w=3840&q=75" alt="abbrev-mode-03"></p>
<h2>The Complete Configuration</h2>
<p>As promised, here is the full use-package declaration that powers this
system. You can copy and paste this directly into your Emacs
configuration to get started.</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> abbrev
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">nil</span>
  <span class="token lisp-property property">:custom</span>
  <span class="token punctuation">(</span><span class="token car">save-abbrevs</span> <span class="token boolean">nil</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:config</span>
  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo/abbrev--replace-placeholders</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
	<span class="token string">"Replace placeholders ###1###, ###2###, ... with minibuffer input.</span>
<span class="token string">If ###@### is found, remove it and place point there at the end."</span>
	<span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">cursor-pos</span> <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token car">save-excursion</span>
		<span class="token punctuation">(</span><span class="token car">goto-char</span> <span class="token punctuation">(</span><span class="token car">point-min</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		<span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">loop</span> <span class="token number">0</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token car">values</span> <span class="token punctuation">(</span><span class="token car">make-hash-table</span> <span class="token lisp-property property">:test</span> <span class="token quoted-symbol variable symbol">'equal</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		  <span class="token punctuation">(</span><span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token car">re-search-forward</span> <span class="token string">"###\\([0-9]+\\|@\\)###"</span> <span class="token boolean">nil</span> <span class="token boolean">t</span><span class="token punctuation">)</span>
			<span class="token punctuation">(</span><span class="token keyword">setq</span> loop <span class="token punctuation">(</span>1+ loop<span class="token punctuation">)</span><span class="token punctuation">)</span>
			<span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">index</span> <span class="token punctuation">(</span><span class="token car">match-string</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				   <span class="token punctuation">(</span><span class="token car">start</span> <span class="token punctuation">(</span><span class="token car">match-beginning</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				   <span class="token punctuation">(</span><span class="token car">end</span> <span class="token punctuation">(</span><span class="token car">match-end</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token keyword">cond</span>
			   <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string=</span> index <span class="token string">"@"</span><span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token keyword">setq</span> cursor-pos start<span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">delete-region</span> start end<span class="token punctuation">)</span><span class="token punctuation">)</span>
			   <span class="token punctuation">(</span><span class="token boolean">t</span>
				<span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">key</span> <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">"###%s###"</span> index<span class="token punctuation">)</span><span class="token punctuation">)</span>
					   <span class="token punctuation">(</span><span class="token car">val</span> <span class="token punctuation">(</span><span class="token keyword">or</span> <span class="token punctuation">(</span><span class="token car">gethash</span> key values<span class="token punctuation">)</span>
								<span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">input</span> <span class="token punctuation">(</span><span class="token car">read-string</span> <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">"Value for %s: "</span> key<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
								  <span class="token punctuation">(</span><span class="token car">puthash</span> key input values<span class="token punctuation">)</span>
								  input<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token car">goto-char</span> start<span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token car">delete-region</span> start end<span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token car">insert</span> val<span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token car">goto-char</span> <span class="token punctuation">(</span><span class="token car">+</span> start <span class="token punctuation">(</span><span class="token car">length</span> val<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token keyword">when</span> cursor-pos
		<span class="token punctuation">(</span><span class="token car">goto-char</span> cursor-pos<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token car">define-abbrev-table</span> <span class="token quoted-symbol variable symbol">'global-abbrev-table</span>
	<span class="token punctuation">'(</span><span class="token comment">;; Arrows</span>
	  <span class="token punctuation">(</span><span class="token string">"ra"</span> <span class="token string">"→"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"la"</span> <span class="token string">"←"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"ua"</span> <span class="token string">"↑"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"da"</span> <span class="token string">"↓"</span><span class="token punctuation">)</span>

	  <span class="token comment">;; Emojis for context markers</span>
	  <span class="token punctuation">(</span><span class="token string">"todo"</span>  <span class="token string">"👷 TODO:"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"fixme"</span> <span class="token string">"🔥 FIXME:"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"note"</span>  <span class="token string">"📎 NOTE:"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"hack"</span>  <span class="token string">"👾 HACK:"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"pinch"</span>  <span class="token string">"🤌"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"smile"</span>  <span class="token string">"😄"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"party"</span> <span class="token string">"🎉"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"up"</span>  <span class="token string">"☝️"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"applause"</span> <span class="token string">"👏"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"manyapplauses"</span> <span class="token string">"👏👏👏👏👏👏👏👏"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"heart"</span> <span class="token string">"❤️"</span><span class="token punctuation">)</span>

	  <span class="token comment">;; NerdFonts</span>
	  <span class="token punctuation">(</span><span class="token string">"nerdfolder"</span> <span class="token string">" "</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"nerdgit"</span> <span class="token string">""</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"nerdemacs"</span> <span class="token string">""</span><span class="token punctuation">)</span>

	  <span class="token comment">;; HTML entities</span>
	  <span class="token punctuation">(</span><span class="token string">"nb"</span> <span class="token string">"&nbsp;"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"lt"</span> <span class="token string">"&lt;"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"gt"</span> <span class="token string">"&gt;"</span><span class="token punctuation">)</span>

	  <span class="token comment">;; Markdown</span>
	  <span class="token punctuation">(</span><span class="token string">"cb"</span> <span class="token string">"```@\n\n```"</span>
	   <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span> <span class="token punctuation">(</span><span class="token car">search-backward</span> <span class="token string">"@"</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">delete-char</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

	  <span class="token comment">;; ORG</span>
	  <span class="token punctuation">(</span><span class="token string">"ocb"</span> <span class="token string">"#+BEGIN_<span class="token argument">SRC</span> @\n\n#+END_SRC"</span>
	   <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span> <span class="token punctuation">(</span><span class="token car">search-backward</span> <span class="token string">"@"</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">delete-char</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"oheader"</span> <span class="token string">"#+TITLE: ###1###\n#+AUTHOR: ###2###\n#+EMAIL: ###3###\n#+OPTIONS: toc:nil\n"</span>
	   emacs-solo/abbrev--replace-placeholders<span class="token punctuation">)</span>

	  <span class="token comment">;; JS/TS snippets</span>
	  <span class="token punctuation">(</span><span class="token string">"imp"</span> <span class="token string">"import { ###1### } from '###2###';"</span>
	   emacs-solo/abbrev--replace-placeholders<span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"fn"</span> <span class="token string">"function ###1### () {\n ###@### ;\n};"</span>
	   emacs-solo/abbrev--replace-placeholders<span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"clog"</span> <span class="token string">"console.log(\">>> LOG:\", { ###@### })"</span>
	   emacs-solo/abbrev--replace-placeholders<span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"cwarn"</span> <span class="token string">"console.warn(\">>> WARN:\", { ###@### })"</span>
	   emacs-solo/abbrev--replace-placeholders<span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"cerr"</span> <span class="token string">"console.error(\">>> ERR:\", { ###@### })"</span>
	   emacs-solo/abbrev--replace-placeholders<span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"afn"</span> <span class="token string">"async function() {\n  \n}"</span>
	   <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span> <span class="token punctuation">(</span><span class="token car">search-backward</span> <span class="token string">"}"</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">forward-line</span> <span class="token number">-1</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">end-of-line</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"ife"</span> <span class="token string">"(function() {\n  \n})();"</span>
	   <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span> <span class="token punctuation">(</span><span class="token car">search-backward</span> <span class="token string">")();"</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">forward-line</span> <span class="token number">-1</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">end-of-line</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"esdeps"</span> <span class="token string">"// eslint-disable-next-line react-hooks/exhaustive-deps"</span>
	   <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span> <span class="token punctuation">(</span><span class="token car">search-backward</span> <span class="token string">")();"</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">forward-line</span> <span class="token number">-1</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">end-of-line</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"eshooks"</span> <span class="token string">"// eslint-disable-next-line react-hooks/rules-of-hooks"</span>
	   <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span> <span class="token punctuation">(</span><span class="token car">search-backward</span> <span class="token string">")();"</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">forward-line</span> <span class="token number">-1</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">end-of-line</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

	  <span class="token comment">;; React/JSX</span>
	  <span class="token punctuation">(</span><span class="token string">"rfc"</span> <span class="token string">"const ###1### = () => {\n  return (\n    &#x3C;div>###2###&#x3C;/div>\n  );\n};"</span>
	   emacs-solo/abbrev--replace-placeholders<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

</code></pre></div>
<h2>Conclusion</h2>
<p><code>abbrev-mode</code> may not be the flashiest tool in the Emacs ecosystem,
but it has something special: <em>it’s yours to shape</em>. With just a
handful of lines of Elisp, you can transform it from a humble text
expander into a personal snippet engine that’s fast, predictable, and
tailored to the way <strong>you</strong> think and write.</p>
<p>By starting small, simple replacements and handy symbols and gradually
layering in cursor control, minibuffer-driven placeholders, and
dynamic templates, you build a system that grows with your
workflow. No external dependencies, no syncing snippet collections
across machines, no black-box magic. Just pure Emacs, bending to your
will.</p>
<p>Whether you stick with this approach or eventually reach for heavier
tools like <code>yasnippet</code> or <code>tempel</code>, I hope this post shows that
sometimes the most powerful solutions are the ones hiding in plain
sight. And with a little crafting, <code>abbrev-mode</code> can become one of the
most quietly transformative parts of your everyday editing.</p>
<p>Happy hacking. And happy expanding!</p>
]]></description>
            <link>https://rahuljuliato.com/posts/abbrev-mode</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/abbrev-mode</guid>
            <pubDate>Fri, 14 Nov 2025 20:44:55 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Creating a Catppuccin-Mocha Theme in Emacs with Modus Themes]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>I have a deep appreciation for both the
<a href="https://github.com/catppuccin/catppuccin">Catppuccin</a> and
<a href="https://github.com/protesilaos/modus-themes">Modus</a> themes. Having contributed
to both projects in the past, I've grown to love their design principles.
Catppuccin's popularity and my preference for a consistent theme across all my
tools make it a natural choice. However, I also admire the clean, core-focused
design of the Modus themes.</p>
<p>This led me to an exciting experiment: what if I could get the best of both
worlds? A Catppuccin-Mocha-like theme, but lighter and built on top of the
rock-solid foundation of the Modus themes. The result is a highly personalized
Emacs setup that feels both familiar and fresh.</p>
<p>Here is the code that makes it all happen:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token heading comment title">;;; ┌──────────────────── THEMES</span>
<span class="token heading comment title">;;; │ Catppuccin Mocha Based Theme (hacked Modus)</span>
<span class="token comment">;;</span>
<span class="token comment">;; This tries to follow: https://github.com/catppuccin/catppuccin/blob/main/docs/style-guide.md</span>
<span class="token comment">;; With the colors from: https://github.com/catppuccin/catppuccin/ (Mocha)</span>
<span class="token punctuation">(</span><span class="token keyword">use-package</span> modus-themes
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">nil</span>
  <span class="token lisp-property property">:defer</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:custom</span>
  <span class="token punctuation">(</span><span class="token car">modus-themes-italic-constructs</span> <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">modus-themes-bold-constructs</span> <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">modus-themes-mixed-fonts</span> <span class="token boolean">nil</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">modus-themes-prompts</span> <span class="token punctuation">'(</span><span class="token car">bold</span> intense<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">modus-themes-common-palette-overrides</span>
   <span class="token punctuation">`(</span><span class="token punctuation">(</span><span class="token car">accent-0</span> <span class="token string">"#89b4fa"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">accent-1</span> <span class="token string">"#89dceb"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-active</span> bg-main<span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-added</span> <span class="token string">"#364144"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-added-refine</span> <span class="token string">"#4A5457"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-changed</span> <span class="token string">"#3e4b6c"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-changed-refine</span> <span class="token string">"#515D7B"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-completion</span> <span class="token string">"#45475a"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-completion-match-0</span> <span class="token string">"#1e1e2e"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-completion-match-1</span> <span class="token string">"#1e1e2e"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-completion-match-2</span> <span class="token string">"#1e1e2e"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-completion-match-3</span> <span class="token string">"#1e1e2e"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-hl-line</span> <span class="token string">"#2a2b3d"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-hover-secondary</span> <span class="token string">"#585b70"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-line-number-active</span> unspecified<span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-line-number-inactive</span> <span class="token string">"#1e1e2e"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-main</span> <span class="token string">"#1e1e2e"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-mark-delete</span> <span class="token string">"#443245"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-mark-select</span> <span class="token string">"#3e4b6c"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-mode-line-active</span> <span class="token string">"#181825"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-mode-line-inactive</span> <span class="token string">"#181825"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-prominent-err</span> <span class="token string">"#443245"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-prompt</span> unspecified<span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-prose-block-contents</span> <span class="token string">"#313244"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-prose-block-delimiter</span> bg-prose-block-contents<span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-region</span> <span class="token string">"#585b70"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-removed</span> <span class="token string">"#443245"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-removed-refine</span> <span class="token string">"#574658"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-tab-bar</span>      <span class="token string">"#1e1e2e"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-tab-current</span>  bg-main<span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">bg-tab-other</span>    <span class="token string">"#1e1e2e"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">border-mode-line-active</span> <span class="token boolean">nil</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">border-mode-line-inactive</span> <span class="token boolean">nil</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">builtin</span> <span class="token string">"#89b4fa"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">comment</span> <span class="token string">"#9399b2"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">constant</span>  <span class="token string">"#f38ba8"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">cursor</span>  <span class="token string">"#f5e0dc"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">date-weekday</span> <span class="token string">"#89b4fa"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">date-weekend</span> <span class="token string">"#fab387"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">docstring</span> <span class="token string">"#a6adc8"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">err</span>     <span class="token string">"#f38ba8"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-active</span> fg-main<span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-completion</span> <span class="token string">"#cdd6f4"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-completion-match-0</span> <span class="token string">"#89b4fa"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-completion-match-1</span> <span class="token string">"#f38ba8"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-completion-match-2</span> <span class="token string">"#a6e3a1"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-completion-match-3</span> <span class="token string">"#fab387"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-heading-0</span> <span class="token string">"#f38ba8"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-heading-1</span> <span class="token string">"#fab387"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-heading-2</span> <span class="token string">"#f9e2af"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-heading-3</span> <span class="token string">"#a6e3a1"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-heading-4</span> <span class="token string">"#74c7ec"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-line-number-active</span> <span class="token string">"#b4befe"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-line-number-inactive</span> <span class="token string">"#7f849c"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-link</span>  <span class="token string">"#89b4fa"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-main</span> <span class="token string">"#cdd6f4"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-mark-delete</span> <span class="token string">"#f38ba8"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-mark-select</span> <span class="token string">"#89b4fa"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-mode-line-active</span> <span class="token string">"#bac2de"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-mode-line-inactive</span> <span class="token string">"#585b70"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-prominent-err</span> <span class="token string">"#f38ba8"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-prompt</span> <span class="token string">"#cba6f7"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-prose-block-delimiter</span> <span class="token string">"#9399b2"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-prose-verbatim</span> <span class="token string">"#a6e3a1"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fg-region</span> <span class="token string">"#cdd6f4"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fnname</span>    <span class="token string">"#89b4fa"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">fringe</span> <span class="token string">"#1e1e2e"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">identifier</span> <span class="token string">"#cba6f7"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">info</span>    <span class="token string">"#94e2d5"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">keyword</span>   <span class="token string">"#cba6f7"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">keyword</span> <span class="token string">"#cba6f7"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">name</span> <span class="token string">"#89b4fa"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">number</span> <span class="token string">"#fab387"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">property</span> <span class="token string">"#89b4fa"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">string</span> <span class="token string">"#a6e3a1"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">type</span>      <span class="token string">"#f9e2af"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">variable</span>  <span class="token string">"#fab387"</span><span class="token punctuation">)</span>
	 <span class="token punctuation">(</span><span class="token car">warning</span> <span class="token string">"#f9e2af"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:config</span>
  <span class="token punctuation">(</span><span class="token car">modus-themes-with-colors</span>
	<span class="token punctuation">(</span><span class="token car">custom-set-faces</span>
	 <span class="token punctuation">`(</span><span class="token car">change-log-acknowledgment</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#b4befe"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">change-log-date</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#a6e3a1"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">change-log-name</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#fab387"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">diff-context</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#89b4fa"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">diff-file-header</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#f5c2e7"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">diff-header</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#89b4fa"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">diff-hunk-header</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#fab387"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">gnus-button</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#8aadf4"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">gnus-group-mail-3</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#8aadf4"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">gnus-group-mail-3-empty</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#8aadf4"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">gnus-header-content</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#7dc4e4"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">gnus-header-from</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#cba6f7"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">gnus-header-name</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#a6e3a1"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">gnus-header-subject</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#8aadf4"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">log-view-message</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#b4befe"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">match</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:background</span> <span class="token string">"#3e5768"</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#cdd6f5"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">modus-themes-search-current</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:background</span> <span class="token string">"#f38ba8"</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#11111b"</span> <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">;; :foreground "#cdd6f4" -- Catppuccin default, not that visible...</span>
	 <span class="token punctuation">`(</span><span class="token car">modus-themes-search-lazy</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:background</span> <span class="token string">"#3e5768"</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#cdd6f5"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>     <span class="token comment">;; :foreground "#cdd6f4" :background "#94e2d5" -- Catppuccin default, not that visible...</span>
	 <span class="token punctuation">`(</span><span class="token car">newsticker-extra-face</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#9399b2"</span> <span class="token lisp-property property">:height</span> <span class="token number">0.8</span> <span class="token lisp-property property">:slant</span> italic<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">newsticker-feed-face</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#f38ba8"</span> <span class="token lisp-property property">:height</span> <span class="token number">1.2</span> <span class="token lisp-property property">:weight</span> bold<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">newsticker-treeview-face</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#cdd6f4"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">newsticker-treeview-selection-face</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:background</span> <span class="token string">"#3e5768"</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#cdd6f5"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">tab-bar</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:background</span> <span class="token string">"#1e1e2e"</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#bac2de"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">tab-bar-tab</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:background</span> <span class="token string">"#1e1e2e"</span> <span class="token lisp-property property">:underline</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">tab-bar-tab-group-current</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:background</span> <span class="token string">"#1e1e2e"</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#bac2de"</span> <span class="token lisp-property property">:underline</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">tab-bar-tab-group-inactive</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:background</span> <span class="token string">"#1e1e2e"</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#9399b2"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">tab-bar-tab-inactive</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:background</span> <span class="token string">"#1e1e2e"</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#a6adc8"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">vc-dir-file</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#89b4fa"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token punctuation">`(</span><span class="token car">vc-dir-header-value</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token splice symbol variable">,c</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#b4befe"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:init</span>
  <span class="token punctuation">(</span><span class="token car">load-theme</span> <span class="token quoted-symbol variable symbol">'modus-vivendi</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>With the cost of a few lines of code over the built-in theme, we now have our
beloved <code>modus-vivendi</code> theme dressed as a nice catppucin-mocha theme.</p>
<p>How it looks?</p>
<p>Some Emacs Lisp Code:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fmodus-catppuccin-01.png&w=3840&q=75" alt="modus-catppuccin-01"></p>
<p>VC-Diff:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fmodus-catppuccin-02.png&w=3840&q=75" alt="modus-catppuccin-02"></p>
<p>Eshell:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fmodus-catppuccin-03.png&w=3840&q=75" alt="modus-catppuccin-03"></p>
<p>Dired:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fmodus-catppuccin-04.png&w=3840&q=75" alt="modus-catppuccin-04"></p>
<p>Some Typescript:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fmodus-catppuccin-05.png&w=3840&q=75" alt="modus-catppuccin-05"></p>
<p>Gnus Mail:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fmodus-catppuccin-06.png&w=3840&q=75" alt="modus-catppuccin-06"></p>
<p>Newsticker:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fmodus-catppuccin-07.png&w=3840&q=75" alt="modus-catppuccin-07"></p>
<p>Some Help Buffer:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fmodus-catppuccin-08.png&w=3840&q=75" alt="modus-catppuccin-08"></p>
<h2>How It Works</h2>
<p>The code is a <code>use-package</code> declaration for the <code>modus-themes</code>. Let's break it
down:</p>
<ul>
<li>
<p><strong><code>:custom</code></strong>: This is where the main customization happens.</p>
<ul>
<li>
<p>We enable italic and bold constructs for better readability.</p>
</li>
<li>
<p>The <code>modus-themes-common-palette-overrides</code> is the heart of our theme. It's
a list of color overrides that map the Modus theme's color variables to the
Catppuccin-Mocha color palette. This is what gives us the Catppuccin look and
feel.</p>
</li>
</ul>
</li>
<li>
<p><strong><code>:config</code></strong>: After the theme is loaded, we use <code>modus-themes-with-colors</code>
to apply some final, specific face customizations for various packages and UI
elements like <code>diff-mode</code>, <code>gnus</code>, and the <code>tab-bar</code>. This allows for
fine-tuning the theme.</p>
</li>
<li>
<p><strong><code>:init</code></strong>: Finally, we load the <code>modus-vivendi-tinted</code> theme.</p>
</li>
</ul>
<h2>Other Catppuccin Flavors?</h2>
<p>Of course, this <em>experiment</em> was limited to the Mocha flavor, but my main goal
was to show you <strong>how</strong> this can be done. Want to try some <code>tokio</code> colors?
Want to create your own theme? Use Modus as a foundation for your creative freedom!</p>
<h2>Conclusion</h2>
<p>This experiment shows that you don’t need to build a theme from scratch to enjoy
a familiar aesthetic in Emacs. By reusing the flexibility of the Modus themes,
you can adapt them to match your favorite palettes, whether Catppuccin, Tokio,
or something entirely your own.</p>
<p>Think of this as a blueprint rather than a finished product: a small example of
how powerful Emacs theming can be when you combine solid foundations with your
own creative touch.</p>
<h3>Edit</h3>
<p><strong>2025-12-10:</strong> Since the release of this post, Protesilaos, the
author of Modus, has started workin on ways for users to derive themes
from Modus by using its internal tools. You can check his release post
here: <a href="https://protesilaos.com/codelog/2025-11-25-emacs-modus-tools-to-generate-complete-palette/">Emacs: new Modus themes tool to generate a complete
palette</a>.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/modus-catppuccin</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/modus-catppuccin</guid>
            <pubDate>Tue, 07 Oct 2025 20:44:55 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Quickly switching between git status files buffers in Emacs]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>When I'm deep into developing a feature, I don't want to think about
whether a file is already open in a buffer, or if I need to search the
whole project to find it.</p>
<p>I just want to jump straight to the files I'm actively working on,
the ones that Git tells me are <strong>modified</strong>, <strong>untracked</strong>, or even
<strong>renamed</strong>.</p>
<p>Emacs already gives us great defaults for different contexts:</p>
<p>➡ <code>C-x b</code> (<code>switch-to-buffer</code>) → jump between open buffers.</p>
<p>➡ <code>C-x p b</code> (<code>project-switch-to-buffer</code>) → jump between buffers in the
current project.</p>
<p>➡ <code>C-x p f</code> (<code>project-find-file</code>) → find any file inside the project.</p>
<p>Each of these has its value and time. But in the middle of a coding
session, when iterating fast on a feature, none of them give me what I
want: a list of just the files I've touched.</p>
<p>That's the itch that led me to write this command.</p>
<h2>The Function and Binding</h2>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo/switch-git-status-buffer</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
  <span class="token string">"Parse git status from an expanded path and switch to a file.</span>
<span class="token string">The completion candidates include the Git status of each file."</span>
  <span class="token punctuation">(</span><span class="token interactive keyword">interactive</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">require</span> <span class="token quoted-symbol variable symbol">'vc-git</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">repo-root</span> <span class="token punctuation">(</span><span class="token car">vc-git-root</span> default-directory<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">not</span> repo-root<span class="token punctuation">)</span>
		<span class="token punctuation">(</span><span class="token keyword">message</span> <span class="token string">"Not inside a Git repository."</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">expanded-root</span> <span class="token punctuation">(</span><span class="token car">expand-file-name</span> repo-root<span class="token punctuation">)</span><span class="token punctuation">)</span>
			 <span class="token punctuation">(</span><span class="token car">command-to-run</span> <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">"git <span class="token argument">-C</span> %s status --porcelain=v1"</span>
									 <span class="token punctuation">(</span><span class="token car">shell-quote-argument</span> expanded-root<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			 <span class="token punctuation">(</span><span class="token car">cmd-output</span> <span class="token punctuation">(</span><span class="token car">shell-command-to-string</span> command-to-run<span class="token punctuation">)</span><span class="token punctuation">)</span>
			 <span class="token punctuation">(</span><span class="token car">target-files</span>
			  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token car">files</span><span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">dolist</span> <span class="token punctuation">(</span><span class="token car">line</span> <span class="token punctuation">(</span><span class="token car">split-string</span> cmd-output <span class="token string">"\n"</span> <span class="token boolean">t</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">nreverse</span> files<span class="token punctuation">)</span><span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token car">></span> <span class="token punctuation">(</span><span class="token car">length</span> line<span class="token punctuation">)</span> <span class="token number">3</span><span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">status</span> <span class="token punctuation">(</span><span class="token car">substring</span> line <span class="token number">0</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
						  <span class="token punctuation">(</span><span class="token car">path-info</span> <span class="token punctuation">(</span><span class="token car">substring</span> line <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
					  <span class="token comment">;; Handle rename specially</span>
					  <span class="token punctuation">(</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token car">string-match</span> <span class="token string">"^R"</span> status<span class="token punctuation">)</span>
						  <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">paths</span> <span class="token punctuation">(</span><span class="token car">split-string</span> path-info <span class="token string">" -> "</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
								 <span class="token punctuation">(</span><span class="token car">new-path</span> <span class="token punctuation">(</span><span class="token car">cadr</span> paths<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
							<span class="token punctuation">(</span><span class="token keyword">when</span> new-path
							  <span class="token punctuation">(</span><span class="token car">push</span> <span class="token punctuation">(</span><span class="token keyword">cons</span> <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">"<span class="token argument">R</span> %s"</span> new-path<span class="token punctuation">)</span> new-path<span class="token punctuation">)</span> files<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
						<span class="token comment">;; Modified or untracked</span>
						<span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token keyword">or</span> <span class="token punctuation">(</span><span class="token car">string-match</span> <span class="token string">"M"</span> status<span class="token punctuation">)</span>
								  <span class="token punctuation">(</span><span class="token car">string-match</span> <span class="token string">"\?\?"</span> status<span class="token punctuation">)</span><span class="token punctuation">)</span>
						  <span class="token punctuation">(</span><span class="token car">push</span> <span class="token punctuation">(</span><span class="token keyword">cons</span> <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">"%s %s"</span> status path-info<span class="token punctuation">)</span> path-info<span class="token punctuation">)</span> files<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		<span class="token punctuation">(</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">not</span> target-files<span class="token punctuation">)</span>
			<span class="token punctuation">(</span><span class="token keyword">message</span> <span class="token string">"No modified or renamed files found."</span><span class="token punctuation">)</span>
		  <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">candidates</span> target-files<span class="token punctuation">)</span>
				 <span class="token punctuation">(</span><span class="token car">selection</span> <span class="token punctuation">(</span><span class="token car">completing-read</span> <span class="token string">"Switch to buffer (Git modified): "</span>
											 <span class="token punctuation">(</span><span class="token car">mapcar</span> <span class="token quoted-symbol variable symbol">#'car</span> candidates<span class="token punctuation">)</span> <span class="token boolean">nil</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			<span class="token punctuation">(</span><span class="token keyword">when</span> selection
			  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">file-path</span> <span class="token punctuation">(</span><span class="token car">cdr</span> <span class="token punctuation">(</span><span class="token car">assoc</span> selection candidates<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token keyword">when</span> file-path
				  <span class="token punctuation">(</span><span class="token car">find-file</span> <span class="token punctuation">(</span><span class="token car">expand-file-name</span> file-path expanded-root<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token punctuation">(</span><span class="token car">global-set-key</span> <span class="token punctuation">(</span><span class="token car">kbd</span> <span class="token string">"C-x C-g"</span><span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'emacs-solo/switch-git-status-buffer</span><span class="token punctuation">)</span>
</code></pre></div>
<p>The command parses <code>git status --porcelain=v1</code>, collects the
interesting files, and offers them through <code>completing-read</code>. This
means it works with whichever completion frontend you already use, and
it switches to the selected file's buffer (opening it first if it
isn't already open).</p>
<h2>Completion in Action</h2>
<p>Here's how it looks in different completion UIs:</p>
<p>➡ <strong>Plain completion buffer</strong>
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fswitch-git-status-buffer-completion.png&w=3840&q=75" alt="completion-example"></p>
<p>➡ <strong>Fido</strong>
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fswitch-git-status-buffer-fido.png&w=3840&q=75" alt="completion-example"></p>
<p>➡ <strong>Fido vertical</strong>
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fswitch-git-status-buffer-fido-vertical.png&w=3840&q=75" alt="completion-example"></p>
<p>➡ <strong>Icomplete vertical</strong>
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fswitch-git-status-buffer-solo-icomplete.png&w=3840&q=75" alt="completion-example"></p>
<p>➡ <strong>Vertico</strong>
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fswitch-git-status-buffer-vertico.png&w=3840&q=75" alt="completion-example"></p>
<p>No matter which you prefer, you get a filtered list of just the files that matter right now.</p>
<h2>Why emacs-solo?</h2>
<p>This command is part of my
<a href="https://github.com/LionyxML/emacs-solo"><strong>emacs-solo</strong></a> project, a
collection of Emacs enhancements that stick to built-in tools and
minimal glue code.</p>
<p>The goal is to show how far we can go without depending on a huge
package ecosystem, while still making day-to-day workflows smoother.</p>
<h2>Conclusion</h2>
<p>When I'm developing a feature, I care about the files I've just
modified, created, or moved.</p>
<p>This command scratches exactly that itch: fast navigation to
Git-relevant files, without worrying if they're open or buried
somewhere in the project tree.</p>
<p>Give it a try, and check out
<a href="https://github.com/LionyxML/emacs-solo"><strong>emacs-solo</strong></a> for more
small, practical commands like this one. 🚀</p>
<h3>Edit:</h3>
<p><strong>2025-09-04:</strong> Fixed the global binding to
<code>emacs-solo/switch-git-status-buffer</code>, as pointed by <code>u/jplindstrom</code>
on <a href="https://www.reddit.com/r/emacs/comments/1n7vl8j/quickly_switching_between_git_status_files/">r/emacs
(reddit)</a>.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/switch-git-status-buffer</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/switch-git-status-buffer</guid>
            <pubDate>Wed, 03 Sep 2025 20:11:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Emacs Kick 0.3.0: Floating Docs, Snappy Completion, and Corfu Goodness]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>The 0.3.0 release of <a href="https://github.com/LionyxML/emacs-kick">Emacs
Kick</a> lands today, bringing
quiet but quality-of-life improvements while paving the way for future
support in Emacs 31.</p>
<p>Gone is the <code>company-mode</code> UI. Enter: <code>corfu</code>, floating tooltips, rich
font support, and more predictable behavior. Whether you use Emacs in
GUI or terminal, the UX feels tighter, more modern, and (if you're on
Emacs 31) frankly beautiful.</p>
<p>Let’s walk through what changed, and why this matters.</p>
<hr>
<h2>✨ What's New in 0.3.0</h2>
<p>This release is focused on simplifying and modernizing the core
experience—particularly <strong>completion</strong> and <strong>inline documentation</strong>.</p>
<hr>
<h3>🧠 Corfu replaces Company</h3>
<p><code>company-mode</code> has served us well, but it’s showing its age. In 0.3.0,
it’s replaced with <a href="https://github.com/minad/corfu"><code>corfu</code></a>.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Femacs-kick-030-02.png&w=3840&q=75" alt="emacs-kicks-corfu"></p>
<p>This:</p>
<p>➖ Easily supports <strong>Nerd Fonts</strong> icons on TUI.</p>
<p>➖ Provides info about completion candidate on TUI (Emacs >31).</p>
<p>➖ Feels native and snappy.</p>
<p>➖ Integrates beautifully with <code>cape</code>, <code>vertico</code>, <code>orderless</code>, the modern minibuffer stack.</p>
<p>➖ Plays nice with LSP and non-LSP backends alike.</p>
<p>Corfu stays out of your way until you need it. Completion is now
<strong>manual by default</strong>, triggered via <code>TAB</code>. No more random popups
mid-thought.</p>
<p>You can re-enable auto-completion if you prefer, but the default now
gives you back control.</p>
<h3>💡 Floating Eldoc (with eldoc-box) on Emacs 31</h3>
<p>If you're running the bleeding-edge Emacs 31, you now get floating
documentation (via child-frame) out of the box using eldoc-box.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Femacs-kick-030-01.png&w=3840&q=75" alt="emacs-kicks-eldoc-box"></p>
<p>That means pressing <code>K</code> (uppercase!) shows a clean, floating doc
tooltip right next to your point.</p>
<p>No more jumping to temporary buffers to read type signatures or
docstrings. It feels like a native IDE. And if you’re still on Emacs
30? No problem, the fallback is still the <em>eldoc</em> buffer.</p>
<h3>✨ Smaller Tweaks That Matter</h3>
<p>True to the Emacs spirit, small details make a big difference. This
release includes several subtle but impactful visual and behavioral
changes:</p>
<p>➖ <strong>Company Mode Removed</strong>: All <code>company-mode</code> related packages have
been fully removed for a cleaner, Corfu-native experience.</p>
<p>➖ <strong>Consistent <code>TAB</code> Behavior</strong>: <code>TAB</code> is now exclusively for
completion, removing the ambiguity where it might trigger
indentation instead.</p>
<p>➖ <strong>Quicker Dired</strong>: <code>&#x3C;leader> e d</code> now opens dired on current
working directory. This complements <code>&#x3C;leader> e e</code> which opens the
side explorer.</p>
<p>➖ <strong>Cleaner Diffs</strong>: The markers used by <code>diff-hl</code> in the margin have
been updated to clearer box-drawing characters (<code>┃</code>, <code>┆</code>), making
it easier to see new, modified, and saved changes.</p>
<p>➖ <strong>Iconic Magit</strong>: When you have Nerd Fonts enabled, your Magit
status buffer now includes file-type icons, giving it a richer,
modern feel.</p>
<p>➖ <strong>Less Noise</strong>: The automatic highlighting of the current line
(<code>global-hl-line-mode</code>) is now off by default to reduce visual
distraction.</p>
<h3>🚀 What This Means for You</h3>
<p>Remember this:</p>
<div class="remark-highlight"><pre class="language-txt"><code class="language-txt">Emacs-Kick isn’t a full-fledged distribution
but rather a starting point for building your
own Emacs configuration. It’s designed to be
especially accessible for Vim/Neovim users,
letting you explore the power of Emacs without
committing to its entire ecosystem.</code></pre></div>
<p>This release doubles down on that. It gets out of your way. It gives
you just enough: snappy completions, modern visuals, but no monolithic
frameworks.</p>
<h3>📦 How to Upgrade</h3>
<p>Check install instructions on the official Github Repository:
<a href="https://github.com/LionyxML/emacs-kick">https://github.com/LionyxML/emacs-kick</a></p>
<h3>💬 Final Thoughts</h3>
<p>This release makes Emacs Kick feel... well, kick-ass. It’s smoother,
quieter, and more intentional. If you value clean defaults, fast
completion, and less cognitive noise. You’ll feel the difference.</p>
<p>Let me know what you think, what broke, and what could improve. PRs
and issues welcome as always.</p>
<p>Happy hacking! ⚡️</p>
]]></description>
            <link>https://rahuljuliato.com/posts/emacs-kick-0-3-0</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/emacs-kick-0-3-0</guid>
            <pubDate>Tue, 29 Jul 2025 15:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Setting up Emacs native tab-bar and tab-bar-groups for a tmux-like experience]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Explore how to turn Emacs' native <code>tab-bar</code> and <code>tab-bar-groups</code> into
a powerful, tmux-like window and session management experience—no
external packages needed. Organize your workflows with tabs, group
them by project or context, and navigate with ease inside your Emacs
session, all while keeping tmux nearby for when it still shines.</p>
<p>Here I'm traversing an open session using this concept of organization
by simply issuing <code>C-TAB</code>.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Femacs-tab-bar-03.gif&w=3840&q=75" alt="tab-bar-config-demo"></p>
<p>If you prefer not to show the group name, want to display buffer
names, use other custom decorations, jump right into your group, don’t
worry, we’ll explore all these possibilities step by step.</p>
<p>Now, how do we achieve this! 🤩</p>
<hr>
<h2>Motivation</h2>
<p>It’s no secret that many Emacs users take advantage of its excellent
window management capabilities, like: splitting windows, saving layouts,
undoing and redoing them and even use <code>tab-bar</code> as a sort of
<code>tmux-like</code> workflow.</p>
<p>What I’m presenting here takes it a step further: bringing in a
<em>"split by session"</em> feature, just like tmux UI. In other words, we’re
expanding our window management arsenal with:</p>
<p>➖ Tabs, as in Emacs we call it <code>tab-bar</code> (not to be confused with the
<code>VSCode</code>-like <code>tab-line</code> mode): which can hold splits of different
buffers, either in the same file, different files, terminals, and
everything else Emacs can print in a buffer.</p>
<p>➖ Tab Groups, which can hold groups of tabs, mimicking <code>sessions</code> as
we call them in <code>tmux</code>, or <code>perspectives</code> if you know this concept
from <code>persp-mode</code> or <code>perspective-el</code>, or even <code>activities</code> if you
use <code>Doom Emacs</code>.</p>
<p>Also, did I mention we're going to do it without any external package
dependencies?</p>
<p>With the provided configuration, we're going to organize our current
running Emacs session in "two levels":</p>
<h2>The 'tab-bar-groups'</h2>
<p>This level holds the <code>tab-group</code>. This might contain a "topic" like
"Chat", "Mail" or "News", or simply your project name like "My
Project", or if you're working with multiple projects at the same
time, one level that might be organized by "Your Workflow". And of
course, you can have all of this at the same time, like:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Femacs-tab-bar-01.png&w=3840&q=75" alt="tab-bar-groups"></p>
<h2>The 'tab-bars'</h2>
<p>This level contains your <code>tabs</code>, which can hold all sorts of window
arrangements (for the uninitiated, from Emacs's point of view, the OS-
level 'window' that holds the Emacs application is called a 'frame',
while 'windows' are the inner splits that hold our buffers).</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Femacs-tab-bar-02.png&w=3840&q=75" alt="tab-bar-groups-group"></p>
<hr>
<p>So, first things first. I'm reproducing here the steps to the final
form I just showed. But of course, it is all customizable. Want to do
another sort of decorations? Want to hide the group name? Want to show
filenames? Want to navigate differently? Go for it! It is all
transparent to you!</p>
<h2>Variables configurations</h2>
<p>This is personal taste, take a look at each variable's documentation and
tweak it yourself, basically:</p>
<p>➖ I do not want the close button, nor the new button, as I seldom use
mouse navigation.</p>
<p>➖ I do want tab-hints, which are numbers on each tab-name for better
navigation. I do override the internal function, though, to get it
"decorated" my way.</p>
<p>➖ I want a clean separator, so, a single space.</p>
<p>➖ We want the tab-group name shown, hence we add to <code>tab-bar-format</code>
the <code>tab-bar-format-tabs-groups</code> option.</p>
<p>All of this can be defined with:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token keyword">setq</span> tab-bar-close-button-show <span class="token boolean">nil</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> tab-bar-new-button-show <span class="token boolean">nil</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> tab-bar-tab-hints <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> tab-bar-auto-width <span class="token boolean">nil</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> tab-bar-separator <span class="token string">" "</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> tab-bar-format <span class="token punctuation">'(</span><span class="token car">tab-bar-format-tabs-groups</span>
					tab-bar-format-tabs tab-bar-separator
					tab-bar-format-add-tab<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<h2>A few (IMHO justified) overrides</h2>
<p>Tab bar doesn't allow us many customizations. Fortunately, we can
override a couple of functions as they're small and easy to keep up
with. Of course, this is totally optional; I'm just trying to mimic a
more <code>tmux-like</code> UI feel.</p>
<p>First, <code>tab-bar-tab-name-format-hints</code>: I want to put some arrows
around the hints number, and <em>NOT</em> show the buffer name.</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">tab-bar-tab-name-format-hints</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">name</span> <span class="token argument variable">_tab</span> <span class="token argument variable">i</span></span><span class="token punctuation">)</span></span>
	  <span class="token punctuation">(</span><span class="token keyword">if</span> tab-bar-tab-hints <span class="token punctuation">(</span><span class="token keyword">concat</span> <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">"»%d«"</span> i<span class="token punctuation">)</span> <span class="token string">""</span><span class="token punctuation">)</span> name<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Second, <code>tab-bar-tab-group-format-default</code>: By default, groups
show the hint of the first tab under it. I want a clean group name, so:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">tab-bar-tab-group-format-default</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">tab</span> <span class="token argument variable">_i</span> <span class="token other-marker-vars"><span class="token lisp-marker">&optional</span> <span class="token argument variable">current-p</span></span></span><span class="token punctuation">)</span></span>
	<span class="token punctuation">(</span><span class="token car">propertize</span>
	 <span class="token punctuation">(</span><span class="token keyword">concat</span> <span class="token punctuation">(</span><span class="token car">funcall</span> tab-bar-tab-group-function tab<span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token quoted-symbol variable symbol">'face</span> <span class="token punctuation">(</span><span class="token keyword">if</span> current-p <span class="token quoted-symbol variable symbol">'tab-bar-tab-group-current</span> <span class="token quoted-symbol variable symbol">'tab-bar-tab-group-inactive</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<h2>Nice QoL Utility functions</h2>
<p>With the above config, we can already do something like <code>C-x t G</code>,
setting a group name for your current tab and start organizing your
life!</p>
<p>You could also have automatically groups created by setting tab-group
in your <code>display-buffer-alist</code>, like:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token car">add-to-list</span> <span class="token quoted-symbol variable symbol">'display-buffer-alist</span>
			   <span class="token punctuation">'(</span><span class="token string">"\\*scratch\\*"</span>
				 <span class="token punctuation">(</span><span class="token car">display-buffer-in-tab</span> display-buffer-full-frame<span class="token punctuation">)</span>
				 <span class="token punctuation">(</span><span class="token car">tab-group</span> <span class="token punctuation">.</span> <span class="token string">"[EMACS]"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>We're not focusing on automatically tab-grouping stuff in this post
though.</p>
<p>Truth is, yes, I want groups for my News, Mail, Chat, but most of
my work is done in the form of <em>Projects</em>.</p>
<p>And yes, I want these settings to be manually issued. I can recall the
pain of having to sneak-peak another project utility function or doc,
just to have my crazy custom <code>persp-mode</code> pulling a new persp and
messing with everything.</p>
<h3>Function to set tab to group based on project</h3>
<p>So, I want a function that can "promote" my current tab to the group
<code>[ProjectName]</code>, creating it if there are none. Of course, if the current
buffer is part of a project. This allows me to switch projects, open
new splits, without automagic jumps.</p>
<p>Here we have a function to do so, and a suggested bind:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo/tab-group-from-project</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
	<span class="token string">"Call `tab-group` with the current project name as the group."</span>
	<span class="token punctuation">(</span><span class="token interactive keyword">interactive</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token car">when-let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">proj</span> <span class="token punctuation">(</span><span class="token car">project-current</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">name</span> <span class="token punctuation">(</span><span class="token car">file-name-nondirectory</span>
					   <span class="token punctuation">(</span><span class="token car">directory-file-name</span> <span class="token punctuation">(</span><span class="token car">project-root</span> proj<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token car">tab-group</span> <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">"[%s]"</span> name<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token car">global-set-key</span> <span class="token punctuation">(</span><span class="token car">kbd</span> <span class="token string">"C-x t P"</span><span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">#'emacs-solo/tab-group-from-project</span><span class="token punctuation">)</span>
</code></pre></div>
<p>So, recap: I can <code>C-x t G</code> and "add" my tab to a group, and now I can
also simply <code>C-x t P</code> and "add" my tab to the project group.</p>
<p>😎 Workflow?</p>
<p>➖ <code>C-x t p p</code>: starts a new tab selecting a project</p>
<p>➖ Select a file, dired or shell...</p>
<p>➖ <code>C-x t P</code>: add your new tab to the project group, creating it</p>
<p>Want some more tabs?</p>
<p><code>C-x t 2</code> will automatically add tabs to your current group.</p>
<p>Isn't it nice? Now, you can feel the power in your hands, you open 10
projects, you create a bunch of groups for your inner <code>Emacs is my OS</code>
workflow, how do you traverse all this madness?</p>
<h3>Function to jump to group</h3>
<p>I found my self abusing of the default <code>C-TAB</code> and <code>C-S-TAB</code> to
quickly "jump" between closer tabs. Now, I wanna quickly check my
Mail, I'd like something more "precise" jumping than eye balling
everything.</p>
<p>This is were our second utility function comes to hand:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo/tab-switch-to-group</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
  <span class="token string">"Prompt for a tab group and switch to its first tab.</span>
<span class="token string">Uses position instead of index field."</span>
  <span class="token punctuation">(</span><span class="token interactive keyword">interactive</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">tabs</span> <span class="token punctuation">(</span><span class="token car">funcall</span> tab-bar-tabs-function<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">groups</span> <span class="token punctuation">(</span><span class="token car">delete-dups</span> <span class="token punctuation">(</span><span class="token car">mapcar</span> <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">tab</span></span><span class="token punctuation">)</span></span>
										  <span class="token punctuation">(</span><span class="token car">funcall</span> tab-bar-tab-group-function tab<span class="token punctuation">)</span><span class="token punctuation">)</span>
										tabs<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">group</span> <span class="token punctuation">(</span><span class="token car">completing-read</span> <span class="token string">"Switch to group: "</span> groups <span class="token boolean">nil</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">i</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">found</span> <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		<span class="token punctuation">(</span><span class="token car">dolist</span> <span class="token punctuation">(</span><span class="token car">tab</span> tabs<span class="token punctuation">)</span>
		  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">tab-group</span> <span class="token punctuation">(</span><span class="token car">funcall</span> tab-bar-tab-group-function tab<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			<span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token keyword">not</span> found<span class="token punctuation">)</span>
					   <span class="token punctuation">(</span><span class="token car">string=</span> tab-group group<span class="token punctuation">)</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token keyword">setq</span> found <span class="token boolean">t</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token car">tab-bar-select-tab</span> i<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		  <span class="token punctuation">(</span><span class="token keyword">setq</span> i <span class="token punctuation">(</span>1+ i<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">global-set-key</span> <span class="token punctuation">(</span><span class="token car">kbd</span> <span class="token string">"C-x t g"</span><span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">#'emacs-solo/tab-switch-to-group</span><span class="token punctuation">)</span>
</code></pre></div>
<p>This allows us to "list all available groups", select and switch to
the first tab of that group.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Femacs-tab-bar-04.png&w=3840&q=75" alt="tab-bar-group-change"></p>
<h2>Packing the entire config</h2>
<p>The code here presented by parts is now part of my <code>emacs-solo</code> config
(hence the prefix on the function names), I usually keep my
configuration somewhat organized by <code>use-package</code> blocks, they keep
everything in the right place and I suggest you do the same. Also it
is a lot faster to grab this code, copy and paste to your config and
make it work!</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> tab-bar
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">nil</span>
  <span class="token lisp-property property">:defer</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:custom</span>
  <span class="token punctuation">(</span><span class="token car">tab-bar-close-button-show</span> <span class="token boolean">nil</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">tab-bar-new-button-show</span> <span class="token boolean">nil</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">tab-bar-tab-hints</span> <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">tab-bar-auto-width</span> <span class="token boolean">nil</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">tab-bar-separator</span> <span class="token string">" "</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">tab-bar-format</span> <span class="token punctuation">'(</span><span class="token car">tab-bar-format-tabs-groups</span>
					Tab-bar-format-tabs tab-bar-separator
					tab-bar-format-add-tab<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:init</span>
  <span class="token heading comment title">;;; --- OPTIONAL INTERNAL FN OVERRIDES TO DECORATE NAMES</span>
  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">tab-bar-tab-name-format-hints</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">name</span> <span class="token argument variable">_tab</span> <span class="token argument variable">i</span></span><span class="token punctuation">)</span></span>
	  <span class="token punctuation">(</span><span class="token keyword">if</span> tab-bar-tab-hints <span class="token punctuation">(</span><span class="token keyword">concat</span> <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">"»%d«"</span> i<span class="token punctuation">)</span> <span class="token string">""</span><span class="token punctuation">)</span> name<span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">tab-bar-tab-group-format-default</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">tab</span> <span class="token argument variable">_i</span> <span class="token other-marker-vars"><span class="token lisp-marker">&optional</span> <span class="token argument variable">current-p</span></span></span><span class="token punctuation">)</span></span>
	<span class="token punctuation">(</span><span class="token car">propertize</span>
	 <span class="token punctuation">(</span><span class="token keyword">concat</span> <span class="token punctuation">(</span><span class="token car">funcall</span> tab-bar-tab-group-function tab<span class="token punctuation">)</span><span class="token punctuation">)</span>
	 <span class="token quoted-symbol variable symbol">'face</span> <span class="token punctuation">(</span><span class="token keyword">if</span> current-p <span class="token quoted-symbol variable symbol">'tab-bar-tab-group-current</span> <span class="token quoted-symbol variable symbol">'tab-bar-tab-group-inactive</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>


  <span class="token heading comment title">;;; --- UTILITIES FUNCTIONS</span>
  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo/tab-group-from-project</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
	<span class="token string">"Call `tab-group` with the current project name as the group."</span>
	<span class="token punctuation">(</span><span class="token interactive keyword">interactive</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token car">when-let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">proj</span> <span class="token punctuation">(</span><span class="token car">project-current</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">name</span> <span class="token punctuation">(</span><span class="token car">file-name-nondirectory</span>
					   <span class="token punctuation">(</span><span class="token car">directory-file-name</span> <span class="token punctuation">(</span><span class="token car">project-root</span> proj<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token car">tab-group</span> <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">"[%s]"</span> name<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo/tab-switch-to-group</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
  <span class="token string">"Prompt for a tab group and switch to its first tab.</span>
<span class="token string">Uses position instead of index field."</span>
  <span class="token punctuation">(</span><span class="token interactive keyword">interactive</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">tabs</span> <span class="token punctuation">(</span><span class="token car">funcall</span> tab-bar-tabs-function<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">groups</span> <span class="token punctuation">(</span><span class="token car">delete-dups</span> <span class="token punctuation">(</span><span class="token car">mapcar</span> <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">tab</span></span><span class="token punctuation">)</span></span>
										  <span class="token punctuation">(</span><span class="token car">funcall</span> tab-bar-tab-group-function tab<span class="token punctuation">)</span><span class="token punctuation">)</span>
										tabs<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">group</span> <span class="token punctuation">(</span><span class="token car">completing-read</span> <span class="token string">"Switch to group: "</span> groups <span class="token boolean">nil</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">i</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">found</span> <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		<span class="token punctuation">(</span><span class="token car">dolist</span> <span class="token punctuation">(</span><span class="token car">tab</span> tabs<span class="token punctuation">)</span>
		  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">tab-group</span> <span class="token punctuation">(</span><span class="token car">funcall</span> tab-bar-tab-group-function tab<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			<span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token keyword">not</span> found<span class="token punctuation">)</span>
					   <span class="token punctuation">(</span><span class="token car">string=</span> tab-group group<span class="token punctuation">)</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token keyword">setq</span> found <span class="token boolean">t</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token car">tab-bar-select-tab</span> i<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		  <span class="token punctuation">(</span><span class="token keyword">setq</span> i <span class="token punctuation">(</span>1+ i<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token heading comment title">;;; --- EXTRA KEYBINDINGS</span>
  <span class="token punctuation">(</span><span class="token car">global-set-key</span> <span class="token punctuation">(</span><span class="token car">kbd</span> <span class="token string">"C-x t P"</span><span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">#'emacs-solo/tab-group-from-project</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">global-set-key</span> <span class="token punctuation">(</span><span class="token car">kbd</span> <span class="token string">"C-x t g"</span><span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">#'emacs-solo/tab-switch-to-group</span><span class="token punctuation">)</span>

  <span class="token heading comment title">;;; --- TURNS ON BY DEFAULT</span>
  <span class="token punctuation">(</span><span class="token car">tab-bar-mode</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<h2>Customizations on tab-bar-properties</h2>
<p>You might want to customize the <code>tab-bar</code> line, what I am using in
these screenshots is:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token car">custom-set-faces</span>
  <span class="token punctuation">'(</span><span class="token car">tab-bar</span>
	<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token boolean">t</span> <span class="token punctuation">(</span><span class="token lisp-property property">:background</span> <span class="token string">"#232635"</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#A6Accd"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">'(</span><span class="token car">tab-bar-tab</span>
	<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token boolean">t</span> <span class="token punctuation">(</span><span class="token lisp-property property">:background</span> <span class="token string">"#232635"</span> <span class="token lisp-property property">:underline</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">'(</span><span class="token car">tab-bar-tab-inactive</span>
	<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token boolean">t</span> <span class="token punctuation">(</span> <span class="token comment">;; :background "#232635" ;; uncomment to use this</span>
		  <span class="token comment">;; :box (:line-width 1 :color "#676E95")</span>
		  <span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">'(</span><span class="token car">tab-bar-tab-group-current</span>
	<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token boolean">t</span> <span class="token punctuation">(</span><span class="token lisp-property property">:background</span> <span class="token string">"#232635"</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#A6Accd"</span> <span class="token lisp-property property">:underline</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">'(</span><span class="token car">tab-bar-tab-group-inactive</span>
	<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token boolean">t</span> <span class="token punctuation">(</span><span class="token lisp-property property">:background</span> <span class="token string">"#232635"</span> <span class="token lisp-property property">:foreground</span> <span class="token string">"#777"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<h2>So, time to ditch tmux?</h2>
<p>I wish...</p>
<p>This functionality is indeed very useful, the UI mimics <code>tmux-like</code>
power. And if this is enough for you, go for it! Ditch tmux!</p>
<p>For my use cases, the sheer possibility of any of my <code>emacs-lisp</code> code
locking the one and only Emacs process means my beautifully designed
and crafted <em>Emacs session</em> is going bye-bye with it. And yes, while
<code>emacs --daemon</code> and restarting clients helps a lot here, let’s not
pretend Emacs never goes sideways.</p>
<p>There are still solid reasons to keep <code>tmux</code> around:</p>
<p>➖ <strong>Fault tolerance</strong>. When you’re SSH’d into a remote machine and
something crashes, <code>tmux</code> is still there, your shell lives on. Emacs
tabs don’t protect you from network drops or X11/Wayland hiccups.</p>
<p>➖ <strong>Shell multiplexing</strong>. Sometimes you just want 3 quick shells,
nothing fancy, don’t even want to boot up Emacs. <code>tmux</code> wins
here. Fast, lightweight, and scriptable. You just install tmux, no
fancy config needed to 'just use it'.</p>
<p>➖ <strong>System-level process separation</strong>. I like to keep long-running
REPLs, tailing logs, or even a docker attach session in <code>tmux</code>. If
Emacs dies, they don’t.</p>
<p>➖ <strong>Startup time</strong>. Emacs with heavy configuration can still take a
second to feel "fully alive". When I want to attach to a ready-to-go
shell session instantly, <code>tmux a</code> is just faster.</p>
<p>➖ <strong>Better separation</strong>. While the whole tab-bar and tab-group
approach is super flexible, sometimes you just need the hard boundary
of a terminal session completely isolated from the rest. There are
things you do <em>outside Emacs</em> for good reason.</p>
<p>And let’s be honest, you don’t need to <em>choose</em>. These tools
<em>complement</em> each other. What this configuration gives you is a
powerful <code>Emacs-as-an-OS</code> experience, with clarity, agility, and a
clean mental model. Use Emacs for your inner workflows, and <code>tmux</code> as
your outer shell guardian.</p>
<hr>
<h2>Wrapping Up</h2>
<p>With just a few lines of Elisp, no external packages, and some clever
overriding, Emacs’ <code>tab-bar</code> and <code>tab-bar-groups</code> become serious
productivity tools. If you’re someone juggling multiple projects,
workflows, or simply enjoy clean organization inside your Emacs
session, this setup gives you control and clarity.</p>
<p>While we might not throw <code>tmux</code> out of the toolbox just yet, we now
have a native Emacs experience that feels modern, fast, and
surprisingly intuitive. Use what’s best for <em>your</em> workflow, but know
that Emacs is more than capable of stepping up its game.</p>
<p>So go ahead, give it a try, tweak it, theme it, and make Emacs your
tmux... and more.</p>
<p>Happy hacking. ✨💻🤓🚀</p>
]]></description>
            <link>https://rahuljuliato.com/posts/emacs-tab-bar-groups</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/emacs-tab-bar-groups</guid>
            <pubDate>Tue, 24 Jun 2025 20:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Minimal Clipboard Support in Terminal Emacs]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Terminal Emacs users often face an annoying limitation: <strong>copying and
pasting</strong> between Emacs and the system clipboard doesn’t "just work."
While graphical Emacs integrates with the OS clipboard by default, the
terminal version leaves that responsibility to you, especially if
you're inside <code>tmux</code>, <code>ssh</code>, or simply prefer living in the terminal.</p>
<p>Thankfully, there are excellent packages like:
<a href="https://github.com/emacsmirror/xclip/blob/master/xclip.el"><code>xclip</code></a> and
<a href="https://github.com/spudlyo/clipetty"><code>clipetty</code></a>, as well as guides like
<a href="https://www.emacswiki.org/emacs/CopyAndPaste"><code>Emacswiki: CopyAndPaste</code></a> that
tackle this. They offer elegant solutions, often with additional
features and broader compatibility.</p>
<p>But sometimes, you just want something small and direct, something
you can <strong>copy-paste into your config</strong> and tweak per OS, with no
external Emacs dependencies.</p>
<p>That’s what I present here.</p>
<hr>
<h2>✂️ emacs-solo-clipboard: A Minimal Clipboard Bridge</h2>
<p>This snippet is part of my
<a href="https://github.com/LionyxML/emacs-solo"><code>emacs-solo</code></a> configuration. It gives
terminal Emacs clipboard support using native system tools (which, of course, you
need installed in your system):</p>
<p>➖ <code>pbcopy</code> / <code>pbpaste</code> for macOS</p>
<p>➖ <code>clip.exe</code> / <code>powershell.exe</code> for WSL</p>
<p>➖ <code>wl-copy</code> / <code>wl-paste</code> for Wayland</p>
<p>➖ <code>xclip</code> for X11</p>
<p>It hooks into Emacs' standard <code>interprogram-cut-function</code> and <code>interprogram-paste-function</code> APIs.</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token heading comment title">;;; EMACS-SOLO-CLIPBOARD</span>
<span class="token comment">;;</span>
<span class="token comment">;;  Allows proper copy/pasting on terminals</span>
<span class="token comment">;;</span>
<span class="token punctuation">(</span><span class="token keyword">use-package</span> emacs-solo-clipboard
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">nil</span>
  <span class="token lisp-property property">:no-require</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:defer</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:init</span>
  <span class="token punctuation">(</span><span class="token keyword">cond</span>
   <span class="token comment">;; macOS: use pbcopy/pbpaste</span>
   <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">eq</span> system-type <span class="token quoted-symbol variable symbol">'darwin</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">setq</span> interprogram-cut-function
		  <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">text</span> <span class="token other-marker-vars"><span class="token lisp-marker">&optional</span> <span class="token argument variable">_</span></span></span><span class="token punctuation">)</span></span>
			<span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">process-connection-type</span> <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">proc</span> <span class="token punctuation">(</span><span class="token car">start-process</span> <span class="token string">"pbcopy"</span> <span class="token string">"*Messages*"</span> <span class="token string">"pbcopy"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">process-send-string</span> proc text<span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">process-send-eof</span> proc<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">setq</span> interprogram-paste-function
		  <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
			<span class="token punctuation">(</span><span class="token car">shell-command-to-string</span> <span class="token string">"pbpaste"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

   <span class="token comment">;; WSL (Windows Subsystem for Linux): Use clip.exe for copy and powershell.exe for paste</span>
   <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token car">eq</span> system-type <span class="token quoted-symbol variable symbol">'gnu/linux</span><span class="token punctuation">)</span>
		 <span class="token punctuation">(</span><span class="token car">getenv</span> <span class="token string">"WSLENV"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">setq</span> interprogram-cut-function
		  <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">text</span> <span class="token other-marker-vars"><span class="token lisp-marker">&optional</span> <span class="token argument variable">_</span></span></span><span class="token punctuation">)</span></span>
			<span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">process-connection-type</span> <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">proc</span> <span class="token punctuation">(</span><span class="token car">start-process</span> <span class="token string">"clip.exe"</span> <span class="token string">"*Messages*"</span> <span class="token string">"clip.exe"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">process-send-string</span> proc text<span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">process-send-eof</span> proc<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">setq</span> interprogram-paste-function
		  <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
			<span class="token punctuation">(</span><span class="token car">string-trim</span> <span class="token punctuation">(</span><span class="token car">shell-command-to-string</span> <span class="token string">"powershell.exe -command Get-Clipboard"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

   <span class="token comment">;; Linux with wl-copy/wl-paste (Wayland)</span>
   <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token car">eq</span> system-type <span class="token quoted-symbol variable symbol">'gnu/linux</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">executable-find</span> <span class="token string">"wl-copy"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">setq</span> interprogram-cut-function
		  <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">text</span> <span class="token other-marker-vars"><span class="token lisp-marker">&optional</span> <span class="token argument variable">_</span></span></span><span class="token punctuation">)</span></span>
			<span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">process-connection-type</span> <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">proc</span> <span class="token punctuation">(</span><span class="token car">start-process</span> <span class="token string">"wl-copy"</span> <span class="token string">"*Messages*"</span> <span class="token string">"wl-copy"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">process-send-string</span> proc text<span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">process-send-eof</span> proc<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">setq</span> interprogram-paste-function
		  <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
			<span class="token punctuation">(</span><span class="token car">shell-command-to-string</span> <span class="token string">"wl-paste -n"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

   <span class="token comment">;; Linux with xclip (X11)</span>
   <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token car">eq</span> system-type <span class="token quoted-symbol variable symbol">'gnu/linux</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">executable-find</span> <span class="token string">"xclip"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">setq</span> interprogram-cut-function
		  <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">text</span> <span class="token other-marker-vars"><span class="token lisp-marker">&optional</span> <span class="token argument variable">_</span></span></span><span class="token punctuation">)</span></span>
			<span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">process-connection-type</span> <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">proc</span> <span class="token punctuation">(</span><span class="token car">start-process</span> <span class="token string">"xclip"</span> <span class="token string">"*Messages*"</span> <span class="token string">"xclip"</span> <span class="token string">"-selection"</span> <span class="token string">"clipboard"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">process-send-string</span> proc text<span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">process-send-eof</span> proc<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">setq</span> interprogram-paste-function
		  <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
			<span class="token punctuation">(</span><span class="token car">shell-command-to-string</span> <span class="token string">"xclip -selection clipboard -o"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<h2>⚠️ This Is Hacky, and That's the Point</h2>
<p>This is <strong>not</strong> a library or polished package. It's a minimal Emacs Lisp
snippet that works well <em>if</em> your system already provides the right clipboard
utilities. It doesn't abstract anything and won't handle edge cases. But that
also means:</p>
<p>✅ Easy to audit</p>
<p>✅ Easy to tweak</p>
<p>✅ Easy to share small pieces</p>
<p>You can literally just copy the macOS or Wayland part and ignore the rest.</p>
<hr>
<h2>🖥️ Bonus: OSC 52 Might Be All You Need</h2>
<p>If you’re using a modern terminal emulator that supports <strong>OSC 52</strong>
(like Kitty, Windows Terminal, or Xterm with proper settings), you
might not need <em>any</em> of the above clipboard setup.</p>
<p>Emacs has built-in support for OSC 52 clipboard integration via this simple line:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token keyword">setq</span> xterm-extra-capabilities <span class="token punctuation">'(</span><span class="token car">getSelection</span> setSelection modifyOtherKeys<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>This tells Emacs to assume your terminal supports some extra features, including:</p>
<ul>
<li><code>getSelection</code>: paste from the system clipboard</li>
<li><code>setSelection</code>: copy to the system clipboard</li>
<li><code>modifyOtherKeys</code>: unlock more reliable keybindings (like <code>C-,</code>)</li>
</ul>
<p>This works <strong>without any external tools</strong> as long as your terminal
supports OSC 52 and your Emacs was built with Xterm support (most
builds are).</p>
<blockquote>
<p>💡 <strong>Tip</strong>: Try it! Copy something in Emacs with <code>M-w</code> and paste outside. If it works, you’re set.
Otherwise, fallback to one of the system-specific setups above.</p>
</blockquote>
<blockquote>
<p>🔒 <strong>tmux users</strong>: OSC 52 support may require this to your <code>~/.tmux.conf</code>:</p>
</blockquote>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">set-option <span class="token parameter variable">-s</span> set-clipboard on
<span class="token builtin class-name">set</span> <span class="token parameter variable">-g</span> allow-passthrough on
</code></pre></div>
<hr>
<h2>✅ Wrap-Up</h2>
<p>If you’re running Emacs in the terminal and want clipboard support without
extra layers or packages, this might be just what you need.</p>
<p>It’s not pretty. It might be not <em>that</em> smart. But it works.</p>
<p>And sometimes, that’s exactly the kind of config you want.</p>
<hr>
<p>Let me know if you run into clipboard quirks I didn’t cover here, or if you’ve
built your own minimalist setup, I’m always curious about tiny hacks that
punch above their weight. 🧠🛠️🔥</p>
<hr>
<h3>Edit:</h3>
<p><strong>2025-06-20:</strong> Added the <em>Bonus</em> section reffering to
<code>xterm-extra-capabilities</code> as suggested by user <code>u/passkyw</code> on
<a href="https://www.reddit.com/r/emacs/comments/1leu2r7/hacky_minimal_clipboard_support_in_terminal_emacs/">r/emacs</a>.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/emacs-clipboard-terminal</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/emacs-clipboard-terminal</guid>
            <pubDate>Wed, 18 Jun 2025 20:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Improving Dired in Emacs Solo: Git Status and File Icons]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <h3>⚠️ WARNING: EMOJI HEAVY CONTENT AHEAD ⚠️</h3>
<p>🚨📢 <strong>Pro Tip</strong>: Need more emoji in your life? Emacs <code>C-x 8 RET</code> is
magic 🪄✨</p>
<hr>
<p>There are many ways to enhance Dired in Emacs. From full-featured
packages like <code>diff-hl</code>, <code>all-the-icons-dired</code> and <code>nerd-icons-dired</code>
to built-in solutions. There's absolutely nothing wrong with using
well-maintained packages (I do for many things!), but sometimes you
might want something more minimal or tailored to your workflow.</p>
<p>These are my personal implementations from
<a href="https://github.com/lionyxml/emacs-solo">Emacs Solo</a> that follow a
specific philosophy:</p>
<p>🛠️ <strong>No dependencies</strong>: beyond Emacs itself</p>
<p>📋 <strong>Copy/paste installable</strong>: into any config</p>
<p>🧰 <strong>Hacky but practical</strong>: they solve <em>my</em> needs first and small imperfections are ok</p>
<p>🔧 <strong>Easily modifiable</strong>: if you know basic Elisp</p>
<p>Some screenshots of what were are talking about:</p>
<p><img src="https://rahuljuliato.com/assets/blog/posts/dired-enhanced-demo-01.png" alt="Enhancements demo 01"></p>
<p><img src="https://rahuljuliato.com/assets/blog/posts/dired-enhanced-demo-02.png" alt="Enhancements demo 02"></p>
<p><img src="https://rahuljuliato.com/assets/blog/posts/dired-enhanced-demo-03.png" alt="Enhancements demo 03"></p>
<p><img src="https://rahuljuliato.com/assets/blog/posts/dired-enhanced-demo-04.png" alt="Enhancements demo 04"></p>
<h2>What These Do</h2>
<p>1️⃣ <strong>Git Status Gutter</strong>: Left-margin indicators for file status (modified/added/deleted)</p>
<p>2️⃣ <strong>File Type Icons</strong>: Unicode symbols instead of heavy icon fonts</p>
<p><strong>Note:</strong> These aren't trying to replace full packages. They're
alternatives for those who prefer lightweight solutions.</p>
<hr>
<h2>1. File Icons Using Unicode</h2>
<p>A font-free alternative to icon packages:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token heading comment title">;;; EMACS-SOLO-DIRED-ICONS</span>
<span class="token comment">;;</span>
<span class="token punctuation">(</span><span class="token keyword">use-package</span> emacs-solo-dired-icons
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">nil</span>
  <span class="token lisp-property property">:no-require</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:defer</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:init</span>
  <span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defvar</span> <span class="token variable">emacs-solo/dired-icons-file-icons</span></span>
	<span class="token punctuation">'(</span><span class="token punctuation">(</span><span class="token string">"el"</span> <span class="token punctuation">.</span> <span class="token string">"📜"</span><span class="token punctuation">)</span>      <span class="token punctuation">(</span><span class="token string">"rb"</span> <span class="token punctuation">.</span> <span class="token string">"💎"</span><span class="token punctuation">)</span>      <span class="token punctuation">(</span><span class="token string">"js"</span> <span class="token punctuation">.</span> <span class="token string">"⚙️"</span><span class="token punctuation">)</span>      <span class="token punctuation">(</span><span class="token string">"ts"</span> <span class="token punctuation">.</span> <span class="token string">"⚙️"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"json"</span> <span class="token punctuation">.</span> <span class="token string">"🗂️"</span><span class="token punctuation">)</span>    <span class="token punctuation">(</span><span class="token string">"md"</span> <span class="token punctuation">.</span> <span class="token string">"📝"</span><span class="token punctuation">)</span>      <span class="token punctuation">(</span><span class="token string">"txt"</span> <span class="token punctuation">.</span> <span class="token string">"📝"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"html"</span> <span class="token punctuation">.</span> <span class="token string">"🌐"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"css"</span> <span class="token punctuation">.</span> <span class="token string">"🎨"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"scss"</span> <span class="token punctuation">.</span> <span class="token string">"🎨"</span><span class="token punctuation">)</span>    <span class="token punctuation">(</span><span class="token string">"png"</span> <span class="token punctuation">.</span> <span class="token string">"🖼️"</span><span class="token punctuation">)</span>    <span class="token punctuation">(</span><span class="token string">"jpg"</span> <span class="token punctuation">.</span> <span class="token string">"🖼️"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"jpeg"</span> <span class="token punctuation">.</span> <span class="token string">"🖼️"</span><span class="token punctuation">)</span>   <span class="token punctuation">(</span><span class="token string">"gif"</span> <span class="token punctuation">.</span> <span class="token string">"🖼️"</span><span class="token punctuation">)</span>    <span class="token punctuation">(</span><span class="token string">"svg"</span> <span class="token punctuation">.</span> <span class="token string">"🖼️"</span><span class="token punctuation">)</span>    <span class="token punctuation">(</span><span class="token string">"pdf"</span> <span class="token punctuation">.</span> <span class="token string">"📄"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"zip"</span> <span class="token punctuation">.</span> <span class="token string">"📦"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"tar"</span> <span class="token punctuation">.</span> <span class="token string">"📦"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"gz"</span> <span class="token punctuation">.</span> <span class="token string">"📦"</span><span class="token punctuation">)</span>      <span class="token punctuation">(</span><span class="token string">"bz2"</span> <span class="token punctuation">.</span> <span class="token string">"📦"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"7z"</span> <span class="token punctuation">.</span> <span class="token string">"📦"</span><span class="token punctuation">)</span>      <span class="token punctuation">(</span><span class="token string">"org"</span> <span class="token punctuation">.</span> <span class="token string">"📝"</span><span class="token punctuation">)</span>    <span class="token punctuation">(</span><span class="token string">"sh"</span> <span class="token punctuation">.</span> <span class="token string">"💻"</span><span class="token punctuation">)</span>      <span class="token punctuation">(</span><span class="token string">"c"</span> <span class="token punctuation">.</span> <span class="token string">"🔧"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"h"</span> <span class="token punctuation">.</span> <span class="token string">"📘"</span><span class="token punctuation">)</span>       <span class="token punctuation">(</span><span class="token string">"cpp"</span> <span class="token punctuation">.</span> <span class="token string">"➕"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"hpp"</span> <span class="token punctuation">.</span> <span class="token string">"📘"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"py"</span> <span class="token punctuation">.</span> <span class="token string">"🐍"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"java"</span> <span class="token punctuation">.</span> <span class="token string">"☕"</span><span class="token punctuation">)</span>    <span class="token punctuation">(</span><span class="token string">"go"</span> <span class="token punctuation">.</span> <span class="token string">"🌍"</span><span class="token punctuation">)</span>      <span class="token punctuation">(</span><span class="token string">"rs"</span> <span class="token punctuation">.</span> <span class="token string">"💨"</span><span class="token punctuation">)</span>      <span class="token punctuation">(</span><span class="token string">"php"</span> <span class="token punctuation">.</span> <span class="token string">"🐘"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"pl"</span> <span class="token punctuation">.</span> <span class="token string">"🐍"</span><span class="token punctuation">)</span>      <span class="token punctuation">(</span><span class="token string">"lua"</span> <span class="token punctuation">.</span> <span class="token string">"🎮"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"ps1"</span> <span class="token punctuation">.</span> <span class="token string">"🔧"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"exe"</span> <span class="token punctuation">.</span> <span class="token string">"⚡"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"dll"</span> <span class="token punctuation">.</span> <span class="token string">"🔌"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"bat"</span> <span class="token punctuation">.</span> <span class="token string">"⚡"</span><span class="token punctuation">)</span>      <span class="token punctuation">(</span><span class="token string">"yaml"</span> <span class="token punctuation">.</span> <span class="token string">"⚙️"</span><span class="token punctuation">)</span>    <span class="token punctuation">(</span><span class="token string">"toml"</span> <span class="token punctuation">.</span> <span class="token string">"⚙️"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"ini"</span> <span class="token punctuation">.</span> <span class="token string">"⚙️"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"csv"</span> <span class="token punctuation">.</span> <span class="token string">"📊"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"xls"</span> <span class="token punctuation">.</span> <span class="token string">"📊"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"xlsx"</span> <span class="token punctuation">.</span> <span class="token string">"📊"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"sql"</span> <span class="token punctuation">.</span> <span class="token string">"🗄️"</span><span class="token punctuation">)</span>    <span class="token punctuation">(</span><span class="token string">"log"</span> <span class="token punctuation">.</span> <span class="token string">"📝"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"apk"</span> <span class="token punctuation">.</span> <span class="token string">"📱"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"dmg"</span> <span class="token punctuation">.</span> <span class="token string">"💻"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"iso"</span> <span class="token punctuation">.</span> <span class="token string">"💿"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"torrent"</span> <span class="token punctuation">.</span> <span class="token string">"⏳"</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token string">"bak"</span> <span class="token punctuation">.</span> <span class="token string">"🗃️"</span><span class="token punctuation">)</span>    <span class="token punctuation">(</span><span class="token string">"tmp"</span> <span class="token punctuation">.</span> <span class="token string">"⚠️"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"desktop"</span> <span class="token punctuation">.</span> <span class="token string">"🖥️"</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token string">"md5"</span> <span class="token punctuation">.</span> <span class="token string">"🔐"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"sha256"</span> <span class="token punctuation">.</span> <span class="token string">"🔐"</span><span class="token punctuation">)</span>  <span class="token punctuation">(</span><span class="token string">"pem"</span> <span class="token punctuation">.</span> <span class="token string">"🔐"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"sqlite"</span> <span class="token punctuation">.</span> <span class="token string">"🗄️"</span><span class="token punctuation">)</span>  <span class="token punctuation">(</span><span class="token string">"db"</span> <span class="token punctuation">.</span> <span class="token string">"🗄️"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"mp3"</span> <span class="token punctuation">.</span> <span class="token string">"🎶"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"wav"</span> <span class="token punctuation">.</span> <span class="token string">"🎶"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"flac"</span> <span class="token punctuation">.</span> <span class="token string">"🎶"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"ogg"</span> <span class="token punctuation">.</span> <span class="token string">"🎶"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"m4a"</span> <span class="token punctuation">.</span> <span class="token string">"🎶"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"mp4"</span> <span class="token punctuation">.</span> <span class="token string">"🎬"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"avi"</span> <span class="token punctuation">.</span> <span class="token string">"🎬"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"mov"</span> <span class="token punctuation">.</span> <span class="token string">"🎬"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"mkv"</span> <span class="token punctuation">.</span> <span class="token string">"🎬"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"webm"</span> <span class="token punctuation">.</span> <span class="token string">"🎬"</span><span class="token punctuation">)</span>    <span class="token punctuation">(</span><span class="token string">"flv"</span> <span class="token punctuation">.</span> <span class="token string">"🎬"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"ico"</span> <span class="token punctuation">.</span> <span class="token string">"🖼️"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"ttf"</span> <span class="token punctuation">.</span> <span class="token string">"🔠"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"otf"</span> <span class="token punctuation">.</span> <span class="token string">"🔠"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"eot"</span> <span class="token punctuation">.</span> <span class="token string">"🔠"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"woff"</span> <span class="token punctuation">.</span> <span class="token string">"🔠"</span><span class="token punctuation">)</span>    <span class="token punctuation">(</span><span class="token string">"woff2"</span> <span class="token punctuation">.</span> <span class="token string">"🔠"</span><span class="token punctuation">)</span>   <span class="token punctuation">(</span><span class="token string">"epub"</span> <span class="token punctuation">.</span> <span class="token string">"📚"</span><span class="token punctuation">)</span>    <span class="token punctuation">(</span><span class="token string">"mobi"</span> <span class="token punctuation">.</span> <span class="token string">"📚"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"azw3"</span> <span class="token punctuation">.</span> <span class="token string">"📚"</span><span class="token punctuation">)</span>    <span class="token punctuation">(</span><span class="token string">"fb2"</span> <span class="token punctuation">.</span> <span class="token string">"📚"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"chm"</span> <span class="token punctuation">.</span> <span class="token string">"📚"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"tex"</span> <span class="token punctuation">.</span> <span class="token string">"📚"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"bib"</span> <span class="token punctuation">.</span> <span class="token string">"📚"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"apk"</span> <span class="token punctuation">.</span> <span class="token string">"📱"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"rar"</span> <span class="token punctuation">.</span> <span class="token string">"📦"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"xz"</span> <span class="token punctuation">.</span> <span class="token string">"📦"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"zst"</span> <span class="token punctuation">.</span> <span class="token string">"📦"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"tar.xz"</span> <span class="token punctuation">.</span> <span class="token string">"📦"</span><span class="token punctuation">)</span>  <span class="token punctuation">(</span><span class="token string">"tar.zst"</span> <span class="token punctuation">.</span> <span class="token string">"📦"</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token string">"tar.gz"</span> <span class="token punctuation">.</span> <span class="token string">"📦"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"tgz"</span> <span class="token punctuation">.</span> <span class="token string">"📦"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"bz2"</span> <span class="token punctuation">.</span> <span class="token string">"📦"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"mpg"</span> <span class="token punctuation">.</span> <span class="token string">"🎬"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"webp"</span> <span class="token punctuation">.</span> <span class="token string">"🖼️"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"flv"</span> <span class="token punctuation">.</span> <span class="token string">"🎬"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"3gp"</span> <span class="token punctuation">.</span> <span class="token string">"🎬"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"ogv"</span> <span class="token punctuation">.</span> <span class="token string">"🎬"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"srt"</span> <span class="token punctuation">.</span> <span class="token string">"🔠"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token string">"vtt"</span> <span class="token punctuation">.</span> <span class="token string">"🔠"</span><span class="token punctuation">)</span>     <span class="token punctuation">(</span><span class="token string">"cue"</span> <span class="token punctuation">.</span> <span class="token string">"📀"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token string">"Icons for specific file extensions in Dired."</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo/dired-icons-icon-for-file</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">file</span></span><span class="token punctuation">)</span></span>
	<span class="token punctuation">(</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token car">file-directory-p</span> file<span class="token punctuation">)</span>
		<span class="token string">"📁"</span>
	  <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">ext</span> <span class="token punctuation">(</span><span class="token car">file-name-extension</span> file<span class="token punctuation">)</span><span class="token punctuation">)</span>
			 <span class="token punctuation">(</span><span class="token car">icon</span> <span class="token punctuation">(</span><span class="token keyword">and</span> ext <span class="token punctuation">(</span><span class="token car">assoc-default</span> <span class="token punctuation">(</span><span class="token car">downcase</span> ext<span class="token punctuation">)</span> emacs-solo/dired-icons-file-icons<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		<span class="token punctuation">(</span><span class="token keyword">or</span> icon <span class="token string">"📄"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo/dired-icons-icons-regexp</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
	<span class="token string">"Return a regexp that matches any icon we use."</span>
	<span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">icons</span> <span class="token punctuation">(</span><span class="token car">mapcar</span> <span class="token quoted-symbol variable symbol">#'cdr</span> emacs-solo/dired-icons-file-icons<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token keyword">concat</span> <span class="token string">"^\\("</span> <span class="token punctuation">(</span><span class="token car">regexp-opt</span> <span class="token punctuation">(</span><span class="token keyword">cons</span> <span class="token string">"📁"</span> icons<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token string">"\\) "</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo/dired-icons-add-icons</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
	<span class="token string">"Add icons to filenames in Dired buffer."</span>
	<span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token car">derived-mode-p</span> <span class="token quoted-symbol variable symbol">'dired-mode</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">inhibit-read-only</span> <span class="token boolean">t</span><span class="token punctuation">)</span>
			<span class="token punctuation">(</span><span class="token car">icon-regex</span> <span class="token punctuation">(</span><span class="token car">emacs-solo/dired-icons-icons-regexp</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		<span class="token punctuation">(</span><span class="token car">save-excursion</span>
		  <span class="token punctuation">(</span><span class="token car">goto-char</span> <span class="token punctuation">(</span><span class="token car">point-min</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		  <span class="token punctuation">(</span><span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token keyword">not</span> <span class="token punctuation">(</span><span class="token car">eobp</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			<span class="token punctuation">(</span><span class="token car">condition-case</span> <span class="token boolean">nil</span>
				<span class="token punctuation">(</span><span class="token car">when-let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">file</span> <span class="token punctuation">(</span><span class="token car">dired-get-filename</span> <span class="token boolean">nil</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token car">dired-move-to-filename</span><span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token keyword">unless</span> <span class="token punctuation">(</span><span class="token car">looking-at-p</span> icon-regex<span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token car">insert</span> <span class="token punctuation">(</span><span class="token keyword">concat</span> <span class="token punctuation">(</span><span class="token car">emacs-solo/dired-icons-icon-for-file</span> file<span class="token punctuation">)</span> <span class="token string">" "</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token keyword">error</span> <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">)</span>  <span class="token comment">;; gracefully skip invalid lines</span>
			<span class="token punctuation">(</span><span class="token car">forward-line</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token car">add-hook</span> <span class="token quoted-symbol variable symbol">'dired-after-readin-hook</span> <span class="token quoted-symbol variable symbol">#'emacs-solo/dired-icons-add-icons</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p><strong>Tradeoffs:</strong></p>
<p>✔️ Works everywhere (no special fonts)</p>
<p>✔️ Adds negligible overhead</p>
<p>❌ Less pretty than proper icons</p>
<p>❌ Manual extension mapping</p>
<hr>
<h2>2. Git Status Gutter for Dired</h2>
<p>A "good enough" implementation showing Git status without external packages:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token heading comment title">;;; EMACS-SOLO-DIRED-GUTTER</span>
<span class="token comment">;;</span>
<span class="token punctuation">(</span><span class="token keyword">use-package</span> emacs-solo-dired-gutter
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">nil</span>
  <span class="token lisp-property property">:no-require</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:defer</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:init</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> emacs-solo-dired-gutter-enabled <span class="token boolean">t</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defvar</span> <span class="token variable">emacs-solo/dired-git-status-overlays</span></span> <span class="token boolean">nil</span>
	<span class="token string">"List of active overlays in Dired for Git status."</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo/dired--git-status-face</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">code</span></span><span class="token punctuation">)</span></span>
	<span class="token string">"Return a cons cell (<span class="token argument">STATUS</span> . FACE) for a given Git porcelain <span class="token argument">CODE</span>."</span>
	<span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">git-status-untracked</span> <span class="token string">"??"</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">git-status-modified</span> <span class="token string">" M"</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">git-status-modified-alt</span> <span class="token string">"<span class="token argument">M</span> "</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">git-status-deleted</span> <span class="token string">"<span class="token argument">D</span> "</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">git-status-added</span> <span class="token string">"<span class="token argument">A</span> "</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">git-status-renamed</span> <span class="token string">"<span class="token argument">R</span> "</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">git-status-copied</span> <span class="token string">"<span class="token argument">C</span> "</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">git-status-ignored</span> <span class="token string">"!!"</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">status</span> <span class="token punctuation">(</span><span class="token keyword">cond</span>
					<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string-match-p</span> <span class="token string">"\\?\\?"</span> code<span class="token punctuation">)</span> git-status-untracked<span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string-match-p</span> <span class="token string">"^ M"</span> code<span class="token punctuation">)</span> git-status-modified<span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string-match-p</span> <span class="token string">"^<span class="token argument">M</span> "</span> code<span class="token punctuation">)</span> git-status-modified-alt<span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string-match-p</span> <span class="token string">"^D"</span> code<span class="token punctuation">)</span> git-status-deleted<span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string-match-p</span> <span class="token string">"^A"</span> code<span class="token punctuation">)</span> git-status-added<span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string-match-p</span> <span class="token string">"^R"</span> code<span class="token punctuation">)</span> git-status-renamed<span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string-match-p</span> <span class="token string">"^C"</span> code<span class="token punctuation">)</span> git-status-copied<span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string-match-p</span> <span class="token string">"\\!\\!"</span> code<span class="token punctuation">)</span> git-status-ignored<span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token boolean">t</span> <span class="token string">"  "</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">face</span> <span class="token punctuation">(</span><span class="token keyword">cond</span>
				  <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string=</span> status git-status-ignored<span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'shadow</span><span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string=</span> status git-status-untracked<span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'warning</span><span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string=</span> status git-status-modified<span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'font-lock-function-name-face</span><span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string=</span> status git-status-modified-alt<span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'font-lock-function-name-face</span><span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string=</span> status git-status-deleted<span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'error</span><span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">string=</span> status git-status-added<span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'success</span><span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token boolean">t</span> <span class="token quoted-symbol variable symbol">'font-lock-keyword-face</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token keyword">cons</span> status face<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo/dired-git-status-overlay</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
	<span class="token string">"Overlay Git status indicators on the first column in Dired."</span>
	<span class="token punctuation">(</span><span class="token interactive keyword">interactive</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">require</span> <span class="token quoted-symbol variable symbol">'vc-git</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">git-root</span> <span class="token punctuation">(</span><span class="token car">ignore-errors</span> <span class="token punctuation">(</span><span class="token car">vc-git-root</span> default-directory<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token keyword">and</span> git-root
				 <span class="token punctuation">(</span><span class="token keyword">not</span> <span class="token punctuation">(</span><span class="token car">file-remote-p</span> default-directory<span class="token punctuation">)</span><span class="token punctuation">)</span>
				 emacs-solo-dired-gutter-enabled<span class="token punctuation">)</span>
		<span class="token punctuation">(</span><span class="token keyword">setq</span> git-root <span class="token punctuation">(</span><span class="token car">expand-file-name</span> git-root<span class="token punctuation">)</span><span class="token punctuation">)</span>
		<span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">git-status</span> <span class="token punctuation">(</span><span class="token car">vc-git--run-command-string</span> <span class="token boolean">nil</span> <span class="token string">"status"</span> <span class="token string">"--porcelain"</span> <span class="token string">"--ignored"</span> <span class="token string">"--untracked-files=normal"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			   <span class="token punctuation">(</span><span class="token car">status-map</span> <span class="token punctuation">(</span><span class="token car">make-hash-table</span> <span class="token lisp-property property">:test</span> <span class="token quoted-symbol variable symbol">'equal</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		  <span class="token punctuation">(</span><span class="token car">mapc</span> <span class="token quoted-symbol variable symbol">#'delete-overlay</span> emacs-solo/dired-git-status-overlays<span class="token punctuation">)</span>
		  <span class="token punctuation">(</span><span class="token keyword">setq</span> emacs-solo/dired-git-status-overlays <span class="token boolean">nil</span><span class="token punctuation">)</span>

		  <span class="token punctuation">(</span><span class="token car">dolist</span> <span class="token punctuation">(</span><span class="token car">line</span> <span class="token punctuation">(</span><span class="token car">split-string</span> git-status <span class="token string">"\n"</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			<span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token car">string-match</span> <span class="token string">"^\\(..\\) \\(.+\\)$"</span> line<span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">code</span> <span class="token punctuation">(</span><span class="token car">match-string</span> <span class="token number">1</span> line<span class="token punctuation">)</span><span class="token punctuation">)</span>
					 <span class="token punctuation">(</span><span class="token car">file</span> <span class="token punctuation">(</span><span class="token car">match-string</span> <span class="token number">2</span> line<span class="token punctuation">)</span><span class="token punctuation">)</span>
					 <span class="token punctuation">(</span><span class="token car">fullpath</span> <span class="token punctuation">(</span><span class="token car">expand-file-name</span> file git-root<span class="token punctuation">)</span><span class="token punctuation">)</span>
					 <span class="token punctuation">(</span><span class="token car">status-face</span> <span class="token punctuation">(</span><span class="token car">emacs-solo/dired--git-status-face</span> code<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token car">puthash</span> fullpath status-face status-map<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

		  <span class="token punctuation">(</span><span class="token car">save-excursion</span>
			<span class="token punctuation">(</span><span class="token car">goto-char</span> <span class="token punctuation">(</span><span class="token car">point-min</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			<span class="token punctuation">(</span><span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token keyword">not</span> <span class="token punctuation">(</span><span class="token car">eobp</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">file</span> <span class="token punctuation">(</span><span class="token car">ignore-errors</span> <span class="token punctuation">(</span><span class="token car">expand-file-name</span> <span class="token punctuation">(</span><span class="token car">dired-get-filename</span> <span class="token boolean">nil</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				<span class="token punctuation">(</span><span class="token keyword">when</span> file
				  <span class="token punctuation">(</span><span class="token keyword">setq</span> file <span class="token punctuation">(</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token car">file-directory-p</span> file<span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token keyword">concat</span> file <span class="token string">"/"</span><span class="token punctuation">)</span> file<span class="token punctuation">)</span><span class="token punctuation">)</span>
				  <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">status-face</span> <span class="token punctuation">(</span><span class="token car">gethash</span> file status-map <span class="token punctuation">(</span><span class="token keyword">cons</span> <span class="token string">"  "</span> <span class="token quoted-symbol variable symbol">'font-lock-keyword-face</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
						 <span class="token punctuation">(</span><span class="token car">status</span> <span class="token punctuation">(</span><span class="token car">car</span> status-face<span class="token punctuation">)</span><span class="token punctuation">)</span>
						 <span class="token punctuation">(</span><span class="token car">face</span> <span class="token punctuation">(</span><span class="token car">cdr</span> status-face<span class="token punctuation">)</span><span class="token punctuation">)</span>
						 <span class="token punctuation">(</span><span class="token car">status-str</span> <span class="token punctuation">(</span><span class="token car">propertize</span> <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">" %s "</span> status<span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'face</span> face<span class="token punctuation">)</span><span class="token punctuation">)</span>
						 <span class="token punctuation">(</span><span class="token car">ov</span> <span class="token punctuation">(</span><span class="token car">make-overlay</span> <span class="token punctuation">(</span><span class="token car">line-beginning-position</span><span class="token punctuation">)</span> <span class="token punctuation">(</span>1+ <span class="token punctuation">(</span><span class="token car">line-beginning-position</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token car">overlay-put</span> ov <span class="token quoted-symbol variable symbol">'before-string</span> status-str<span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token car">push</span> ov emacs-solo/dired-git-status-overlays<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token car">forward-line</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token car">add-hook</span> <span class="token quoted-symbol variable symbol">'dired-after-readin-hook</span> <span class="token quoted-symbol variable symbol">#'emacs-solo/dired-git-status-overlay</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p><strong>Tradeoffs:</strong></p>
<p>✔️ Native Emacs speed</p>
<p>✔️ Visual feedback without clutter</p>
<p>✔️ No extra packages</p>
<p>❌ Less detailed than <code>diff-hl-dired-mode</code></p>
<p>❌ Local files only</p>
<p>❌ Requires manual refresh (with <code>g</code>)</p>
<hr>
<h2>Philosophy Behind These Hacks</h2>
<p>🎯 <strong>Solve immediate needs</strong>: These do exactly what <em>I</em> need. Your
mileage may vary, and that's ok!</p>
<p>🔍 <strong>Stay editable</strong>: No abstractions hiding the core logic.</p>
<p>✨ <strong>Embrace imperfection</strong>: The icons don't cover every file type,
and that's okay.</p>
<p>And <strong>AGAIN</strong>: These aren't polished packages. They're starter code
for your own tweaks. 😊</p>
<hr>
<h2>When To Use These vs Packages</h2>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">| Topic         | My Version    | Full Packages       |
| ------------- | ------------- | ------------------- |
| Installation  | Copy/paste    | Package-install     |
| Customization | Edit directly | Read package docs   |
| Appearance    | Functional    | Polished            |
| Maintenance   | You own it    | Community-supported |</code></pre></div>
<p><strong>Choose these if:</strong> You value simplicity over features. You want to
deal with things on your own. You want to learn while creating your
own tools.</p>
<p><strong>Choose packages if:</strong> You want battle-tested solutions</p>
<hr>
<h2>🚀 Try It Out</h2>
<ol>
<li>📋 <strong>Copy</strong> either/both snippets to your config</li>
<li>🎨 <strong>Tweak</strong> the icons or status symbols</li>
<li>⚙️ <strong>Adapt</strong> to your workflow</li>
</ol>
<p>Or grab the latest from:
<a href="https://github.com/lionyxml/emacs-solo">Emacs Solo</a>.</p>
<p>Happy hacking! 💻</p>
]]></description>
            <link>https://rahuljuliato.com/posts/dired-enhanced</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/dired-enhanced</guid>
            <pubDate>Wed, 30 Apr 2025 22:58:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Emacs Solo: A Surprise System Crafters Live Demo]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Last Friday, I was genuinely surprised by a live demo of my <strong>Emacs
Solo</strong> configuration on the <strong>System Crafters Weekly Show</strong>. Watching
the live demo was an eye-opener, as I hadn't expected the project to
get such attention, especially in a live setting. Seeing <strong>David
Wilson</strong> take a deep dive into the setup, testing the configuration
live, and exploring how powerful Emacs can be with only its built-in
packages was both humbling and inspiring.</p>
<p>For more details and to explore the configuration yourself, visit the
<a href="https://github.com/LionyxML/emacs-solo/">Emacs Solo GitHub
repository</a>.</p>
<p>The <strong>Emacs Solo</strong> configuration is all about returning to the roots
of Emacs. It's a minimalist setup designed to challenge myself and
test the full potential of Emacs using only its built-in
functionality. The goal was to create an efficient, yet fully
functional environment, all while keeping things as light and fast as
possible. No external dependencies, no clutter. Just pure,
unadulterated Emacs.</p>
<h3>The Project: Emacs Solo</h3>
<p><strong>Emacs Solo</strong> is a configuration that embraces the power of Emacs
without relying on external packages. It's a setup I go back to from
time to time to remind myself of how much can be accomplished with
just what Emacs offers out of the box.</p>
<p>This configuration is designed to be both powerful and lightweight,
allowing for a fast, efficient workflow with a focus on simplicity and
minimalism. The project includes several useful features for
day-to-day tasks like searching, editing, and navigating—everything
you need for an efficient Emacs experience.</p>
<p>Some of the highlights of the project include:</p>
<p>» A preview of <code>icomplete-verical</code> enhancements I proposed to the
Emacs core team (custom prefixes, vertico style setup, and inline
completion closer to corfu/company that works on text buffers and
eshell).</p>
<p>» An experimental custom <code>git-gutter-like</code> feature.</p>
<p>» Supercharged eshell customization.</p>
<p>» Custom solutions for editing multiple search entries.</p>
<p>» Built-in news readers like Gnus and Newsticker.</p>
<p>» Advanced file diffing and version control.</p>
<p>» Extended viper mode for those who prefer vim-style editing.</p>
<p>» Tree-sitter modes.</p>
<p>» LSP configurations.</p>
<p>» Custom <code>rainbown-mode</code> like.</p>
<p>» And many customizations of built-in packages.</p>
<p>The idea is that Emacs is already a powerful IDE, and with a bit of
clever customization, it can be made into something even more
streamlined, adaptable, and effective without the need for external
packages.</p>
<h3>Watch the Demo</h3>
<p>Here's the video of the live demo from the <strong>System Crafters Weekly
Show</strong>:</p>
<iframe width="100%"
		height="100%"
		style="aspect-ratio: 16 / 9;"
		src="https://www.youtube.com/embed/j_2QkCcf8zE?si=UnFWlLIP41tkB6XJ"
		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>
<p><a href="https://www.youtube.com/watch?v=j_2QkCcf8zE">» Also available here</a></p>
<h3>Conclusion</h3>
<p>I’d like to take this opportunity to thank <strong>David Wilson</strong> for the
amazing show and to the <strong>System Crafters</strong> community for their
continued support and enthusiasm around Emacs. I also want to express
my gratitude to everyone who has contributed code that I’ve borrowed
and learned from over the years. Particularly <strong>Gopar</strong> and
<strong>Protesilaos</strong>. Without the shared knowledge and experience from
these fantastic people, the <strong>Emacs Solo</strong> project wouldn't have been
possible.</p>
<p>As always, the beauty of Emacs lies in its community, and I'm grateful
for all the inspiration, contributions, and shared wisdom that make
projects like <strong>Emacs Solo</strong> come to life. Thank you to everyone who
continues to inspire and teach me along the way.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/emacs-solo-demo</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/emacs-solo-demo</guid>
            <pubDate>Thu, 27 Mar 2025 03:32:07 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Custom VC-Focused Emacs Functions I Created to Enhance My Git Workflow]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>As much as anyone else, I love and use <strong>MAGIT</strong>. It’s an incredibly
powerful tool, and I’ve spent countless hours relying on it for my Git
workflow. However, from time to time, I find myself trying to stick to
Emacs internals and avoid relying on external packages. This is where
my <code>emacs-solo</code> config comes in (you can find it at
<a href="https://github.com/lionyxml/emacs-solo">https://github.com/lionyxml/emacs-solo</a>). The
functions I’m sharing today are part of this config, hence the
<code>emacs-solo/</code> prefix in their names.</p>
<p>These functions are meant to be quick copy/paste snippets that anyone
can tweak to suit their needs. They’re not complete, beautifully
tailored packages but rather "quick tips and ideas" that I’ve found
useful in my daily workflow. If you know a bit of Elisp, you can
easily adapt them to your preferences.</p>
<p>Here’s a quick overview of the keybindings and what each function
does:</p>
<ul>
<li>
<p><strong><code>C-x v R</code></strong> - Show Git reflog with ANSI colors and custom keybindings.</p>
</li>
<li>
<p><strong><code>C-x v B</code></strong> - Browse the repository’s remote URL in the browser.</p>
</li>
<li>
<p><strong><code>C-u C-x v B</code></strong> - Browse the repository’s remote URL and point to the current branch, file, and line.</p>
</li>
<li>
<p><strong><code>C-x v =</code></strong> - Show the diff for the current file and jump to the hunk containing the current line.</p>
</li>
</ul>
<p>Let’s dive into each function in detail!</p>
<hr>
<h2>1. <code>emacs-solo/vc-git-reflog</code> (<code>C-x v R</code>)</h2>
<p>This function allows you to view the Git reflog in a new buffer with
ANSI colors and custom keybindings. It’s a great way to quickly
inspect the history of your Git repository.</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo/vc-git-reflog</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
  <span class="token string">"Show git reflog in a new buffer with <span class="token argument">ANSI</span> colors and custom keybindings."</span>
  <span class="token punctuation">(</span><span class="token interactive keyword">interactive</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">root</span> <span class="token punctuation">(</span><span class="token car">vc-root-dir</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		 <span class="token punctuation">(</span><span class="token car">buffer</span> <span class="token punctuation">(</span><span class="token car">get-buffer-create</span> <span class="token string">"*vc-git-reflog*"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token car">with-current-buffer</span> buffer
	  <span class="token punctuation">(</span><span class="token car">setq-local</span> vc-git-reflog-root root<span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">inhibit-read-only</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token car">erase-buffer</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token car">vc-git-command</span> buffer <span class="token boolean">nil</span> <span class="token boolean">nil</span>
					  <span class="token string">"reflog"</span>
					  <span class="token string">"--color=always"</span>
					  <span class="token string">"--pretty=format:%C(yellow)%h%Creset %C(auto)%d%Creset %Cgreen%gd%Creset %s %Cblue(%cr)%Creset"</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token car">goto-char</span> <span class="token punctuation">(</span><span class="token car">point-min</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token car">ansi-color-apply-on-region</span> <span class="token punctuation">(</span><span class="token car">point-min</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">point-max</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

	<span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">map</span> <span class="token punctuation">(</span><span class="token car">make-sparse-keymap</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token car">define-key</span> map <span class="token punctuation">(</span><span class="token car">kbd</span> <span class="token string">"/"</span><span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">#'isearch-forward</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token car">define-key</span> map <span class="token punctuation">(</span><span class="token car">kbd</span> <span class="token string">"p"</span><span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">#'previous-line</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token car">define-key</span> map <span class="token punctuation">(</span><span class="token car">kbd</span> <span class="token string">"n"</span><span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">#'next-line</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token car">define-key</span> map <span class="token punctuation">(</span><span class="token car">kbd</span> <span class="token string">"q"</span><span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">#'kill-buffer-and-window</span><span class="token punctuation">)</span>

	  <span class="token punctuation">(</span><span class="token car">use-local-map</span> map<span class="token punctuation">)</span><span class="token punctuation">)</span>

	<span class="token punctuation">(</span><span class="token keyword">setq</span> buffer-read-only <span class="token boolean">t</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">setq</span> mode-name <span class="token string">"Git-Reflog"</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">setq</span> major-mode <span class="token quoted-symbol variable symbol">'special-mode</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">pop-to-buffer</span> buffer<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token punctuation">(</span><span class="token car">global-set-key</span> <span class="token punctuation">(</span><span class="token car">kbd</span> <span class="token string">"C-x v R"</span><span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'emacs-solo/vc-git-reflog</span><span class="token punctuation">)</span>
</code></pre></div>
<hr>
<h2>2. <code>emacs-solo/vc-browse-remote</code> (<code>C-x v B</code> and <code>C-u C-x v B</code>)</h2>
<p>This function opens the repository’s remote URL in the browser. If
<code>CURRENT-LINE</code> is non-nil, it points to the current branch, file, and
line. Otherwise, it opens the repository’s main page.</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo/vc-browse-remote</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token other-marker-vars"><span class="token lisp-marker">&optional</span> <span class="token argument variable">current-line</span></span></span><span class="token punctuation">)</span></span>
  <span class="token string">"Open the repository's remote <span class="token argument">URL</span> in the browser.
If <span class="token argument">CURRENT-LINE</span> is non-nil, point to the current branch, file, and line.
Otherwise, open the repository's main page."</span>
  <span class="token punctuation">(</span><span class="token interactive keyword">interactive</span> <span class="token string">"P"</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">remote-url</span> <span class="token punctuation">(</span><span class="token car">string-trim</span> <span class="token punctuation">(</span><span class="token car">vc-git--run-command-string</span> <span class="token boolean">nil</span> <span class="token string">"config"</span> <span class="token string">"--get"</span> <span class="token string">"remote.origin.url"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		 <span class="token punctuation">(</span><span class="token car">branch</span> <span class="token punctuation">(</span><span class="token car">string-trim</span> <span class="token punctuation">(</span><span class="token car">vc-git--run-command-string</span> <span class="token boolean">nil</span> <span class="token string">"rev-parse"</span> <span class="token string">"--abbrev-ref"</span> <span class="token string">"HEAD"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		 <span class="token punctuation">(</span><span class="token car">file</span> <span class="token punctuation">(</span><span class="token car">string-trim</span> <span class="token punctuation">(</span><span class="token car">file-relative-name</span> <span class="token punctuation">(</span><span class="token car">buffer-file-name</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">vc-root-dir</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		 <span class="token punctuation">(</span><span class="token car">line</span> <span class="token punctuation">(</span><span class="token car">line-number-at-pos</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">message</span> <span class="token string">"Opening remote on browser: %s"</span> remote-url<span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">and</span> remote-url <span class="token punctuation">(</span><span class="token car">string-match</span> <span class="token string">"\\(?:git@\\|https://\\)\\([^:/]+\\)[:/]\\(.+?\\)\\(?:\\.git\\)?$"</span> remote-url<span class="token punctuation">)</span><span class="token punctuation">)</span>
		<span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">host</span> <span class="token punctuation">(</span><span class="token car">match-string</span> <span class="token number">1</span> remote-url<span class="token punctuation">)</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token car">path</span> <span class="token punctuation">(</span><span class="token car">match-string</span> <span class="token number">2</span> remote-url<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		  <span class="token comment">;; Convert SSH URLs to HTTPS (e.g., git@github.com:user/repo.git -> https://github.com/user/repo)</span>
		  <span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token car">string-prefix-p</span> <span class="token string">"git@"</span> host<span class="token punctuation">)</span>
			<span class="token punctuation">(</span><span class="token keyword">setq</span> host <span class="token punctuation">(</span><span class="token car">replace-regexp-in-string</span> <span class="token string">"^git@"</span> <span class="token string">""</span> host<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		  <span class="token comment">;; Construct the appropriate URL based on CURRENT-LINE</span>
		  <span class="token punctuation">(</span><span class="token car">browse-url</span>
		   <span class="token punctuation">(</span><span class="token keyword">if</span> current-line
			   <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">"https://%s/%s/blob/%s/%s#L%d"</span> host path branch file line<span class="token punctuation">)</span>
			 <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">"https://%s/%s"</span> host path<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token keyword">message</span> <span class="token string">"Could not determine repository URL"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token punctuation">(</span><span class="token car">global-set-key</span> <span class="token punctuation">(</span><span class="token car">kbd</span> <span class="token string">"C-x v B"</span><span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'emacs-solo/vc-browse-remote</span><span class="token punctuation">)</span>

</code></pre></div>
<p>If you use the universal argument <code>C-u</code> before <code>C-x v B</code> it browses the
current line.</p>
<hr>
<h2>3. <code>emacs-solo/vc-diff-on-current-hunk</code> (<code>C-x v =</code>)</h2>
<p>This function extends the default functionality, meaning it shows the
diff for the current file, but also jumps to the hunk containing the current
line. It’s a handy tool for reviewing changes on large files.</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">emacs-solo/vc-diff-on-current-hunk</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
  <span class="token string">"Show the diff for the current file and jump to the hunk containing the current line."</span>
  <span class="token punctuation">(</span><span class="token interactive keyword">interactive</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">current-line</span> <span class="token punctuation">(</span><span class="token car">line-number-at-pos</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token keyword">message</span> <span class="token string">"Current line in file: %d"</span> current-line<span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token car">vc-diff</span><span class="token punctuation">)</span> <span class="token comment">; Generate the diff buffer</span>
	<span class="token punctuation">(</span><span class="token car">with-current-buffer</span> <span class="token string">"*vc-diff*"</span>
	  <span class="token punctuation">(</span><span class="token car">goto-char</span> <span class="token punctuation">(</span><span class="token car">point-min</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">found-hunk</span> <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		<span class="token punctuation">(</span><span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token keyword">not</span> found-hunk<span class="token punctuation">)</span>
					<span class="token punctuation">(</span><span class="token car">re-search-forward</span> <span class="token string">"^@@ -\\([0-9]+\\), *[0-9]+ \\+\\([0-9]+\\), *\\([0-9]+\\) @@"</span> <span class="token boolean">nil</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		  <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">start-line</span> <span class="token punctuation">(</span><span class="token car">string-to-number</span> <span class="token punctuation">(</span><span class="token car">match-string</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				   <span class="token punctuation">(</span><span class="token car">line-count</span> <span class="token punctuation">(</span><span class="token car">string-to-number</span> <span class="token punctuation">(</span><span class="token car">match-string</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
				   <span class="token punctuation">(</span><span class="token car">end-line</span> <span class="token punctuation">(</span><span class="token car">+</span> start-line line-count<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
			<span class="token punctuation">(</span><span class="token keyword">message</span> <span class="token string">"Found hunk: %d to %d"</span> start-line end-line<span class="token punctuation">)</span>
			<span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token keyword">and</span> <span class="token punctuation">(</span><span class="token car">>=</span> current-line start-line<span class="token punctuation">)</span>
						 <span class="token punctuation">(</span><span class="token car">&#x3C;=</span> current-line end-line<span class="token punctuation">)</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token keyword">message</span> <span class="token string">"Current line %d is within hunk range %d to %d"</span> current-line start-line end-line<span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token keyword">setq</span> found-hunk <span class="token boolean">t</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token car">goto-char</span> <span class="token punctuation">(</span><span class="token car">match-beginning</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
		<span class="token punctuation">(</span><span class="token keyword">unless</span> found-hunk
		  <span class="token punctuation">(</span><span class="token keyword">message</span> <span class="token string">"Current line %d is not within any hunk range."</span> current-line<span class="token punctuation">)</span>
		  <span class="token punctuation">(</span><span class="token car">goto-char</span> <span class="token punctuation">(</span><span class="token car">point-min</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token punctuation">(</span><span class="token car">global-set-key</span> <span class="token punctuation">(</span><span class="token car">kbd</span> <span class="token string">"C-x v ="</span><span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'emacs-solo/vc-diff-on-current-hunk</span><span class="token punctuation">)</span>
</code></pre></div>
<hr>
<h2>Wrapping Up</h2>
<p>These custom VC-focused Emacs functions have become essential tools in
my Git workflow, and I hope they can be useful to others as
well. Whether you’re inspecting the reflog, browsing remote
repositories, or reviewing diffs, these functions are designed to make
your workflow smoother and more efficient. Happy coding! 🚀</p>
<h3>Edit</h3>
<p><strong>2026-02-13:</strong> Fixed "univeral" typo, thanks to <a href="https://finke.dev/">Lennart</a>
for reporting it!</p>
]]></description>
            <link>https://rahuljuliato.com/posts/vc-git-functions</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/vc-git-functions</guid>
            <pubDate>Fri, 21 Mar 2025 00:02:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Compiling Emacs 30.1 from the source on Debian]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>This guide walks you through compiling Emacs 30.1 on Debian 12,
covering the download, checksum verification (SHA1, SHA256), and build
process. With Debian’s package dependencies, you can quickly compile,
install, and uninstall Emacs with ease.</p>
<p>Emacs 30.1 introduces security fixes, performance improvements, and
new features. If you prefer to build it from source, this guide walks
you through the process step by step.</p>
<h2>Compiling Emacs 30.1 from the source</h2>
<p>Today, Emacs community received a really nice message from
Stefan Kangas which currently is a maintainer of GNU Emacs.</p>
<p>You can read it here:
<a href="https://lists.gnu.org/archive/html/emacs-devel/2025-02/msg00997.html">https://lists.gnu.org/archive/html/emacs-devel/2025-02/msg00997.html</a>.</p>
<p>This gives us the opportunity of building Emacs from the source (which I
usually prefer, since I like to toggle some switches).</p>
<p>The next steps in this short tutorial will take in consideration you
have the latest Debian release, in my case, running <code>uname -a</code> returns:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">Linux debian <span class="token number">6.1</span>.0-31-amd64 <span class="token comment">#1 SMP PREEMPT_DYNAMIC Debian 6.1.128-1 (2025-02-07) x86_64 GNU/Linux</span>
</code></pre></div>
<h2>Downloading Emacs Source-Code</h2>
<p>Create a new directory of your liking and cd into it:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">mkdir</span> ~/emacs_build
<span class="token builtin class-name">cd</span> emacs_build
</code></pre></div>
<p>Download the Emacs source code file. You can do this from
<a href="https://ftp.gnu.org/gnu/emacs/">https://ftp.gnu.org/gnu/emacs/</a>, by
accessing it from your web-browser, or:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">wget -c  https://ftpmirror.gnu.org/emacs/emacs-30.1.tar.gz</code></pre></div>
<h2>Verifying the tarball checksum</h2>
<p>Now verify the tarball (.tar.gz compressed file) checksum by running:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">sha1sum emacs-30.1.tar.gz
</code></pre></div>
<p>or</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">sha256sum emacs-30.1.tar.gz
</code></pre></div>
<p>The returned sums should match those provided on the original release note. In my case:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">57c382f8cd2bd58b146b4b120ab8941f261b82b7  emacs-30.1.tar.gz
54404782ea5de37e8fcc4391fa9d4a41359a4ba9689b541f6bc97dd1ac283f6c  emacs-30.1.tar.gz
</code></pre></div>
<p>If something is strange, stop here, check the sources and make sure
you have an authentic copy of Emacs source code.</p>
<h2>Unpacking the tarball</h2>
<p>You can now unpack the tarball by running:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">tar</span> xvfz emacs-30.1.tar.gz
</code></pre></div>
<p>After that enter the created folder with:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> emacs-30.1
</code></pre></div>
<h2>Configuring for the build</h2>
<p>Usually, building something from source means going trough config and make, several
times, resolving dependencies and so on.</p>
<p>Here we're gonna cheat a little bit. Since Debian already ships some
sort (normally older) of Emacs. We can ask to install the build
dependencies for Emacs and save us some configure-make loop time.</p>
<p>Do this with:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">apt-get</span> build-dep emacs
</code></pre></div>
<p>After this, it is time to configure things.</p>
<p>You can check all Emacs flags by running <code>./configure --help</code>.</p>
<p>I usually go with these options:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">./configure --with-native-compilation<span class="token operator">=</span>aot<span class="token punctuation">\</span>
            --with-tree-sitter<span class="token punctuation">\</span>
            --with-gif<span class="token punctuation">\</span>
            --with-png<span class="token punctuation">\</span>
            --with-jpeg<span class="token punctuation">\</span>
            --with-rsvg<span class="token punctuation">\</span>
            --with-tiff<span class="token punctuation">\</span>
            --with-imagemagick<span class="token punctuation">\</span>
            --with-pgtk<span class="token punctuation">\</span>
            --with-mailutils
</code></pre></div>
<p>Customize it to your will.</p>
<h2>Making and Installing</h2>
<p>In this step we're actually building the software and installing.</p>
<p>Start by cleaning any older building with:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">make</span> clean
</code></pre></div>
<p>If you had some problem during a previous make, or had to stop it for some reason,
this will ensure you new "build" is clean and starting from the beginning.</p>
<p>Now we actually run make with:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">make</span> <span class="token parameter variable">-j8</span>
</code></pre></div>
<p>This will compile Emacs by allowing 8 jobs at once. You can leave make with only <code>-j</code>
flag for <code>infinite</code> jobs or customize at will with a number.</p>
<p>If everything runs ok and make exits successfully you can test Emacs with <code>./src/emacs</code>, I recommend just doing a version check with:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">./src/emacs <span class="token parameter variable">--version</span>
</code></pre></div>
<p>That may return:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">GNU Emacs <span class="token number">30.1</span>
Copyright <span class="token punctuation">(</span>C<span class="token punctuation">)</span> <span class="token number">2025</span> Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of GNU Emacs
under the terms of the GNU General Public License.
For <span class="token function">more</span> information about these matters, see the <span class="token function">file</span> named COPYING.
</code></pre></div>
<p>To have your built Emacs readily available, install it to your system with:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">make</span> <span class="token function">install</span>
</code></pre></div>
<p>Verify if you have the compiled version to your path by issuing:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">emacs <span class="token parameter variable">--version</span>
</code></pre></div>
<p>You may have again:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">GNU Emacs <span class="token number">30.1</span>
<span class="token punctuation">..</span>.
</code></pre></div>
<p>And that's it!</p>
<h2>Uninstalling Emacs</h2>
<p>If things go wrong or you need to uninstall a version of Emacs
before compiling a new one, it is a "necessity practice" to keep the
folder from where you built your software, so you can run: <code>make uninstall</code> and remove it completely from your system.</p>
<h2>Wrapping Up</h2>
<p>You’ve successfully compiled and installed Emacs 30.1 from source!
Now, enjoy the latest Emacs features and customize it to your
workflow. Happy hacking! 🚀</p>
]]></description>
            <link>https://rahuljuliato.com/posts/compiling_emacs_30_1</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/compiling_emacs_30_1</guid>
            <pubDate>Sun, 23 Feb 2025 00:02:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Enhancing icomplete-vertical-mode in Emacs: A Follow-Up]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>In my previous post, I shared how I improved the usability of
<code>icomplete-vertical-mode</code> by customizing its rendering to make
completions more visually accessible. Since then, I’ve taken things a
step further by generalizing the solution into a reusable function and
introducing a range of customization options, including prefix markers
and alignment controls. In this follow-up, I’ll walk you through these
updates and show you how to get even more out of
<code>icomplete-vertical-mode</code>.</p>
<p>In order to understand the Emacs original behavior and the history
behind this, please take a look at my previous post before continue
reading: <a href="in-buffer-icomplete/">Enhancing icomplete-vertical-mode in Emacs</a></p>
<p>Let's start with a little show and tell. The default config with this patch:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Ficomplete-2-01.gif&w=3840&q=75" alt="icomplete with custom prefix"></p>
<p>Some customizations:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Ficomplete-2-02.gif&w=3840&q=75" alt="icomplete with another custom prefix"></p>
<h2>Key Features of the New Implementation</h2>
<h3>1. Prefix Markers for Selected and Unselected Candidates</h3>
<p>To enhance visual clarity, I added customizable prefix markers for
selected and unselected candidates. These markers make it easy to
identify the current selection at a glance.</p>
<h3>Customization Variables:</h3>
<ul>
<li>
<p><code>icomplete-vertical-selected-prefix-marker</code>: A string used as the
prefix for the currently selected completion candidate.</p>
<p>Default: "» "</p>
</li>
<li>
<p><code>icomplete-vertical-unselected-prefix-marker</code>: A string used as the
prefix for unselected completion candidates.</p>
<p>Default: "  " (two spaces).</p>
</li>
<li>
<p><code>icomplete-vertical-selected-prefix-face</code>: Controls the appearance
of the selected prefix marker. Default: cyan text with bold weight.</p>
</li>
<li>
<p><code>icomplete-vertical-unselected-prefix-face</code>: Controls the appearance
of the unselected prefix marker. Default: gray text with normal
weight.</p>
</li>
</ul>
<h3>2.  Alignment for In-Buffer Completions</h3>
<p>The alignment of in-buffer completions has been improved with the
introduction of <code>icomplete-vertical-in-buffer-adjust-list</code>. When
enabled, it aligns completions with the cursor position where the
completion started, instead of defaulting to the first column. This
makes the completions feel more natural and connected to the context.</p>
<ul>
<li>
<p><code>icomplete-vertical-in-buffer-adjust-list</code>:</p>
<p>Default: t (enabled).</p>
<p>If nil, completions will align to the first column as usual.</p>
</li>
</ul>
<h3>3.  Toggleable Prefix Marker Rendering</h3>
<p>The entire prefix marker functionality can be toggled on or off using
<code>icomplete-vertical-render-prefix-marker</code>. If you prefer a cleaner list
without markers, simply set this to nil.</p>
<h3>4.  Overridable Functions</h3>
<p>Both new functions <code>icomplete-vertical--adjust-lines-for-column</code> and
<code>icomplete-vertical--add-marker-to-selected</code>, can be overridden to
implement new features. This is a little bit easier than re-write the
entire <code>icomplete--render-vertical</code> function.</p>
<h2>How do I get it?</h2>
<p>We're going to explore two ways of applying this patch:</p>
<ol>
<li><strong>Applying the patch to your Emacs source or package directory</strong></li>
<li><strong>Overwriting the setup directly in your <code>init.el</code></strong></li>
</ol>
<p>Let’s dive into both methods.</p>
<h3>Method 1: Applying the Patch</h3>
<p>You’ll need to locate the <code>lisp/icomplete.el</code> file in your system or
in the Emacs source directory if you compile Emacs yourself. Follow
these steps to apply the patch:</p>
<p>1.) <strong>Locate the File</strong></p>
<p>Identify the location of <code>icomplete.el</code> on your system. If you're
using a precompiled version of Emacs, you can find it under the
<code>lisp/</code> directory of your Emacs installation. For users compiling
Emacs from source, look for the file in the Emacs source tree.</p>
<p>2.) <strong>Download the Patch</strong></p>
<p>Download the patch file from
<a href="/assets/blog/posts/icomplete-2-patch.patch">here</a>. Save it somewhere
easily accessible.</p>
<p>3.) <strong>Apply the Patch with Git</strong></p>
<p>Navigate to the directory containing <code>icomplete.el</code> and run the
following command:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">git</span> apply path-to-patch-file.patch
</code></pre></div>
<p>Replace <code>path-to-patch-file.patch</code> with the actual file path to the
downloaded patch.</p>
<p>4.) <strong>Load the Updated Version in Your <code>init.el</code></strong>
After applying the patch, use the following <code>use-package</code>
configuration to load the updated version. The gif demo above uses the
following configuration:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> icomplete
  <span class="token lisp-property property">:bind</span> <span class="token punctuation">(</span><span class="token lisp-property property">:map</span> icomplete-minibuffer-map
              <span class="token punctuation">(</span><span class="token string">"C-n"</span> <span class="token punctuation">.</span> icomplete-forward-completions<span class="token punctuation">)</span>
              <span class="token punctuation">(</span><span class="token string">"C-p"</span> <span class="token punctuation">.</span> icomplete-backward-completions<span class="token punctuation">)</span>
              <span class="token punctuation">(</span><span class="token string">"C-v"</span> <span class="token punctuation">.</span> icomplete-vertical-toggle<span class="token punctuation">)</span>
              <span class="token punctuation">(</span><span class="token string">"RET"</span> <span class="token punctuation">.</span> icomplete-force-complete-and-exit<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:hook</span>
  <span class="token punctuation">(</span><span class="token car">after-init</span> <span class="token punctuation">.</span> <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
                  <span class="token punctuation">(</span><span class="token car">fido-mode</span> <span class="token number">-1</span><span class="token punctuation">)</span>
                  <span class="token punctuation">(</span><span class="token car">icomplete-vertical-mode</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:config</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-delay-completions-threshold <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-compute-delay <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-show-matches-on-no-input <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-hide-common-prefix <span class="token boolean">nil</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-prospects-height <span class="token number">10</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-separator <span class="token string">" . "</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-with-completion-tables <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-in-buffer <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-max-delay-chars <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-scroll <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">advice-add</span> <span class="token quoted-symbol variable symbol">'completion-at-point</span>
              <span class="token lisp-property property">:after</span> <span class="token quoted-symbol variable symbol">#'minibuffer-hide-completions</span><span class="token punctuation">)</span>
              
  <span class="token comment">;; These are our new post-patch options</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-vertical-selected-prefix-marker <span class="token string">"» "</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-vertical-unselected-prefix-marker <span class="token string">"  "</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-vertical-in-buffer-adjust-list <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-vertical-render-prefix-marker <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<h3>Method 2: Overriding in <code>init.el</code></h3>
<p>This method involves directly overriding the necessary options in your
<code>init.el</code> without applying the patch. While this is not the
recommended approach, it can be used as a quick way to try out the
changes.</p>
<ol>
<li>
<p><strong>Add the Custom Code</strong></p>
<p>You can directly customize <code>icomplete-vertical-mode</code> with the following code in your <code>init.el</code>:</p>
</li>
</ol>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token heading comment title">;;; ICOMPLETE</span>
<span class="token punctuation">(</span><span class="token keyword">use-package</span> icomplete
  <span class="token lisp-property property">:bind</span> <span class="token punctuation">(</span><span class="token lisp-property property">:map</span> icomplete-minibuffer-map
              <span class="token punctuation">(</span><span class="token string">"C-n"</span> <span class="token punctuation">.</span> icomplete-forward-completions<span class="token punctuation">)</span>
              <span class="token punctuation">(</span><span class="token string">"C-p"</span> <span class="token punctuation">.</span> icomplete-backward-completions<span class="token punctuation">)</span>
              <span class="token punctuation">(</span><span class="token string">"C-v"</span> <span class="token punctuation">.</span> icomplete-vertical-toggle<span class="token punctuation">)</span>
              <span class="token punctuation">(</span><span class="token string">"RET"</span> <span class="token punctuation">.</span> icomplete-force-complete-and-exit<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:hook</span>
  <span class="token punctuation">(</span><span class="token car">after-init</span> <span class="token punctuation">.</span> <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
                  <span class="token punctuation">(</span><span class="token car">fido-mode</span> <span class="token number">-1</span><span class="token punctuation">)</span>
                  <span class="token punctuation">(</span><span class="token car">icomplete-vertical-mode</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:config</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-delay-completions-threshold <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-compute-delay <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-show-matches-on-no-input <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-hide-common-prefix <span class="token boolean">nil</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-prospects-height <span class="token number">10</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-separator <span class="token string">" . "</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-with-completion-tables <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-in-buffer <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-max-delay-chars <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-scroll <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">advice-add</span> <span class="token quoted-symbol variable symbol">'completion-at-point</span>
              <span class="token lisp-property property">:after</span> <span class="token quoted-symbol variable symbol">#'minibuffer-hide-completions</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defcustom</span> <span class="token variable">icomplete-vertical-selected-prefix-marker</span></span> <span class="token string">"» "</span>
    <span class="token string">"Prefix string used to mark the selected completion candidate.
If <span class="token symbol">`icomplete-vertical-render-prefix-marker'</span> is t, the string
setted here is used as a prefix of the currently selected entry in the
list.  It can be further customized by the face
<span class="token symbol">`icomplete-vertical-selected-prefix-face'</span>."</span>
    <span class="token lisp-property property">:type</span> <span class="token quoted-symbol variable symbol">'string</span>
    <span class="token lisp-property property">:group</span> <span class="token quoted-symbol variable symbol">'icomplete</span>
    <span class="token lisp-property property">:version</span> <span class="token string">"31"</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defcustom</span> <span class="token variable">icomplete-vertical-unselected-prefix-marker</span></span> <span class="token string">"  "</span>
    <span class="token string">"Prefix string used on the unselected completion candidates.
If <span class="token symbol">`icomplete-vertical-render-prefix-marker'</span> is t, the string
setted here is used as a prefix for all unselected entries in the list.
list.  It can be further customized by the face
<span class="token symbol">`icomplete-vertical-unselected-prefix-face'</span>."</span>
    <span class="token lisp-property property">:type</span> <span class="token quoted-symbol variable symbol">'string</span>
    <span class="token lisp-property property">:group</span> <span class="token quoted-symbol variable symbol">'icomplete</span>
    <span class="token lisp-property property">:version</span> <span class="token string">"31"</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defcustom</span> <span class="token variable">icomplete-vertical-in-buffer-adjust-list</span></span> <span class="token boolean">t</span>
    <span class="token string">"Control whether in-buffer completion should align the cursor position.
If this is t and <span class="token symbol">`icomplete-in-buffer'</span> is t, and <span class="token symbol">`icomplete-vertical-mode'</span>
is activated, the in-buffer vertical completions are shown aligned to the
cursor position when the completion started, not on the first column, as
the default behaviour."</span>
    <span class="token lisp-property property">:type</span> <span class="token quoted-symbol variable symbol">'boolean</span>
    <span class="token lisp-property property">:group</span> <span class="token quoted-symbol variable symbol">'icomplete</span>
    <span class="token lisp-property property">:version</span> <span class="token string">"31"</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defcustom</span> <span class="token variable">icomplete-vertical-render-prefix-marker</span></span> <span class="token boolean">t</span>
    <span class="token string">"Control whether a marker is added as a prefix to each candidate.
If this is t and <span class="token symbol">`icomplete-vertical-mode'</span> is activated, a marker,
controlled by <span class="token symbol">`icomplete-vertical-selected-prefix-marker'</span> is shown
as a prefix to the current under selection candidate, while the
remaining of the candidates will receive the marker controlled
by <span class="token symbol">`icomplete-vertical-unselected-prefix-marker'</span>."</span>
    <span class="token lisp-property property">:type</span> <span class="token quoted-symbol variable symbol">'boolean</span>
    <span class="token lisp-property property">:group</span> <span class="token quoted-symbol variable symbol">'icomplete</span>
    <span class="token lisp-property property">:version</span> <span class="token string">"31"</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token car">defface</span> icomplete-vertical-selected-prefix-face
    <span class="token punctuation">'(</span><span class="token punctuation">(</span><span class="token boolean">t</span> <span class="token lisp-property property">:inherit</span> font-lock-keyword-face <span class="token lisp-property property">:weight</span> bold <span class="token lisp-property property">:foreground</span> <span class="token string">"cyan"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token string">"Face used for the prefix set by <span class="token symbol">`icomplete-vertical-selected-prefix-marker'</span>."</span>
    <span class="token lisp-property property">:group</span> <span class="token quoted-symbol variable symbol">'icomplete</span>
    <span class="token lisp-property property">:version</span> <span class="token string">"31"</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token car">defface</span> icomplete-vertical-unselected-prefix-face
    <span class="token punctuation">'(</span><span class="token punctuation">(</span><span class="token boolean">t</span> <span class="token lisp-property property">:inherit</span> font-lock-keyword-face <span class="token lisp-property property">:weight</span> normal <span class="token lisp-property property">:foreground</span> <span class="token string">"gray"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token string">"Face used for the prefix set by <span class="token symbol">`icomplete-vertical-unselected-prefix-marker'</span>."</span>
    <span class="token lisp-property property">:group</span> <span class="token quoted-symbol variable symbol">'icomplete</span>
    <span class="token lisp-property property">:version</span> <span class="token string">"31"</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">icomplete-vertical--adjust-lines-for-column</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">lines</span> <span class="token argument variable">buffer</span> <span class="token argument variable">data</span></span><span class="token punctuation">)</span></span>
    <span class="token string">"Adjust the <span class="token argument">LINES</span> to align with the column in <span class="token argument">BUFFER</span> based on <span class="token argument">DATA</span>."</span>
    <span class="token punctuation">(</span><span class="token keyword">if</span> icomplete-vertical-in-buffer-adjust-list
        <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">column</span>
               <span class="token punctuation">(</span><span class="token car">with-current-buffer</span> buffer
                 <span class="token punctuation">(</span><span class="token car">save-excursion</span>
                   <span class="token punctuation">(</span><span class="token car">goto-char</span> <span class="token punctuation">(</span><span class="token car">car</span> data<span class="token punctuation">)</span><span class="token punctuation">)</span>
                   <span class="token punctuation">(</span><span class="token car">current-column</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
          <span class="token punctuation">(</span><span class="token car">dolist</span> <span class="token punctuation">(</span><span class="token car">l</span> lines<span class="token punctuation">)</span>
            <span class="token punctuation">(</span><span class="token car">add-text-properties</span>
             <span class="token number">0</span> <span class="token number">1</span> <span class="token punctuation">`(</span><span class="token car">display</span> <span class="token punctuation">,(</span><span class="token keyword">concat</span> <span class="token punctuation">(</span><span class="token car">make-string</span> column ?\s<span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">substring</span> l <span class="token number">0</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
             l<span class="token punctuation">)</span><span class="token punctuation">)</span>
          lines<span class="token punctuation">)</span>
      lines<span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">icomplete-vertical--add-marker-to-selected</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">comp</span></span><span class="token punctuation">)</span></span>
    <span class="token string">"Add markers to the selected/unselected <span class="token argument">COMP</span> completions."</span>
    <span class="token punctuation">(</span><span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">and</span> icomplete-vertical-render-prefix-marker
             <span class="token punctuation">(</span><span class="token car">get-text-property</span> <span class="token number">0</span> <span class="token quoted-symbol variable symbol">'icomplete-selected</span> comp<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">(</span><span class="token keyword">concat</span> <span class="token punctuation">(</span><span class="token car">propertize</span> icomplete-vertical-selected-prefix-marker
                            <span class="token quoted-symbol variable symbol">'face</span> <span class="token quoted-symbol variable symbol">'icomplete-vertical-selected-prefix-face</span><span class="token punctuation">)</span>
                comp<span class="token punctuation">)</span>
      <span class="token punctuation">(</span><span class="token keyword">concat</span> <span class="token punctuation">(</span><span class="token car">propertize</span> icomplete-vertical-unselected-prefix-marker
                          <span class="token quoted-symbol variable symbol">'face</span> <span class="token quoted-symbol variable symbol">'icomplete-vertical-unselected-prefix-face</span><span class="token punctuation">)</span>
              comp<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">cl-defun</span> <span class="token function">icomplete--render-vertical</span>
      <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">comps</span> <span class="token argument variable">md</span> <span class="token other-marker-vars"><span class="token lisp-marker">&aux</span> <span class="token argument variable">scroll-above</span> <span class="token argument variable">scroll-below</span>
             <span class="token varform"><span class="token punctuation">(</span><span class="token car">total-space</span> <span class="token comment">; number of mini-window lines available</span>
              <span class="token punctuation">(</span>1- <span class="token punctuation">(</span><span class="token car">min</span>
                   icomplete-prospects-height
                   <span class="token punctuation">(</span><span class="token car">truncate</span> <span class="token punctuation">(</span><span class="token car">max-mini-window-lines</span><span class="token punctuation">)</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span></span></span></span><span class="token punctuation">)</span></span>
    <span class="token comment">;; Welcome to loopapalooza!</span>
    <span class="token comment">;;</span>
    <span class="token comment">;; First, be mindful of `icomplete-scroll' and manual scrolls.  If</span>
    <span class="token comment">;; `icomplete--scrolled-completions' and `icomplete--scrolled-past'</span>
    <span class="token comment">;; are:</span>
    <span class="token comment">;;</span>
    <span class="token comment">;; - both nil, there is no manual scroll;</span>
    <span class="token comment">;; - both non-nil, there is a healthy manual scroll that doesn't need</span>
    <span class="token comment">;;   to be readjusted (user just moved around the minibuffer, for</span>
    <span class="token comment">;;   example);</span>
    <span class="token comment">;; - non-nil and nil, respectively, a refiltering took place and we</span>
    <span class="token comment">;;   may need to readjust them to the new filtered `comps'.</span>
    <span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token keyword">and</span> icomplete-scroll
               icomplete--scrolled-completions
               <span class="token punctuation">(</span><span class="token keyword">null</span> icomplete--scrolled-past<span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">(</span><span class="token keyword">cl-loop</span> with preds
               for <span class="token punctuation">(</span><span class="token car">comp</span> <span class="token punctuation">.</span> rest<span class="token punctuation">)</span> on comps
               when <span class="token punctuation">(</span><span class="token car">equal</span> comp <span class="token punctuation">(</span><span class="token car">car</span> icomplete--scrolled-completions<span class="token punctuation">)</span><span class="token punctuation">)</span>
               do
               <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete--scrolled-past preds
                     comps <span class="token punctuation">(</span><span class="token keyword">cons</span> comp rest<span class="token punctuation">)</span><span class="token punctuation">)</span>
               <span class="token punctuation">(</span><span class="token car">completion--cache-all-sorted-completions</span>
                <span class="token punctuation">(</span><span class="token car">icomplete--field-beg</span><span class="token punctuation">)</span>
                <span class="token punctuation">(</span><span class="token car">icomplete--field-end</span><span class="token punctuation">)</span>
                comps<span class="token punctuation">)</span>
               and return <span class="token boolean">nil</span>
               do <span class="token punctuation">(</span><span class="token car">push</span> comp preds<span class="token punctuation">)</span>
               finally <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete--scrolled-completions <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token comment">;; Then, in this pretty ugly loop, collect completions to display</span>
    <span class="token comment">;; above and below the selected one, considering scrolling</span>
    <span class="token comment">;; positions.</span>
    <span class="token punctuation">(</span><span class="token keyword">cl-loop</span> with preds = icomplete--scrolled-past
             with succs = <span class="token punctuation">(</span><span class="token car">cdr</span> comps<span class="token punctuation">)</span>
             with space-above = <span class="token punctuation">(</span><span class="token car">-</span> total-space
                                   <span class="token number">1</span>
                                   <span class="token punctuation">(</span><span class="token keyword">cl-loop</span> for <span class="token punctuation">(</span><span class="token car">_</span> <span class="token punctuation">.</span> r<span class="token punctuation">)</span> on comps
                                            repeat <span class="token punctuation">(</span><span class="token car">truncate</span> total-space <span class="token number">2</span><span class="token punctuation">)</span>
                                            while <span class="token punctuation">(</span><span class="token car">listp</span> r<span class="token punctuation">)</span>
                                            count <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
             repeat total-space
             for neighbor = <span class="token boolean">nil</span>
             if <span class="token punctuation">(</span><span class="token keyword">and</span> preds <span class="token punctuation">(</span><span class="token car">></span> space-above <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span> do
             <span class="token punctuation">(</span><span class="token car">push</span> <span class="token punctuation">(</span><span class="token keyword">setq</span> neighbor <span class="token punctuation">(</span><span class="token car">pop</span> preds<span class="token punctuation">)</span><span class="token punctuation">)</span> scroll-above<span class="token punctuation">)</span>
             <span class="token punctuation">(</span><span class="token car">cl-decf</span> space-above<span class="token punctuation">)</span>
             else if <span class="token punctuation">(</span><span class="token car">consp</span> succs<span class="token punctuation">)</span> collect
             <span class="token punctuation">(</span><span class="token keyword">setq</span> neighbor <span class="token punctuation">(</span><span class="token car">pop</span> succs<span class="token punctuation">)</span><span class="token punctuation">)</span> into scroll-below-aux
             while neighbor
             finally <span class="token punctuation">(</span><span class="token keyword">setq</span> scroll-below scroll-below-aux<span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token comment">;; Halfway there...</span>
    <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">selected</span> <span class="token punctuation">(</span><span class="token car">propertize</span> <span class="token punctuation">(</span><span class="token car">car</span> comps<span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'icomplete-selected</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
           <span class="token punctuation">(</span><span class="token car">chosen</span> <span class="token punctuation">(</span><span class="token keyword">append</span> scroll-above <span class="token punctuation">(</span><span class="token car">list</span> selected<span class="token punctuation">)</span> scroll-below<span class="token punctuation">)</span><span class="token punctuation">)</span>
           <span class="token punctuation">(</span><span class="token car">tuples</span> <span class="token punctuation">(</span><span class="token car">icomplete--augment</span> md chosen<span class="token punctuation">)</span><span class="token punctuation">)</span>
           max-prefix-len max-comp-len lines nsections<span class="token punctuation">)</span>
      <span class="token punctuation">(</span><span class="token car">add-face-text-property</span> <span class="token number">0</span> <span class="token punctuation">(</span><span class="token car">length</span> selected<span class="token punctuation">)</span>
                              <span class="token quoted-symbol variable symbol">'icomplete-selected-match</span> <span class="token quoted-symbol variable symbol">'append</span> selected<span class="token punctuation">)</span>
      <span class="token comment">;; Figure out parameters for horizontal spacing</span>
      <span class="token punctuation">(</span><span class="token keyword">cl-loop</span>
       for <span class="token punctuation">(</span><span class="token car">comp</span> prefix<span class="token punctuation">)</span> in tuples
       maximizing <span class="token punctuation">(</span><span class="token car">length</span> prefix<span class="token punctuation">)</span> into max-prefix-len-aux
       maximizing <span class="token punctuation">(</span><span class="token car">length</span> comp<span class="token punctuation">)</span> into max-comp-len-aux
       finally <span class="token punctuation">(</span><span class="token keyword">setq</span> max-prefix-len max-prefix-len-aux
                     max-comp-len max-comp-len-aux<span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token comment">;; Serialize completions and section titles into a list</span>
      <span class="token comment">;; of lines to render</span>
      <span class="token punctuation">(</span><span class="token keyword">cl-loop</span>
       for <span class="token punctuation">(</span><span class="token car">comp</span> prefix suffix section<span class="token punctuation">)</span> in tuples
       when section
       collect <span class="token punctuation">(</span><span class="token car">propertize</span> section <span class="token quoted-symbol variable symbol">'face</span> <span class="token quoted-symbol variable symbol">'icomplete-section</span><span class="token punctuation">)</span> into lines-aux
       and count <span class="token number">1</span> into nsections-aux
       for comp = <span class="token punctuation">(</span><span class="token car">icomplete-vertical--add-marker-to-selected</span> comp<span class="token punctuation">)</span>
       when <span class="token punctuation">(</span><span class="token car">get-text-property</span> <span class="token number">0</span> <span class="token quoted-symbol variable symbol">'icomplete-selected</span> comp<span class="token punctuation">)</span>
       do <span class="token punctuation">(</span><span class="token car">add-face-text-property</span> <span class="token number">0</span> <span class="token punctuation">(</span><span class="token car">length</span> comp<span class="token punctuation">)</span>
                                  <span class="token quoted-symbol variable symbol">'icomplete-selected-match</span> <span class="token quoted-symbol variable symbol">'append</span> comp<span class="token punctuation">)</span>
       collect <span class="token punctuation">(</span><span class="token keyword">concat</span> prefix
                       <span class="token punctuation">(</span><span class="token car">make-string</span> <span class="token punctuation">(</span><span class="token car">max</span> <span class="token number">0</span> <span class="token punctuation">(</span><span class="token car">-</span> max-prefix-len <span class="token punctuation">(</span><span class="token car">length</span> prefix<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> ? <span class="token punctuation">)</span>
                       <span class="token punctuation">(</span><span class="token car">completion-lazy-hilit</span> comp<span class="token punctuation">)</span>
                       <span class="token punctuation">(</span><span class="token car">make-string</span> <span class="token punctuation">(</span><span class="token car">max</span> <span class="token number">0</span> <span class="token punctuation">(</span><span class="token car">-</span> max-comp-len <span class="token punctuation">(</span><span class="token car">length</span> comp<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> ? <span class="token punctuation">)</span>
                       suffix<span class="token punctuation">)</span>
       into lines-aux
       finally <span class="token punctuation">(</span><span class="token keyword">setq</span> lines lines-aux
                     nsections nsections-aux<span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token comment">;; Kick out some lines from the beginning due to extra sections.</span>
      <span class="token comment">;; This hopes to keep the selected entry more or less in the</span>
      <span class="token comment">;; middle of the dropdown-like widget when `icomplete-scroll' is</span>
      <span class="token comment">;; t.  Funky, but at least I didn't use `cl-loop'</span>
      <span class="token punctuation">(</span><span class="token keyword">setq</span> lines
            <span class="token punctuation">(</span><span class="token car">nthcdr</span>
             <span class="token punctuation">(</span><span class="token keyword">cond</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">&#x3C;=</span> <span class="token punctuation">(</span><span class="token car">length</span> lines<span class="token punctuation">)</span> total-space<span class="token punctuation">)</span> <span class="token number">0</span><span class="token punctuation">)</span>
                   <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">></span> <span class="token punctuation">(</span><span class="token car">length</span> scroll-above<span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">length</span> scroll-below<span class="token punctuation">)</span><span class="token punctuation">)</span> nsections<span class="token punctuation">)</span>
                   <span class="token punctuation">(</span><span class="token boolean">t</span> <span class="token punctuation">(</span><span class="token car">min</span> <span class="token punctuation">(</span><span class="token car">ceiling</span> nsections <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">length</span> scroll-above<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
             lines<span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">(</span><span class="token keyword">when</span> icomplete--in-region-buffer
        <span class="token punctuation">(</span><span class="token keyword">setq</span> lines <span class="token punctuation">(</span><span class="token car">icomplete-vertical--adjust-lines-for-column</span>
                     lines icomplete--in-region-buffer completion-in-region--data<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token comment">;; At long last, render final string return value.  This may still</span>
      <span class="token comment">;; kick out lines at the end.</span>
      <span class="token punctuation">(</span><span class="token keyword">concat</span> <span class="token string">" \n"</span>
              <span class="token punctuation">(</span><span class="token keyword">cl-loop</span> for l in lines repeat total-space concat l concat <span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

</code></pre></div>
<h2>Conclusion</h2>
<p>With the patch applied or the custom configuration set in your
<code>init.el</code>, you've successfully enhanced your <code>icomplete-vertical-mode</code> to
support vertical alignment and customizable markers. These
improvements offer a cleaner and more user-friendly completion
interface in Emacs, making it easier to navigate long lists of
completions.</p>
<p>Whether you prefer applying the patch directly to the source code or
overriding settings in your <code>init.el</code>, both methods offer a flexible way
to tailor <code>icomplete-vertical-mode</code> to your workflow. Experiment with
the options that best suit your needs, and feel free to tweak the
configuration further to make it even more personalized.</p>
<p>If you encounter any issues or have suggestions for further
improvements, don't hesitate to reach out. Emacs is all about
customization, and the possibilities are endless!</p>
]]></description>
            <link>https://rahuljuliato.com/posts/in-buffer-icomplete-2</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/in-buffer-icomplete-2</guid>
            <pubDate>Thu, 23 Jan 2025 14:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Enhancing icomplete-vertical-mode in Emacs]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p><code>icomplete-vertical-mode</code> is a popular built-in option for Emacs users
who prefer a vertical display of completions, offering a more modern
feel similar to packages like Vertico or Ivy. Beyond its default use,
it can also handle in-buffer completions. However, its behavior in
this context may feel counterintuitive if you're not familiar with it
or if you're accustomed to more modern in-buffer completion systems
like Company, Corfu, or Auto-Complete.</p>
<p>In this post, I’d like to revisit a discussion I initiated back in
April 2024, which led to a quick patch you can apply to make
<code>icomplete-vertical</code> work more seamlessly for in-buffer
completions, bringing it closer to the style of <code>company</code> or <code>corfu</code>.</p>
<h2>The issue</h2>
<p>Specifically regarding <em>in buffer</em> behaviour of icomplete, let's
explore some variations.</p>
<p>Let's supose this minimal config:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> icomplete
  <span class="token lisp-property property">:bind</span> <span class="token punctuation">(</span><span class="token lisp-property property">:map</span> icomplete-minibuffer-map
              <span class="token punctuation">(</span><span class="token string">"C-n"</span> <span class="token punctuation">.</span> icomplete-forward-completions<span class="token punctuation">)</span>
              <span class="token punctuation">(</span><span class="token string">"C-p"</span> <span class="token punctuation">.</span> icomplete-backward-completions<span class="token punctuation">)</span>
              <span class="token punctuation">(</span><span class="token string">"C-v"</span> <span class="token punctuation">.</span> icomplete-vertical-toggle<span class="token punctuation">)</span>
              <span class="token punctuation">(</span><span class="token string">"RET"</span> <span class="token punctuation">.</span> icomplete-force-complete-and-exit<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:hook</span>
  <span class="token punctuation">(</span><span class="token car">after-init</span> <span class="token punctuation">.</span> <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
                  <span class="token punctuation">(</span><span class="token car">fido-mode</span> <span class="token number">-1</span><span class="token punctuation">)</span>
                  <span class="token punctuation">(</span><span class="token car">icomplete-mode</span> <span class="token number">1</span><span class="token punctuation">)</span>
                  <span class="token comment">;; (icomplete-vertical-mode 1)</span>
                  <span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:config</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> tab-always-indent <span class="token quoted-symbol variable symbol">'complete</span><span class="token punctuation">)</span>  <span class="token comment">;; Starts completion with TAB</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-delay-completions-threshold <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-compute-delay <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-show-matches-on-no-input <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-hide-common-prefix <span class="token boolean">nil</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-prospects-height <span class="token number">10</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-separator <span class="token string">" . "</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-with-completion-tables <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-in-buffer <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-max-delay-chars <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-scroll <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">advice-add</span> <span class="token quoted-symbol variable symbol">'completion-at-point</span>
              <span class="token lisp-property property">:after</span> <span class="token quoted-symbol variable symbol">#'minibuffer-hide-completions</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

</code></pre></div>
<p>In this example I'll be searching for completions to <code>(setq...</code> and
hit TAB for completion.</p>
<p>With <code>icomplete-mode</code> the beginning of the line:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Ficomplete-01.png&w=3840&q=75" alt="icomplete"></p>
<p>With <code>icomplete-mode</code> on some advanced column:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Ficomplete-02.png&w=3840&q=75" alt="icomplete"></p>
<p>Now lets toggle comments in our configuration:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token comment">;; (icomplete-mode 1)</span>
<span class="token punctuation">(</span><span class="token car">icomplete-vertical-mode</span> <span class="token number">1</span><span class="token punctuation">)</span>
</code></pre></div>
<p>With <code>icomplete-vertical-mode</code> the beginning of the line:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Ficomplete-03.png&w=3840&q=75" alt="icomplete"></p>
<p>With <code>icomplete-vertical-mode</code> on some advanced column:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Ficomplete-04.png&w=3840&q=75" alt="icomplete"></p>
<p>As you can see, the <code>icomplete-vertical-mode</code> completion won't respect
the cursor position, as it happens with its classic horizontal counterpart.
It always starts at the beginning of the next line.</p>
<h2>A Proposed Solution</h2>
<p>Messaging the Emacs help mail list
<a href="https://mail.gnu.org/archive/html/help-gnu-emacs/2024-04/msg00121.html">here</a>,
quickly got me some answers to this issue.</p>
<p>Zhengyi Fu suggested a patch to address this issue. The patch modifies
<code>icomplete.el</code> to prepend spaces to the completion lines, aligning
them with the cursor’s column. Here’s the patch:</p>
<div class="remark-highlight"><pre class="language-diff"><code class="language-diff">Index: emacs/lisp/icomplete.el
===================================================================
<span class="token coord">--- emacs.orig/lisp/icomplete.el</span>
<span class="token coord">+++ emacs/lisp/icomplete.el</span>
@@ -913,6 +913,16 @@ icomplete--render-vertical
<span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line">                ((> (length scroll-above) (length scroll-below)) nsections)</span>
<span class="token line"></span><span class="token prefix unchanged"> </span><span class="token line">                (t (min (ceiling nsections 2) (length scroll-above))))</span>
<span class="token line"></span><span class="token prefix unchanged"> </span><span class="token line">          lines))</span>
<span class="token line"></span></span><span class="token inserted-sign inserted"><span class="token prefix inserted">+</span><span class="token line">    (when icomplete--in-region-buffer</span>
<span class="token line"></span><span class="token prefix inserted">+</span><span class="token line">      (let ((column</span>
<span class="token line"></span><span class="token prefix inserted">+</span><span class="token line">            (with-current-buffer icomplete--in-region-buffer</span>
<span class="token line"></span><span class="token prefix inserted">+</span><span class="token line">              (save-excursion</span>
<span class="token line"></span><span class="token prefix inserted">+</span><span class="token line">                (goto-char (car completion-in-region--data))</span>
<span class="token line"></span><span class="token prefix inserted">+</span><span class="token line">                (current-column)))))</span>
<span class="token line"></span><span class="token prefix inserted">+</span><span class="token line">       (dolist (l lines)</span>
<span class="token line"></span><span class="token prefix inserted">+</span><span class="token line">         (add-text-properties</span>
<span class="token line"></span><span class="token prefix inserted">+</span><span class="token line">           0 1 `(display ,(concat (make-string column ?\s) (substring l 0 1)))</span>
<span class="token line"></span><span class="token prefix inserted">+</span><span class="token line">           l))))</span>
<span class="token line"></span></span><span class="token unchanged"><span class="token prefix unchanged"> </span><span class="token line">    ;; At long last, render final string return value.  This may still</span>
<span class="token line"></span><span class="token prefix unchanged"> </span><span class="token line">    ;; kick out lines at the end.</span>
<span class="token line"></span><span class="token prefix unchanged"> </span><span class="token line">    (concat " \n"</span>
<span class="token line"></span></span>
</code></pre></div>
<p>As noted by Eli Zaretskii, contrary to initial impressions, applying
this patch does not require rebuilding Emacs from source. Instead:</p>
<p>• Locate <code>icomplete.el</code> in your Emacs installation.</p>
<p>• Apply the patch.</p>
<p>• Byte-compile the updated file using <code>M-x byte-compile-file</code>.</p>
<p>• Restart Emacs to load the updated behavior.</p>
<p>And as magic, we get:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Ficomplete-05.png&w=3840&q=75" alt="icomplete"></p>
<p>Another example in a buffer that provides completions with <code>eglot</code> (Typescript LSP Server):
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Ficomplete-demo.gif&w=3840&q=75" alt="icomplete-eglot"></p>
<h2>A hacky copy/paste & try it</h2>
<p>Of course you can just go <em>hacky</em> and override this function with the
applied patch, it is ugly, it is not recommended to do, but if you'd
like to quickly try this behavior you could.</p>
<p>Here's a version that may work with Emacs 30.0.92, shh try it and delete, don't tell anyone ;)</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> icomplete
  <span class="token lisp-property property">:bind</span> <span class="token punctuation">(</span><span class="token lisp-property property">:map</span> icomplete-minibuffer-map
              <span class="token punctuation">(</span><span class="token string">"C-n"</span> <span class="token punctuation">.</span> icomplete-forward-completions<span class="token punctuation">)</span>
              <span class="token punctuation">(</span><span class="token string">"C-p"</span> <span class="token punctuation">.</span> icomplete-backward-completions<span class="token punctuation">)</span>
              <span class="token punctuation">(</span><span class="token string">"C-v"</span> <span class="token punctuation">.</span> icomplete-vertical-toggle<span class="token punctuation">)</span>
              <span class="token punctuation">(</span><span class="token string">"RET"</span> <span class="token punctuation">.</span> icomplete-force-complete-and-exit<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:hook</span>
  <span class="token punctuation">(</span><span class="token car">after-init</span> <span class="token punctuation">.</span> <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
                  <span class="token punctuation">(</span><span class="token car">fido-mode</span> <span class="token number">-1</span><span class="token punctuation">)</span>
                  <span class="token comment">;; (icomplete-mode 1)</span>
                  <span class="token punctuation">(</span><span class="token car">icomplete-vertical-mode</span> <span class="token number">1</span><span class="token punctuation">)</span>
                  <span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:config</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> tab-always-indent <span class="token quoted-symbol variable symbol">'complete</span><span class="token punctuation">)</span>  <span class="token comment">;; Starts completion with TAB</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-delay-completions-threshold <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-compute-delay <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-show-matches-on-no-input <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-hide-common-prefix <span class="token boolean">nil</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-prospects-height <span class="token number">10</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-separator <span class="token string">" . "</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-with-completion-tables <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-in-buffer <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-max-delay-chars <span class="token number">0</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete-scroll <span class="token boolean">t</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">advice-add</span> <span class="token quoted-symbol variable symbol">'completion-at-point</span>
              <span class="token lisp-property property">:after</span> <span class="token quoted-symbol variable symbol">#'minibuffer-hide-completions</span><span class="token punctuation">)</span>

  <span class="token comment">;; FIXME - this is actually an override of internal icomplete to provide</span>
  <span class="token comment">;;         in buffer on column completion</span>
  <span class="token comment">;;</span>
  <span class="token comment">;; As first suggested by Zhengyi Fu:</span>
  <span class="token comment">;; https://mail.gnu.org/archive/html/help-gnu-emacs/2024-04/msg00126.html</span>
  <span class="token comment">;;</span>
  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">cl-defun</span> <span class="token function">icomplete--render-vertical</span>
      <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">comps</span> <span class="token argument variable">md</span> <span class="token other-marker-vars"><span class="token lisp-marker">&aux</span> <span class="token argument variable">scroll-above</span> <span class="token argument variable">scroll-below</span>
             <span class="token varform"><span class="token punctuation">(</span><span class="token car">total-space</span> <span class="token comment">; number of mini-window lines available</span>
              <span class="token punctuation">(</span>1- <span class="token punctuation">(</span><span class="token car">min</span>
                   icomplete-prospects-height
                   <span class="token punctuation">(</span><span class="token car">truncate</span> <span class="token punctuation">(</span><span class="token car">max-mini-window-lines</span><span class="token punctuation">)</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span></span></span></span><span class="token punctuation">)</span></span>
    <span class="token comment">;; Welcome to loopapalooza!</span>
    <span class="token comment">;;</span>
    <span class="token comment">;; First, be mindful of `icomplete-scroll' and manual scrolls.  If</span>
    <span class="token comment">;; `icomplete--scrolled-completions' and `icomplete--scrolled-past'</span>
    <span class="token comment">;; are:</span>
    <span class="token comment">;;</span>
    <span class="token comment">;; - both nil, there is no manual scroll;</span>
    <span class="token comment">;; - both non-nil, there is a healthy manual scroll that doesn't need</span>
    <span class="token comment">;;   to be readjusted (user just moved around the minibuffer, for</span>
    <span class="token comment">;;   example)l</span>
    <span class="token comment">;; - non-nil and nil, respectively, a refiltering took place and we</span>
    <span class="token comment">;;   may need to readjust them to the new filtered `comps'.</span>
    <span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token keyword">and</span> icomplete-scroll
               icomplete--scrolled-completions
               <span class="token punctuation">(</span><span class="token keyword">null</span> icomplete--scrolled-past<span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">(</span><span class="token keyword">cl-loop</span> with preds
               for <span class="token punctuation">(</span><span class="token car">comp</span> <span class="token punctuation">.</span> rest<span class="token punctuation">)</span> on comps
               when <span class="token punctuation">(</span><span class="token car">equal</span> comp <span class="token punctuation">(</span><span class="token car">car</span> icomplete--scrolled-completions<span class="token punctuation">)</span><span class="token punctuation">)</span>
               do
               <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete--scrolled-past preds
                     comps <span class="token punctuation">(</span><span class="token keyword">cons</span> comp rest<span class="token punctuation">)</span><span class="token punctuation">)</span>
               <span class="token punctuation">(</span><span class="token car">completion--cache-all-sorted-completions</span>
                <span class="token punctuation">(</span><span class="token car">icomplete--field-beg</span><span class="token punctuation">)</span>
                <span class="token punctuation">(</span><span class="token car">icomplete--field-end</span><span class="token punctuation">)</span>
                comps<span class="token punctuation">)</span>
               and return <span class="token boolean">nil</span>
               do <span class="token punctuation">(</span><span class="token car">push</span> comp preds<span class="token punctuation">)</span>
               finally <span class="token punctuation">(</span><span class="token keyword">setq</span> icomplete--scrolled-completions <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token comment">;; Then, in this pretty ugly loop, collect completions to display</span>
    <span class="token comment">;; above and below the selected one, considering scrolling</span>
    <span class="token comment">;; positions.</span>
    <span class="token punctuation">(</span><span class="token keyword">cl-loop</span> with preds = icomplete--scrolled-past
             with succs = <span class="token punctuation">(</span><span class="token car">cdr</span> comps<span class="token punctuation">)</span>
             with space-above = <span class="token punctuation">(</span><span class="token car">-</span> total-space
                                   <span class="token number">1</span>
                                   <span class="token punctuation">(</span><span class="token keyword">cl-loop</span> for <span class="token punctuation">(</span><span class="token car">_</span> <span class="token punctuation">.</span> r<span class="token punctuation">)</span> on comps
                                            repeat <span class="token punctuation">(</span><span class="token car">truncate</span> total-space <span class="token number">2</span><span class="token punctuation">)</span>
                                            while <span class="token punctuation">(</span><span class="token car">listp</span> r<span class="token punctuation">)</span>
                                            count <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
             repeat total-space
             for neighbor = <span class="token boolean">nil</span>
             if <span class="token punctuation">(</span><span class="token keyword">and</span> preds <span class="token punctuation">(</span><span class="token car">></span> space-above <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span> do
             <span class="token punctuation">(</span><span class="token car">push</span> <span class="token punctuation">(</span><span class="token keyword">setq</span> neighbor <span class="token punctuation">(</span><span class="token car">pop</span> preds<span class="token punctuation">)</span><span class="token punctuation">)</span> scroll-above<span class="token punctuation">)</span>
             <span class="token punctuation">(</span><span class="token car">cl-decf</span> space-above<span class="token punctuation">)</span>
             else if <span class="token punctuation">(</span><span class="token car">consp</span> succs<span class="token punctuation">)</span> collect
             <span class="token punctuation">(</span><span class="token keyword">setq</span> neighbor <span class="token punctuation">(</span><span class="token car">pop</span> succs<span class="token punctuation">)</span><span class="token punctuation">)</span> into scroll-below-aux
             while neighbor
             finally <span class="token punctuation">(</span><span class="token keyword">setq</span> scroll-below scroll-below-aux<span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token comment">;; Halfway there...</span>
    <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">selected</span> <span class="token punctuation">(</span><span class="token car">propertize</span> <span class="token punctuation">(</span><span class="token car">car</span> comps<span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">'icomplete-selected</span> <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
           <span class="token punctuation">(</span><span class="token car">chosen</span> <span class="token punctuation">(</span><span class="token keyword">append</span> scroll-above <span class="token punctuation">(</span><span class="token car">list</span> selected<span class="token punctuation">)</span> scroll-below<span class="token punctuation">)</span><span class="token punctuation">)</span>
           <span class="token punctuation">(</span><span class="token car">tuples</span> <span class="token punctuation">(</span><span class="token car">icomplete--augment</span> md chosen<span class="token punctuation">)</span><span class="token punctuation">)</span>
           max-prefix-len max-comp-len lines nsections<span class="token punctuation">)</span>
      <span class="token punctuation">(</span><span class="token car">add-face-text-property</span> <span class="token number">0</span> <span class="token punctuation">(</span><span class="token car">length</span> selected<span class="token punctuation">)</span>
                              <span class="token quoted-symbol variable symbol">'icomplete-selected-match</span> <span class="token quoted-symbol variable symbol">'append</span> selected<span class="token punctuation">)</span>
      <span class="token comment">;; Figure out parameters for horizontal spacing</span>
      <span class="token punctuation">(</span><span class="token keyword">cl-loop</span>
       for <span class="token punctuation">(</span><span class="token car">comp</span> prefix<span class="token punctuation">)</span> in tuples
       maximizing <span class="token punctuation">(</span><span class="token car">length</span> prefix<span class="token punctuation">)</span> into max-prefix-len-aux
       maximizing <span class="token punctuation">(</span><span class="token car">length</span> comp<span class="token punctuation">)</span> into max-comp-len-aux
       finally <span class="token punctuation">(</span><span class="token keyword">setq</span> max-prefix-len max-prefix-len-aux
                     max-comp-len max-comp-len-aux<span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token comment">;; Serialize completions and section titles into a list</span>
      <span class="token comment">;; of lines to render</span>
      <span class="token punctuation">(</span><span class="token keyword">cl-loop</span>
       for <span class="token punctuation">(</span><span class="token car">comp</span> prefix suffix section<span class="token punctuation">)</span> in tuples
       when section
       collect <span class="token punctuation">(</span><span class="token car">propertize</span> section <span class="token quoted-symbol variable symbol">'face</span> <span class="token quoted-symbol variable symbol">'icomplete-section</span><span class="token punctuation">)</span> into lines-aux
       and count <span class="token number">1</span> into nsections-aux
       when <span class="token punctuation">(</span><span class="token car">get-text-property</span> <span class="token number">0</span> <span class="token quoted-symbol variable symbol">'icomplete-selected</span> comp<span class="token punctuation">)</span>
       do <span class="token punctuation">(</span><span class="token car">add-face-text-property</span> <span class="token number">0</span> <span class="token punctuation">(</span><span class="token car">length</span> comp<span class="token punctuation">)</span>
                                  <span class="token quoted-symbol variable symbol">'icomplete-selected-match</span> <span class="token quoted-symbol variable symbol">'append</span> comp<span class="token punctuation">)</span>
       collect <span class="token punctuation">(</span><span class="token keyword">concat</span> prefix
                       <span class="token punctuation">(</span><span class="token car">make-string</span> <span class="token punctuation">(</span><span class="token car">-</span> max-prefix-len <span class="token punctuation">(</span><span class="token car">length</span> prefix<span class="token punctuation">)</span><span class="token punctuation">)</span> ? <span class="token punctuation">)</span>
                       <span class="token punctuation">(</span><span class="token car">completion-lazy-hilit</span> comp<span class="token punctuation">)</span>
                       <span class="token punctuation">(</span><span class="token car">make-string</span> <span class="token punctuation">(</span><span class="token car">-</span> max-comp-len <span class="token punctuation">(</span><span class="token car">length</span> comp<span class="token punctuation">)</span><span class="token punctuation">)</span> ? <span class="token punctuation">)</span>
                       suffix<span class="token punctuation">)</span>
       into lines-aux
       finally <span class="token punctuation">(</span><span class="token keyword">setq</span> lines lines-aux
                     nsections nsections-aux<span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token comment">;; Kick out some lines from the beginning due to extra sections.</span>
      <span class="token comment">;; This hopes to keep the selected entry more or less in the</span>
      <span class="token comment">;; middle of the dropdown-like widget when `icomplete-scroll' is</span>
      <span class="token comment">;; t.  Funky, but at least I didn't use `cl-loop'</span>
      <span class="token punctuation">(</span><span class="token keyword">setq</span> lines
            <span class="token punctuation">(</span><span class="token car">nthcdr</span>
             <span class="token punctuation">(</span><span class="token keyword">cond</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">&#x3C;=</span> <span class="token punctuation">(</span><span class="token car">length</span> lines<span class="token punctuation">)</span> total-space<span class="token punctuation">)</span> <span class="token number">0</span><span class="token punctuation">)</span>
                   <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">></span> <span class="token punctuation">(</span><span class="token car">length</span> scroll-above<span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">length</span> scroll-below<span class="token punctuation">)</span><span class="token punctuation">)</span> nsections<span class="token punctuation">)</span>
                   <span class="token punctuation">(</span><span class="token boolean">t</span> <span class="token punctuation">(</span><span class="token car">min</span> <span class="token punctuation">(</span><span class="token car">ceiling</span> nsections <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">length</span> scroll-above<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
             lines<span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token heading comment title">;;; ------- NON ORIGINAL HERE...</span>
      <span class="token punctuation">(</span><span class="token keyword">when</span> icomplete--in-region-buffer
        <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">column</span>
               <span class="token punctuation">(</span><span class="token car">with-current-buffer</span> icomplete--in-region-buffer
                 <span class="token punctuation">(</span><span class="token car">save-excursion</span>
                   <span class="token punctuation">(</span><span class="token car">goto-char</span> <span class="token punctuation">(</span><span class="token car">car</span> completion-in-region--data<span class="token punctuation">)</span><span class="token punctuation">)</span>
                   <span class="token punctuation">(</span><span class="token car">current-column</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
          <span class="token punctuation">(</span><span class="token car">dolist</span> <span class="token punctuation">(</span><span class="token car">l</span> lines<span class="token punctuation">)</span>
            <span class="token punctuation">(</span><span class="token car">add-text-properties</span>
             <span class="token number">0</span> <span class="token number">1</span> <span class="token punctuation">`(</span><span class="token car">display</span> <span class="token punctuation">,(</span><span class="token keyword">concat</span> <span class="token punctuation">(</span><span class="token car">make-string</span> column ?\s<span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">substring</span> l <span class="token number">0</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
             l<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token heading comment title">;;; -------- NON ORIGINAL ENDS HERE...</span>
      <span class="token comment">;; At long last, render final string return value.  This may still</span>
      <span class="token comment">;; kick out lines at the end.</span>
      <span class="token punctuation">(</span><span class="token keyword">concat</span> <span class="token string">" \n"</span>
              <span class="token punctuation">(</span><span class="token keyword">cl-loop</span> for l in lines repeat total-space concat l concat <span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<h2>Is this patch the new default?</h2>
<p>Not at all. As you might know, an initial "it works" does not mean it
is fully tested and free of bugs, right?</p>
<p>I ended up not having the time to properly suggest some new features
to <code>icomplete</code>, such as:</p>
<p>• Turning this "follow the cursor" feature on/off</p>
<p>• Providing a "callback" function where the user could customize what
function is wanted to perform this action</p>
<p>• Providing a way to add markings, such as arrow indicators, prefixes,
suffixes, or maybe icons</p>
<p>I thought I’d have the time, but it has been a while since April, and
other projects with already delayed statuses took priority. I figured
it might be a good idea to share with the community that this sort of
in-buffer completion is already possible with no external
packages, especially for those trying to keep their configurations more
purist.</p>
<h2>Conclusion</h2>
<p>The enhancements to <code>icomplete-vertical-mode</code> presented in this post
demonstrate how a small patch can significantly improve the in-buffer
completion experience, making it more intuitive and aligned with
modern expectations. While this solution isn't yet part of the default
Emacs distribution, it shows the potential of leveraging existing
tools and a bit of customization to achieve powerful results.</p>
<p>If you're an Emacs purist or just someone looking to simplify your
configuration without relying on external packages, this approach is
worth exploring. And who knows? With enough community interest, we
might see such improvements integrated into Emacs in the future.</p>
<p>As always, feel free to share your thoughts, improvements, or
challenges in implementing this solution. Collaboration is what makes
the Emacs community thrive!</p>
<h3>Edit</h3>
<p><strong>2024-12-25:</strong> full code included the <code>icomplete--augment</code> function, which we
did not change. Since it was mistakenly pasted there, I removed it.</p>
<p><strong>2025-01-23:</strong> there's now a follow up to this blogpost, check it
<a href="in-buffer-icomplete-2/">here</a>.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/in-buffer-icomplete</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/in-buffer-icomplete</guid>
            <pubDate>Thu, 19 Dec 2024 14:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[How to Share Your Emacs Configuration Between Different Machines (and Architectures) with Native Compilation]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <h2>EDIT:</h2>
<p><strong>Important!</strong> This was always a very specific solution to a very
specific issue. However, starting from Emacs <strong>30</strong>, it will no longer
work or have any beneficial effects.</p>
<p>From Emacs 30 onward, <code>.eln</code> files are <strong>linked per machine</strong>, meaning
the <code>eln-cache</code> directory will automatically include a subfolder based
on the <code>comp-abi-hash</code> variable and no adjustments from the user side
are needed.</p>
<p>For more details, see this discussion: <a href="https://debbugs.gnu.org/cgi/bugreport.cgi?bug=76586">Bug
#76586</a>.</p>
<p><strong>TL;DR:</strong> Do not use these hacks anymore.</p>
<h2>How to Share Your Emacs Configuration Between Different Machines (and Architectures) with Native Compilation</h2>
<p>If you use Emacs on multiple machines, especially ones running
different architectures or operating systems, sharing your Emacs
configuration across those machines can become tricky. Add native
compilation (introduced in Emacs 28) to the mix, and you might run
into conflicts when Emacs tries to reuse compiled <code>.eln</code> files between
machines.</p>
<p>Fortunately, with a bit of smart configuration, you can make Emacs
share your configuration while keeping native compilation enabled for
each machine. In this post, I'll show you how to set up your Emacs so
that native compilation caches (<code>.eln</code> files) are kept separate for
each machine. We'll also discuss why this is important and what your
directory structure will look like.</p>
<h2>Why Is This Important?</h2>
<p>Emacs uses native compilation to compile Elisp files into optimized
<code>.eln</code> binaries, which are architecture and system-dependent. If you
share your Emacs configuration across machines without accounting for
this, you may encounter issues:</p>
<ol>
<li>
<p><strong>Conflicting <code>.eln</code> files</strong>: A <code>.eln</code> file compiled for a Linux
machine might not work on a macOS machine.</p>
</li>
<li>
<p><strong>Unnecessary recompilations</strong>: Emacs may attempt to recompile
packages on each startup, which can slow things down and clutter your
<code>eln-cache</code> directory.</p>
</li>
</ol>
<p>By separating the native compilation cache for each machine, you ensure:</p>
<p>• Faster startup times since Emacs doesn't recompile already-compiled
code.</p>
<p>• A cleaner and more predictable setup across machines.</p>
<h2>The Solution: Machine-Specific <code>eln-cache</code> Directories</h2>
<p>To keep <code>.eln</code> files organized and avoid conflicts, you can configure
Emacs to use a machine-specific <code>eln-cache</code> directory. Here's the
configuration snippet to add into your <code>early-init.el</code>:</p>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token heading comment title">;;; Native Compile Settings</span>
<span class="token comment">;; I use a &#x3C;emacs-default-dir>/eln-cache-&#x3C;machine-hostname>/ dir to store</span>
<span class="token comment">;; my different machines' eln compiled code. This allows the same config</span>
<span class="token comment">;; to be used on several machines without conflicts.</span>
<span class="token comment">;; This is added in early-init.el to prevent unwanted recompilations.</span>

<span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token car">featurep</span> <span class="token quoted-symbol variable symbol">'native-compile</span><span class="token punctuation">)</span>
  <span class="token comment">;; Set the right directory to store the native compilation cache</span>
  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">path</span> <span class="token punctuation">(</span><span class="token car">expand-file-name</span> <span class="token punctuation">(</span><span class="token keyword">concat</span> <span class="token string">"eln-cache-"</span> <span class="token punctuation">(</span><span class="token car">system-name</span><span class="token punctuation">)</span> <span class="token string">"/"</span><span class="token punctuation">)</span> user-emacs-directory<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token car">setq-default</span> native-comp-eln-load-path       <span class="token punctuation">(</span><span class="token car">list</span> path<span class="token punctuation">)</span>
				  native-compile-target-directory path<span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token car">startup-redirect-eln-cache</span> path<span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token car">setq-default</span> native-comp-async-report-warnings-errors <span class="token boolean">nil</span>  <span class="token comment">;; Silence compiler warnings as they can be disruptive</span>
				native-comp-jit-compilation              <span class="token boolean">t</span>    <span class="token comment">;; Enable async native compilation</span>
				package-native-compile                   <span class="token boolean">t</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">;; Compile installed packages</span>
</code></pre></div>
<h2>What Does This Code Do?</h2>
<ol>
<li>
<p><code>(system-name):</code> Retrieves the hostname of the machine. This is
used to create a unique directory for each machine's eln-cache.</p>
</li>
<li>
<p><code>expand-file-name:</code> Combines the Emacs configuration directory
(user-emacs-directory) with the machine-specific
<code>eln-cache-&#x3C;hostname></code> folder.</p>
</li>
<li>
<p><code>native-comp-eln-load-path</code> and <code>native-compile-target-directory:</code>
Set the paths for Emacs to store and load the compiled <code>.eln</code> files.</p>
</li>
<li>
<p><code>startup-redirect-eln-cache:</code> Ensures Emacs uses the specified
eln-cache directory right from startup.</p>
</li>
</ol>
<p>Optional settings:</p>
<p>• <code>native-comp-async-report-warnings-errors:</code> Silences disruptive compiler warnings.</p>
<p>• <code>native-comp-jit-compilation:</code> Enables Just-In-Time (JIT) native
compilation for faster execution.</p>
<p>• <code>package-native-compile:</code> Ensures all installed packages are
natively compiled.</p>
<p>By placing this in your <code>early-init.el</code>, you make sure Emacs sets up
the <code>eln-cache</code> directory <em>before</em> it starts loading packages or
recompiling files.</p>
<h2>Folder Structure Example</h2>
<p>Let's say you have two machines, with the following hostnames:</p>
<p>• <code>debian:</code> A Linux workstation.</p>
<p>• <code>macbook:</code> A macOS laptop.</p>
<p>With the above configuration, your Emacs directory structure will look like this:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">~/.emacs.d/
<span class="token operator">|</span>-- early-init.el
<span class="token operator">|</span>-- init.el
<span class="token operator">|</span>-- eln-cache-debian/          <span class="token comment"># Cache for 'debian'</span>
<span class="token operator">|</span>   <span class="token operator">|</span>-- abcdef01-abcdefgh01.eln
<span class="token operator">|</span>   <span class="token operator">|</span>-- xyz12345-xyzabc123.eln
<span class="token operator">|</span>
<span class="token operator">|</span>-- eln-cache-macbook/         <span class="token comment"># Cache for 'macbook'</span>
	<span class="token operator">|</span>-- abcdef01-abcdefgh01.eln
	<span class="token operator">|</span>-- pqr67890-pqrxyz678.eln
</code></pre></div>
<h2>Setting Up for a New Machine</h2>
<p>If you're setting up Emacs on a new machine:</p>
<ol>
<li>
<p>Clone or copy your shared Emacs configuration (e.g., from GitHub).</p>
</li>
<li>
<p>Make sure the above snippet is in your early-init.el.</p>
</li>
<li>
<p>Start Emacs. It will automatically create a new
<code>eln-cache-&#x3C;hostname></code> directory and begin compiling packages natively
for the current machine.</p>
</li>
</ol>
<h2>Conclusion</h2>
<p>Sharing Emacs configurations across machines doesn't have to be a
hassle, even when using native compilation. By directing Emacs to use
machine-specific eln-cache directories, you can:</p>
<p>• Avoid conflicts caused by incompatible .eln files.</p>
<p>• Speed up startup times by preventing unnecessary recompilations.</p>
<p>• Maintain a clean and organized Emacs setup.</p>
<p>I hope with the provided configuration, you can easily manage Emacs on
multiple machines—whether you're switching between Linux, macOS, or
different hardware architectures.</p>
<p>Happy hacking!</p>
<h3>Edit</h3>
<p><strong>2025-02-26:</strong> Added the "do not use this" note above the header.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/multiple-eln-cache</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/multiple-eln-cache</guid>
            <pubDate>Tue, 17 Dec 2024 17:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Using Emacs for Container Development: Configuring Emacs for Podman and Docker Support]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Turn Emacs into a powerful Docker development environment that
supports both Docker and Podman workflows. This guide walks you
through setting up Dockerfile editing, container management, and
automated builds, all within Emacs. Whether you’re switching between
Docker and Podman or managing complex containerized projects, Emacs
can streamline your development process. Dive in to discover how to
integrate Docker with Emacs and boost your workflow!</p>
<h2>Introduction</h2>
<p>Emacs is a powerhouse for development, and with the right
configuration, it can even manage your Docker (or Podman) workflows
without leaving the editor. In this guide, we’ll walk through setting
up Emacs specifically to work with Docker and Podman. We’ll cover
editing Dockerfiles, managing containers, and integrating
Docker-specific language support.</p>
<h2>External (non Emacs related) Dependencies</h2>
<p>To use Docker or Podman effectively within Emacs, ensure the
following external dependencies are installed and functioning on your
system:</p>
<ul>
<li>
<p><strong>Docker</strong>: Expected to be installed and running.</p>
</li>
<li>
<p><strong>Docker-Compose</strong>: Expected to be installed and functional.</p>
</li>
</ul>
<p>and/or</p>
<ul>
<li>
<p><strong>Podman</strong>: Expected to be installed and running.</p>
</li>
<li>
<p><strong>Podman-Compose</strong>: Expected to be installed and functional.</p>
</li>
</ul>
<h2>Setting the Docker Executable</h2>
<p>In LEmacs (my own config for Emacs), I've created a flexible setup
that allows you to toggle between Docker and Podman as your primary
container engine. This makes it easy to adapt your workflow depending
on your environment. No needs to use LEmacs by the way, I'll show here
all the code needed.</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defcustom</span> <span class="token variable">lemacs-docker-executable</span></span> <span class="token quoted-symbol variable symbol">'docker</span>
  <span class="token string">"The executable to be used with docker-mode."</span>
  <span class="token lisp-property property">:type</span> <span class="token punctuation">'(</span><span class="token car">choice</span>
		   <span class="token punctuation">(</span><span class="token car">const</span> <span class="token lisp-property property">:tag</span> <span class="token string">"docker"</span> docker<span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">const</span> <span class="token lisp-property property">:tag</span> <span class="token string">"podman"</span> podman<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:group</span> <span class="token quoted-symbol variable symbol">'lemacs</span><span class="token punctuation">)</span>
</code></pre></div>
<p><strong>Explanation:</strong> This customizable variable allows you to switch
between Docker and Podman in Emacs by simply updating the
<code>lemacs-docker-executable</code> setting. It’s an efficient way to keep your
setup flexible, especially if you work with both Docker and Podman
environments.</p>
<p>The <code>docker</code> package provides a way to manage containers directly from
Emacs. With the following setup, you can open the docker menu with
<code>C-c d</code> and manage your containers, images, and volumes without ever
leaving Emacs.</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> docker
	<span class="token lisp-property property">:defer</span> <span class="token boolean">t</span>
	<span class="token lisp-property property">:ensure</span> <span class="token boolean">t</span>
	<span class="token lisp-property property">:bind</span> <span class="token punctuation">(</span><span class="token string">"C-c d"</span> <span class="token punctuation">.</span> docker<span class="token punctuation">)</span>
	<span class="token lisp-property property">:config</span>
	<span class="token punctuation">(</span><span class="token car">pcase</span> lemacs-docker-executable
	  <span class="token punctuation">(</span><span class="token quoted-symbol variable symbol">'docker</span>
	   <span class="token punctuation">(</span><span class="token car">setf</span> docker-command <span class="token string">"docker"</span>
			 docker-compose-command <span class="token string">"docker-compose"</span>
			 docker-container-tramp-method <span class="token string">"docker"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token quoted-symbol variable symbol">'podman</span>
	   <span class="token punctuation">(</span><span class="token car">setf</span> docker-command <span class="token string">"podman"</span>
			 docker-compose-command <span class="token string">"podman-compose"</span>
			 docker-container-tramp-method <span class="token string">"podman"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p><strong>Explanation:</strong> By setting up docker.el with a keybinding, you can
quickly access Docker or Podman management commands. The
<code>lemacs-docker-executable</code> check allows docker.el to adapt to the
selected engine, setting the appropriate commands for docker-command
and docker-compose-command.</p>
<h2>Editing Dockerfiles with <code>dockerfile-mode</code></h2>
<p>Writing Dockerfiles in Emacs is made easier with <code>dockerfile-mode</code>,
which provides syntax highlighting, indentation, and command
customization. Here’s how we configure it:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> dockerfile-mode
  <span class="token lisp-property property">:defer</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:config</span>
  <span class="token punctuation">(</span><span class="token car">pcase</span> lemacs-docker-executable
	<span class="token punctuation">(</span><span class="token quoted-symbol variable symbol">'docker</span>
	 <span class="token punctuation">(</span><span class="token keyword">setq</span> dockerfile-mode-command <span class="token string">"docker"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token quoted-symbol variable symbol">'podman</span>
	 <span class="token punctuation">(</span><span class="token keyword">setq</span> dockerfile-docker-command <span class="token string">"podman"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p><strong>Explanation:</strong> This setup activates <code>dockerfile-mode</code> for any file
named <code>Dockerfile</code>, providing Dockerfile-specific syntax
support. Additionally, based on <code>lemacs-docker-executable</code>, it sets the
command used to build images, either <code>docker</code> or <code>podman</code>, so you can run
<code>dockerfile-build-buffer</code> with the correct tool.</p>
<h2>Adding Language Support for Dockerfiles with <code>lsp-mode</code></h2>
<p>To enhance editing with features like autocompletion, diagnostics, and
linting, you’ve set up <code>lsp-mode</code> with
<code>dockerfile-language-server-nodejs</code>. This provides IDE-like
capabilities for Dockerfile editing in Emacs.</p>
<p>In order to do so, just run <code>M-x lsp-install-server RET</code> and look for
<code>docker</code>, of course, you have to properly setup <code>lsp-mode</code> first.</p>
<p><code>Explanation:</code> With <code>lsp-mode</code> and <code>dockerfile-language-server-nodejs</code>, you
gain smart language features while writing Dockerfiles, such as error
checking and autocomplete. This is especially useful for complex
Dockerfiles, where syntax and structure are critical for successful
builds.</p>
<h2>Setting Up <code>yaml-mode</code> for Docker-Compose Files</h2>
<p>To effectively work with <code>docker-compose.yml</code> files, it’s beneficial to
have syntax highlighting and proper indentation for YAML. We can
achieve this by setting up yaml-mode in Emacs. Here's how you can
configure it:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> yaml-mode
  <span class="token lisp-property property">:defer</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:mode</span>
  <span class="token punctuation">(</span><span class="token string">"\\.yaml\\'"</span> <span class="token string">"\\.yml\\'"</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:custom-face</span>
  <span class="token punctuation">(</span><span class="token car">font-lock-variable-name-face</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token boolean">t</span> <span class="token punctuation">(</span><span class="token lisp-property property">:foreground</span> <span class="token string">"#cba6f7"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:config</span><span class="token punctuation">)</span>
</code></pre></div>
<p><code>Explanation:</code> This setup uses <code>use-package</code> to ensure <code>yaml-mode</code> is
installed and deferred until needed, activates it for .yaml and .yml
files, customizes the appearance of variable names with a specific
foreground color, and allows for additional
configurations as required.</p>
<h2>LAB Time!</h2>
<p>Now that we’ve set up Emacs for Docker (or Podman), let's dive into
some hands-on tasks to see how this configuration works in action.</p>
<h3>1. Create and Edit a Dockerfile</h3>
<p>Start by creating a new <code>Dockerfile</code> in Emacs. Open a new buffer and
save it with the filename <code>Dockerfile</code>. Once saved, <code>dockerfile-mode</code> will
kick in automatically, giving you syntax highlighting and other
Dockerfile-specific features.</p>
<p>Given we have a React project (it could've been any other project, this
is just an example) we could containerize it by creating this <code>Dockerfile</code>.</p>
<div class="remark-highlight"><pre class="language-docker"><code class="language-docker"><span class="token instruction"><span class="token keyword">FROM</span> node:21-alpine</span>

<span class="token instruction"><span class="token keyword">WORKDIR</span> /app</span>

<span class="token instruction"><span class="token keyword">ENV</span> PATH /app/node_modules/.bin:<span class="token variable">$PATH</span></span>

<span class="token instruction"><span class="token keyword">COPY</span> package.json ./</span>
<span class="token instruction"><span class="token keyword">COPY</span> package-lock.json ./</span>
<span class="token instruction"><span class="token keyword">RUN</span> npm install --silent</span>
<span class="token instruction"><span class="token keyword">RUN</span> npm install react-scripts@5.0.0 -g --silent</span>

<span class="token instruction"><span class="token keyword">COPY</span> . ./</span>

<span class="token instruction"><span class="token keyword">CMD</span> [<span class="token string">"npm"</span>, <span class="token string">"start"</span>]</span>
</code></pre></div>
<p><strong>Tip:</strong> With lsp-mode configured for Dockerfiles, you’ll get
autocompletion, syntax checking, and even inline diagnostics, making
it easier to spot issues as you write.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-01.png&w=3840&q=75" alt="docker"></p>
<h3>2. Build the Dockerfile</h3>
<p>After saving your Dockerfile, it’s time to build it.</p>
<p>Of course, you can open <code>shell</code> or <code>eshell</code> and run something like:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">docker</span> build <span class="token parameter variable">-t</span> my-app <span class="token builtin class-name">.</span>
</code></pre></div>
<p>or</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">podman</span> build <span class="token parameter variable">-t</span> my-app <span class="token builtin class-name">.</span>

</code></pre></div>
<p>But since we have the <code>dockerfile-mode</code> set. We can simply issue
<code>M-x dockerfile-build-buffer</code> or <code>M-x dockerfile-build-no-cache-buffer</code>.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-02.png&w=3840&q=75" alt="docker"></p>
<p>You'll be prompted for an image name, like <code>docker-app</code>.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-03.png&w=3840&q=75" alt="docker"></p>
<p>And a new buffer with the build status will appear.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-04.png&w=3840&q=75" alt="docker"></p>
<p>Wait for it until it is finished.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-05.png&w=3840&q=75" alt="docker"></p>
<h3>3. Run a Container with Custom Options</h3>
<p>After building your image, we could, once again, issue some shell
command to have it running, like:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">docker</span> run <span class="token parameter variable">-p</span> <span class="token number">3000</span>:3000 docker-app
</code></pre></div>
<p>or</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">podman</span> run <span class="token parameter variable">-p</span> <span class="token number">3000</span>:3000 docker-app
</code></pre></div>
<p>Now <code>docker</code> package shines again, running <code>M-x docker RET</code> we get:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-06.png&w=3840&q=75" alt="docker"></p>
<p>The bottom buffer is a transient menu, much like what you get when
opening <code>magit</code>, this means there's no need to focus the buffer or
navigate your cursor inside it.</p>
<p>We can check our built images hitting <code>i</code>.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-07.png&w=3840&q=75" alt="docker"></p>
<p>In our case we have an node image from what our image derives, and our
nice <code>docker-app</code> image.</p>
<p>You can also mark it with <code>m</code>, unmark it with <code>u</code>, spin up what is
marked, delete and so on, at any sub-menu just hit <code>?</code> for a list of
options.</p>
<p>Let's run our recently built image. Put the cursor on the line with
our <code>docker-app</code>. Hit <code>?</code> to see the options:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-08.png&w=3840&q=75" alt="docker"></p>
<p>Now hit <code>R</code> to run it, and add any arguments, like <code>p</code> for port forwarding:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-10.png&w=3840&q=75" alt="docker"></p>
<p><code>R</code> again and <code>RET</code>.</p>
<p>And there we have it, our app is running.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-11.png&w=3840&q=75" alt="docker"></p>
<p>Issuing <code>M-x docker RET</code> again we can see the containers status:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-12.png&w=3840&q=75" alt="docker"></p>
<p>Hitting <code>c</code> will give us a list with all containers and its statuses:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-13.png&w=3840&q=75" alt="docker"></p>
<p>Again, hitting <code>?</code> prompts us with many options, keep your time and explore it!</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-14.png&w=3840&q=75" alt="docker"></p>
<p>For now, I'll just stop it with <code>O</code>.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-15.png&w=3840&q=75" alt="docker"></p>
<h3>4. Working with Docker-Compose</h3>
<p>While <code>docker.el</code> makes it easy to manage individual Docker containers,
using <code>docker-compose</code> within Emacs allows us to orchestrate multiple
containers at once-perfect for projects with multiple services like
databases, backends, and frontends.</p>
<p>First, ensure you have a <code>docker-compose.yml</code> file in your project
directory. Here’s an example:</p>
<div class="remark-highlight"><pre class="language-yaml"><code class="language-yaml"><span class="token key atrule">version</span><span class="token punctuation">:</span> <span class="token string">"3.7"</span>

<span class="token key atrule">services</span><span class="token punctuation">:</span>
  <span class="token key atrule">docked-app</span><span class="token punctuation">:</span>
	<span class="token key atrule">container_name</span><span class="token punctuation">:</span> docked<span class="token punctuation">-</span>app
	<span class="token key atrule">build</span><span class="token punctuation">:</span>
	  <span class="token key atrule">context</span><span class="token punctuation">:</span> .
	  <span class="token key atrule">dockerfile</span><span class="token punctuation">:</span> Dockerfile
	<span class="token key atrule">volumes</span><span class="token punctuation">:</span>
	  <span class="token punctuation">-</span> <span class="token string">".:/app"</span>
	  <span class="token punctuation">-</span> <span class="token string">"/app/node_modules"</span>
	<span class="token key atrule">ports</span><span class="token punctuation">:</span>
	  <span class="token punctuation">-</span> 3001<span class="token punctuation">:</span><span class="token number">3000</span>
	<span class="token key atrule">environment</span><span class="token punctuation">:</span>
	  <span class="token punctuation">-</span> CHOKIDAR_USEPOLLING=true
</code></pre></div>
<p>Notice you can also install an LSP server to help with editing this
sort of file, like <code>yamlls</code> or any other of your liking.</p>
<p>Also notice this is a <code>yaml</code> file and it is not using our previous
installed <code>dockerfile-mode</code> but <code>yaml-mode</code>.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-16.png&w=3840&q=75" alt="docker"></p>
<p>Once again, we could issue a <code>shell</code> command like:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">docker-compose</span> up <span class="token parameter variable">-d</span>
</code></pre></div>
<p>or</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">podman-compose</span> up <span class="token parameter variable">-d</span>
</code></pre></div>
<p>Fortunately <code>docker</code> package also provides us with a nice frontend for
managing <code>docker-compose</code>.</p>
<p>Issue <code>M-x docker RET</code> once again, see the last option <code>C</code>.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-17.png&w=3840&q=75" alt="docker"></p>
<p>We are presented with all sorts of options regarding <code>docker-compose</code>:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-18.png&w=3840&q=75" alt="docker"></p>
<p>We are choosing <code>B</code> for build, and them <code>A</code> for all services. Note
this example has one service, but <code>docker-compose</code> really shines
in a use case of several services, like <code>backend-api</code>, plus
<code>database</code>, plus <code>frontend</code>, and so on.</p>
<p>Again, we wait for a complete build.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-19.png&w=3840&q=75" alt="docker"></p>
<p>When finished we again issue <code>M-x docker RET</code>, <code>C</code> for compose and <code>R</code> to run.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fdocker-20.png&w=3840&q=75" alt="docker"></p>
<p>Again, add any other custom configuration and hit <code>R RET</code> to run it.</p>
<p>And there we have it, our own little cluster is up!</p>
<p>From now on you can figure out what to do 😉.</p>
<h2>All the covered code</h2>
<p>Here it is all the presented code, for a quicker copy-paste.</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defcustom</span> <span class="token variable">lemacs-docker-executable</span></span> <span class="token quoted-symbol variable symbol">'docker</span>
  <span class="token string">"The executable to be used with docker-mode."</span>
  <span class="token lisp-property property">:type</span> <span class="token punctuation">'(</span><span class="token car">choice</span>
		   <span class="token punctuation">(</span><span class="token car">const</span> <span class="token lisp-property property">:tag</span> <span class="token string">"docker"</span> docker<span class="token punctuation">)</span>
		   <span class="token punctuation">(</span><span class="token car">const</span> <span class="token lisp-property property">:tag</span> <span class="token string">"podman"</span> podman<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:group</span> <span class="token quoted-symbol variable symbol">'lemacs</span><span class="token punctuation">)</span>


<span class="token punctuation">(</span><span class="token keyword">use-package</span> docker
  <span class="token lisp-property property">:defer</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:bind</span> <span class="token punctuation">(</span><span class="token string">"C-c d"</span> <span class="token punctuation">.</span> docker<span class="token punctuation">)</span>
  <span class="token lisp-property property">:config</span>
  <span class="token punctuation">(</span><span class="token car">pcase</span> lemacs-docker-executable
	<span class="token punctuation">(</span><span class="token quoted-symbol variable symbol">'docker</span>
	 <span class="token punctuation">(</span><span class="token car">setf</span> docker-command <span class="token string">"docker"</span>
		 docker-compose-command <span class="token string">"docker-compose"</span>
		 docker-container-tramp-method <span class="token string">"docker"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token quoted-symbol variable symbol">'podman</span>
	 <span class="token punctuation">(</span><span class="token car">setf</span> docker-command <span class="token string">"podman"</span>
		 docker-compose-command <span class="token string">"podman-compose"</span>
		 docker-container-tramp-method <span class="token string">"podman"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>


<span class="token punctuation">(</span><span class="token keyword">use-package</span> dockerfile-mode
  <span class="token lisp-property property">:defer</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:config</span>
  <span class="token punctuation">(</span><span class="token car">pcase</span> lemacs-docker-executable
	<span class="token punctuation">(</span><span class="token quoted-symbol variable symbol">'docker</span>
	 <span class="token punctuation">(</span><span class="token keyword">setq</span> dockerfile-mode-command <span class="token string">"docker"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
	<span class="token punctuation">(</span><span class="token quoted-symbol variable symbol">'podman</span>
	 <span class="token punctuation">(</span><span class="token keyword">setq</span> dockerfile-docker-command <span class="token string">"podman"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

<span class="token punctuation">(</span><span class="token keyword">use-package</span> yaml-mode
  <span class="token lisp-property property">:defer</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:mode</span>
  <span class="token punctuation">(</span><span class="token string">"\\.yaml\\'"</span> <span class="token string">"\\.yml\\'"</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:custom-face</span>
  <span class="token punctuation">(</span><span class="token car">font-lock-variable-name-face</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token boolean">t</span> <span class="token punctuation">(</span><span class="token lisp-property property">:foreground</span> <span class="token string">"#cba6f7"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token lisp-property property">:config</span><span class="token punctuation">)</span>
</code></pre></div>
<h2>Conclusion</h2>
<p>In this blog post, we explored how to effectively set up Emacs for
Docker and Docker-Compose management, leveraging the power of
<code>docker.el</code> to streamline container orchestration within our
development environment. From building Docker images to running and
managing containers seamlessly, Emacs provides an efficient interface
that enhances productivity and simplifies workflows.</p>
<p>By integrating <code>yaml-mode</code>, we ensured that our docker-compose.yml
files are easy to read and edit, allowing us to focus on coding rather
than configuration. With these tools at our disposal, we can harness
the full potential of containerization directly from our favorite text
editor.</p>
<p>We encourage you to explore the myriad options available within
docker.el and Docker-Compose to tailor your Emacs setup even
further. Happy coding, and may your containers run smoothly!</p>
<h3>Edit</h3>
<p><strong>2024-11-05:</strong> Updated from <code>when</code> to <code>pcase</code> logic style and removed
not required mode load for <code>dockerfile-mode</code>. References, suggestions, credits:
<a href="https://www.reddit.com/r/emacs/comments/1gk4hk7/using_emacs_for_container_development_configuring/">Reddit (r/emacs)</a></p>
<p><strong>2024-12-17:</strong> After finishing this article, I submitted an PR to
<code>docker.el</code> so we can directly open a shell and/or use shell commands
from its interface. It was already possible with docker but not with
podman. This PR got accepted and we now have the new option variable
<code>docker-container-tramp-method</code>, that can be set to docker/podman as
the other options presented here. For further reference: <a href="https://github.com/Silex/docker.el/pull/239#issuecomment-2467588155">Github
(docker.el)</a></p>
]]></description>
            <link>https://rahuljuliato.com/posts/emacs-docker-podman</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/emacs-docker-podman</guid>
            <pubDate>Mon, 04 Nov 2024 00:02:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Emacs-Kick: A Neovim User’s Friendly Start to Emacs]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <h2>Emacs-Kick: A Neovim User’s Friendly Start to Emacs</h2>
<p><img src="https://raw.githubusercontent.com/LionyxML/emacs-kick/refs/heads/master/doc/demo01.png" alt="demo"></p>
<p>-- Get it on Github: <a href="https://github.com/LionyxML/emacs-kick/">https://github.com/LionyxML/emacs-kick/</a></p>
<h3>Introduction</h3>
<p>As an Emacs enthusiast who has also spent significant time with Neovim,
I wanted to create something that would bridge the gap between these two
powerful tools. After exploring both ecosystems, I felt there was a need
for a configuration that would allow Vim/Neovim users to get acquainted with
Emacs without feeling overwhelmed.</p>
<p>Enter <strong>Emacs-Kick</strong>—a lightweight, minimal configuration for Emacs
that caters specifically to Vim/Neovim users who want to experiment with
Emacs without completely committing to a new workflow.</p>
<h3>The Inspiration: Kickstart for Neovim</h3>
<p>Neovim has its own lightweight configuration starter kit,
<strong>kickstart.nvim</strong>, which is incredibly popular. It offers a quick and
easy way to get started with Neovim, providing users a minimal yet powerful
setup to build upon.</p>
<p><strong>Emacs-Kick</strong> takes a similar approach but for Emacs users. It aims to
provide the essentials for Vim/Neovim users who want to try out Emacs
without needing to dive deep into complex configurations like Doom Emacs or
Spacemacs.</p>
<h3>What Makes Emacs-Kick Special?</h3>
<p>There are plenty of starter configurations out there, but <strong>Emacs-Kick</strong>
is designed with a specific audience in mind: people who are already comfortable
with Vim/Neovim. Here are a few standout features:</p>
<h4>1. Terminal-First Approach</h4>
<p>For users who spend most of their time in the terminal, <strong>Emacs-Kick</strong> allows
you to work within <strong>tmux</strong>, <strong>Zellij</strong>, and other terminal-based tools.
There's no need to switch to a graphical interface, making it easy for
terminal enthusiasts to integrate Emacs into their existing workflow.</p>
<h4>2. Vim Bindings by Default</h4>
<p>If you're coming from Vim/Neovim, you probably have years of muscle memory
associated with their keybindings. <strong>Emacs-Kick</strong> respects that by setting
up Vim keybindings by default, so you don’t have to spend time relearning
how to navigate.</p>
<h4>3. Pre-configured Tree-sitter and LSP</h4>
<p>Modern development workflows demand advanced code parsing, syntax highlighting,
and language server support. <strong>Emacs-Kick</strong> comes pre-configured with <strong>Tree-sitter</strong>
and <strong>LSP</strong> to give you these features right out of the box, making it ideal
for developers who want to hit the ground running.</p>
<h4>4. Minimal Defaults with Room to Grow</h4>
<p>While Emacs can be complex and overwhelming, <strong>Emacs-Kick</strong> keeps things simple.
It provides a minimal configuration that’s easy to expand as you become more
comfortable. You can start small and only add the features you need over time.</p>
<h3>Installation and Setup</h3>
<p>Here’s how you can get started with <strong>Emacs-Kick</strong>. The installation process
is straightforward, and you'll be up and running in no time.</p>
<h3>Step 1: Backup Your Existing Configuration</h3>
<p>If you already have an existing Emacs configuration, it's a good idea to back
it up before proceeding:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">mv</span> ~/.emacs.d ~/.emacs.d.backup
</code></pre></div>
<h3>Step 2: Clone the Repository</h3>
<p>Clone the <strong>Emacs-Kick</strong> repository from GitHub:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">git</span> clone https://github.com/LionyxML/emacs-kick.git ~/.emacs.d
</code></pre></div>
<h3>Step 3: Run the Installation</h3>
<p>After cloning, run the installation process by executing:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">emacs <span class="token parameter variable">-nw</span> <span class="token parameter variable">--eval</span><span class="token operator">=</span><span class="token string">"(ek/first-install)"</span>
</code></pre></div>
<p>Alternatively, you can run the provided script:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> ~/.emacs.d/ <span class="token operator">&&</span> ./ek-reinstall.sh
</code></pre></div>
<h4>Step 4: Set Terminal Mode by Default</h4>
<p>If you want to always use Emacs in terminal mode, add the following alias to
your <code>.bashrc</code> or <code>.zshrc</code>:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">alias</span> <span class="token assign-left variable">emacs</span><span class="token operator">=</span><span class="token string">'emacs -nw'</span>
</code></pre></div>
<p>Then reload your shell configuration:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">source</span> ~/.bashrc  <span class="token comment"># for bash</span>
<span class="token builtin class-name">source</span> ~/.zshrc   <span class="token comment"># for zsh</span>
</code></pre></div>
<h4>Step 5: Start Emacs</h4>
<p>Now you can launch Emacs by simply typing:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">emacs
</code></pre></div>
<h3>Exploring Emacs with Familiar Keybindings</h3>
<p><strong>Emacs-Kick</strong> is designed to be intuitive for users coming from Vim/Neovim.
Here are some keybindings you’ll find useful:</p>
<ul>
<li><strong>Leader Key</strong>: The leader key is set to <code>SPC</code> (spacebar), similar to
many Vim configurations.</li>
<li><strong>File Navigation</strong>: Use <code>&#x3C;leader> s f</code> to find files and <code>&#x3C;leader> p f</code>
to search within projects.</li>
<li><strong>Search</strong>: <code>&#x3C;leader> s g</code> for grep, <code>&#x3C;leader> s r</code> for ripgrep.</li>
</ul>
<p>With <strong>which-key</strong> enabled, discovering more keybindings becomes easy
as they are dynamically displayed as you type.</p>
<h3>Why Should a Neovim User Try Emacs?</h3>
<p>If you're already happy with Neovim, you may wonder why you should
bother trying Emacs at all. Here’s why:</p>
<ul>
<li><strong>Org Mode</strong>: Emacs’ Org Mode is one of its most famous features—an incredible
tool for note-taking, to-do lists, and project management.</li>
<li><strong>Magit</strong>: A powerful Git interface that many users find faster and
more intuitive than command-line Git.</li>
<li><strong>Customization</strong>: The possibilities with Emacs are endless. You can build
your own workflow or even turn Emacs into a programming IDE, personal
organizer, or anything else you can imagine.</li>
</ul>
<p><strong>Emacs-Kick</strong> provides a gateway into these features without forcing
you to abandon your familiar Neovim tools or habits.</p>
<h3>Contributing to Emacs-Kick</h3>
<p><strong>Emacs-Kick</strong> is a work in progress, and I welcome contributions from
the community. While I have a particular vision for this project, I
appreciate feedback and ideas on how to make it even better.</p>
<p>If you'd like to contribute, feel free to open issues or submit pull
requests on GitHub. Let’s continue to build a configuration that makes
it easy for Vim/Neovim users to explore the power of Emacs.</p>
<hr>
<p><strong>Ready to give Emacs a try?</strong> Download <a href="https://github.com/LionyxML/emacs-kick/">Emacs-Kick</a>
from GitHub and start experimenting with Emacs today, using the same
keybindings and tools you’re already familiar with.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/emacs-kick</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/emacs-kick</guid>
            <pubDate>Wed, 09 Oct 2024 00:02:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Making Emacs Work with Project's ESLint]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Discover how to configure Emacs to use the project-specific ESLint
binary, ensuring compatibility with older projects. Learn about the
issue caused by the ESLint v9.0.0 update and how to hack Flymake (via
flymake-eslint) for a happy experience.</p>
<h2>Making Emacs Work with Project's ESLint</h2>
<p>This means: local ESlint from node_modules, the one you installed to
your project.</p>
<h3>Introduction</h3>
<p>After a recent clean reinstall of the <code>asdf</code> plugin, which manages my
Node.js versions via <code>.tool-versions</code>, I encountered an issue: ESLint
stopped working in Emacs. My older projects, which were not compatible
with the newer globally installed ESLint, caused Emacs to fail
silently when trying to load ESLint. Debugging revealed that the
incompatibility stemmed from the ESLint v9.0.0 update, which
deprecated the previous configuration format, <code>.eslintrc</code>, in favor of
the new default configuration format, <code>eslint.config.js</code>
[<a href="https://eslint.org/docs/latest/use/migrate-to-9.0.0#-new-default-config-format-eslintconfigjs">source</a>].
This change affected both my Emacs and Neovim personal configurations,
as neither editor was set to use the local ESLint binary, but rather
the global one.</p>
<h3>The Hack: Using Local ESLint Binary with Flymake</h3>
<p>To solve this problem, I created/adapted a hack to make Flymake in
Emacs use the project-local ESLint binary located in
<code>node_modules/.bin/eslint</code> instead of the globally installed
version. This ensures that each project uses the version of ESLint it
was originally configured with, avoiding compatibility issues.</p>
<p>Here’s how to set it up:</p>
<ol>
<li>
<p><strong>Install flymake-eslint</strong></p>
<p>First, make sure you have <code>flymake-eslint</code> installed. You can do
this by adding the following to your Emacs configuration file:</p>
</li>
</ol>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> flymake-eslint
      <span class="token lisp-property property">:ensure</span> <span class="token boolean">t</span>
      <span class="token lisp-property property">:config</span>
      <span class="token comment">;; If Emacs is compiled with JSON support</span>
      <span class="token punctuation">(</span><span class="token keyword">setq</span> flymake-eslint-prefer-json-diagnostics <span class="token boolean">t</span><span class="token punctuation">)</span>
</code></pre></div>
<ol start="2">
<li>
<p><strong>Define Function to Use Local ESLint</strong></p>
<p>Next, define a function that sets the project's <code>node_modules</code>
binary ESLint as the first priority. Note that my functions are
prefixed with <code>lemacs</code>, which is the name of my Emacs
configuration available at
<a href="https://github.com/LionyxML/LEmacs">LEmacs</a>:</p>
</li>
</ol>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">lemacs/use-local-eslint</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
      <span class="token string">"Set project's <span class="token symbol">`node_modules'</span> binary eslint as first priority.
    If nothing is found, keep the default value flymake-eslint set or
    your override of `flymake-eslint-executable-name.'"</span>
      <span class="token punctuation">(</span><span class="token interactive keyword">interactive</span><span class="token punctuation">)</span>
      <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">root</span> <span class="token punctuation">(</span><span class="token car">locate-dominating-file</span> <span class="token punctuation">(</span><span class="token car">buffer-file-name</span><span class="token punctuation">)</span> <span class="token string">"node_modules"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
             <span class="token punctuation">(</span><span class="token car">eslint</span> <span class="token punctuation">(</span><span class="token keyword">and</span> root
                          <span class="token punctuation">(</span><span class="token car">expand-file-name</span> <span class="token string">"node_modules/.bin/eslint"</span>
                                            root<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token keyword">and</span> eslint <span class="token punctuation">(</span><span class="token car">file-executable-p</span> eslint<span class="token punctuation">)</span><span class="token punctuation">)</span>
          <span class="token punctuation">(</span><span class="token car">setq-local</span> flymake-eslint-executable-name eslint<span class="token punctuation">)</span>
          <span class="token punctuation">(</span><span class="token keyword">message</span> <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">"Found local ESLINT! Setting: %s"</span> eslint<span class="token punctuation">)</span><span class="token punctuation">)</span>
          <span class="token punctuation">(</span><span class="token car">flymake-eslint-enable</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<ol start="3">
<li>
<p><strong>Configure ESLint with Flymake</strong></p>
<p>You can configure Flymake to use the local ESLint for specific
major modes like <code>tsx-ts-mode</code>, <code>typescript-ts-mode</code>, and
<code>typescriptreact-mode</code>:</p>
</li>
</ol>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">lemacs/configure-eslint-with-flymake</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
	<span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token keyword">or</span> <span class="token punctuation">(</span><span class="token car">eq</span> major-mode <span class="token quoted-symbol variable symbol">'tsx-ts-mode</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token car">eq</span> major-mode <span class="token quoted-symbol variable symbol">'typescript-ts-mode</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token car">eq</span> major-mode <span class="token quoted-symbol variable symbol">'typescriptreact-mode</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">(</span><span class="token car">lemacs/use-local-eslint</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<ol start="4">
<li>
<p><strong>Add Hooks</strong></p>
<p>Finally, add the function to the <code>eglot-managed-mode-hook</code> and
other relevant hooks:</p>
</li>
</ol>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token car">add-hook</span> <span class="token quoted-symbol variable symbol">'eglot-managed-mode-hook</span> <span class="token quoted-symbol variable symbol">#'lemacs/use-local-eslint</span><span class="token punctuation">)</span>

    <span class="token comment">;; With older projects without LSP or if eglot fails</span>
    <span class="token comment">;; you can call interactivelly M-x lemacs/use-local-eslint RET</span>
    <span class="token comment">;; or add a hook like:</span>
    <span class="token punctuation">(</span><span class="token car">add-hook</span> <span class="token quoted-symbol variable symbol">'js-ts-mode-hook</span> <span class="token quoted-symbol variable symbol">#'lemacs/use-local-eslint</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Notice that as <code>lemacs/use-local-eslint</code> is an interactive function it
might also be called manually with <code>M-x lemacs/use-local-eslint RET</code>.</p>
<h3>Full Code</h3>
<div class="remark-highlight"><pre class="language-emacs-lisp"><code class="language-emacs-lisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> flymake-eslint
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:config</span>
  <span class="token comment">;; If Emacs is compiled with JSON support</span>
  <span class="token punctuation">(</span><span class="token keyword">setq</span> flymake-eslint-prefer-json-diagnostics <span class="token boolean">t</span><span class="token punctuation">)</span>
    
  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">lemacs/use-local-eslint</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
    <span class="token string">"Set project's <span class="token symbol">`node_modules'</span> binary eslint as first priority.
If nothing is found, keep the default value flymake-eslint set or
your override of `flymake-eslint-executable-name.'"</span>
    <span class="token punctuation">(</span><span class="token interactive keyword">interactive</span><span class="token punctuation">)</span>
    <span class="token punctuation">(</span><span class="token keyword">let*</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">root</span> <span class="token punctuation">(</span><span class="token car">locate-dominating-file</span> <span class="token punctuation">(</span><span class="token car">buffer-file-name</span><span class="token punctuation">)</span> <span class="token string">"node_modules"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
           <span class="token punctuation">(</span><span class="token car">eslint</span> <span class="token punctuation">(</span><span class="token keyword">and</span> root
                        <span class="token punctuation">(</span><span class="token car">expand-file-name</span> <span class="token string">"node_modules/.bin/eslint"</span>
                                          root<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token keyword">and</span> eslint <span class="token punctuation">(</span><span class="token car">file-executable-p</span> eslint<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">(</span><span class="token car">setq-local</span> flymake-eslint-executable-name eslint<span class="token punctuation">)</span>
        <span class="token punctuation">(</span><span class="token keyword">message</span> <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">"Found local ESLINT! Setting: %s"</span> eslint<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">(</span><span class="token car">flymake-eslint-enable</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>


  <span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">lemacs/configure-eslint-with-flymake</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
	<span class="token punctuation">(</span><span class="token keyword">when</span> <span class="token punctuation">(</span><span class="token keyword">or</span> <span class="token punctuation">(</span><span class="token car">eq</span> major-mode <span class="token quoted-symbol variable symbol">'tsx-ts-mode</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token car">eq</span> major-mode <span class="token quoted-symbol variable symbol">'typescript-ts-mode</span><span class="token punctuation">)</span>
			  <span class="token punctuation">(</span><span class="token car">eq</span> major-mode <span class="token quoted-symbol variable symbol">'typescriptreact-mode</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">(</span><span class="token car">lemacs/use-local-eslint</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token car">add-hook</span> <span class="token quoted-symbol variable symbol">'eglot-managed-mode-hook</span> <span class="token quoted-symbol variable symbol">#'lemacs/use-local-eslint</span><span class="token punctuation">)</span>

  <span class="token comment">;; With older projects without LSP or if eglot fails</span>
  <span class="token comment">;; you can call interactivelly M-x lemacs/use-local-eslint RET</span>
  <span class="token comment">;; or add a hook like:</span>
  <span class="token punctuation">(</span><span class="token car">add-hook</span> <span class="token quoted-symbol variable symbol">'js-ts-mode-hook</span> <span class="token quoted-symbol variable symbol">#'lemacs/use-local-eslint</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<h3>Demo</h3>
<h4>Case A:</h4>
<p>Project with Typescript and ESLint version 8.x.x.</p>
<p>Without the Hack (only typescript server errors are shown):</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Feslint_01.png&w=3840&q=75" alt="eslint_01"></p>
<p>With the Hack (both typescript server and eslint errors are shown):</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Feslint_02.png&w=3840&q=75" alt="eslint_02"></p>
<h4>Case B:</h4>
<p>Project with only ESLint in an ancient version.</p>
<p>Without the Hack (no linting):</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Feslint_03.png&w=3840&q=75" alt="eslint_03"></p>
<p>With the Hack (the right 'age compatible' linting):</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Feslint_04.png&w=3840&q=75" alt="eslint_04"></p>
<h3>Conclusion</h3>
<p>By hacking <code>flymake-eslint</code> to use the local ESLint binary, you can
maintain compatibility with older projects without relying on globally
installed versions that may introduce breaking changes. This approach
ensures a smooth development experience in Emacs, keeping ESLint
functional across various project setups.</p>
<p>As a small sidenote, I did noticed some time between the first time
the first project buffer opens and flymake starts to work, but it
looks like this is already the case even without the hack, just start
editing and things will adjust themselves.</p>
<p>Also, if you do not use your projects with the built-in <code>project.el</code>
(as you probably should), I believe the hack is easy enough to be
changed to your needs.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/eslint-on-emacs</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/eslint-on-emacs</guid>
            <pubDate>Fri, 05 Jul 2024 11:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[My personal Emacs Config (LEmacs - L(ionyx)Emacs)]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>For me, one of the finest things of using Emacs is having the same user experience both when I am
sessioning trough SSH, hacking with Tmux, reading my RSS news or working as a software engineer. Having
no worries about changing between text editors is really nice. Also, starting a "one session to rule" then
all as a deamon and opening several GUI/TUI frames in the same session, wow... Emacs is still very cool :)</p>
<p>It's been a while since I "launched" my public Emacs config. It is something I was relutant to do as it
reflected some 15+ years of learnig, patching and well, not cleaning it up as I should.</p>
<p>This led me to many situations where I wasn't confortable sharing stuff, either if I needed help or
if I wanted to help someone.</p>
<p>And just as this blog is kind of an effort project to expose my self more. I redid my Emacs config
to be at least "readable", maybe "enjoyable" :)</p>
<p>As I said before having GUI and TUI behaving the same is very important to me. It is horrible to see
flymake anottating things on the fringe, just to find out that TUI has no fringe. An option to enable
marking on the margin? No thanks. And that's one of several reasons I preferred flycheck over the
years.</p>
<p>Do you want the cool Eglot to show documentation? Maybe use eldoc-box? No support for TUI unfortunally. And
that's another big win to lsp-mode.</p>
<p>Little things like these added up trough the years to make this config the way it is nowadays.</p>
<p>What I expected from sharing it? Just the joy of providing other people with some insights and maybe
receiving some positive improvable feedbacks.</p>
<p>You can find it in here: <a href="https://github.com/LionyxML/LEmacs">LEmacs Config</a></p>
<p>Bellow I provide a copy of LEmacs README so you can take a look at it.</p>
<h2>LEmacs - L(ionyx)Emacs Config</h2>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">    ██╗     ███████╗███╗   ███╗ █████╗  ██████╗███████╗
    ██║     ██╔════╝████╗ ████║██╔══██╗██╔════╝██╔════╝
    ██║     █████╗  ██╔████╔██║███████║██║     ███████╗
    ██║     ██╔══╝  ██║╚██╔╝██║██╔══██║██║     ╚════██║
    ███████╗███████╗██║ ╚═╝ ██║██║  ██║╚██████╗███████║
    ╚══════╝╚══════╝╚═╝     ╚═╝╚═╝  ╚═╝ ╚═════╝╚══════╝</code></pre></div>
<p>Emacs for the modern developer focused on seamlessly TUI/GUI experience, either standalone or in
a server/client mode.</p>
<p>Left (Terminal User Interface) / Right (Graphical User Interface)</p>
<p>Demo 01:
<img src="https://raw.githubusercontent.com/LionyxML/lemacs/main/doc/demo01.png" alt="img"></p>
<p>Demo 02:
<img src="https://raw.githubusercontent.com/LionyxML/lemacs/main/doc/demo02.png" alt="img"></p>
<p>Demo 03:
<img src="https://raw.githubusercontent.com/LionyxML/lemacs/main/doc/demo03.png" alt="img"></p>
<p>Demo 04 (highlight guideline):
<img src="https://raw.githubusercontent.com/LionyxML/lemacs/main/doc/demo04.png" alt="img"></p>
<p>Demo 05 (git gutter):
<img src="https://raw.githubusercontent.com/LionyxML/lemacs/main/doc/demo05.png" alt="img"></p>
<p>Demo 06 (line blame):
<img src="https://raw.githubusercontent.com/LionyxML/lemacs/main/doc/demo06.png" alt="img"></p>
<p>And all the power of Vertico, Orderless, Marginalia, Embark, Consult, LSP, TreeSitter, Vterm, and many more!</p>
<p>Fork it at will! :)</p>
<p><a id="orgdabcea0"></a></p>
<h2>Motivation</h2>
<p>Greetings to LEmacs, my customized configuration now shared with the community! This configuration
is crafted to deliver a seamless and delightful Emacs experience, whether you're navigating through the
Text User Interface (TUI) or the Graphical User Interface (GUI). It's designed to excel in both
standalone mode and as a daemon/client setup.</p>
<p>This means (of course to my personal taste and opinions) that I will prefer packages that support
both Terminal and Graphics, so you may never be worried about where to use Emacs or other editors.</p>
<p>You can use Emacs, everywhere, always ;)</p>
<h2>Installation</h2>
<h3>Preparation</h3>
<ol>
<li>
<p>Emacs Version</p>
<p>Ensure you have Emacs version 29 or higher, compiled with native compilation, JSON, and tree-sitter support.</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">emacs --version
emacs -nw -q --batch --eval &#39;(message system-configuration-options)&#39;</code></pre></div>
</li>
<li>
<p>JS/TS LSP Servers</p>
<p>To use LSP (and also node/typescript/eslint,  prettier), you can install Node JS globally or use a version
management tool, in the case you have several projects with several node versions it is common to use <strong><strong>nvm</strong></strong>
or <strong><strong>asdf</strong></strong>. I recommend to install Node JS via <strong><strong>asdf</strong></strong> (<a href="https://asdf-vm.com/">https://asdf-vm.com/</a>).</p>
<p>Note: asdf must be loaded on .bash<sub>profile</sub> for macos, and .bashrc for Linux,
for testing (after Lemacs install), run eshell and look at <strong><strong>asdf –version</strong></strong> output.</p>
<p>You need to Install globally (and for every every asdf plugin shim if you're using asdf):</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">npm i -g vscode-langservers-extracted prettier@2.8.8
npm i -g typescript-language-server typescript</code></pre></div>
</li>
<li>
<p>Backup your config</p>
<p>Make a backup of your ~/.emacs.d/, ~/.emacs files and delete them, recommended:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">cp -r ~/.emacs.d/ ~/.emacs.d_backup
cp ~/.emacs ~/.emacs_backup

rm -rf ~/.emacs.d ~/.emacs</code></pre></div>
</li>
</ol>
<h3>Clone and install LEmacs</h3>
<p>Now, let's get you set up:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">git clone https://github.com/LionyxML/LEmacs ~/.emacs.d
emacs -nw --eval=&quot;(my-first-install)&quot;</code></pre></div>
<p>During installation, you'll be prompted to:</p>
<ul>
<li>Choose whether to compile vterm now or later (recommended: yes)</li>
<li>Specify the Tree Sitter library bundle version (hit RET for default)</li>
<li>Opt to display installed grammars (recommended: yes)</li>
<li>Decide on downloading and installing fonts for use with NerdFonts (recommended: yes)</li>
</ul>
<p>If anything goes awry, exit and restart the installation script. If all goes smoothly, you'll be back at your shell prompt.</p>
<p>Launch Emacs, whether from the GUI or TUI (emacs -nw or emacs), and you're good to roll!</p>
<h2>Troubleshooting</h2>
<h3>LSP-mode</h3>
<p>It's always a good idea to run <strong><strong>M-x lsp-doctor</strong></strong> to check that everything is working.</p>
<p>This might be necessary when dealing with nodeJS, watches, etc:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">echo fs.inotify.max_user_watches=393210 \
| sudo tee -a /etc/sysctl.conf \
&amp;&amp; sudo sysctl -p</code></pre></div>
<h3>Emacs is hanging…</h3>
<p>If you're experiencing UI freezes in Emacs, here's a handy way to pinpoint the culprit:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">M-x profiler-start
;; choose CPU
;; do stuff and make the UI freeze
M-x profiler-stop
M-x profiler-report</code></pre></div>
<p>This will help you identify what's causing the slowdown. Pay attention to the profiler
report for insights into resource-intensive operations.</p>
<p>It's worth noting that this configuration makes native compilation asynchronous.
Consequently, the first time you use a package, there might be a background process
compiling it. Check for any Async-native-compile-log buffers using:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">M-x ibuffer</code></pre></div>
<p>Inspect these buffers to ensure that compilation processes are running as expected.</p>
<h2>FAQ</h2>
<h3>Why not X Feature?</h3>
<p>If you're wondering, "Why not X feature?"—great question!</p>
<p>Open an issue on our GitHub repository, and let's dive into the
discussion. I am open to exploring new additions or substitutions.</p>
<h2>Extra: Emacs install</h2>
<h3>Debian (or Debian Based distros)</h3>
<p>For Debian or Debian based Distros, such as Ubuntu and it's derivatives.</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">sudo apt install emacs</code></pre></div>
<p>Check the installed version with:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">emacs --version</code></pre></div>
<h3>MacOS</h3>
<p>On macOS compiling with a brew formulae is the recommendated way:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">brew install \
  --ignore-dependencies \
  emacs-plus@30 \
  --with-native-comp \
  --with-xwidgets \
  --with-imagemagick \
  --with-mailutils \
  --with-poll \
  --with-no-frame-refocus</code></pre></div>
<h3>Compile Emacs from scratch (Debian)</h3>
<p>Before everything, this is optional, but may help on reducing troubleshooting time:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">sudo apt-get build-dep emacs</code></pre></div>
<p>Take a look on the repo first to make sure Emacs on master branch matches the above version requirement.</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">git clone git://git.savannah.gnu.org/emacs.git

./configure --with-native-compilation=aot --with-tree-sitter --with-gif --with-png --with-jpeg --with-rsvg --with-tiff --with-imagemagick --with-x-toolkit=lucid --with-json --with-mailutils

make clean

make -j8

sudo make install</code></pre></div>
]]></description>
            <link>https://rahuljuliato.com/posts/lemacs</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/lemacs</guid>
            <pubDate>Wed, 28 Feb 2024 00:02:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Compiling Emacs 29.2 from the source on Debian]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Compile Emacs 29.2 from source with a recent bug-fix release
highlighted by Eli Zaretskii. This Debian 12-focused tutorial
simplifies the process, covering downloading, signature verification,
and configuration. With an emphasis on ease, Debian's build
dependencies are leveraged, allowing users to quickly build, install,
and even uninstall Emacs for a seamless experience.</p>
<h2>Compiling Emacs 29.2 from the source</h2>
<p>Some days ago the Emacs community received a really nice message from
Eli Zaretskii, which currently is a co-maintainer of GNU Emacs.</p>
<p>You can read it here:
<a href="">https://lists.gnu.org/archive/html/emacs-devel/2024-01/msg00666.html</a>.</p>
<p>This is a bug-fix release, that means no new features were added.</p>
<p>That said, this gives us the opportunity of building Emacs from the source (which I
usually prefer, since I like to toggle some switches).</p>
<p>The next steps in this short tutorial will take in consideration you
have the latest Debian release, in my case:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">(Linux debian 6.1.0-17-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.69-1 (2023-12-30) x86_64 GNU/Linux).</code></pre></div>
<h2>Downloading Emacs Source-Code</h2>
<p>Create a new directory of your liking and cd into it:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">mkdir ~/emacs_build
cd emacs_build</code></pre></div>
<p>Download the Emacs source code and the signature file. You can do this
from
<a href="https://ftp.gnu.org/gnu/emacs/">https://ftp.gnu.org/gnu/emacs/</a>, by
accessing it from your web-browser, or:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">wget -c https://ftpmirror.gnu.org/emacs/emacs-29.2.tar.gz
wget -c https://ftpmirror.gnu.org/emacs/emacs-29.2.tar.gz.sig</code></pre></div>
<h2>Verifying the tarball Authenticity</h2>
<p>Now verify the tarball (.tar.gz compressed file) authenticity by running:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">gpg --verify emacs-29.2.tar.gz.sig</code></pre></div>
<p>If you have some error message, it is possible you haven't yet
imported Eli Zaretskii public key. You can do So by issuing:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">gpg --keyserver keyserver.ubuntu.com --recv-keys \
    17E90D521672C04631B1183EE78DAE0F3115E06B</code></pre></div>
<p>That will return:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">gpg: key E78DAE0F3115E06B: public key &quot;Eli Zaretskii &lt;eliz@gnu.org&gt;&quot; imported
gpg: Total number processed: 1
gpg:               imported: 1</code></pre></div>
<p>Now running <code>gpg --verify emacs-29.2.tar.gz.sig</code> will return something like:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">gpg: assuming signed data in &#39;emacs-29.2.tar.gz&#39;
gpg: Signature made Thu 18 Jan 2024 07:55:42 AM -03
gpg:                using RSA key 17E90D521672C04631B1183EE78DAE0F3115E06B
gpg: Good signature from &quot;Eli Zaretskii &lt;eliz@gnu.org&gt;&quot; [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: 17E9 0D52 1672 C046 31B1  183E E78D AE0F 3115 E06B</code></pre></div>
<p>And you can verify the signature of the package. If something is
strange, stop here, check the sources and make sure you have an
authentic copy of Emacs source code.</p>
<h2>Unpacking the tarball</h2>
<p>You can now unpack the tarball by running:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">tar xvfz emacs-29.2.tar.gz</code></pre></div>
<p>After that enter the created folder with:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">cd emacs-29.2</code></pre></div>
<h2>Configuring for the build</h2>
<p>Usually, building something from source means going trough config and make, several
times, resolving dependencies and so on.</p>
<p>Here we're gonna cheat a little bit. Since Debian already ships some
sort (normally older) of Emacs. We can ask to install the build
dependencies for Emacs and save us some configure-make loop time.</p>
<p>Do this with:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">sudo apt-get build-dep emacs</code></pre></div>
<p>After this, it is time to configure things.</p>
<p>You can check all Emacs flags running <code>./configure --help</code>.</p>
<p>I usually go with these options:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">./configure --with-native-compilation=aot\
            --with-tree-sitter\
			--with-gif\
			--with-png\
			--with-jpeg\
			--with-rsvg\
			--with-tiff\
			--with-imagemagick\
			--with-x-toolkit=lucid\
			--with-json\
			--with-mailutils</code></pre></div>
<p>Customize it to your will.</p>
<h2>Making and Installing</h2>
<p>In this step we're actually building the software and installing.</p>
<p>Start by cleaning any older building with:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">make clean</code></pre></div>
<p>If you had some problem during a previous make, or had to stop it for some reason,
this will ensure you new "build" is clean and starting from the beginning.</p>
<p>Now we actually run make with:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">make -j8</code></pre></div>
<p>This will compile Emacs by allowing 8 jobs at once. You can leave make with no <code>-j</code>
flag for <code>infinite</code> jobs or customize at will.</p>
<p>If everything runs ok and make exits successfully you can test Emacs with <code>./src/emacs</code>, I recommend just doing a version check with:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">./src/emacs --version</code></pre></div>
<p>That may return:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">GNU Emacs 29.2
Copyright (C) 2024 Free Software Foundation, Inc.
GNU Emacs comes with ABSOLUTELY NO WARRANTY.
You may redistribute copies of GNU Emacs
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING.</code></pre></div>
<p>To have your built Emacs readily available, install it to your system with:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">make install</code></pre></div>
<p>Verify if you have the compiled version to your path by issuing:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">emacs --version</code></pre></div>
<p>You may have again:</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">GNU Emacs 29.2
...</code></pre></div>
<p>And that's it!</p>
<h2>Uninstalling Emacs</h2>
<p>If things go wrong or you need to uninstall a version of Emacs
before compiling a new one, it is a "necessity practice" to keep the
folder from where you built your software, so you can run: <code>make uninstall</code> and remove it completely from your system.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/compiling_emacs_29_2</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/compiling_emacs_29_2</guid>
            <pubDate>Mon, 22 Jan 2024 00:02:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Ollama on Emacs with Ellama]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Are you interested in running a local AI companion within Emacs? If
so, you're in the right place! In this article, we'll guide you
through setting up an Ollama server to run Llama2, Code Llama, and
other AI models. This way, you'll have the power to seamlessly
integrate these models into your Emacs workflow.</p>
<h2>How to Install Ollama</h2>
<p>Installing Ollama on your system is a straightforward process.</p>
<p>To get started, visit <a href="https://ollama.ai/download">https://ollama.ai/download</a>
and follow the provided instructions.</p>
<p>It's essential not to blindly execute commands and scripts. Instead,
take the time to review the source code and ensure it aligns with your
requirements. You can modify the code to suit your needs or make
adjustments after installation.</p>
<p>For a quick installation via the command line, you can use the following command:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">curl</span> https://ollama.ai/install.sh <span class="token operator">|</span> <span class="token function">sh</span>
</code></pre></div>
<p>This command not only installs Ollama but also sets it up as a service
that runs by default on your system. While it consumes minimal system
resources when idle, it's a good practice to inspect the script's
source code, make any necessary modifications, and configure it
according to your preferences.</p>
<p>You can find the current installation script's source code:
<a href="https://github.com/jmorganca/ollama/blob/main/scripts/install.sh">Current ollama install script</a>.</p>
<p>Once you've set up Ollama, you can easily initiate interactions like these:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">ollama run codelamma <span class="token string">"Write me a function in Javascript that outputs the fibonacci sequence"</span>
</code></pre></div>
<p>Or if you prefer a command-line chat interface:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">olama run codelamma
</code></pre></div>
<p>During the initial run, the codellama model will be downloaded. This
model is just one of the many offered by the Ollama project, so you
have the flexibility to choose your favorite model based on your
preferences. Keep in mind that each model may have varying hardware
requirements.</p>
<p>As of today, Ollama supports the following models, as indicated on their
<a href="https://github.com/jmorganca/ollama">Github Page</a>.</p>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">| Model              | Parameters | Size  |
| ------------------ | ---------- | ----- |
| Mistral            | 7B         | 4.1GB |
| Llama 2            | 7B         | 3.8GB |
| Code Llama         | 7B         | 3.8GB |
| Llama 2 Uncensored | 7B         | 3.8GB |
| Llama 2 13B        | 13B        | 7.3GB |
| Llama 2 70B        | 70B        | 39GB  |
| Orca Mini          | 3B         | 1.9GB |
| Vicuna             | 7B         | 3.8GB |</code></pre></div>
<p>Please note that you should have at least 8 GB of RAM to run the 3B
models, 16 GB for the 7B models, and 32 GB for the 13B models.</p>
<p>If you're interested in exploring more models, you can find a
comprehensive library <a href="https://ollama.ai/library">here</a>.</p>
<p>For the purposes of this article, we'll be using the <code>codellama</code> model.</p>
<h2>Installing Ellama</h2>
<p>Ellama is a very nice assembled package by Sergey Kostyaev, built on
the foundation of the llm library package. It offers a set of powerful
functions designed to seamlessly integrate Emacs and Ollama, enhancing
your workflow and productivity.</p>
<p>For a closer look at Ellama and to stay updated on the project's
current status, you can visit the official repository on GitHub:
<a href="https://github.com/s-kostyaev/ellama">https://github.com/s-kostyaev/ellama</a>.</p>
<p>You can install it via <code>package-install</code> or simply set <code>use-package</code>
on your <code>init.el</code>, like:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> ellama
  <span class="token lisp-property property">:init</span>
  <span class="token punctuation">(</span><span class="token car">setopt</span> ellama-language <span class="token string">"English"</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token keyword">require</span> <span class="token quoted-symbol variable symbol">'llm-ollama</span><span class="token punctuation">)</span>
  <span class="token punctuation">(</span><span class="token car">setopt</span> ellama-provider
		  <span class="token punctuation">(</span><span class="token car">make-llm-ollama</span>
		   <span class="token lisp-property property">:chat-model</span> <span class="token string">"codellama"</span> <span class="token lisp-property property">:embedding-model</span> <span class="token string">"codellama"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>You're almost there! To activate these new features, simply evaluate
this region or reset your Emacs.</p>
<p>Once you've done this, you can use the <code>M-x</code> command to access a
wealth of handy functions for querying your local Ollama server
directly from within Emacs. This will greatly enhance your workflow
and make your interaction with Ollama more seamless and efficient.</p>
<h2>Using Ellama</h2>
<p>Commands:</p>
<p>- <strong>ellama-chat</strong>: Initiate a conversation with Ellama by entering prompts in an interactive buffer.</p>
<p>- <strong>ellama-ask</strong> (Alias for ellama-chat): Ask questions and converse with Ellama.</p>
<p>- <strong>ellama-ask-about</strong>: Ask Ellama about a selected region or the current buffer's content.</p>
<p>- <strong>ellama-translate</strong>: Request Ellama to translate a selected region or word at the cursor.</p>
<p>- <strong>ellama-define-word</strong>: Find definitions for the current word using Ellama.</p>
<p>- <strong>ellama-summarize</strong>: Generate a summary for a selected region or the current buffer.</p>
<p>- <strong>ellama-code-review</strong>: Review code in a selected region or the current buffer with Ellama.</p>
<p>- <strong>ellama-change</strong>: Modify text in a selected region or the current buffer according to a provided change.</p>
<p>- <strong>ellama-enhance-grammar-spelling</strong>: Improve grammar and spelling in the selected region or buffer using Ellama.</p>
<p>- <strong>ellama-enhance-wording</strong>: Enhance wording in the selected region or buffer.</p>
<p>- <strong>ellama-make-concise</strong>: Simplify and make the text in the selected region or buffer more concise.</p>
<p>- <strong>ellama-change-code</strong>: Change selected code according to a provided change.</p>
<p>- <strong>ellama-enhance-code</strong>: Enhance selected code according to a provided change.</p>
<p>- <strong>ellama-complete-code</strong>: Complete selected code according to a provided change.</p>
<p>- <strong>ellama-add-code</strong>: Add new code based on a description, generated with provided context.</p>
<p>- <strong>ellama-render</strong>: Convert selected text or the text in the current buffer to a specified format.</p>
<p>- <strong>ellama-make-list</strong>: Create a markdown list from the selected region or the current buffer.</p>
<p>- <strong>ellama-make-table</strong>: Generate a markdown table from the selected region or the current buffer.</p>
<p>- <strong>ellama-summarize-webpage</strong>: Summarize a webpage fetched from a URL using Ellama.</p>
<p>You can check the full documentation on the <a href="https://github.com/s-kostyaev/ellama">Ellama Github
Page</a>.</p>
<h2>Some special Ellama customizations</h2>
<p>While this project already offers fantastic functions for seamless
integration of Ollama into Emacs, I discovered the need for some
additional keybindings to further boost my productivity.</p>
<p>As a result, I've developed a customization that introduces two
valuable features:</p>
<p><strong>1.</strong> Global Keybinding Prefix: I've created a global keybinding prefix
<code>C-x e</code>, which can serve as a host for a wide range of commands
related to Ellama. To explore the full list of available commands,
you can simply use <code>C-x e ?</code> or take advantage of the which-key
package to receive hints for command completion.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fellama-1.png&w=3840&q=75" alt="cx-e"></p>
<p>These features, including the toggle and the keybinding prefix, are
fully configurable through the <code>customize-group ellama</code>. This allows you
to tailor your Ellama integration in Emacs to suit your unique
workflow and preferences.</p>
<p><strong>2.</strong> Visual-Line Mode for All <code>*ellama*</code> Buffers: I've introduced a
straightforward customization that automatically applies the
visual-line mode to all <code>*ellama*</code> buffers. This mode ensures that lines
are wrapped for improved readability.</p>
<p>Additionally, I've included an option in <code>customize-group</code> ellama that
allows you to switch this feature on or off based on your
preference. As a result, a buffer like the one depicted below:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fellama-2.png&w=3840&q=75" alt="non-wrapped-lines"></p>
<p>Will be displayed as follows:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fellama-3.png&w=3840&q=75" alt="wrapped-lines"></p>
<p>This enhancement simplifies the reading experience within
Ellama-related buffers, making it more user-friendly and adaptable to
your needs.</p>
<p>As mentioned earlier, invoking <code>customize-group ellama</code> grants access to these
settings:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fellama-4.png&w=3840&q=75" alt="customizations"></p>
<p>To make this functionality easily accessible, you can incorporate the
following into your configuration:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token defun"><span class="token keyword">defun</span> <span class="token function">ellama-setup-keymap</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
	  <span class="token string">"Set up the Ellama keymap and bindings."</span>
	  <span class="token punctuation">(</span><span class="token interactive keyword">interactive</span><span class="token punctuation">)</span>
	  <span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defvar</span> <span class="token variable">ellama-keymap</span></span> <span class="token punctuation">(</span><span class="token car">make-sparse-keymap</span><span class="token punctuation">)</span>
      <span class="token string">"Keymap for Ellama Commands"</span><span class="token punctuation">)</span>

	  <span class="token punctuation">(</span><span class="token car">define-key</span> global-map <span class="token punctuation">(</span><span class="token car">kbd</span> ellama-keymap-prefix<span class="token punctuation">)</span> ellama-keymap<span class="token punctuation">)</span>

	  <span class="token punctuation">(</span><span class="token keyword">let</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token car">key-commands</span>
            <span class="token punctuation">'(</span><span class="token punctuation">(</span><span class="token string">"a"</span> ellama-ask-about <span class="token string">"Ask about selected region"</span><span class="token punctuation">)</span>
			         <span class="token punctuation">(</span><span class="token string">"b"</span> ellama-make-concise <span class="token string">"Better text"</span><span class="token punctuation">)</span>
			         <span class="token punctuation">(</span><span class="token string">"c"</span> ellama-chat <span class="token string">"Chat with Ellama"</span><span class="token punctuation">)</span>
			         <span class="token punctuation">(</span><span class="token string">"d"</span> ellama-define-word <span class="token string">"Define selected word"</span><span class="token punctuation">)</span>
			         <span class="token punctuation">(</span><span class="token string">"r"</span> ellama-code-review <span class="token string">"Code-review selected code"</span><span class="token punctuation">)</span>
			         <span class="token punctuation">(</span><span class="token string">"s"</span> ellama-summarize <span class="token string">"Summarize selected text"</span><span class="token punctuation">)</span>
			         <span class="token punctuation">(</span><span class="token string">"t"</span> ellama-translate <span class="token string">"Translate the selected region"</span><span class="token punctuation">)</span>
			         <span class="token punctuation">(</span><span class="token string">"w"</span> ellama-summarize-webpage <span class="token string">"Summarize a web page"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">(</span><span class="token car">dolist</span> <span class="token punctuation">(</span><span class="token car">key-command</span> key-commands<span class="token punctuation">)</span>
		    <span class="token punctuation">(</span><span class="token car">define-key</span> ellama-keymap <span class="token punctuation">(</span><span class="token car">kbd</span> <span class="token punctuation">(</span><span class="token car">car</span> key-command<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">cadr</span> key-command<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>


  <span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defcustom</span> <span class="token variable">ellama-keymap-prefix</span></span> <span class="token string">"C-x e"</span>
	  <span class="token string">"Key sequence for Ellama Commands."</span>
	  <span class="token lisp-property property">:type</span> <span class="token quoted-symbol variable symbol">'string</span>
	  <span class="token lisp-property property">:group</span> <span class="token quoted-symbol variable symbol">'ellama</span><span class="token punctuation">)</span>

  <span class="token punctuation">(</span><span class="token defvar"><span class="token keyword">defcustom</span> <span class="token variable">ellama-enable-keymap</span></span> <span class="token boolean">t</span>
	  <span class="token string">"Enable or disable Ellama keymap."</span>
	  <span class="token lisp-property property">:type</span> <span class="token quoted-symbol variable symbol">'boolean</span>
	  <span class="token lisp-property property">:group</span> <span class="token quoted-symbol variable symbol">'ellama</span>
	  <span class="token lisp-property property">:set</span> <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"><span class="token argument variable">symbol</span> <span class="token argument variable">value</span></span><span class="token punctuation">)</span></span>
           <span class="token punctuation">(</span><span class="token car">set</span> symbol value<span class="token punctuation">)</span>
           <span class="token punctuation">(</span><span class="token keyword">if</span> value
             <span class="token punctuation">(</span><span class="token car">ellama-setup-keymap</span><span class="token punctuation">)</span>
			       <span class="token comment">;; If ellama-enable-keymap is nil, remove the key bindings</span>
			       <span class="token punctuation">(</span><span class="token car">define-key</span> global-map <span class="token punctuation">(</span><span class="token car">kbd</span> ellama-keymap-prefix<span class="token punctuation">)</span> <span class="token boolean">nil</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">)</span>
</code></pre></div>
<p>I proposed these enhancements in a
<a href="https://github.com/s-kostyaev/ellama/pull/7">PR</a>. As you read this
post, it might have been accepted and integrated into the core
package, or perhaps it wasn't accepted, partially accepted, or it's
already old news. Nevertheless, you have access to these functions for
customizing as you see fit.</p>
<h2>Dealing with hanging requests</h2>
<p>If you, like me, sometimes find yourself running commands only to
later realize that your AI is overthinking or stuck, it's valuable to
know how to "cancel" a request.</p>
<p>While there wasn't an apparent cancel feature for AI requests, Emacs
offers a way to promptly terminate its internal processes.</p>
<p>So, in case your request is taking too long or you suspect an error,
and you wish to cancel it, you can follow these steps:</p>
<p><strong>1.</strong> Execute <code>M-x list-processes</code> to display a list of all processes
currently running in Emacs.</p>
<p><strong>2.</strong> Locate the line corresponding to the process you want to terminate.</p>
<p><strong>3.</strong> Press <code>d</code> to kill that specific process.</p>
<p>This quick and effective method allows you to regain control and
manage your processes efficiently within Emacs.</p>
<h2>Conclusion</h2>
<p>In conclusion, we've explored the exciting world of integrating Ollama with
Emacs, enhancing our workflow and productivity. While the core package offers
impressive functionality, we've taken customization a step further, introducing
global keybindings and visual-line mode for ellama buffers.</p>
<p>These features not only simplify your interactions but also put you in the
driver's seat when it comes to fine-tuning your Emacs-Ollama
integration. Whether you're reading this with these enhancements already
integrated, in anticipation of their acceptance, or as a source of inspiration
for your own customizations, the tools are here for you to wield.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/ellama</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/ellama</guid>
            <pubDate>Sun, 29 Oct 2023 00:02:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Catppuccin Themes with Auto-Dark in Emacs]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Discover the Beauty of Catppuccin Themes in Emacs, Coupled with
Auto-Dark, Crafting a Perfectly Tailored and Eye-Pleasing Coding
Experience. We hope you found this guide enjoyable and useful. If you
have any questions or need help, please don't hesitate to reach out by
opening an issue on the Auto-Dark-Emacs repository.</p>
<h2>What is auto-dark ?</h2>
<p>In today's digital world, the interface of your preferred text editor
plays a crucial role in your productivity. As developers and writers,
we often spend long hours staring at our screens, and it's essential
that our tools are easy on the eyes. One vital aspect of this is
choosing the right color scheme, or theme, for your text
editor. However, we all know that our surroundings change throughout
the day, and we want our tools to adapt to those changes as well. This
is where Auto-Dark for Emacs comes into play.</p>
<p>Auto-Dark is a nifty Emacs package available via MELPA that ensures
your Emacs environment changes its theme based on your operating
system's dark-mode settings. Whether you're using macOS, Linux, or
Windows, this tool seamlessly integrates with your system's
preferences.</p>
<h3>How Does Auto-Dark Work?</h3>
<p><img src="https://raw.githubusercontent.com/LionyxML/auto-dark-emacs/master/images/demo_gnome.gif" alt="auto-dark-demo"></p>
<p>Auto-Dark simplifies the process of switching between two user-defined
themes that automatically change when your system's dark mode is
toggled on or off. It currently supports Linux through Gnome and
Termux for Android users, with more platforms potentially being added
in the future. The default themes are 'wombat' and 'leuven,' as these
are bundled with Emacs.</p>
<p>Installing Auto-Dark is straightforward. You can easily grab it from
MELPA and add the following lines to your <code>.emacs</code> or
<code>~/.emacs.d/init.el</code> file:</p>
<div class="remark-highlight"><pre class="language-lisp"><code class="language-lisp"><span class="token punctuation">(</span><span class="token keyword">require</span> <span class="token quoted-symbol variable symbol">'auto-dark</span><span class="token punctuation">)</span>
<span class="token punctuation">(</span><span class="token car">auto-dark-mode</span> <span class="token boolean">t</span><span class="token punctuation">)</span>
</code></pre></div>
<p>For more detailed guides, tips, and tricks on setting up Auto-Dark
with <code>Spacemacs</code> and <code>DoomEmacs</code>, you can explore the official Auto-Dark
Emacs repository on GitHub. Here, you'll find comprehensive
documentation and resources to help you get the most out of this handy
package. The repository can be found at <a href="https://github.com/LionyxML/auto-dark-emacs">Auto-Dark on
GitHub</a>.</p>
<p>The light/dark themes can be customized using the Emacs customization
system: <code>M-x customize-group auto-dark</code>.</p>
<p>Or set directly with:</p>
<div class="remark-highlight"><pre class="language-lisp"><code class="language-lisp"><span class="token punctuation">(</span><span class="token keyword">setq</span> auto-dark-themes <span class="token punctuation">'(</span><span class="token punctuation">(</span><span class="token car">doom-one</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">doom-one-light</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<h2>Why Catppuccin?</h2>
<p>In the colorful world of code theming, Catppuccin stands as a
testament to the perfect balance between visual aesthetics and
functionality. This community-driven pastel theme is meticulously
crafted to be the sweet spot between low and high contrast
themes. With four soothing "flavors," each offering a palette of 26
eye-catching colors, Catppuccin isn't just for coding—it's a
delightful experience that enhances your designing and much more.</p>
<p>Within the Catppuccin package, you'll discover four distinct
"flavors": Latte, Frappe, Macchiato, and Mocha. Each variant presents
a unique shade, allowing you to choose your preferred level of
contrast, whether you're inclined towards a darker or lighter theme.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fauto-dark-cat-colors.png&w=3840&q=75" alt="catppuccin"></p>
<p>Catppuccin isn't just a theme; it's become a substantial project in
its own right. You can explore the expansive world of Catppuccin on
<a href="https://github.com/catppuccin">Catppuccin Repo</a>, where it has left its mark on various
platforms. You might have already encountered Catppuccin on your
terminal emulator, in your tmux configuration, on your Chrome browser,
within your Discord server, and across several code editors. And, of
course, it's made its way into the heart of one of the most beloved
text editors—Emacs.</p>
<h3>Catppuccin and Emacs: A Perfect Blend</h3>
<p>The Emacs variation of Catppuccin has found a special place in the
hearts of many, including myself. I've had the privilege of
contributing to this project by theming bits of various packages,
such as: Ivy, Popup, Swiper, Counsel, LSP-Mode, Indent-Guide, and
Treemacs. It's a testament to the open-source spirit, where
collaboration and creativity come together to create something truly
exceptional.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fauto-dark-catppuccin.webp&w=3840&q=75" alt="emacs-catppuccin"></p>
<p>Before we wrap up, I'd like to give a shout-out to the fantastic
contributors who have made Catppuccin what it is today. Special thanks
to <a href="https://github.com/NamesCode">@Name</a> and
<a href="https://github.com/nyxkrage">@Nyx</a> for your patience, guidance, and
the joy of collaboration. 😄</p>
<h2>Bringing Catppuccin and Auto-Dark Together</h2>
<p>Catppuccin, with its unique theme and variations, uses variable
settings for its flavors. However, these settings don't align
perfectly with Auto-Dark, which expects separate dark and light
themes. To make them work harmoniously, we can leverage the
flexibility of Auto-Dark's hook system.</p>
<p>Here's a snippet to configure the integration:</p>
<div class="remark-highlight"><pre class="language-lisp"><code class="language-lisp"><span class="token punctuation">(</span><span class="token keyword">use-package</span> auto-dark
  <span class="token lisp-property property">:ensure</span> <span class="token boolean">t</span>
  <span class="token lisp-property property">:config</span>
  <span class="token punctuation">(</span><span class="token car">ignore-errors</span>
    <span class="token punctuation">(</span><span class="token keyword">setq</span> auto-dark-themes <span class="token punctuation">'(</span><span class="token punctuation">(</span><span class="token car">catppuccin</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token car">catppuccin</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token punctuation">(</span><span class="token car">add-hook</span> <span class="token quoted-symbol variable symbol">'auto-dark-dark-mode-hook</span>
              <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
                <span class="token punctuation">(</span><span class="token keyword">setq</span> catppuccin-flavor <span class="token quoted-symbol variable symbol">'mocha</span><span class="token punctuation">)</span>
                <span class="token punctuation">(</span><span class="token car">catppuccin-reload</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token punctuation">(</span><span class="token car">add-hook</span> <span class="token quoted-symbol variable symbol">'auto-dark-light-mode-hook</span>
              <span class="token punctuation">(</span><span class="token lambda"><span class="token keyword">lambda</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
                <span class="token punctuation">(</span><span class="token keyword">setq</span> catppuccin-flavor <span class="token quoted-symbol variable symbol">'frappe</span><span class="token punctuation">)</span>
                <span class="token punctuation">(</span><span class="token car">catppuccin-reload</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token punctuation">(</span><span class="token car">auto-dark-mode</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>With this setup, Catppuccin seamlessly adapts to your system's dark
and light modes, ensuring a smooth and visually pleasing coding
experience.</p>
<p>Explore this dynamic duo, make your Emacs environment uniquely yours,
and I hope you found this guide enjoyable and useful. Happy theming!</p>
<p>If you have any questions or doubts, please feel free to open an issue
on the <a href="https://github.com/LionyxML/auto-dark-emacs">Auto-Dark
Repository</a>. Your
feedback and inquiries are always welcome!</p>
]]></description>
            <link>https://rahuljuliato.com/posts/auto-dark-catppuccin</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/auto-dark-catppuccin</guid>
            <pubDate>Sat, 14 Oct 2023 00:02:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Launching Emacs: A Simplified Approach]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>As you might recall from my previous post, where I delved into the
intricacies of launching Emacs "like a pro," I must confess that my
muscle memory sometimes leads me down peculiar paths when I'm not in
full "code development" mode, but rather tinkering with and
configuring my operating system.</p>
<p>You see, both <code>vim</code> and <code>emacs</code> have become ingrained in my muscle memory
over the years. However, there are moments when I don't want to open
up a quick configuration file like <code>.bashrc</code> or <code>.tmux.conf</code> and clutter
my buffer list. Sometimes, all I need is a simple <code>open -> edit -> close</code> workflow without the worry of every single package being
loaded, and more importantly, without the wait associated with it.</p>
<p>With this in mind, I stumbled upon a nifty alias for streamlining the
process while catering to muscle memory. I added the following line to
my <code>.bashrc</code>:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">alias</span> <span class="token assign-left variable">emacs</span><span class="token operator">=</span><span class="token string">"emacs -Q -nw --eval <span title="\&#x22;" class="token entity">\"</span>(load-theme 'wombat t)<span title="\&#x22;" class="token entity">\"</span>"</span>
</code></pre></div>
<p>That's all there is to it. This alias launches Emacs with no
additional configurations, enforces a terminal interface, and loads a
sleek, default dark theme—perfect for those moments I just described.</p>
<p>To further integrate this streamlined Emacs setup into your workflow,
you can also consider setting the <code>$EDITOR</code> environment variable in your
.bashrc to point to this customized Emacs alias. This way, you'll
seamlessly use Emacs as your editor of choice across various
command-line tools and utilities.</p>
<p>In your <code>.bashrc</code>, you can add:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">export</span> <span class="token assign-left variable">EDITOR</span><span class="token operator">=</span><span class="token string">"emacs -Q -nw --eval <span title="\&#x22;" class="token entity">\"</span>(load-theme 'wombat t)<span title="\&#x22;" class="token entity">\"</span>"</span>
</code></pre></div>
<p>This ensures that whenever you invoke <code>$EDITOR</code>, you'll launch Emacs
with the specified configuration, providing a consistent and efficient
editing experience.</p>
<p>With this approach, you can harness the power of Emacs for quick edits
and configurations without the overhead of loading extensive
configurations. It's a versatile addition to your toolkit, ensuring
you're always equipped for both focused coding sessions and casual
system tweaking. Happy editing!</p>
]]></description>
            <link>https://rahuljuliato.com/posts/basic-emacs-alias</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/basic-emacs-alias</guid>
            <pubDate>Wed, 04 Oct 2023 00:02:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Quick Tip: Launching Emacs from the Terminal Like a Pro]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Speed up your Emacs experience and enjoy quicker startup times with these clever tricks and optimizations.</p>
<h2>Launching Emacs</h2>
<p>As you can see in the image above, I have configured my Emacs to be
fully featured, capable of handling a wide range of tasks.</p>
<p>I use it as an integrated development environment (IDE), a music
player, a note-taking app, a frontend for several daemon services, and
more.</p>
<p>However, this versatility comes at a cost—Emacs takes a
significant amount of time to start up due to my preference for
installing packages manually rather than using use-package (the
reasons for this choice could fill another post).</p>
<p>In this context, the "right way" to use Emacs is to take advantage of
its server/client architecture. Essentially, you can run Emacs as a
server and open multiple command-line (CLI) or graphical user
interface (GUI) clients, all of which share the same server instance.</p>
<p>To achieve this, I like to set up a few aliases in my .bashrc file:</p>
<div class="remark-highlight"><pre class="language-sh"><code class="language-sh"><span class="token builtin class-name">alias</span> <span class="token assign-left variable">emd</span><span class="token operator">=</span><span class="token string">'emacs --daemon'</span>
<span class="token builtin class-name">alias</span> <span class="token assign-left variable">em</span><span class="token operator">=</span><span class="token string">'emacsclient -t'</span>
<span class="token builtin class-name">alias</span> <span class="token assign-left variable">emg</span><span class="token operator">=</span><span class="token string">'emacsclient -c'</span>
</code></pre></div>
<p>Using these aliases, running <code>emd</code> starts the Emacs server. You only
need to do this once when you start your terminal or set it to run as
a server/daemon on system startup.</p>
<p>The initial startup time is the only downside, but this delay occurs
only once. Afterward, using <code>em</code> opens the full-featured Emacs
instantly. You can even use it to open a specific file like this: <code>em my_file.txt</code>.</p>
<p>Similarly, we have <code>emg</code>, which does the same as <code>em</code> but opens a client
in graphical mode.</p>
<p>Any instance opened with <code>em</code> or <code>emg</code> will share the same Emacs server,
allowing you to take advantage of data sharing between different
"sessions."</p>
<p>In conclusion, by harnessing the power of Emacs' server/client
architecture and a few nifty aliases, you can transform your Emacs
experience into a seamlessly versatile tool for your daily tasks. So,
why wait? Dive into the world of efficient, lightning-fast Emacs
sessions, and let your creativity and productivity soar. Happy
hacking!</p>
]]></description>
            <link>https://rahuljuliato.com/posts/launching-emacs-terminal</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/launching-emacs-terminal</guid>
            <pubDate>Wed, 04 Oct 2023 00:00:00 GMT</pubDate>
        </item>
    </channel>
</rss>