<?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 | RSS Feed]]></title>
        <description><![CDATA[Welcome to Rahul's Blog 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 | RSS Feed</title>
            <link>https://rahuljuliato.com</link>
        </image>
        <generator>RSS for Node</generator>
        <lastBuildDate>Mon, 09 Mar 2026 01:20:47 GMT</lastBuildDate>
        <atom:link href="https://rahuljuliato.com/rss.xml" rel="self" type="application/rss+xml"/>
        <pubDate>Mon, 09 Mar 2026 01:20:28 GMT</pubDate>
        <copyright><![CDATA[All rights reserved 2026]]></copyright>
        <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[gitlineage.nvim: git history for selected lines in Neovim]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>There's a feature in Emacs that I've always loved: <code>vc-git-region-history</code>. You
select a range of lines, call the command, and Emacs shows you how those exact
lines evolved through git commits.</p>
<p>When I'm working in Neovim, I genuinely miss this. There are great git plugins
out there, sure, but none of them gave me exactly this: select lines, see their
history, navigate commits. And that's it. No extras. No <em>repeated features</em> I
already have provided by other plugins and sometimes even fight between them.</p>
<hr>
<h2>The mini.nvim philosophy</h2>
<p>Before I talk about what I built, I want to mention something that
deeply influenced the approach:
<a href="https://github.com/echasnovski/mini.nvim">mini.nvim</a>.</p>
<p>If you haven't seen it, <code>mini.nvim</code> is a collection of small,
independent Neovim modules. Each one does <em>one thing</em>, and does it
well. You don't have to install the whole collection, you can pick
exactly the functionality you need.</p>
<p>This resonates with me. I don't want to install a massive git suite
just to get one feature. I don't want a plugin that tries to be
everything for everyone. I want a small, focused tool that does its
job and gets out of the way.</p>
<p>That's the spirit behind what I made.</p>
<hr>
<h2>gitlineage.nvim</h2>
<p><a href="https://github.com/LionyxML/gitlineage.nvim">gitlineage.nvim</a>: a small Neovim
plugin that lets you view git history for selected lines.</p>
<p><img src="https://raw.githubusercontent.com/LionyxML/gitlineage.nvim/refs/heads/media/logo.png" alt="logo"></p>
<p>What follows is largely based on the project's <code>README.md</code>. Since things may
change over time, check the repository for the latest information.</p>
<hr>
<h2>How it Works</h2>
<ol>
<li>
<p>Select a range of lines in visual mode.</p>
<p><img src="https://raw.githubusercontent.com/LionyxML/gitlineage.nvim/refs/heads/media/demo_1.png" alt="demo_1"></p>
</li>
<li>
<p>Press <code>&#x3C;leader>gl</code> (all bindings are customizable). A new split
window opens with the git history of the selected lines.</p>
<p><img src="https://raw.githubusercontent.com/LionyxML/gitlineage.nvim/refs/heads/media/demo_2.png" alt="demo_2"></p>
</li>
<li>
<p>Advance through commits with <code>]c</code>.</p>
<p><img src="https://raw.githubusercontent.com/LionyxML/gitlineage.nvim/refs/heads/media/demo_3.png" alt="demo_3"></p>
</li>
<li>
<p>Quickly yank the commit SHA with <code>yc</code>.</p>
<p><img src="https://raw.githubusercontent.com/LionyxML/gitlineage.nvim/refs/heads/media/demo_4.png" alt="demo_4"></p>
</li>
<li>
<p>Go back to previous commits with <code>[c</code>.</p>
<p><img src="https://raw.githubusercontent.com/LionyxML/gitlineage.nvim/refs/heads/media/demo_5.png" alt="demo_5"></p>
</li>
<li>
<p>If <code>diffview.nvim</code> is installed, open the full commit diff by
hitting <code>&#x3C;CR></code> on a commit line.</p>
<p><img src="https://raw.githubusercontent.com/LionyxML/gitlineage.nvim/refs/heads/media/demo_6.png" alt="demo_6"></p>
</li>
</ol>
<hr>
<h2>Requirements</h2>
<p>Before install it, check the requirements:</p>
<p><strong>Required:</strong></p>
<ul>
<li>Neovim >= 0.7.0</li>
<li>Git</li>
</ul>
<p><strong>Optional:</strong></p>
<ul>
<li><a href="https://github.com/sindrets/diffview.nvim">diffview.nvim</a> - for viewing full commit diffs</li>
</ul>
<hr>
<h2>Installation</h2>
<p>You can clone the repository and load everything manually, but it is highly
recommended to use a plugin manager.</p>
<h3>lazy.nvim</h3>
<div class="remark-highlight"><pre class="language-lua"><code class="language-lua"><span class="token punctuation">{</span>
    <span class="token string">"lionyxml/gitlineage.nvim"</span><span class="token punctuation">,</span>
    dependencies <span class="token operator">=</span> <span class="token punctuation">{</span>
        <span class="token string">"sindrets/diffview.nvim"</span><span class="token punctuation">,</span> <span class="token comment">-- optional, for open_diff feature</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    config <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"gitlineage"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">end</span>
<span class="token punctuation">}</span>
</code></pre></div>
<h3>mini.deps</h3>
<p>Using mini.deps:</p>
<div class="remark-highlight"><pre class="language-lua"><code class="language-lua"><span class="token keyword">local</span> add <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"mini.deps"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>add

<span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"sindrets/diffview.nvim"</span><span class="token punctuation">)</span> <span class="token comment">-- optional, for open_diff feature</span>
<span class="token function">add</span><span class="token punctuation">(</span><span class="token string">"lionyxml/gitlineage.nvim"</span><span class="token punctuation">)</span>

<span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"gitlineage"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div>
<h3>vim.pack.add() (Neovim >= 0.12)</h3>
<p>Using native vim.pack.add():</p>
<div class="remark-highlight"><pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>pack<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token string">"https://github.com/sindrets/diffview.nvim"</span><span class="token punctuation">,</span> <span class="token comment">-- optional, for open_diff feature</span>
    <span class="token string">"https://github.com/lionyxml/gitlineage.nvim"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"gitlineage"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div>
<h3>vim-plug</h3>
<div class="remark-highlight"><pre class="language-vim"><code class="language-vim"><span class="token keyword">call</span> plug#<span class="token function">begin</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

Plug <span class="token string">'lionyxml/gitlineage.nvim'</span>
Plug <span class="token string">'sindrets/diffview.nvim'</span> <span class="token comment">" optional, for open_diff feature</span>

<span class="token keyword">call</span> plug#<span class="token function">end</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

lua <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"gitlineage"</span><span class="token punctuation">)</span><span class="token operator">.</span><span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</code></pre></div>
<hr>
<h2>Configuration</h2>
<div class="remark-highlight"><pre class="language-lua"><code class="language-lua"><span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"gitlineage"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    split <span class="token operator">=</span> <span class="token string">"auto"</span><span class="token punctuation">,</span>       <span class="token comment">-- "vertical", "horizontal", or "auto"</span>
    keymap <span class="token operator">=</span> <span class="token string">"&#x3C;leader>gl"</span><span class="token punctuation">,</span> <span class="token comment">-- set to nil to disable default keymap</span>
    keys <span class="token operator">=</span> <span class="token punctuation">{</span>
        close <span class="token operator">=</span> <span class="token string">"q"</span><span class="token punctuation">,</span>       <span class="token comment">-- set to nil to disable</span>
        next_commit <span class="token operator">=</span> <span class="token string">"]c"</span><span class="token punctuation">,</span> <span class="token comment">-- set to nil to disable</span>
        prev_commit <span class="token operator">=</span> <span class="token string">"[c"</span><span class="token punctuation">,</span> <span class="token comment">-- set to nil to disable</span>
        yank_commit <span class="token operator">=</span> <span class="token string">"yc"</span><span class="token punctuation">,</span> <span class="token comment">-- set to nil to disable</span>
        open_diff <span class="token operator">=</span> <span class="token string">"&#x3C;CR>"</span><span class="token punctuation">,</span> <span class="token comment">-- set to nil to disable (requires diffview.nvim)</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div>
<div class="remark-highlight"><pre class="language-markdown"><code class="language-markdown"><span class="token table"><span class="token table-header-row"><span class="token punctuation">|</span><span class="token table-header important"> Option             </span><span class="token punctuation">|</span><span class="token table-header important"> Default      </span><span class="token punctuation">|</span><span class="token table-header important"> Description                                                                                  </span><span class="token punctuation">|</span>
</span><span class="token table-line"><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><span class="token table-data-rows"><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`split`</span>            </span><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`auto`</span>       </span><span class="token punctuation">|</span><span class="token table-data"> How to open the history buffer. <span class="token code-snippet code keyword">`auto`</span> picks vertical for wide windows, horizontal for tall. </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`keymap`</span>           </span><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`&#x3C;leader>gl`</span> </span><span class="token punctuation">|</span><span class="token table-data"> Visual mode keymap. Set to <span class="token code-snippet code keyword">`nil`</span> to define your own.                                         </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`keys.close`</span>       </span><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`q`</span>          </span><span class="token punctuation">|</span><span class="token table-data"> Close the history buffer.                                                                    </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`keys.next_commit`</span> </span><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`]c`</span>         </span><span class="token punctuation">|</span><span class="token table-data"> Jump to next commit.                                                                         </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`keys.prev_commit`</span> </span><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`[c`</span>         </span><span class="token punctuation">|</span><span class="token table-data"> Jump to previous commit.                                                                     </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`keys.yank_commit`</span> </span><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`yc`</span>         </span><span class="token punctuation">|</span><span class="token table-data"> Yank commit SHA when on a commit line.                                                       </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`keys.open_diff`</span>   </span><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`&#x3C;CR>`</span>       </span><span class="token punctuation">|</span><span class="token table-data"> Open full commit diff (requires diffview.nvim).                                              </span><span class="token punctuation">|</span></span></span>
</code></pre></div>
<h3>Custom keymaps</h3>
<div class="remark-highlight"><pre class="language-lua"><code class="language-lua"><span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"gitlineage"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    keymap <span class="token operator">=</span> <span class="token string">"&#x3C;leader>gh"</span><span class="token punctuation">,</span>
    keys <span class="token operator">=</span> <span class="token punctuation">{</span>
        close <span class="token operator">=</span> <span class="token string">"&#x3C;Esc>"</span><span class="token punctuation">,</span>
        next_commit <span class="token operator">=</span> <span class="token string">"&#x3C;C-n>"</span><span class="token punctuation">,</span>
        prev_commit <span class="token operator">=</span> <span class="token string">"&#x3C;C-p>"</span><span class="token punctuation">,</span>
        yank_commit <span class="token operator">=</span> <span class="token string">"y"</span><span class="token punctuation">,</span>
        open_diff <span class="token operator">=</span> <span class="token string">"d"</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>
<hr>
<h2>Usage</h2>
<ol>
<li>Enter visual mode (<code>v</code>, <code>V</code>, or <code>&#x3C;C-v></code>)</li>
<li>Select the lines you want to inspect</li>
<li>Press <code>&#x3C;leader>gl</code> (or your configured keymap)</li>
<li>A split window opens with the git history</li>
<li>Navigate using buffer keymaps:</li>
</ol>
<div class="remark-highlight"><pre class="language-markdown"><code class="language-markdown"><span class="token table"><span class="token table-header-row"><span class="token punctuation">|</span><span class="token table-header important"> Key    </span><span class="token punctuation">|</span><span class="token table-header important"> Action                                         </span><span class="token punctuation">|</span>
</span><span class="token table-line"><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><span class="token table-data-rows"><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`q`</span>    </span><span class="token punctuation">|</span><span class="token table-data"> Close the history buffer                       </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`]c`</span>   </span><span class="token punctuation">|</span><span class="token table-data"> Jump to next commit                            </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`[c`</span>   </span><span class="token punctuation">|</span><span class="token table-data"> Jump to previous commit                        </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`yc`</span>   </span><span class="token punctuation">|</span><span class="token table-data"> Yank commit SHA (on commit line)               </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`&#x3C;CR>`</span> </span><span class="token punctuation">|</span><span class="token table-data"> Open full commit diff (requires diffview.nvim) </span><span class="token punctuation">|</span></span></span>
</code></pre></div>
<hr>
<h2>Health check</h2>
<p>Verify your setup:</p>
<div class="remark-highlight"><pre class="language-vim"><code class="language-vim"><span class="token punctuation">:</span>checkhealth gitlineage
</code></pre></div>
<p>This checks:</p>
<p>➖ Neovim version</p>
<p>➖ Git availability</p>
<p>➖ Git repository status</p>
<p>➖ diffview.nvim availability (optional)</p>
<p>➖ Plugin configuration</p>
<hr>
<h2>Conclusion</h2>
<p>If you're someone who moves between Emacs and Neovim, or if you've ever wanted
a focused, minimal way to inspect line-level git history without installing a
full git suite, give
<a href="https://github.com/LionyxML/gitlineage.nvim">https://github.com/LionyxML/gitlineage.nvim</a>
a try.</p>
<p>It's small, it does one thing, and it stays out of your way. Just like
a good plugin should.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/nvim-gitlineage</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/nvim-gitlineage</guid>
            <pubDate>Thu, 05 Feb 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[Exploring Service Workers with React: From Offline to Push Notifications]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Hey everyone! Following up on my last post about <a href="https://www.rahuljuliato.com/posts/react-workers">Web Workers with
React</a>, I'm excited to dive
into another powerful browser API: <strong>Service Workers</strong>.</p>
<p>In this guide, we'll explore how Service Workers can make our React
applications more resilient and engaging. We'll start with a basic online-only
app and progressively enhance it with offline capabilities, background data
synchronization, and real push notifications.</p>
<p>The complete source code for each step is available in <a href="https://github.com/LionyxML/service-workers-react-talk">my GitHub
repository</a>.</p>
<h2>Part 1: The Problem - The App That Needs a Connection</h2>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Freact-service-workers-09.png&w=3840&q=75" alt="service-workers-react-demo-09"></p>
<p>Let's start with a standard React application. It's a simple app that fetches a
random joke from an API and displays it.</p>
<div class="remark-highlight"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// service-workers-demos/01-react-no-sw/src/App.jsx</span>
<span class="token keyword">function</span> <span class="token function"><span class="token maybe-class-name">App</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> <span class="token punctuation">[</span>quote<span class="token punctuation">,</span> setQuote<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token string">"Loading..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
    <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"https://official-joke-api.appspot.com/random_joke"</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">r</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> r<span class="token punctuation">.</span><span class="token method function property-access">json</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">j</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token function">setQuote</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>j<span class="token operator">?.</span>setup<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> - </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>j<span class="token operator">?.</span>punchline<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token keyword control-flow">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token function">setQuote</span><span class="token punctuation">(</span><span class="token string">"❌ Error fetching quote."</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 control-flow">return</span> <span class="token punctuation">(</span>
    <span class="token operator">&#x3C;</span><span class="token operator">></span>
      <span class="token operator">&#x3C;</span>h1<span class="token operator">></span><span class="token maybe-class-name">App1</span> <span class="token operator">-</span> <span class="token maybe-class-name">Common</span> <span class="token maybe-class-name">React</span> <span class="token maybe-class-name">App</span><span class="token operator">&#x3C;</span><span class="token operator">/</span>h1<span class="token operator">></span>
      <span class="token operator">&#x3C;</span>div className<span class="token operator">=</span><span class="token string">"card"</span><span class="token operator">></span>
        <span class="token operator">&#x3C;</span>p<span class="token operator">></span><span class="token punctuation">{</span>quote<span class="token punctuation">}</span><span class="token operator">&#x3C;</span><span class="token operator">/</span>p<span class="token operator">></span>
      <span class="token operator">&#x3C;</span><span class="token operator">/</span>div<span class="token operator">></span>
      <span class="token operator">&#x3C;</span>button onClick<span class="token operator">=</span><span class="token punctuation">{</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token property-access">location</span><span class="token punctuation">.</span><span class="token method function property-access">reload</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span><span class="token maybe-class-name">Reload</span> <span class="token maybe-class-name">Page</span><span class="token operator">&#x3C;</span><span class="token operator">/</span>button<span class="token operator">></span>
    <span class="token operator">&#x3C;</span><span class="token operator">/</span><span class="token operator">></span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>A quick note: you might notice we're fetching data directly inside <code>useEffect</code>.
For this guide, I've simplified some patterns to keep the focus squarely on the
Service Worker implementations themselves, avoiding more complex state
management or data-fetching abstractions. Now, back to business.</p>
<p>This fetch works perfectly fine... as long as you're online. If you open your
browser's DevTools, go to the "Network" tab, and simulate being offline, the
app breaks completely upon reload. This is because it can't fetch its own
assets or the joke from the API.</p>
<p>Hello dinosaur friend:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Freact-service-workers-10.png&w=3840&q=75" alt="service-workers-react-demo-10"></p>
<h2>Part 2: The Solution - A Manual Service Worker</h2>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Freact-service-workers-01.png&w=3840&q=75" alt="service-workers-react-demo-01"></p>
<p>To solve the offline problem, we introduce a Service Worker. It acts as a proxy
between our application and the network, allowing us to cache resources and
serve them even when there's no internet connection.</p>
<p>First, we need to register the Service Worker. We do this in our application's
entry point.</p>
<div class="remark-highlight"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// service-workers-demos/02-react-sw-manual/src/sw-register.js</span>
<span class="token keyword module">export</span> <span class="token keyword">function</span> <span class="token function">registerSW</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token string">"serviceWorker"</span> <span class="token keyword">in</span> <span class="token dom variable">navigator</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token dom variable">window</span><span class="token punctuation">.</span><span class="token method function property-access">addEventListener</span><span class="token punctuation">(</span><span class="token string">"load"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
      <span class="token dom variable">navigator</span><span class="token punctuation">.</span><span class="token property-access">serviceWorker</span>
        <span class="token punctuation">.</span><span class="token method function property-access">register</span><span class="token punctuation">(</span><span class="token string">"/service-worker.js"</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">reg</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token string">" 🟢 Registered SW:"</span><span class="token punctuation">,</span> reg<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token keyword control-flow">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">error</span><span class="token punctuation">(</span><span class="token string">" 🔴 Error registering SW:"</span><span class="token punctuation">,</span> err<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>Next, we define the Service Worker's behavior. In the <code>install</code> event, we cache
our application's shell, the essential files needed for it to run. In the
<code>activate</code> event, we clean up old caches.</p>
<div class="remark-highlight"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// service-workers-demos/02-react-sw-manual/public/service-worker.js</span>
<span class="token keyword">const</span> <span class="token constant">CACHE_NAME</span> <span class="token operator">=</span> <span class="token string">"app-cache-v1"</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token constant">URLS_TO_PRECACHE</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"/"</span><span class="token punctuation">,</span> <span class="token string">"vite.svg"</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

self<span class="token punctuation">.</span><span class="token method function property-access">addEventListener</span><span class="token punctuation">(</span><span class="token string">"install"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
  <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token string">"🔧 [SW] install"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  event<span class="token punctuation">.</span><span class="token method function property-access">waitUntil</span><span class="token punctuation">(</span>
    caches<span class="token punctuation">.</span><span class="token method function property-access">open</span><span class="token punctuation">(</span><span class="token constant">CACHE_NAME</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">cache</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> cache<span class="token punctuation">.</span><span class="token method function property-access">addAll</span><span class="token punctuation">(</span><span class="token constant">URLS_TO_PRECACHE</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>
  self<span class="token punctuation">.</span><span class="token method function property-access">skipWaiting</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>

self<span class="token punctuation">.</span><span class="token method function property-access">addEventListener</span><span class="token punctuation">(</span><span class="token string">"activate"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
  <span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token method function property-access">log</span><span class="token punctuation">(</span><span class="token string">"🔧 [SW] activate"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  event<span class="token punctuation">.</span><span class="token method function property-access">waitUntil</span><span class="token punctuation">(</span>
    caches
      <span class="token punctuation">.</span><span class="token method function property-access">keys</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">names</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span>
        <span class="token known-class-name class-name">Promise</span><span class="token punctuation">.</span><span class="token method function property-access">all</span><span class="token punctuation">(</span>
          names<span class="token punctuation">.</span><span class="token method function property-access">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">n</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> n <span class="token operator">!==</span> <span class="token constant">CACHE_NAME</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">n</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> caches<span class="token punctuation">.</span><span class="token method function property-access">delete</span><span class="token punctuation">(</span>n<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>
  self<span class="token punctuation">.</span><span class="token property-access">clients</span><span class="token punctuation">.</span><span class="token method function property-access">claim</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>
<h3>❗Important! Be friends with Dev Tools, you'll need them a lot!</h3>
<p>With Dev Tools, you can view the Service Worker's status, inspect the cache,
and perform manual resets or overrides. When working with Service Workers,
you'll often need to manually clear loaded services and caches. Also, when
following the examples in this post, make sure to start with a clean cache and
no registered workers before testing.</p>
<p>Service Worker DevTools here:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Freact-service-workers-02.png&w=3840&q=75" alt="service-workers-react-demo-02"></p>
<p>Cache DevTools here:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Freact-service-workers-03.png&w=3840&q=75" alt="service-workers-react-demo-03"></p>
<h3>Now back to business</h3>
<p>The real magic happens in the <code>fetch</code> event. Here, we intercept every network
request and implement a "cache-first" strategy.</p>
<div class="remark-highlight"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// service-workers-demos/02-react-sw-manual/public/service-worker.js</span>
self<span class="token punctuation">.</span><span class="token method function property-access">addEventListener</span><span class="token punctuation">(</span><span class="token string">"fetch"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> req <span class="token operator">=</span> event<span class="token punctuation">.</span><span class="token property-access">request</span><span class="token punctuation">;</span>
  event<span class="token punctuation">.</span><span class="token method function property-access">respondWith</span><span class="token punctuation">(</span>
    caches<span class="token punctuation">.</span><span class="token method function property-access">match</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">cachedResp</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>cachedResp<span class="token punctuation">)</span> <span class="token keyword control-flow">return</span> cachedResp<span class="token punctuation">;</span> <span class="token comment">// Return from cache if found</span>
      <span class="token keyword control-flow">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span> <span class="token comment">// Otherwise, fetch from network</span>
        <span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">networkResp</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
          <span class="token comment">// If the request is for our own origin, cache the response</span>
          <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>
            req<span class="token punctuation">.</span><span class="token property-access">method</span> <span class="token operator">===</span> <span class="token string">"GET"</span> <span class="token operator">&&</span>
            networkResp <span class="token operator">&&</span>
            networkResp<span class="token punctuation">.</span><span class="token property-access">status</span> <span class="token operator">===</span> <span class="token number">200</span> <span class="token operator">&&</span>
            req<span class="token punctuation">.</span><span class="token property-access">url</span><span class="token punctuation">.</span><span class="token method function property-access">startsWith</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span><span class="token property-access">location</span><span class="token punctuation">.</span><span class="token property-access">origin</span><span class="token punctuation">)</span>
          <span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">const</span> copy <span class="token operator">=</span> networkResp<span class="token punctuation">.</span><span class="token method function property-access">clone</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            caches<span class="token punctuation">.</span><span class="token method function property-access">open</span><span class="token punctuation">(</span><span class="token constant">CACHE_NAME</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">cache</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> cache<span class="token punctuation">.</span><span class="token method function property-access">put</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> copy<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
          <span class="token punctuation">}</span>
          <span class="token keyword control-flow">return</span> networkResp<span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token keyword control-flow">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
          <span class="token comment">// If network fails, provide a fallback</span>
          <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>req<span class="token punctuation">.</span><span class="token property-access">headers</span><span class="token punctuation">.</span><span class="token method function property-access">get</span><span class="token punctuation">(</span><span class="token string">"accept"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">includes</span><span class="token punctuation">(</span><span class="token string">"text/html"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword control-flow">return</span> caches<span class="token punctuation">.</span><span class="token method function property-access">match</span><span class="token punctuation">(</span><span class="token string">"/index.html"</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 punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>With this in place, our app now works offline! The app shell is served from the
cache, and while the external API call might fail, the app itself remains
functional.</p>
<p>Try changing the network status and then refresh the page:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Freact-service-workers-04.png&w=3840&q=75" alt="service-workers-react-demo-04"></p>
<p>This should be our new result!
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Freact-service-workers-05.png&w=3840&q=75" alt="service-workers-react-demo-05"></p>
<p>You might notice how everything is served from the Network tab:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Freact-service-workers-06.png&w=3840&q=75" alt="service-workers-react-demo-06"></p>
<h2>Part 3: Going Further with Background Sync and Push</h2>
<p>Service Workers unlock more than just offline caching.</p>
<h3>Background Sync</h3>
<p>What if a user tries to submit a form while offline? With Background Sync, we
can defer the action until the connection is restored.</p>
<p>In our app, we register a <code>sync</code> event:</p>
<div class="remark-highlight"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// service-workers-demos/02-react-sw-manual/src/App.jsx</span>
<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">scheduleSendData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token string">"serviceWorker"</span> <span class="token keyword">in</span> <span class="token dom variable">navigator</span> <span class="token operator">&&</span> <span class="token string">"SyncManager"</span> <span class="token keyword">in</span> <span class="token dom variable">window</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> reg <span class="token operator">=</span> <span class="token keyword control-flow">await</span> <span class="token dom variable">navigator</span><span class="token punctuation">.</span><span class="token property-access">serviceWorker</span><span class="token punctuation">.</span><span class="token property-access">ready</span><span class="token punctuation">;</span>
    <span class="token keyword control-flow">try</span> <span class="token punctuation">{</span>
      <span class="token keyword control-flow">await</span> reg<span class="token punctuation">.</span><span class="token property-access">sync</span><span class="token punctuation">.</span><span class="token method function property-access">register</span><span class="token punctuation">(</span><span class="token string">"send-form"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Scheduled sending. Will be executed when back online."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword control-flow">catch</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Error scheduling: "</span> <span class="token operator">+</span> err<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>The Service Worker listens for this event and executes the task when the
network is available.</p>
<div class="remark-highlight"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// service-workers-demos/02-react-sw-manual/public/service-worker.js</span>
self<span class="token punctuation">.</span><span class="token method function property-access">addEventListener</span><span class="token punctuation">(</span><span class="token string">"sync"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span><span class="token property-access">tag</span> <span class="token operator">===</span> <span class="token string">"send-form"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    event<span class="token punctuation">.</span><span class="token method function property-access">waitUntil</span><span class="token punctuation">(</span><span class="token function">sendPendingData</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">function</span> <span class="token function">sendPendingData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">return</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"/api/save"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
    <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token known-class-name class-name">JSON</span><span class="token punctuation">.</span><span class="token method function property-access">stringify</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">msg</span><span class="token operator">:</span> <span class="token string">"Example data!!!!"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">"Content-Type"</span><span class="token operator">:</span> <span class="token string">"application/json"</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><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Freact-service-workers-08.png&w=3840&q=75" alt="service-workers-react-demo-08"></p>
<h3>Push Notifications</h3>
<p>Service Workers can also receive push notifications from a server, even when
the app's tab is closed. First, the app must request permission.</p>
<div class="remark-highlight"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// service-workers-demos/02-react-sw-manual/src/App.jsx</span>
<span class="token keyword">function</span> <span class="token function">askPermission</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span><span class="token string">"Notification"</span> <span class="token keyword">in</span> <span class="token dom variable">window</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token maybe-class-name">Notification</span><span class="token punctuation">.</span><span class="token method function property-access">requestPermission</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">perm</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
      <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>perm <span class="token operator">===</span> <span class="token string">"granted"</span><span class="token punctuation">)</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Notifications permission granted!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token keyword control-flow">else</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Notifications permissions denied."</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>Then, the Service Worker handles the <code>push</code> event to display the notification.</p>
<div class="remark-highlight"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// service-workers-demos/02-react-sw-manual/public/service-worker.js</span>
self<span class="token punctuation">.</span><span class="token method function property-access">addEventListener</span><span class="token punctuation">(</span><span class="token string">"push"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">let</span> title <span class="token operator">=</span> <span class="token string">"Default title"</span><span class="token punctuation">;</span>
  <span class="token keyword">let</span> body <span class="token operator">=</span> <span class="token string">"Hello from fake push"</span><span class="token punctuation">;</span>

  <span class="token keyword control-flow">if</span> <span class="token punctuation">(</span>event<span class="token punctuation">.</span><span class="token property-access">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword control-flow">try</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> parsed <span class="token operator">=</span> <span class="token known-class-name class-name">JSON</span><span class="token punctuation">.</span><span class="token method function property-access">parse</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span><span class="token property-access">data</span><span class="token punctuation">.</span><span class="token method function property-access">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
      title <span class="token operator">=</span> parsed<span class="token punctuation">.</span><span class="token property-access">title</span> <span class="token operator">||</span> title<span class="token punctuation">;</span>
      body <span class="token operator">=</span> parsed<span class="token punctuation">.</span><span class="token property-access">body</span> <span class="token operator">||</span> body<span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword control-flow">catch</span> <span class="token punctuation">{</span>
      body <span class="token operator">=</span> event<span class="token punctuation">.</span><span class="token property-access">data</span><span class="token punctuation">.</span><span class="token method function property-access">text</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">const</span> options <span class="token operator">=</span> <span class="token punctuation">{</span> body<span class="token punctuation">,</span> <span class="token literal-property property">icon</span><span class="token operator">:</span> <span class="token string">"/vite.svg"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
  event<span class="token punctuation">.</span><span class="token method function property-access">waitUntil</span><span class="token punctuation">(</span>self<span class="token punctuation">.</span><span class="token property-access">registration</span><span class="token punctuation">.</span><span class="token method function property-access">showNotification</span><span class="token punctuation">(</span>title<span class="token punctuation">,</span> options<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>You can now simulate a push event from the browser's DevTools:
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Freact-service-workers-02.png&w=3840&q=75" alt="service-workers-react-demo-02"></p>
<p>Note that not only you need permission you grant in your browser, but your OS
should also grant permission. This means you might need to mess around giving
your browser permission to send notifications before this step works.</p>
<p>This means the showing behaviour is also controlled by your OS, there's no
guarantee it will work the same across every browser/OS combination, implement
your icons, or even show the full message. This is what I get on macOS in my
machine:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Freact-service-workers-07.png&w=3840&q=75" alt="service-workers-react-demo-07"></p>
<h2>Part 4: Simplifying with Workbox</h2>
<p>Writing a Service Worker from scratch can be verbose and error-prone.
<strong>Workbox</strong>, a library from Google, simplifies this by providing
production-ready strategies for caching and background tasks.</p>
<p>Here's how the <code>fetch</code> logic looks with Workbox:</p>
<div class="remark-highlight"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// service-workers-demos/03-react-sw-workbox/public/sw.js</span>
<span class="token comment">/* global workbox importScripts */</span>
<span class="token function">importScripts</span><span class="token punctuation">(</span>
  <span class="token string">"https://storage.googleapis.com/workbox-cdn/releases/6.5.4/workbox-sw.js"</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// SPA navigation route (NetworkFirst)</span>
workbox<span class="token punctuation">.</span><span class="token property-access">routing</span><span class="token punctuation">.</span><span class="token method function property-access">registerRoute</span><span class="token punctuation">(</span>
  <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> request <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> request<span class="token punctuation">.</span><span class="token property-access">mode</span> <span class="token operator">===</span> <span class="token string">"navigate"</span><span class="token punctuation">,</span>
  <span class="token keyword">new</span> <span class="token class-name">workbox<span class="token punctuation">.</span>strategies<span class="token punctuation">.</span>NetworkFirst</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">cacheName</span><span class="token operator">:</span> <span class="token string">"html-shell"</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">// Jokes API: StaleWhileRevalidate</span>
workbox<span class="token punctuation">.</span><span class="token property-access">routing</span><span class="token punctuation">.</span><span class="token method function property-access">registerRoute</span><span class="token punctuation">(</span>
  <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> url <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> url<span class="token punctuation">.</span><span class="token property-access">origin</span> <span class="token operator">===</span> <span class="token string">"https://official-joke-api.appspot.com"</span><span class="token punctuation">,</span>
  <span class="token keyword">new</span> <span class="token class-name">workbox<span class="token punctuation">.</span>strategies<span class="token punctuation">.</span>StaleWhileRevalidate</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">cacheName</span><span class="token operator">:</span> <span class="token string">"api-jokes-cache"</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">// Static assets: StaleWhileRevalidate</span>
workbox<span class="token punctuation">.</span><span class="token property-access">routing</span><span class="token punctuation">.</span><span class="token method function property-access">registerRoute</span><span class="token punctuation">(</span>
  <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> request <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">[</span><span class="token string">"style"</span><span class="token punctuation">,</span> <span class="token string">"script"</span><span class="token punctuation">,</span> <span class="token string">"worker"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token method function property-access">includes</span><span class="token punctuation">(</span>request<span class="token punctuation">.</span><span class="token property-access">destination</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token keyword">new</span> <span class="token class-name">workbox<span class="token punctuation">.</span>strategies<span class="token punctuation">.</span>StaleWhileRevalidate</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">cacheName</span><span class="token operator">:</span> <span class="token string">"static-resources"</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 comment">// Background Sync with a plugin</span>
<span class="token keyword">const</span> bgSyncPlugin <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">workbox<span class="token punctuation">.</span>backgroundSync<span class="token punctuation">.</span>BackgroundSyncPlugin</span><span class="token punctuation">(</span>
  <span class="token string">"form-queue"</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
workbox<span class="token punctuation">.</span><span class="token property-access">routing</span><span class="token punctuation">.</span><span class="token method function property-access">registerRoute</span><span class="token punctuation">(</span>
  <span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span> url<span class="token punctuation">,</span> request <span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> request<span class="token punctuation">.</span><span class="token property-access">method</span> <span class="token operator">===</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
  <span class="token keyword">new</span> <span class="token class-name">workbox<span class="token punctuation">.</span>strategies<span class="token punctuation">.</span>NetworkOnly</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">plugins</span><span class="token operator">:</span> <span class="token punctuation">[</span>bgSyncPlugin<span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  <span class="token string">"POST"</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>Workbox makes the code much more declarative and less boilerplate, while
providing robust, battle-tested caching strategies.</p>
<h2>Part 5: Real Push Notifications with VAPID</h2>
<p>To send real push notifications, our server needs to identify itself to the
browser's push service. We use the VAPID protocol for this.</p>
<p>The flow is:</p>
<p>➖ The client requests a <code>PushSubscription</code> and sends it to our server.</p>
<p>➖ The server stores this subscription.</p>
<p>➖ The server uses the <code>web-push</code> library to send a message to the push
service, which then delivers it to the correct Service Worker.</p>
<p>Here's the client-side code to subscribe:</p>
<div class="remark-highlight"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// service-workers-demos/04-push-example/client/src/App.jsx</span>
<span class="token keyword">const</span> <span class="token constant">PUBLIC_VAPID_KEY</span> <span class="token operator">=</span> <span class="token string">"same as server"</span><span class="token punctuation">;</span> <span class="token comment">// This should be your public VAPID key</span>

<span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">subscribeUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> reg <span class="token operator">=</span> <span class="token keyword control-flow">await</span> <span class="token dom variable">navigator</span><span class="token punctuation">.</span><span class="token property-access">serviceWorker</span><span class="token punctuation">.</span><span class="token method function property-access">register</span><span class="token punctuation">(</span><span class="token string">"/sw-push.js"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> sub <span class="token operator">=</span> <span class="token keyword control-flow">await</span> reg<span class="token punctuation">.</span><span class="token property-access">pushManager</span><span class="token punctuation">.</span><span class="token method function property-access">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">userVisibleOnly</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token literal-property property">applicationServerKey</span><span class="token operator">:</span> <span class="token function">urlBase64ToUint8Array</span><span class="token punctuation">(</span><span class="token constant">PUBLIC_VAPID_KEY</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">// Send subscription to the server</span>
  <span class="token keyword control-flow">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">"http://localhost:4000/subscribe"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token literal-property property">method</span><span class="token operator">:</span> <span class="token string">"POST"</span><span class="token punctuation">,</span>
    <span class="token literal-property property">body</span><span class="token operator">:</span> <span class="token known-class-name class-name">JSON</span><span class="token punctuation">.</span><span class="token method function property-access">stringify</span><span class="token punctuation">(</span>sub<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token string-property property">"Content-Type"</span><span class="token operator">:</span> <span class="token string">"application/json"</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>And the Node.js server that sends the push:</p>
<div class="remark-highlight"><pre class="language-javascript"><code class="language-javascript"><span class="token comment">// service-workers-demos/04-push-example/server/server.js</span>
<span class="token keyword">const</span> webpush <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"web-push"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// ... configure VAPID keys ...</span>

<span class="token keyword">let</span> subscriptions <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>

app<span class="token punctuation">.</span><span class="token method function property-access">post</span><span class="token punctuation">(</span><span class="token string">"/subscribe"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> sub <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token property-access">body</span><span class="token punctuation">;</span>
  subscriptions<span class="token punctuation">.</span><span class="token method function property-access">push</span><span class="token punctuation">(</span>sub<span class="token punctuation">)</span><span class="token punctuation">;</span>
  res<span class="token punctuation">.</span><span class="token method function property-access">status</span><span class="token punctuation">(</span><span class="token number">201</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token method function property-access">json</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">ok</span><span class="token operator">:</span> <span class="token boolean">true</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 comment">// Send a push to all subscribers</span>
<span class="token keyword">function</span> <span class="token function">sendToAll</span><span class="token punctuation">(</span><span class="token parameter">payload</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  subscriptions<span class="token punctuation">.</span><span class="token method function property-access">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">sub</span><span class="token punctuation">)</span> <span class="token arrow operator">=></span> <span class="token punctuation">{</span>
    webpush<span class="token punctuation">.</span><span class="token method function property-access">sendNotification</span><span class="token punctuation">(</span>sub<span class="token punctuation">,</span> <span class="token known-class-name class-name">JSON</span><span class="token punctuation">.</span><span class="token method function property-access">stringify</span><span class="token punctuation">(</span>payload<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword control-flow">catch</span><span class="token punctuation">(</span><span class="token console class-name">console</span><span class="token punctuation">.</span><span class="token property-access">error</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>This setup provides a complete end-to-end push notification system.</p>
<h2>Conclusion</h2>
<p>Service Workers are a cornerstone of modern web development, enabling
Progressive Web Apps (PWAs) that are reliable, fast, and engaging. We've seen
how they can:</p>
<p>➖ Provide a seamless <strong>offline experience</strong> by caching resources.</p>
<p>➖ Defer actions until the network is available with <strong>Background Sync</strong>.</p>
<p>➖ Re-engage users with <strong>Push Notifications</strong>.</p>
<p>While manual implementation is possible, libraries like <strong>Workbox</strong> are highly
recommended to simplify development and avoid common pitfalls.</p>
<h2>A Quick Comparison: Web, Shared, and Service Workers</h2>
<p>To recap, here's how the different types of workers compare:</p>
<div class="remark-highlight"><pre class="language-markdown"><code class="language-markdown"><span class="token table"><span class="token table-header-row"><span class="token punctuation">|</span><span class="token table-header important"> Feature / Capability            </span><span class="token punctuation">|</span><span class="token table-header important"> Web Worker              </span><span class="token punctuation">|</span><span class="token table-header important"> Shared Worker                    </span><span class="token punctuation">|</span><span class="token table-header important"> Service Worker                               </span><span class="token punctuation">|</span>
</span><span class="token table-line"><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><span class="token table-data-rows"><span class="token punctuation">|</span><span class="token table-data"> Scope                           </span><span class="token punctuation">|</span><span class="token table-data"> Single page/tab         </span><span class="token punctuation">|</span><span class="token table-data"> Shared across tabs (same origin) </span><span class="token punctuation">|</span><span class="token table-data"> Global (site-wide, independent of tabs)      </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> Shared across tabs              </span><span class="token punctuation">|</span><span class="token table-data"> No                      </span><span class="token punctuation">|</span><span class="token table-data"> Yes                              </span><span class="token punctuation">|</span><span class="token table-data"> Yes                                          </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> Communication                   </span><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`postMessage`</span> (1:1)     </span><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`port.postMessage`</span> (many:1)      </span><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`postMessage`</span>, <span class="token code-snippet code keyword">`fetch`</span>, Push API, etc.       </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> Persists after tab closes       </span><span class="token punctuation">|</span><span class="token table-data"> No                      </span><span class="token punctuation">|</span><span class="token table-data"> No                               </span><span class="token punctuation">|</span><span class="token table-data"> Yes (managed by browser)                     </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> Use case                        </span><span class="token punctuation">|</span><span class="token table-data"> Offload CPU-heavy tasks </span><span class="token punctuation">|</span><span class="token table-data"> Coordinate logic across tabs     </span><span class="token punctuation">|</span><span class="token table-data"> Background sync, caching, push notifications </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> DOM access                      </span><span class="token punctuation">|</span><span class="token table-data"> No                      </span><span class="token punctuation">|</span><span class="token table-data"> No                               </span><span class="token punctuation">|</span><span class="token table-data"> No                                           </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> Network interception            </span><span class="token punctuation">|</span><span class="token table-data"> No                      </span><span class="token punctuation">|</span><span class="token table-data"> No                               </span><span class="token punctuation">|</span><span class="token table-data"> Yes (<span class="token code-snippet code keyword">`fetch`</span> interception)                   </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> Requires secure context (HTTPS) </span><span class="token punctuation">|</span><span class="token table-data"> No                      </span><span class="token punctuation">|</span><span class="token table-data"> No                               </span><span class="token punctuation">|</span><span class="token table-data"> Yes (HTTPS required)                         </span><span class="token punctuation">|</span></span></span>
</code></pre></div>
<p>I hope this guide has been a helpful introduction to using Service Workers with
React! Feel free to explore the <a href="https://github.com/LionyxML/service-workers-react-talk">code on
GitHub</a> and experiment
with these powerful features.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/react-service-workers</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/react-service-workers</guid>
            <pubDate>Sun, 21 Sep 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[Building a Custom Tabline in Neovim with Lua]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>When people hear "tabs" in an editor, they usually imagine something
like browser tabs in Chrome, Firefox, or even VSCode. But Neovim's
tabs are quite different, they are <strong>workspaces</strong>, each containing
its own set of windows and splits. Think of them more like tmux's
sessions or Emacs' <code>tab-bar</code>, rather than VSCode's tab-line that just
lists files.</p>
<p>By default, Neovim’s tabline shows placeholders like <code>[No Name]</code> or full
buffer names, but I find this neither attractive nor particularly
useful. I prefer something more minimal, closer to how tmux presents
workspaces: numbered slots with just enough styling to highlight the
active one. This way, I avoid the distraction of long file names and
can stay focused on the workspace itself.</p>
<p>In the screenshot below, at the top left, you can see three tabs: the
first has three splits (indicated by the blue “3” along with the
filename of the selected split), the second is empty, and the third
contains another open file.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fneovim-tabline-demo-01.png&w=3840&q=75" alt="neovim-custom-tabline-demo-01"></p>
<p>In this post, I’ll walk you through how I built a <code>pill-style tabline</code>
in Lua, explain some of the design decisions, and show how it fits
neatly into my tmux workflow.</p>
<p>Here’s a preview of the final result: three tabs, numbered, formatted,
and highlighted for clarity.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fneovim-tabline-demo-02.png&w=3840&q=75" alt="neovim-custom-tabline-demo-02"></p>
<hr>
<h2>Part 1: Why Customize the Tabline?</h2>
<p>Here's the situation:</p>
<p>➖ <strong>Default Neovim tabs</strong> → Show file names and placeholders, often cluttering the screen.</p>
<p>➖ <strong>tmux tabs/panes</strong> → Show numbered workspaces, clean and efficient.</p>
<p>➖ <strong>Emacs</strong> → Has two modes: <code>tab-bar</code> (like Neovim's tabs) and <code>tab-line</code> (like VSCode's file tabs).</p>
<p>I wanted my Neovim tabline to look and feel closer to tmux and Emacs'
tab-bar. Just numbered "workspaces," styled as pills for clarity.</p>
<p>Here's a preview:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fneovim-tabline-demo-03.png&w=3840&q=75" alt="neovim-custom-tabline-demo-03"></p>
<hr>
<h2>Part 2: Keymaps for Managing Tabs</h2>
<p>First, I set up a few keymaps to create, toggle, and navigate tabs:</p>
<div class="remark-highlight"><pre class="language-lua"><code class="language-lua"><span class="token comment">-- Create a new tab</span>
vim<span class="token punctuation">.</span>keymap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"n"</span><span class="token punctuation">,</span> <span class="token string">"&#x3C;leader>tn"</span><span class="token punctuation">,</span> <span class="token string">":tabnew&#x3C;CR>"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> desc <span class="token operator">=</span> <span class="token string">"New [t]ab"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token comment">-- Exclude current tab</span>
vim<span class="token punctuation">.</span>keymap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"n"</span><span class="token punctuation">,</span> <span class="token string">"&#x3C;leader>tx"</span><span class="token punctuation">,</span> <span class="token string">":tabclose&#x3C;CR>"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> desc <span class="token operator">=</span> <span class="token string">"E[x]clude tab"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token comment">-- Toggle showing the tabline</span>
vim<span class="token punctuation">.</span>keymap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"n"</span><span class="token punctuation">,</span> <span class="token string">"&#x3C;leader>tt"</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token keyword">if</span> vim<span class="token punctuation">.</span>o<span class="token punctuation">.</span>showtabline <span class="token operator">==</span> <span class="token number">2</span> <span class="token keyword">then</span>
	vim<span class="token punctuation">.</span>o<span class="token punctuation">.</span>showtabline <span class="token operator">=</span> <span class="token number">0</span>
  <span class="token keyword">else</span>
	vim<span class="token punctuation">.</span>o<span class="token punctuation">.</span>showtabline <span class="token operator">=</span> <span class="token number">2</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> desc <span class="token operator">=</span> <span class="token string">"Toggle [t]abs"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token comment">-- Navigate tabs</span>
vim<span class="token punctuation">.</span>keymap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"n"</span><span class="token punctuation">,</span> <span class="token string">"]t"</span><span class="token punctuation">,</span> <span class="token string">":tabnext&#x3C;CR>"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> desc <span class="token operator">=</span> <span class="token string">"Next tab"</span><span class="token punctuation">,</span> silent <span class="token operator">=</span> <span class="token keyword">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>keymap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"n"</span><span class="token punctuation">,</span> <span class="token string">"[t"</span><span class="token punctuation">,</span> <span class="token string">":tabprevious&#x3C;CR>"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> desc <span class="token operator">=</span> <span class="token string">"Previous tab"</span><span class="token punctuation">,</span> silent <span class="token operator">=</span> <span class="token keyword">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div>
<p>This gives me a lightweight tmux-like navigation inside Neovim.</p>
<hr>
<h2>Part 3: Styling with Highlight Groups</h2>
<p>I use custom Catppuccin highlight groups to create the "pill" effect
(to match my Neovim, terminal, and tmux Catppuccin theme):</p>
<div class="remark-highlight"><pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLine"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> bg <span class="token operator">=</span> <span class="token string">"NONE"</span><span class="token punctuation">,</span> fg <span class="token operator">=</span> <span class="token string">"#666666"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLineFill"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> bg <span class="token operator">=</span> <span class="token string">"NONE"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>

vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLinePillActiveLeft"</span><span class="token punctuation">,</span>   <span class="token punctuation">{</span> fg <span class="token operator">=</span> <span class="token string">"#8aadf4"</span><span class="token punctuation">,</span> bg <span class="token operator">=</span> <span class="token string">"#1e1e2e"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLinePillActiveText"</span><span class="token punctuation">,</span>   <span class="token punctuation">{</span> fg <span class="token operator">=</span> <span class="token string">"#1e1e2e"</span><span class="token punctuation">,</span> bg <span class="token operator">=</span> <span class="token string">"#8aadf4"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLinePillActiveRight"</span><span class="token punctuation">,</span>  <span class="token punctuation">{</span> fg <span class="token operator">=</span> <span class="token string">"#8aadf4"</span><span class="token punctuation">,</span> bg <span class="token operator">=</span> <span class="token string">"#1e1e2e"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>

vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLinePillInactiveLeft"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> fg <span class="token operator">=</span> <span class="token string">"#737994"</span><span class="token punctuation">,</span> bg <span class="token operator">=</span> <span class="token string">"#1e1e2e"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLinePillInactiveText"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> fg <span class="token operator">=</span> <span class="token string">"#1e1e2e"</span><span class="token punctuation">,</span> bg <span class="token operator">=</span> <span class="token string">"#737994"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLinePillInactiveRight"</span><span class="token punctuation">,</span><span class="token punctuation">{</span> fg <span class="token operator">=</span> <span class="token string">"#737994"</span><span class="token punctuation">,</span> bg <span class="token operator">=</span> <span class="token string">"#1e1e2e"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Each tab is enclosed by decorative glyphs (<code></code> on the left and <code></code> on
the right). Inside, it shows a number, with styling that changes
depending on whether the tab is active or inactive.</p>
<p><strong>Note:</strong> your terminal font must support these glyphs. The screenshots
use <strong>JetBrains Mono Nerd Font</strong>.</p>
<hr>
<h2>Part 4: The Lua Function for the Tabline</h2>
<p>Finally, I define the tabline function:</p>
<div class="remark-highlight"><pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>o<span class="token punctuation">.</span>tabline <span class="token operator">=</span> <span class="token string">"%!v:lua.PillTabline()"</span>

<span class="token keyword">function</span> _G<span class="token punctuation">.</span><span class="token function">PillTabline</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token keyword">local</span> s <span class="token operator">=</span> <span class="token string">""</span>
  <span class="token keyword">local</span> tabs <span class="token operator">=</span> vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_list_tabpages</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token keyword">local</span> current <span class="token operator">=</span> vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_get_current_tabpage</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

  <span class="token keyword">for</span> i<span class="token punctuation">,</span> tab <span class="token keyword">in</span> <span class="token function">ipairs</span><span class="token punctuation">(</span>tabs<span class="token punctuation">)</span> <span class="token keyword">do</span>
	<span class="token keyword">local</span> is_active <span class="token operator">=</span> <span class="token punctuation">(</span>tab <span class="token operator">==</span> current<span class="token punctuation">)</span>

	<span class="token keyword">local</span> hl_left  <span class="token operator">=</span> is_active <span class="token keyword">and</span> <span class="token string">"%#TabLinePillActiveLeft#"</span>   <span class="token keyword">or</span> <span class="token string">"%#TabLinePillInactiveLeft#"</span>
	<span class="token keyword">local</span> hl_text  <span class="token operator">=</span> is_active <span class="token keyword">and</span> <span class="token string">"%#TabLinePillActiveText#"</span>   <span class="token keyword">or</span> <span class="token string">"%#TabLinePillInactiveText#"</span>
	<span class="token keyword">local</span> hl_right <span class="token operator">=</span> is_active <span class="token keyword">and</span> <span class="token string">"%#TabLinePillActiveRight#"</span>  <span class="token keyword">or</span> <span class="token string">"%#TabLinePillInactiveRight#"</span>

	s <span class="token operator">=</span> s <span class="token operator">..</span> hl_left <span class="token operator">..</span> <span class="token string">""</span>
	s <span class="token operator">=</span> s <span class="token operator">..</span> hl_text <span class="token operator">..</span> <span class="token string">" "</span> <span class="token operator">..</span> i <span class="token operator">..</span> <span class="token string">" "</span>
	s <span class="token operator">=</span> s <span class="token operator">..</span> hl_right <span class="token operator">..</span> <span class="token string">""</span>
	s <span class="token operator">=</span> s <span class="token operator">..</span> <span class="token string">"%#TabLine# "</span>
  <span class="token keyword">end</span>

  <span class="token keyword">return</span> s
<span class="token keyword">end</span>
</code></pre></div>
<p>Each tab gets a pill-shaped segment, numbered sequentially. No
clutter, just a clear workspace indicator.</p>
<hr>
<h2>Part 5: Testing It</h2>
<p>For your convinience, here is the full <code>tabline.lua</code> file:</p>
<div class="remark-highlight"><pre class="language-lua"><code class="language-lua"><span class="token comment">-- Create a new tab</span>
vim<span class="token punctuation">.</span>keymap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"n"</span><span class="token punctuation">,</span> <span class="token string">"&#x3C;leader>tn"</span><span class="token punctuation">,</span> <span class="token string">":tabnew&#x3C;CR>"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> desc <span class="token operator">=</span> <span class="token string">"New [t]ab"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token comment">-- Exclude current tab</span>
vim<span class="token punctuation">.</span>keymap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"n"</span><span class="token punctuation">,</span> <span class="token string">"&#x3C;leader>tx"</span><span class="token punctuation">,</span> <span class="token string">":tabclose&#x3C;CR>"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> desc <span class="token operator">=</span> <span class="token string">"E[x]clude tab"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token comment">-- Toggle showing the tabline</span>
vim<span class="token punctuation">.</span>keymap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"n"</span><span class="token punctuation">,</span> <span class="token string">"&#x3C;leader>tt"</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token keyword">if</span> vim<span class="token punctuation">.</span>o<span class="token punctuation">.</span>showtabline <span class="token operator">==</span> <span class="token number">2</span> <span class="token keyword">then</span>
	vim<span class="token punctuation">.</span>o<span class="token punctuation">.</span>showtabline <span class="token operator">=</span> <span class="token number">0</span>
  <span class="token keyword">else</span>
	vim<span class="token punctuation">.</span>o<span class="token punctuation">.</span>showtabline <span class="token operator">=</span> <span class="token number">2</span>
  <span class="token keyword">end</span>
<span class="token keyword">end</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> desc <span class="token operator">=</span> <span class="token string">"Toggle [t]abs"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token comment">-- Navigate tabs</span>
vim<span class="token punctuation">.</span>keymap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"n"</span><span class="token punctuation">,</span> <span class="token string">"]t"</span><span class="token punctuation">,</span> <span class="token string">":tabnext&#x3C;CR>"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> desc <span class="token operator">=</span> <span class="token string">"Next tab"</span><span class="token punctuation">,</span> silent <span class="token operator">=</span> <span class="token keyword">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>keymap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"n"</span><span class="token punctuation">,</span> <span class="token string">"[t"</span><span class="token punctuation">,</span> <span class="token string">":tabprevious&#x3C;CR>"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> desc <span class="token operator">=</span> <span class="token string">"Previous tab"</span><span class="token punctuation">,</span> silent <span class="token operator">=</span> <span class="token keyword">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>


vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLine"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> bg <span class="token operator">=</span> <span class="token string">"NONE"</span><span class="token punctuation">,</span> fg <span class="token operator">=</span> <span class="token string">"#666666"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLineFill"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> bg <span class="token operator">=</span> <span class="token string">"NONE"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>

vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLinePillActiveLeft"</span><span class="token punctuation">,</span>   <span class="token punctuation">{</span> fg <span class="token operator">=</span> <span class="token string">"#8aadf4"</span><span class="token punctuation">,</span> bg <span class="token operator">=</span> <span class="token string">"#1e1e2e"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLinePillActiveText"</span><span class="token punctuation">,</span>   <span class="token punctuation">{</span> fg <span class="token operator">=</span> <span class="token string">"#1e1e2e"</span><span class="token punctuation">,</span> bg <span class="token operator">=</span> <span class="token string">"#8aadf4"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLinePillActiveRight"</span><span class="token punctuation">,</span>  <span class="token punctuation">{</span> fg <span class="token operator">=</span> <span class="token string">"#8aadf4"</span><span class="token punctuation">,</span> bg <span class="token operator">=</span> <span class="token string">"#1e1e2e"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>

vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLinePillInactiveLeft"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> fg <span class="token operator">=</span> <span class="token string">"#737994"</span><span class="token punctuation">,</span> bg <span class="token operator">=</span> <span class="token string">"#1e1e2e"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLinePillInactiveText"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> fg <span class="token operator">=</span> <span class="token string">"#1e1e2e"</span><span class="token punctuation">,</span> bg <span class="token operator">=</span> <span class="token string">"#737994"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_set_hl</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"TabLinePillInactiveRight"</span><span class="token punctuation">,</span><span class="token punctuation">{</span> fg <span class="token operator">=</span> <span class="token string">"#737994"</span><span class="token punctuation">,</span> bg <span class="token operator">=</span> <span class="token string">"#1e1e2e"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>


vim<span class="token punctuation">.</span>o<span class="token punctuation">.</span>tabline <span class="token operator">=</span> <span class="token string">"%!v:lua.PillTabline()"</span>

<span class="token keyword">function</span> _G<span class="token punctuation">.</span><span class="token function">PillTabline</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token keyword">local</span> s <span class="token operator">=</span> <span class="token string">""</span>
  <span class="token keyword">local</span> tabs <span class="token operator">=</span> vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_list_tabpages</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token keyword">local</span> current <span class="token operator">=</span> vim<span class="token punctuation">.</span>api<span class="token punctuation">.</span><span class="token function">nvim_get_current_tabpage</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

  <span class="token keyword">for</span> i<span class="token punctuation">,</span> tab <span class="token keyword">in</span> <span class="token function">ipairs</span><span class="token punctuation">(</span>tabs<span class="token punctuation">)</span> <span class="token keyword">do</span>
	<span class="token keyword">local</span> is_active <span class="token operator">=</span> <span class="token punctuation">(</span>tab <span class="token operator">==</span> current<span class="token punctuation">)</span>

	<span class="token keyword">local</span> hl_left  <span class="token operator">=</span> is_active <span class="token keyword">and</span> <span class="token string">"%#TabLinePillActiveLeft#"</span>   <span class="token keyword">or</span> <span class="token string">"%#TabLinePillInactiveLeft#"</span>
	<span class="token keyword">local</span> hl_text  <span class="token operator">=</span> is_active <span class="token keyword">and</span> <span class="token string">"%#TabLinePillActiveText#"</span>   <span class="token keyword">or</span> <span class="token string">"%#TabLinePillInactiveText#"</span>
	<span class="token keyword">local</span> hl_right <span class="token operator">=</span> is_active <span class="token keyword">and</span> <span class="token string">"%#TabLinePillActiveRight#"</span>  <span class="token keyword">or</span> <span class="token string">"%#TabLinePillInactiveRight#"</span>

	s <span class="token operator">=</span> s <span class="token operator">..</span> hl_left <span class="token operator">..</span> <span class="token string">""</span>
	s <span class="token operator">=</span> s <span class="token operator">..</span> hl_text <span class="token operator">..</span> <span class="token string">" "</span> <span class="token operator">..</span> i <span class="token operator">..</span> <span class="token string">" "</span>
	s <span class="token operator">=</span> s <span class="token operator">..</span> hl_right <span class="token operator">..</span> <span class="token string">""</span>
	s <span class="token operator">=</span> s <span class="token operator">..</span> <span class="token string">"%#TabLine# "</span>
  <span class="token keyword">end</span>

  <span class="token keyword">return</span> s
<span class="token keyword">end</span>
</code></pre></div>
<p>You can test this file standalone without touching your main config
with:</p>
<div class="remark-highlight"><pre class="language-sh"><code class="language-sh">nvim <span class="token parameter variable">--clean</span> <span class="token parameter variable">-u</span> NONE <span class="token parameter variable">-c</span> <span class="token string">'luafile tabline.lua'</span> <span class="token parameter variable">-c</span> <span class="token string">'tabnew'</span> <span class="token parameter variable">-c</span> <span class="token string">'tabnew'</span>
</code></pre></div>
<p>This opens Neovim clean, loads your tabline, and creates a couple of
tabs so you can see the style right away. <code>\</code> is the default leader key btw.</p>
<hr>
<h2>Conclusion</h2>
<p>I like to think of this as <strong>a complement to tmux</strong>. tmux manages
workspaces across the system, and inside each tmux pane, Neovim
provides its own tabbed workspaces. By stripping away file names and
fancy descriptions, I keep the focus on structure instead of
distractions.</p>
<p>➖ Neovim tabs ≠ browser tabs. They're more like <strong>workspaces</strong>.</p>
<p>➖ My custom tabline ≈ tmux sessions, but inside Neovim.</p>
<p>➖ The pill design gives enough visual separation without being noisy.</p>
<p>I'll probably refine this over time (maybe adding icons or buffer
names when I really need them), but for now this simple approach keeps
my Neovim and tmux environments consistent and distraction-free.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/nvim-tabline</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/nvim-tabline</guid>
            <pubDate>Tue, 19 Aug 2025 20:10:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Unlocking Web Workers with React: A Step-by-Step Guide]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Hey everyone! I recently gave a presentation to my team about using
Web Workers with React, and the reception was so positive that I
decided to turn the content into a blog post.</p>
<p>In this guide, we'll explore how Web Workers can help us keep our
React interfaces responsive, even when dealing with heavy
computational tasks. We'll go through a practical example, starting
with a common problem and evolving to more robust solutions.</p>
<p>The complete source code for each step is available in <a href="https://github.com/LionyxML/web-workers-react-talk">my GitHub
repository</a>.</p>
<h2>Part 1: The Problem - The UI That Freezes</h2>
<p>Imagine you have a React application that needs to calculate the
Fibonacci number for a relatively high value, like 42. The simplest
way to implement the Fibonacci function is using recursion:</p>
<div class="remark-highlight"><pre class="language-typescript"><code class="language-typescript"><span class="token comment">// src/App.tsx (part-01-heavy-work-lock-ui)</span>
<span class="token keyword">function</span> <span class="token function">fib</span><span class="token punctuation">(</span>n<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">number</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> n <span class="token operator">&#x3C;=</span> <span class="token number">1</span> <span class="token operator">?</span> n <span class="token operator">:</span> <span class="token function">fib</span><span class="token punctuation">(</span>n <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token function">fib</span><span class="token punctuation">(</span>n <span class="token operator">-</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Now, let's call this function when a button is clicked:</p>
<div class="remark-highlight"><pre class="language-typescript"><code class="language-typescript"><span class="token comment">// src/App.tsx (part-01-heavy-work-lock-ui)</span>
<span class="token keyword">const</span> <span class="token function-variable function">handleClick</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token function">setResults</span><span class="token punctuation">(</span><span class="token punctuation">(</span>results<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">[</span>
	<span class="token operator">...</span>results<span class="token punctuation">,</span>
	<span class="token punctuation">{</span> id<span class="token operator">:</span> idRef<span class="token punctuation">.</span>current<span class="token operator">++</span><span class="token punctuation">,</span> result<span class="token operator">:</span> <span class="token function">fib</span><span class="token punctuation">(</span><span class="token number">42</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>
</code></pre></div>
<p>What happens when we click the button? The user interface (UI)
freezes. Buttons stop responding, transitions stutter, and the app
feels like it’s crashed. This happens because JavaScript is
<em>single-threaded</em>, the long-running Fibonacci calculation blocks the
main thread, which also handles user interactions and rendering.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fweb-workers-react-demo-01.gif&w=3840&q=75" alt="web-workers-react-demo-01"></p>
<p>You might notice that the UI is in Portuguese, this demo was
originally built for an internal presentation at work. I decided to
keep it that way since the interface is simple enough to follow even
if you don't speak the language. 😀</p>
<p>Also, if you’re wondering why the rotating icon keeps spinning even
when everything else is frozen, that’s a neat detail! CSS animations
(like <code>transform: rotate</code>) are handled by the browser’s compositor
thread, not JavaScript, so they continue running smoothly even when
the main thread is blocked.</p>
<h2>Part 2: The Solution - Web Workers to the Rescue</h2>
<p>To solve the UI freezing problem, we can move the heavy calculation to
a <em>Web Worker</em>. A Web Worker runs JavaScript code in a separate
thread, allowing the main thread to remain free to handle user
interactions and UI updates.</p>
<p>First, let's create our worker:</p>
<div class="remark-highlight"><pre class="language-typescript"><code class="language-typescript"><span class="token comment">// src/workers/fibWorker.ts (part-02-03-heavy-work-with-workers)</span>
self<span class="token punctuation">.</span><span class="token function-variable function">onmessage</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> data <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">fib</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span>n<span class="token punctuation">)</span><span class="token punctuation">;</span>
  self<span class="token punctuation">.</span><span class="token function">postMessage</span><span class="token punctuation">(</span><span class="token punctuation">{</span> id<span class="token operator">:</span> data<span class="token punctuation">.</span>id<span class="token punctuation">,</span> result <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">function</span> <span class="token function">fib</span><span class="token punctuation">(</span>n<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">number</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> n <span class="token operator">&#x3C;=</span> <span class="token number">1</span> <span class="token operator">?</span> n <span class="token operator">:</span> <span class="token function">fib</span><span class="token punctuation">(</span>n <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token function">fib</span><span class="token punctuation">(</span>n <span class="token operator">-</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Next, in our React component, we create an instance of the worker and
communicate with it:</p>
<div class="remark-highlight"><pre class="language-typescript"><code class="language-typescript"><span class="token comment">// src/App.tsx (part-02-03-heavy-work-with-workers)</span>
<span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  workerRef<span class="token punctuation">.</span>current <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Worker</span><span class="token punctuation">(</span>
	<span class="token keyword">new</span> <span class="token class-name"><span class="token constant">URL</span></span><span class="token punctuation">(</span><span class="token string">"./workers/fibWorker.ts"</span><span class="token punctuation">,</span> <span class="token keyword">import</span><span class="token punctuation">.</span>meta<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">,</span>
	<span class="token punctuation">{</span> type<span class="token operator">:</span> <span class="token string">"module"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>

  workerRef<span class="token punctuation">.</span>current<span class="token punctuation">.</span><span class="token function-variable function">onmessage</span> <span class="token operator">=</span> <span class="token punctuation">(</span>e<span class="token operator">:</span> MessageEvent<span class="token operator">&#x3C;</span>Result<span class="token operator">></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
	<span class="token function">setResults</span><span class="token punctuation">(</span><span class="token punctuation">(</span>prev<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token operator">...</span>prev<span class="token punctuation">,</span> e<span class="token punctuation">.</span>data<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">const</span> <span class="token function-variable function">handleClick</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>workerRef<span class="token punctuation">.</span>current<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	workerRef<span class="token punctuation">.</span>current<span class="token punctuation">.</span><span class="token function">postMessage</span><span class="token punctuation">(</span><span class="token punctuation">{</span> id<span class="token operator">:</span> idRef<span class="token punctuation">.</span>current<span class="token operator">++</span><span class="token punctuation">,</span> n<span class="token operator">:</span> <span class="token number">42</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>Now, when we click the button, the Fibonacci calculation runs in the
background, and the UI remains responsive.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fweb-workers-react-demo-02.gif&w=3840&q=75" alt="web-workers-react-demo-02"></p>
<h2>Part 3: Handling Multiple Tasks</h2>
<p>What happens if we click the button multiple times in quick
succession? With the current implementation, each click sends a new
message to the worker, and it will process all requests concurrently,
with no guaranteed order of completion.</p>
<p>If we, for example, change our <code>fibWorker.ts</code> to performe some
asynchronous tasks:</p>
<div class="remark-highlight"><pre class="language-typescript"><code class="language-typescript"><span class="token comment">// src/workers/fibWorker.ts (part-02-03-heavy-work-with-workers)</span>
<span class="token keyword">function</span> <span class="token function">fib</span><span class="token punctuation">(</span>n<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">number</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> n <span class="token operator">&#x3C;=</span> <span class="token number">1</span> <span class="token operator">?</span> n <span class="token operator">:</span> <span class="token function">fib</span><span class="token punctuation">(</span>n <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token function">fib</span><span class="token punctuation">(</span>n <span class="token operator">-</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 keyword">function</span> <span class="token function">delay</span><span class="token punctuation">(</span>ms<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name"><span class="token builtin">Promise</span></span><span class="token punctuation">(</span><span class="token punctuation">(</span>resolve<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setTimeout</span><span class="token punctuation">(</span>resolve<span class="token punctuation">,</span> ms<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

self<span class="token punctuation">.</span><span class="token function-variable function">onmessage</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span>e<span class="token operator">:</span> MessageEvent<span class="token operator">&#x3C;</span><span class="token punctuation">{</span> id<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span> n<span class="token operator">:</span> <span class="token builtin">number</span> <span class="token punctuation">}</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">await</span> <span class="token function">delay</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">2000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">fib</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>data<span class="token punctuation">.</span>n<span class="token punctuation">)</span><span class="token punctuation">;</span>

  self<span class="token punctuation">.</span><span class="token function">postMessage</span><span class="token punctuation">(</span><span class="token punctuation">{</span> id<span class="token operator">:</span> e<span class="token punctuation">.</span>data<span class="token punctuation">.</span>id<span class="token punctuation">,</span> result <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>This is the result, showing no "output order" is guaranteed.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fweb-workers-react-demo-03.gif&w=3840&q=75" alt="web-workers-react-demo-03"></p>
<h2>Part 4: Controlling the Order with a Queue</h2>
<p>To ensure that tasks are executed in the order they were requested, we
can implement a queue inside our worker:</p>
<div class="remark-highlight"><pre class="language-typescript"><code class="language-typescript"><span class="token comment">// src/workers/fibWorker.ts (part-04-heavy-work-with-workers-queue)</span>
<span class="token keyword">interface</span> <span class="token class-name">Task</span> <span class="token punctuation">{</span>
  id<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
  n<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> queue<span class="token operator">:</span> Task<span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> processing <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>

self<span class="token punctuation">.</span><span class="token function-variable function">onmessage</span> <span class="token operator">=</span> <span class="token punctuation">(</span>e<span class="token operator">:</span> MessageEvent<span class="token operator">&#x3C;</span>Task<span class="token operator">></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  queue<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>processing<span class="token punctuation">)</span> <span class="token function">processNext</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">function</span> <span class="token function">processNext</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>queue<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
	processing <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
	<span class="token keyword">return</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  processing <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> task <span class="token operator">=</span> queue<span class="token punctuation">.</span><span class="token function">shift</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>task<span class="token punctuation">)</span> <span class="token punctuation">{</span>
	<span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">fib</span><span class="token punctuation">(</span>task<span class="token punctuation">.</span>n<span class="token punctuation">)</span><span class="token punctuation">;</span>
	self<span class="token punctuation">.</span><span class="token function">postMessage</span><span class="token punctuation">(</span><span class="token punctuation">{</span> id<span class="token operator">:</span> task<span class="token punctuation">.</span>id<span class="token punctuation">,</span> result <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token function">setTimeout</span><span class="token punctuation">(</span>processNext<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>
</code></pre></div>
<p>With this queue, each task is enqueued and executed one at a time,
ensuring order and control over the workflow.</p>
<h2>Part 5: Sharing Workers Across Tabs with Shared Workers</h2>
<p>What if we want to share the same worker across multiple components or
even multiple browser tabs? That's where <em>Shared Workers</em> come in.</p>
<p>A Shared Worker can be accessed by different contexts (tabs, iframes,
etc.) from the same origin. This is ideal for centralized tasks, like
caching results or managing a WebSocket connection.</p>
<p>Let's create a Shared Worker with a cache for the Fibonacci results:</p>
<div class="remark-highlight"><pre class="language-typescript"><code class="language-typescript"><span class="token comment">// src/workers/sharedFibWorker.ts (part-05-heavy-work-shared-workers)</span>
<span class="token keyword">const</span> fibCache <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Map<span class="token operator">&#x3C;</span><span class="token builtin">number</span><span class="token punctuation">,</span> <span class="token builtin">number</span><span class="token operator">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token function-variable function">onconnect</span> <span class="token operator">=</span> <span class="token punctuation">(</span>e<span class="token operator">:</span> MessageEvent<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> port <span class="token operator">=</span> e<span class="token punctuation">.</span>ports<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
  port<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  port<span class="token punctuation">.</span><span class="token function-variable function">onmessage</span> <span class="token operator">=</span> <span class="token punctuation">(</span>evt<span class="token operator">:</span> MessageEvent<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
	<span class="token comment">// ... (queue logic)</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">function</span> <span class="token function">fib</span><span class="token punctuation">(</span>n<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">number</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>fibCache<span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span>n<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> fibCache<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>n<span class="token punctuation">)</span><span class="token operator">!</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> result <span class="token operator">=</span> <span class="token function">rawFib</span><span class="token punctuation">(</span>n<span class="token punctuation">)</span><span class="token punctuation">;</span>
  fibCache<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>n<span class="token punctuation">,</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">return</span> result<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>And in our React component, we connect to the Shared Worker:</p>
<div class="remark-highlight"><pre class="language-typescript"><code class="language-typescript"><span class="token comment">// src/App.tsx (part-05-heavy-work-shared-workers)</span>
<span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  sharedWorkerRef<span class="token punctuation">.</span>current <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SharedWorker</span><span class="token punctuation">(</span>
	<span class="token keyword">new</span> <span class="token class-name"><span class="token constant">URL</span></span><span class="token punctuation">(</span><span class="token string">"./workers/sharedFibWorker.ts"</span><span class="token punctuation">,</span> <span class="token keyword">import</span><span class="token punctuation">.</span>meta<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">,</span>
	<span class="token punctuation">{</span> type<span class="token operator">:</span> <span class="token string">"module"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
  sharedWorkerRef<span class="token punctuation">.</span>current<span class="token punctuation">.</span>port<span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  sharedWorkerRef<span class="token punctuation">.</span>current<span class="token punctuation">.</span>port<span class="token punctuation">.</span><span class="token function-variable function">onmessage</span> <span class="token operator">=</span> <span class="token punctuation">(</span>e<span class="token operator">:</span> MessageEvent<span class="token operator">&#x3C;</span>Result<span class="token operator">></span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
	<span class="token function">setResults</span><span class="token punctuation">(</span><span class="token punctuation">(</span>prev<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">[</span><span class="token operator">...</span>prev<span class="token punctuation">,</span> e<span class="token punctuation">.</span>data<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>
</code></pre></div>
<p>Now, if you open the application in two different tabs and calculate
the same Fibonacci number, the second tab will get the result from the
cache instantly.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fweb-workers-react-demo-04.gif&w=3840&q=75" alt="web-workers-react-demo-04"></p>
<h2>Conclusion</h2>
<p>Web Workers are an incredibly powerful tool for improving the
performance and responsiveness of web applications. We've seen how:</p>
<p>➖ <strong>Web Workers</strong> can prevent UI freezing by moving heavy tasks to a
separate thread.</p>
<p>➖ A <strong>queue</strong> can be used to control the execution order of tasks in a
worker.</p>
<p>➖ <strong>Shared Workers</strong> allow for state sharing and communication between
different tabs or components.</p>
<p>It's important to remember that Web Workers do not have access to the
DOM. Communication with the main thread is done through messages.</p>
<p>For more complex scenarios, you might want to explore libraries like
Google's <a href="https://github.com/GoogleChromeLabs/comlink">Comlink</a>, which
simplifies communication with workers, allowing you to call functions
in the worker as if they were local functions.</p>
<h2>A Quick Comparison: Web, Shared, and Service Workers</h2>
<p>While this guide focused on Web Workers and Shared Workers, it's
helpful to understand how they differ from Service Workers. Each has a
distinct purpose.</p>
<div class="remark-highlight"><pre class="language-markdown"><code class="language-markdown"><span class="token table"><span class="token table-header-row"><span class="token punctuation">|</span><span class="token table-header important"> Feature / Capability            </span><span class="token punctuation">|</span><span class="token table-header important"> Web Worker              </span><span class="token punctuation">|</span><span class="token table-header important"> Shared Worker                    </span><span class="token punctuation">|</span><span class="token table-header important"> Service Worker                               </span><span class="token punctuation">|</span>
</span><span class="token table-line"><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><span class="token table-data-rows"><span class="token punctuation">|</span><span class="token table-data"> Scope                           </span><span class="token punctuation">|</span><span class="token table-data"> Single page/tab         </span><span class="token punctuation">|</span><span class="token table-data"> Shared across tabs (same origin) </span><span class="token punctuation">|</span><span class="token table-data"> Global (site-wide, independent of tabs)      </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> Shared across tabs              </span><span class="token punctuation">|</span><span class="token table-data"> No                      </span><span class="token punctuation">|</span><span class="token table-data"> Yes                              </span><span class="token punctuation">|</span><span class="token table-data"> Yes                                          </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> Communication                   </span><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`postMessage`</span> (1:1)     </span><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`port.postMessage`</span> (many:1)      </span><span class="token punctuation">|</span><span class="token table-data"> <span class="token code-snippet code keyword">`postMessage`</span>, <span class="token code-snippet code keyword">`fetch`</span>, Push API, etc.       </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> Persists after tab closes       </span><span class="token punctuation">|</span><span class="token table-data"> No                      </span><span class="token punctuation">|</span><span class="token table-data"> No                               </span><span class="token punctuation">|</span><span class="token table-data"> Yes (managed by browser)                     </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> Use case                        </span><span class="token punctuation">|</span><span class="token table-data"> Offload CPU-heavy tasks </span><span class="token punctuation">|</span><span class="token table-data"> Coordinate logic across tabs     </span><span class="token punctuation">|</span><span class="token table-data"> Background sync, caching, push notifications </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> DOM access                      </span><span class="token punctuation">|</span><span class="token table-data"> No                      </span><span class="token punctuation">|</span><span class="token table-data"> No                               </span><span class="token punctuation">|</span><span class="token table-data"> No                                           </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> Network interception            </span><span class="token punctuation">|</span><span class="token table-data"> No                      </span><span class="token punctuation">|</span><span class="token table-data"> No                               </span><span class="token punctuation">|</span><span class="token table-data"> Yes (<span class="token code-snippet code keyword">`fetch`</span> interception)                   </span><span class="token punctuation">|</span>
<span class="token punctuation">|</span><span class="token table-data"> Requires secure context (HTTPS) </span><span class="token punctuation">|</span><span class="token table-data"> No                      </span><span class="token punctuation">|</span><span class="token table-data"> No                               </span><span class="token punctuation">|</span><span class="token table-data"> Yes (HTTPS required)                         </span><span class="token punctuation">|</span></span></span>
</code></pre></div>
<h3>Key Observations</h3>
<p>➖ <strong>Web Workers</strong> are the simplest and most common choice. Their goal
is to take a specific, computationally intensive task off the
main thread to keep a single page responsive. Think of them as
temporary helpers for a single view.</p>
<p>➖ <strong>Shared Workers</strong> are all about coordination. Use them when
multiple tabs or windows of your application need to share a
single resource, like a WebSocket connection, a shared cache (as
in our example), or a centralized state.</p>
<p>➖ <strong>Service Workers</strong> are fundamentally different. They act as a
network proxy for your entire site and are the foundation of
Progressive Web Apps (PWAs). While they also run on a separate
thread, their primary role is not to perform calculations for a
specific page. Instead, they handle tasks that require a longer
lifecycle, such as enabling offline functionality by
intercepting network requests and serving cached assets, or
managing push notifications even when the user doesn't have your
site open.</p>
<p>So, while we didn't build a Service Worker today, it's a crucial tool
for creating modern, resilient, and engaging web applications. For
CPU-bound tasks, stick with Web Workers; for cross-tab communication,
use Shared Workers; and for offline capabilities and push
notifications, the Service Worker is your go-to.</p>
<p>I hope this guide has been helpful! Feel free to explore the <a href="https://github.com/LionyxML/web-workers-react-talk">code on
GitHub</a> and try it
out for yourself.</p>
<hr>
<p><strong>PS:</strong> If you're ready to take the ne step in building resilient web
applications, I've written a follow-up post. In <a href="/posts/react-service-workers">Exploring Service
Workers with React: From Offline to Push
Notifications</a>, we'll go beyond th CPU-bound
tasks of Web Workers and dive into the world of offline-first
architecture, background sync, and push notifications that only
Service Workers can provide.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/react-workers</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/react-workers</guid>
            <pubDate>Mon, 04 Aug 2025 20:44:55 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[Jujutsu VCS: My Personal Cheat Sheet]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>A practical quick-reference for the JJ (Jujutsu) version control
system: not a tutorial, but a ready-to-use guide with the most
essential commands and workflows.</p>
<h2>🧠 Heads-Up: This Is <em>Not</em> a Tutorial!</h2>
<p>If you're expecting a walkthrough on how to use <a href="https://github.com/jj-vcs/jj">Jujutsu
(JJ)</a> from scratch, this post probably
isn't what you're looking for.</p>
<p>There are already some great tutorials
out there, including the excelent <a href="https://jj-vcs.github.io/jj/latest/tutorial/">official one</a>.</p>
<p>While this post serves as a <strong>cheat sheet</strong> and not a beginner
tutorial, if you're looking for a video walkthrough to complement it,
check out <code>DevOps Toolbox</code> awesome video:</p>
<iframe width="100%"
		height="100%"
		style="aspect-ratio: 16 / 9;"
		src="https://www.youtube.com/embed/cZqFaMlufDY?si=mxihKYoz4LTr0NnX"
		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=cZqFaMlufDY">» Also available here</a></p>
<hr>
<h2>🐦 Why JJ?</h2>
<p>Jujutsu is a powerful version control system for software
projects. You use it to get a copy of your code, track changes to the
code, and finally publish those changes for others to see and use. It
is designed from the ground up to be easy to use, whether you're new or
experienced, working on brand new projects alone, or large scale
software projects with large histories and teams.</p>
<p>What sets JJ apart is its focus on <strong>automatic working commits</strong>,
which track your changes continuously without the usual manual commit
overhead. This design makes JJ extremely fast, highly scriptable, and
encourages maintaining a cleaner, more intuitive project history.</p>
<p>That said, JJ introduces new workflows and concepts that may feel
unfamiliar at first. Common operations like <code>merge</code> or <code>rebase</code> behave
differently, so keeping a quick reference or cheat sheet handy can
make your transition smoother and more productive.</p>
<hr>
<h2>📎 The cheat sheet!</h2>
<h2>Basic Commands</h2>
<table class="org-table-2-columns" border="2" cellspacing="0" cellpadding="6">
<tbody>
<tr>
<td scope="col" class="org-left">jj git init</td>
<td scope="col" class="org-left">Inits jj with git backend</td>
</tr>
<tr>
<td class="org-left">jj st</td>
<td class="org-left">prints status</td>
</tr>
<tr>
<td class="org-left">jj status</td>
<td class="org-left">same as above</td>
</tr>
<tr>
<td class="org-left">jj</td>
<td class="org-left">prints log</td>
</tr>
<tr>
<td class="org-left">jj log</td>
<td class="org-left">same as above</td>
</tr>
<tr>
<td class="org-left">jj diff</td>
<td class="org-left">diffs current change</td>
</tr>
<tr>
<td class="org-left">jj diff --git</td>
<td class="org-left">diffs current change in git style</td>
</tr>
<tr>
<td class="org-left">jj desc</td>
<td class="org-left">adds a description to the current change</td>
</tr>
<tr>
<td class="org-left">jj describe</td>
<td class="org-left">same as above</td>
</tr>
<tr>
<td class="org-left">jj describe -m "..."</td>
<td class="org-left">same as above, but inline</td>
</tr>
<tr>
<td class="org-left">jj new</td>
<td class="org-left">ends a change and inits a new one</td>
</tr>
<tr>
<td class="org-left">jj new -m</td>
<td class="org-left">ends a change and inits a new one</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">setting a description</td>
</tr>
<tr>
<td class="org-left">jj file annotate filename</td>
<td class="org-left">annotates filename, similar to</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">git blame or hg annotate</td>
</tr>
<tr>
<td class="org-left">jj undo</td>
<td class="org-left">undoes last jj command</td>
</tr>
<tr>
<td class="org-left">jj squash</td>
<td class="org-left">combines changes and descriptions</td>
</tr>
<tr>
<td class="org-left">jj squash file</td>
<td class="org-left">instantly squashes file down to</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">last change</td>
</tr>
<tr>
<td class="org-left">jj squash -i</td>
<td class="org-left">opens an ui to select</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">what to squash</td>
</tr>
<tr>
<td class="org-left">jj abandon</td>
<td class="org-left">drops everything on current change</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">and starts a new one in place.</td>
</tr>
<tr>
<td class="org-left">jj split</td>
<td class="org-left">splits current change creating a new change with the selected content on @-</td>
</tr>
<tr>
<td class="org-left">jj commit -m "..."</td>
<td class="org-left">adds a description for current change and starts a new one (equivalent to <code>jj desc -m "..." && jj new</code>)</td>
</tr>
</tbody>
</table>
<hr>
<h2>Time Traveling</h2>
<table class="org-table-2-columns" border="2" cellspacing="0" cellpadding="6" >
<tbody>
<tr>
<td scope="col" class="org-left">jj new -B @ -m "msg"</td>
<td scope="col" class="org-left">Creates a new change <code>B</code>efore current (@)</td>
</tr>
<tr>
<td scope="col" class="org-left">&#xa0;</td>
<td scope="col" class="org-left">setting a description</td>
</tr>
<tr>
<td class="org-left">jj edit change-id</td>
<td class="org-left">Moves to whathever change-id</td>
</tr>
<tr>
<td class="org-left">jj next --edit</td>
<td class="org-left">Jumps to next change</td>
</tr>
<tr>
<td class="org-left">jj edit @+</td>
<td class="org-left">&#xa0;</td>
</tr>
<tr>
<td class="org-left">jj edit @-</td>
<td class="org-left">Jumps to prev change</td>
</tr>
</tbody>
</table>
<hr>
<h2>Branchless Workflow</h2>
<table class="org-table-2-columns" border="2" cellspacing="0" cellpadding="6" >
<tbody>
<tr>
<td class="org-left">jj new change-id</td>
<td class="org-left">Creates a new change before a</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">given change-id</td>
</tr>
</tbody>
</table>
<hr>
<h2>More on log</h2>
<table class="org-table-2-columns" border="2" cellspacing="0" cellpadding="6" >
<tbody>
<tr>
<td scope="col" class="org-left">jj log -r revsets</td>
<td scope="col" class="org-left">Applies a revset to log, similar</td>
</tr>
<tr>
<td scope="col" class="org-left">&#xa0;</td>
<td scope="col" class="org-left">to hg(1) (Mercurial)</td>
</tr>
<tr>
<td class="org-left">jj --limit number</td>
<td class="org-left">Limits log lines</td>
</tr>
<tr>
<td class="org-left">jj log -r 'heads(all())'</td>
<td class="org-left">Shows all 'heads' or 'forked'</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">changes top change</td>
</tr>
</tbody>
</table>
<hr>
<h2>Merging</h2>
<p>Note: there's no <code>jj checkout</code> nor <code>jj merge</code>, those used to exist but are
now <strong>deprecated</strong>. We use <code>jj new ...</code> for everything.</p>
<table class="org-table-2-columns" border="2" cellspacing="0" cellpadding="6" >
<tbody>
<tr>
<td class="org-left">jj new x yz -m "message"</td>
<td class="org-left">Creates a new change by merging</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">x and yz change ids defining</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">a message "merge". User can</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">merge as many change-ids as</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">they wish.</td>
</tr>
</tbody>
</table>
<hr>
<h2>Rebasing</h2>
<p>Notice: rebase <code>always</code> succeeds even with conflicts <strong>pending</strong>.</p>
<table class="org-table-2-columns" border="2" cellspacing="0" cellpadding="6" >
<tbody>
<tr>
<td class="org-left">jj rebase -s o -d x</td>
<td class="org-left">Rebases change with id o (source)</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">to change with id x (destination)</td>
</tr>
</tbody>
</table>
<hr>
<h2>Merge Conflicts</h2>
<p>If a conflict is present, <code>jj st</code> will tell you on which files
you need to look for conflicts and solve.</p>
<p>Just save your file after solving and nothing else, no need
to <strong>continue</strong> anything.</p>
<table class="org-table-2-columns" border="2" cellspacing="0" cellpadding="6" >
<tbody>
<tr>
<td class="org-left">jj resolve</td>
<td class="org-left">Opens an ui to choose how to solve conflicts</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">(plus: mouse is supported)</td>
</tr>
</tbody>
</table>
<hr>
<h2>Log - Template Language</h2>
<table class="org-table-2-columns" border="2" cellspacing="0" cellpadding="6" >
<tbody>
<tr>
<td scope="col" class="org-left">jj log -T 'TEMPLATE'</td>
<td scope="col" class="org-left">Applies a template to jj log</td>
</tr>
<tr>
<td class="org-left">jj help -k templates</td>
<td class="org-left">Print the help doc with all template</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">language options</td>
</tr>
</tbody>
</table>
<p>A bunch of options are provided to go with templates, some
examples:</p>
<p>Format log to have commit-id, new line, description and <code>----</code> before
next log entry.</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj log <span class="token parameter variable">-T</span> <span class="token string">'commit-id ++ "\n" ++ description ++ "\n------\n"'</span>
</code></pre></div>
<p>Get short commit IDs of the working-copy parents:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj log --no-graph <span class="token parameter variable">-r</span> @ <span class="token parameter variable">-T</span> <span class="token string">'parents.map(|c| c.commit_id().short()).join(",")'</span>
</code></pre></div>
<p>Show machine-readable list of full commit and change IDs:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj log --no-graph <span class="token parameter variable">-T</span> <span class="token string">'commit_id ++ " " ++ change_id ++ "\n"'</span>
</code></pre></div>
<hr>
<h2>Log - Revset Language</h2>
<table class="org-table-2-columns" border="2" cellspacing="0" cellpadding="6" >
<tbody>
<tr>
<td scope="col" class="org-left">jj log -r 'REVSET'</td>
<td scope="col" class="org-left">Applies a revset to jj log</td>
</tr>
<tr>
<td class="org-left">jj help -k revsets</td>
<td class="org-left">Prints the help doc with all revsets</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">language options</td>
</tr>
</tbody>
</table>
<p>A bunch of options are provided to go with templates, some
examples:</p>
<p>Show the parent(s) of the working-copy commit (like <code>git log -1 HEAD</code>):</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj log <span class="token parameter variable">-r</span> @-
</code></pre></div>
<p>Show all ancestors of the working copy (like plain <code>git log</code>):</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj log <span class="token parameter variable">-r</span> ::@
</code></pre></div>
<p>Show commits not on any remote bookmark:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj log <span class="token parameter variable">-r</span> <span class="token string">'remote_bookmarks()..'</span>
</code></pre></div>
<p>Show commits not on `origin` (if you have other remotes like `fork`):</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj log <span class="token parameter variable">-r</span> <span class="token string">'remote_bookmarks(remote=origin)..'</span>
</code></pre></div>
<p>Show the initial commits in the repo (the ones Git calls "root commits"):</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj log <span class="token parameter variable">-r</span> <span class="token string">'root()+'</span>
</code></pre></div>
<p>Show some important commits (like <code>git --simplify-by-decoration</code>):</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj log <span class="token parameter variable">-r</span> <span class="token string">'tags() | bookmarks()'</span>
</code></pre></div>
<p>Show local commits leading up to the working copy, as well as descendants of
those commits:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj log <span class="token parameter variable">-r</span> <span class="token string">'(remote_bookmarks()..@)::'</span>
</code></pre></div>
<p>Show commits authored by "martinvonz" and containing the word "reset" in the
description:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj log <span class="token parameter variable">-r</span> <span class="token string">'author(martinvonz) & description(reset)'</span>
</code></pre></div>
<hr>
<h2>Diff - Fileset Language</h2>
<table class="org-table-2-columns" border="2" cellspacing="0" cellpadding="6" >
<tbody>
<tr>
<td class="org-left">jj help -k filesets</td>
<td class="org-left">Prints the help doc with all filesets</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">language options</td>
</tr>
</tbody>
</table>
<p>A bunch of options are provided to go with templates, some
examples:</p>
<p>Show diff excluding <code>Cargo.lock</code>.</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj <span class="token function">diff</span> <span class="token string">'~Cargo.lock'</span>
</code></pre></div>
<p>List files in <code>src</code> excluding Rust sources.</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj <span class="token function">file</span> list <span class="token string">'src ~ glob:"**/*.rs"'</span>
</code></pre></div>
<p>Split a revision in two, putting `foo` into the second commit.</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj <span class="token function">split</span> <span class="token string">'~foo'</span>
</code></pre></div>
<hr>
<h2>JJ & Git - Co-locate</h2>
<p>This means jj side by side with git.</p>
<p>Your project will have on its root, both a <code>.jj</code> and a <code>.git</code> directory.</p>
<table class="org-table-2-columns" border="2" cellspacing="0" cellpadding="6" >
<tbody>
<tr>
<td class="org-left">jj git init --colocate .</td>
<td class="org-left">Set a new version control</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">with both jj and git, or if</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">git is present, make arrangements</td>
</tr>
<tr>
<td class="org-left">&#xa0;</td>
<td class="org-left">so both can be colocated.</td>
</tr>
</tbody>
</table>
<hr>
<h3>Simple workflow to main branch:</h3>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj log
jj commit <span class="token parameter variable">-m</span> <span class="token string">"msg"</span>
jj bookmark <span class="token builtin class-name">set</span> <span class="token parameter variable">--revision</span> @- main
jj <span class="token function">git</span> push <span class="token parameter variable">-r</span> @-
jj <span class="token function">op</span> log
</code></pre></div>
<hr>
<h3>Workflow to push to a 'new git branch'</h3>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj
jj bookmark <span class="token builtin class-name">set</span> <span class="token parameter variable">-r</span> @ <span class="token string">'feat/blahk'</span>
jj <span class="token function">git</span> push <span class="token parameter variable">-r</span> @ --allow-new <span class="token parameter variable">--remote</span> origin
</code></pre></div>
<p>To the next pushes, simply:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj <span class="token function">git</span> push <span class="token parameter variable">-r</span> @
</code></pre></div>
<p>Some other useful commands since jj/git colocated relies
heavily on bookmarks:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj bookmark move <span class="token parameter variable">--from</span><span class="token operator">=</span>@- <span class="token parameter variable">--to</span><span class="token operator">=</span>@
jj bokmark delete <span class="token string">'...'</span>
jj bookmark track main@origin
jj <span class="token function">git</span> push <span class="token parameter variable">--all</span> <span class="token parameter variable">--deleted</span>
</code></pre></div>
<p>A complete set and more examples with:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj <span class="token builtin class-name">help</span> <span class="token parameter variable">-k</span> bookmarks
</code></pre></div>
<p>Note, after performing jj motions, probably the git part of the thing
will be HEADLESS or in a detached state.</p>
<p>If you wish to perform "regular" git operations, most probably you
need to first "git checkout" to a branch.</p>
<hr>
<h2>Stageless Workflow</h2>
<p>Jujutsu has no traditional <em>staging area</em> like Git. This means changes
you make in your working copy are immediately part of your current
change (also called a <em>working commit</em>). So what if you’ve modified 10
files but only want to “commit” 2 of them?</p>
<p>💡 You can <strong>mimic partial commits</strong> with a few simple commands.</p>
<p>Special thanks to <a href="https://github.com/cassiano">@Cassiano</a> for for
pointing this out to me!</p>
<h3>🪄 The trick: <code>jj split</code></h3>
<p>Use <code>jj split</code> to break your current change into two:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj <span class="token function">split</span>
</code></pre></div>
<p>This opens a TUI (Text User Interface) where you can <strong>select which
files or even hunks</strong> to split into a new change.</p>
<p>What happens:</p>
<ul>
<li>
<p>The selected changes go into a <strong>new change</strong> (on top of your current one)</p>
</li>
<li>
<p>The rest stay in the <strong>original change</strong></p>
</li>
</ul>
<p>💬 Think of it like “staging” part of your work and “committing” it,
without ever touching an index.</p>
<h3>🧪 Example Workflow</h3>
<ol>
<li>You edit <code>fileA.ts</code>, <code>fileB.ts</code>, and <code>fileC.ts</code>.</li>
<li>But you only want to commit the changes to <code>fileA.ts</code>.</li>
<li>Run:</li>
</ol>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj <span class="token function">split</span>
</code></pre></div>
<ol start="4">
<li>Select only <code>fileA.ts</code> in the UI.</li>
<li>Give the new change a description with:</li>
</ol>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">jj describe <span class="token parameter variable">-m</span> <span class="token string">"Refactor fileA logic"</span>
</code></pre></div>
<p>Now your <code>fileA.ts</code> changes are safely committed. You're still on the
remaining changes for <code>fileB.ts</code> and <code>fileC.ts</code>.</p>
<p>🔄 You can repeat the process to incrementally split off changes until
you're happy.</p>
<h2>🏁 Wrapping Up</h2>
<p>This cheat sheet is not a comprehensive tutorial, as said before, it’s
a <strong>quick reference</strong>, a <strong>jumping-off point</strong>, and a <strong>distilled
guide</strong> for navigating <code>jj</code>. Whether you're exploring <code>jj</code> out of
curiosity or looking to speed up your workflow without staging
overhead, I hope this post gave you enough to get started with
confidence.</p>
<p>Remember: tools don’t define your flow, <strong>your habits and clarity
do</strong>. If <code>jj</code> helps you think more clearly about your changes, then
it’s doing its job. And if not? That’s fine too, there’s always <code>git</code>
or even <code>hg</code> right around the corner.</p>
<p>If you have tweaks, corrections, or your own tricks, I’d love to hear
them!</p>
<p>Thanks for reading! 🧠💻🔥</p>
]]></description>
            <link>https://rahuljuliato.com/posts/jj-cheat-sheet</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/jj-cheat-sheet</guid>
            <pubDate>Sat, 31 May 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[nvim-0x0 – Upload files, yanks, and selections to 0x0.st]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>One thing I really missed from Emacs was how easy it was to upload files and
text snippets to <strong>0x0.st</strong>.</p>
<p>For those unfamiliar, <strong>0x0.st</strong> is a simple, no-fuss file and text-sharing
service where you can upload texts and images and get a shareable link
instantly (you can also host your own instance of it).</p>
<p>So, I decided to bring that experience to Neovim with <strong>nvim-0x0</strong>, my first
ever Neovim plugin! 🎉</p>
<h2>Obligatory Demos</h2>
<ul>
<li>
<p>Uploading the current opened file:<br>
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fnvim_0x0_demo_file.gif&w=3840&q=75" alt="icomplete"></p>
</li>
<li>
<p>Uploading a visual selection:<br>
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fnvim_0x0_demo_visual_selection.gif&w=3840&q=75" alt="icomplete"></p>
</li>
<li>
<p>Uploading the last yanked/deleted text:<br>
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fnvim_0x0_demo_yank.gif&w=3840&q=75" alt="icomplete"></p>
</li>
<li>
<p>Uploading a file selected in <code>oil.nvim</code>:<br>
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fnvim_0x0_demo_oil.gif&w=3840&q=75" alt="icomplete"></p>
</li>
<li>
<p>Uploading an image selected in <code>oil.nvim</code>:<br>
<img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fnvim_0x0_demo_oil_image.gif&w=3840&q=75" alt="icomplete"></p>
</li>
</ul>
<h2>Installation</h2>
<h3>Using lazy.nvim</h3>
<p>Add the following to your <code>lazy.nvim</code> configuration:</p>
<div class="remark-highlight"><pre class="language-lua"><code class="language-lua"><span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'lazy'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  <span class="token punctuation">{</span>
    <span class="token string">"LionyxML/nvim-0x0"</span><span class="token punctuation">,</span>
    opts <span class="token operator">=</span> <span class="token punctuation">{</span>
      <span class="token comment">-- base_url = "https://&#x3C;your-0x0-instance>/",  -- only needed if you host your own 0x0 instance</span>
      use_default_keymaps <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">,</span>                    <span class="token comment">-- Set to false if you want to define your own keymaps</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>Usage</h2>
<p>By default, the following keymaps are available:</p>
<ul>
<li><code>&#x3C;leader>0f</code> - Upload the current file</li>
<li><code>&#x3C;leader>0s</code> - Upload the current visual selection</li>
<li><code>&#x3C;leader>0y</code> - Upload the last yank or delete content</li>
<li><code>&#x3C;leader>0o</code> - Upload a file selected in <code>oil.nvim</code></li>
</ul>
<p>If <code>use_default_keymaps = false</code>, you can define your own mappings, like:</p>
<div class="remark-highlight"><pre class="language-lua"><code class="language-lua">vim<span class="token punctuation">.</span>keymap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">'n'</span><span class="token punctuation">,</span> <span class="token string">'&#x3C;leader>uf'</span><span class="token punctuation">,</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"nvim-0x0"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>upload_current_file<span class="token punctuation">,</span> <span class="token punctuation">{</span> desc <span class="token operator">=</span> <span class="token string">"Upload current file"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>keymap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">'v'</span><span class="token punctuation">,</span> <span class="token string">'&#x3C;leader>us'</span><span class="token punctuation">,</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"nvim-0x0"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>upload_selection<span class="token punctuation">,</span> <span class="token punctuation">{</span> desc <span class="token operator">=</span> <span class="token string">"Upload selection"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>keymap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">'n'</span><span class="token punctuation">,</span> <span class="token string">'&#x3C;leader>uy'</span><span class="token punctuation">,</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"nvim-0x0"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>upload_yank<span class="token punctuation">,</span> <span class="token punctuation">{</span> desc <span class="token operator">=</span> <span class="token string">"Upload yank"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
vim<span class="token punctuation">.</span>keymap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">'n'</span><span class="token punctuation">,</span> <span class="token string">'&#x3C;leader>uo'</span><span class="token punctuation">,</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"nvim-0x0"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>upload_oil_file<span class="token punctuation">,</span> <span class="token punctuation">{</span> desc <span class="token operator">=</span> <span class="token string">"Upload oil.nvim file"</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div>
<p>If you would like to host your own instance of 0x0, set <code>base_url = "https://0x0.st/"</code>.</p>
<h2>Conclusion</h2>
<p>I made <strong>nvim-0x0</strong> to bring a simple and fast 0x0.st experience to Neovim, and
I hope it makes your workflow smoother. If you try it out, let me know what you
think!</p>
<p>Check out the plugin on GitHub:<br>
➡ <strong><a href="https://github.com/LionyxML/nvim-0x0">nvim-0x0 Repository</a></strong></p>
<p>Feel free to open issues, share feedback, or contribute. 🚀</p>
]]></description>
            <link>https://rahuljuliato.com/posts/nvim-0x0</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/nvim-0x0</guid>
            <pubDate>Fri, 07 Feb 2025 14:00: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[Setting up Go Lang on Debian]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <h2>Setting up Go Lang on Debian</h2>
<p>So you need Go in your Debian, and apt gives something, but not the version you need? Or worst, you need several versions of Go, one for each project you're working on?</p>
<p>Fear no more!</p>
<p>If you’re looking for a way to manage multiple language runtimes on your Debian system, <code>asdf</code> is an exceptional tool to consider. Not only does it allow you to manage versions of languages like Python, Ruby, Node.js, and many others, but with the <code>asdf-golang</code> plugin, it also offers an easy way to install and manage different versions of Go (Golang). This guide will walk you through setting up Go on a Debian system using <code>asdf</code>.</p>
<h2>Why Use asdf?</h2>
<p><code>asdf</code> is a versatile CLI tool designed to manage multiple language runtimes on a per-project basis. It simplifies the process of switching between different versions of languages, offering a single interface for various runtime environments. Here's why you should consider using <code>asdf</code>:</p>
<ul>
<li>
<p><strong>Single CLI for Multiple Languages</strong>: <code>asdf</code> eliminates the need for separate version managers like <code>nvm</code>, <code>rbenv</code>, or <code>pyenv</code> by combining them into one tool.</p>
</li>
<li>
<p><strong>Consistent Commands</strong>: It provides a uniform set of commands to manage all your language versions.</p>
</li>
<li>
<p><strong>Global and Per-Project Configurations</strong>: With <code>asdf</code>, you can maintain a single global configuration file, as well as per-project <code>.tool-versions</code> files.</p>
</li>
<li>
<p><strong>Automatic Version Switching</strong>: <code>asdf</code> automatically switches runtime versions as you navigate through different directories.</p>
</li>
<li>
<p><strong>Shell Completion</strong>: It offers shell completion for common shells like Bash, Zsh, Fish, and more.</p>
</li>
</ul>
<h2>Installing asdf on Debian</h2>
<p>Before you start, make sure you have the necessary dependencies installed on your system. Here’s how you can get started:</p>
<ol>
<li>
<p><strong>Install Dependencies</strong>:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">apt</span> update
<span class="token function">sudo</span> <span class="token function">apt</span> <span class="token function">install</span> <span class="token function">curl</span> <span class="token function">git</span> coreutils
</code></pre></div>
</li>
<li>
<p><strong>Clone the asdf Repository</strong>:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">git</span> clone https://github.com/asdf-vm/asdf.git ~/.asdf <span class="token parameter variable">--branch</span> v0.12.0
</code></pre></div>
</li>
<li>
<p><strong>Add asdf to Your Shell</strong>:
Add the following lines to your <code>.bashrc</code> or <code>.zshrc</code> file:</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"><span class="token environment constant">PATH</span></span><span class="token operator">=</span><span class="token string">"<span class="token environment constant">$HOME</span>/.asdf/shims/:<span class="token environment constant">$PATH</span>"</span>
<span class="token builtin class-name">.</span> <span class="token environment constant">$HOME</span>/.asdf/asdf.sh
<span class="token builtin class-name">.</span> <span class="token environment constant">$HOME</span>/.asdf/completions/asdf.bash
</code></pre></div>
</li>
<li>
<p><strong>Reload Your Shell</strong>:
After editing the file, reload your shell:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">source</span> ~/.bashrc
</code></pre></div>
</li>
</ol>
<h2>Installing the asdf-golang Plugin</h2>
<p>With <code>asdf</code> installed, you can now add the <code>golang</code> plugin:</p>
<ol>
<li>
<p><strong>Add the golang Plugin</strong>:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">asdf plugin <span class="token function">add</span> golang https://github.com/asdf-community/asdf-golang.git
</code></pre></div>
</li>
<li>
<p><strong>Install a Version of Go</strong>:
To install a specific version of Go, use:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">asdf <span class="token function">install</span> golang <span class="token number">1.22</span>.6
</code></pre></div>
<p>Replace <code>1.22.6</code> with the version you wish to install.</p>
</li>
<li>
<p><strong>Set a Global or Local Version</strong>:
To set the global version of Go (the default for all projects):</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">asdf global golang <span class="token number">1.22</span>.6
</code></pre></div>
<p>Or, set a local version for a specific project:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">asdf <span class="token builtin class-name">local</span> golang <span class="token number">1.22</span>.6
</code></pre></div>
</li>
</ol>
<h2>Configuring Go Environment Variables</h2>
<p>To properly set up Go's environment variables, you need to add a function to your <code>.bashrc</code> file. This ensures that the <code>GOROOT</code>, <code>GOPATH</code>, and <code>GOBIN</code> variables are correctly set each time you start a new shell session.</p>
<p>Add the following to your <code>.bashrc</code> file:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token comment"># GOLANG</span>
<span class="token function-name function">asdf_update_golang_env</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token builtin class-name">local</span> go_bin_path
  <span class="token assign-left variable">go_bin_path</span><span class="token operator">=</span><span class="token string">"<span class="token variable"><span class="token variable">$(</span>asdf <span class="token function">which</span> go <span class="token operator"><span class="token file-descriptor important">2</span>></span>/dev/null<span class="token variable">)</span></span>"</span>
  <span class="token keyword">if</span> <span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token parameter variable">-n</span> <span class="token string">"<span class="token variable">${go_bin_path}</span>"</span> <span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span>
    <span class="token assign-left variable">abs_go_bin_path</span><span class="token operator">=</span><span class="token string">"<span class="token variable"><span class="token variable">$(</span>readlink <span class="token parameter variable">-f</span> <span class="token string">"<span class="token variable">${go_bin_path}</span>"</span><span class="token variable">)</span></span>"</span>

    <span class="token builtin class-name">export</span> GOROOT
    <span class="token assign-left variable">GOROOT</span><span class="token operator">=</span><span class="token string">"$(dirname "<span class="token variable"><span class="token variable">$(</span><span class="token function">dirname</span> <span class="token string">"<span class="token variable">${abs_go_bin_path}</span>"</span><span class="token variable">)</span></span>"</span><span class="token punctuation">)</span><span class="token string">"</span>
<span class="token string"></span>
<span class="token string">    export GOPATH</span>
<span class="token string">    GOPATH="</span><span class="token variable"><span class="token variable">$(</span><span class="token function">dirname</span> <span class="token string">"<span class="token variable">${GOROOT}</span>"</span><span class="token variable">)</span></span>/packages<span class="token string">"</span>
<span class="token string"></span>
<span class="token string">    export GOBIN</span>
<span class="token string">    GOBIN="</span><span class="token variable"><span class="token variable">$(</span><span class="token function">dirname</span> <span class="token string">"<span class="token variable">${GOROOT}</span>"</span><span class="token variable">)</span></span>/bin<span class="token string">"</span>
<span class="token string">    </span>
<span class="token string">    export PATH="</span><span class="token variable">$GOBIN</span><span class="token builtin class-name">:</span><span class="token environment constant">$PATH</span>"
  <span class="token keyword">fi</span>
<span class="token punctuation">}</span>
asdf_update_golang_env
</code></pre></div>
<p>After adding this, reload your shell:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">source</span> ~/.bashrc
</code></pre></div>
<h2>How <code>.tool-versions</code> File Works with <code>asdf local</code></h2>
<p>When you use the <code>asdf local</code> command in a project directory, <code>asdf</code> creates a file named <code>.tool-versions</code> in that directory. This file stores the language versions that <code>asdf</code> should use when you are within that specific directory.</p>
<h3>Example of <code>.tool-versions</code>:</h3>
<p>If you run the following command in your project directory:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">asdf <span class="token builtin class-name">local</span> golang <span class="token number">1.22</span>.6
</code></pre></div>
<p>It will create a <code>.tool-versions</code> file in that directory with the following content:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">golang <span class="token number">1.22</span>.6
</code></pre></div>
<p>This file tells <code>asdf</code> to use Go version <code>1.22.6</code> whenever you are in that project directory. If you have other languages managed by <code>asdf</code> (e.g., Node.js, Python), their versions would also be listed in this file.</p>
<h3>How <code>.tool-versions</code> Affects Version Selection</h3>
<ul>
<li>
<p><strong>Local Version</strong>: When you navigate to the directory containing the <code>.tool-versions</code> file, <code>asdf</code> automatically switches to the specified version of Go (or other languages) for that project.</p>
</li>
<li>
<p><strong>Global Version Override</strong>: The versions specified in the <code>.tool-versions</code> file take precedence over any global versions you have set with <code>asdf global</code>. This allows you to customize the language environment for each project without affecting others.</p>
</li>
<li>
<p><strong>Project-Specific Setup</strong>: This is particularly useful when working on multiple projects that require different versions of the same language. The <code>.tool-versions</code> file ensures that you are always using the correct version for the project at hand.</p>
</li>
</ul>
<h2>Checking Installation of Global Go Packages</h2>
<p>After installing Go, you can install global Go packages using <code>go install</code>. Here’s how you can check that a package is installed globally:</p>
<ol>
<li>
<p><strong>Install a Package Globally</strong>:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">go <span class="token function">install</span> github.com/air-verse/air@latest
</code></pre></div>
</li>
<li>
<p><strong>Check Installation</strong>:
After installation, verify that the package was installed globally by running:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">air <span class="token parameter variable">-v</span>
</code></pre></div>
<p>This command should display the version of <code>air</code>, confirming that the installation was successful.</p>
</li>
</ol>
<h2>Managing Go Versions with <code>asdf</code></h2>
<p><code>asdf</code> makes it easy to switch between different versions of Go, whether globally or locally for a specific project.</p>
<h3>Installing Multiple Versions of Go</h3>
<ul>
<li>
<p><strong>Install a New Version</strong>:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">asdf <span class="token function">install</span> golang <span class="token number">1.18</span>.3
</code></pre></div>
</li>
<li>
<p><strong>Set a Global Version</strong>:
To set <code>1.18.3</code> as the global version:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">asdf global golang <span class="token number">1.18</span>.3
</code></pre></div>
</li>
<li>
<p><strong>Set a Local Version</strong>:
If you want to use a different version for a specific project, navigate to the project directory and run:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">asdf <span class="token builtin class-name">local</span> golang <span class="token number">1.22</span>.6
</code></pre></div>
</li>
</ul>
<h3>Switching Between Versions</h3>
<p>You can easily switch between different Go versions using <code>asdf</code>. For example:</p>
<ul>
<li>
<p>To switch to a globally installed version:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">asdf global golang <span class="token number">1.22</span>.6
</code></pre></div>
</li>
<li>
<p>To switch to a version for a specific project:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">asdf <span class="token builtin class-name">local</span> golang <span class="token number">1.18</span>.3
</code></pre></div>
</li>
</ul>
<h2>Conclusion</h2>
<p>With <code>asdf</code> and the <code>asdf-golang</code> plugin, managing multiple versions of Go on Debian becomes effortless. By following the steps outlined in this guide, you’ll have a robust setup that allows you to switch between Go versions seamlessly, manage your Go environment variables efficiently, and ensure your projects are always using the correct Go version. Happy coding!</p>
]]></description>
            <link>https://rahuljuliato.com/posts/golang_debian</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/golang_debian</guid>
            <pubDate>Wed, 14 Aug 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[Creating Conway's Game of Life with React and TypeScript]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Join me as I revisit a ReactJS and TypeScript project I created two
years ago: an interactive version of Conway's Game of Life. This
journey started as a personal challenge where I wrote the entire code
off the top of my head without any refactoring. In this blog post,
I'll walk you through the technical aspects of the project and reflect
on the growth I've experienced as a developer since then. Let's dive
into the fascinating world of cellular automata and see how this
project evolved.</p>
<h2>Introduction</h2>
<p>Welcome to my (not so) latest creation: a ReactJS application that
brings Conway's Game of Life to your screen! This project,
bootstrapped with Vite and written in TypeScript, was originally
created about two years ago as a personal challenge. My goal was to
write it off the top of my head without refactoring anything
later. This led to some peculiar choices, such as the usage of Ramda,
which I initially thought would be useful for a different
implementation, and well, I regret.</p>
<p>I've opted to keep the code "as is," even though I would most
certainly write it differently today. This is a good indicator of a
programmer's evolution: looking at past code and thinking, "What was I
thinking? This should be completely different." For our 'fun,' let's
see what is in this code.</p>
<h2>Motivation</h2>
<p>The Game of Life is a zero-player game developed by John Conway
in 1970. It consists of a grid of cells that can be either alive or
dead. The game evolves through generations based on simple rules: a
living cell with fewer than two or more than three living neighbors
dies, while a dead cell with exactly three living neighbors becomes
alive. Despite these simple rules, the Game of Life produces
remarkably complex and beautiful patterns.</p>
<p>This project demonstrates how React's component-based architecture and
TypeScript's type safety can be leveraged to build a dynamic and
visually appealing application. Creating a modern, interactive version
using these technologies was both a personal challenge and an
opportunity to provide a fun and educational tool for others.</p>
<p>A quick preview of the project running:</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fgame_of_life_demo.gif&w=3840&q=75" alt="Game_of_Life"></p>
<h2>Technical Aspects</h2>
<p>Here's a breakdown of the technical aspects of the project:</p>
<h3>Setup</h3>
<p>The project is bootstrapped with Vite, which provides a fast and lean
development environment. We use TypeScript for type safety and
improved developer experience. Key dependencies include:</p>
<p>• React: For building the user interface.</p>
<p>• echarts-for-react: For visualizing the number of living cells over generations.</p>
<p>• Ramda: For functional programming utilities.</p>
<h3>Components and State Management</h3>
<p>The application consists of the following main components:</p>
<p>• <strong>App Component</strong>: The root component managing the overall state and
rendering the UI.</p>
<p>• <strong>LifeGrid</strong>: A 2D array representing the grid of cells, where each
cell can be alive or dead.</p>
<p>• <strong>Controls</strong>: Buttons and checkboxes for user interactions, such as
starting/stopping the simulation, randomizing the grid, and toggling
border constraints.</p>
<p>We use React's <code>useState</code> and <code>useEffect</code> hooks to manage state and
lifecycle events, ensuring a responsive and interactive experience.</p>
<h3>Game Logic</h3>
<p>The core logic of the Game of Life involves:</p>
<p>• <strong>Generating the Grid</strong>: Creating a grid with a specified number of
rows and columns, optionally randomizing the initial state of cells.</p>
<p>• <strong>Counting Neighbors</strong>: Determining the number of alive neighbors
for each cell, considering border constraints.</p>
<p>• <strong>Updating the Grid</strong>: Applying the rules of the Game of Life to
update the state of each cell based on its neighbors.</p>
<h4>Generating the Grid</h4>
<div class="remark-highlight"><pre class="language-typescript"><code class="language-typescript"><span class="token keyword">const</span> generateLifeGrid <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">{</span>
  lines <span class="token operator">=</span> <span class="token constant">DEFAULT_LINES</span><span class="token punctuation">,</span>
  columns <span class="token operator">=</span> <span class="token constant">DEFAULT_COLS</span><span class="token punctuation">,</span>
  randomize <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token operator">:</span> ILifeGridProps<span class="token punctuation">)</span><span class="token operator">:</span> LifeGrid <span class="token operator">=></span>
  <span class="token builtin">Array</span><span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span><span class="token function">Array</span><span class="token punctuation">(</span>lines<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">Array</span><span class="token punctuation">(</span>columns<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>line<span class="token punctuation">,</span> lineIndex<span class="token punctuation">)</span> <span class="token operator">=></span>
    line<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>_col<span class="token punctuation">,</span> colIndex<span class="token punctuation">)</span> <span class="token operator">=></span>
      <span class="token function">generateLifeCell</span><span class="token punctuation">(</span>
        lineIndex<span class="token punctuation">,</span>
        colIndex<span class="token punctuation">,</span>
        randomize <span class="token operator">?</span> Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&#x3C;</span> <span class="token constant">DEFAULT_RANDOM_PROBABILITY_OF_LIFE</span> <span class="token operator">:</span> <span class="token boolean">false</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>
<h4>Counting Neighbors</h4>
<div class="remark-highlight"><pre class="language-typescript"><code class="language-typescript"><span class="token keyword">const</span> countCellNeighbors <span class="token operator">=</span> <span class="token punctuation">(</span>
  line<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">,</span>
  col<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">,</span>
  lifeGrid<span class="token operator">:</span> LifeGrid<span class="token punctuation">,</span>
  isBorderLimited<span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">,</span>
<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token builtin">number</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> lastLine <span class="token operator">=</span> lifeGrid<span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> lastCol <span class="token operator">=</span> lifeGrid<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>length <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>

  <span class="token keyword">return</span> <span class="token punctuation">(</span>
    isBorderLimited
      <span class="token operator">?</span> <span class="token punctuation">[</span>
          line <span class="token operator">!==</span> <span class="token number">0</span> <span class="token operator">?</span> <span class="token function">pathOr</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>line <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> col <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lifeGrid<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
          line <span class="token operator">!==</span> <span class="token number">0</span> <span class="token operator">?</span> <span class="token function">pathOr</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>line <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> col<span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lifeGrid<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
          line <span class="token operator">!==</span> <span class="token number">0</span> <span class="token operator">?</span> <span class="token function">pathOr</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>line <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> col <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lifeGrid<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
          col <span class="token operator">!==</span> <span class="token number">0</span> <span class="token operator">?</span> <span class="token function">pathOr</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>line<span class="token punctuation">,</span> col <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lifeGrid<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
          <span class="token function">pathOr</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>line<span class="token punctuation">,</span> col <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lifeGrid<span class="token punctuation">)</span><span class="token punctuation">,</span>
          col <span class="token operator">!==</span> <span class="token number">0</span> <span class="token operator">?</span> <span class="token function">pathOr</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>line <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> col <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lifeGrid<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
          <span class="token function">pathOr</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>line <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> col<span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lifeGrid<span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token function">pathOr</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>line <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> col <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lifeGrid<span class="token punctuation">)</span><span class="token punctuation">,</span>
        <span class="token punctuation">]</span>
      <span class="token operator">:</span> <span class="token punctuation">[</span>
          <span class="token function">pathOr</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>line <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">?</span> line <span class="token operator">-</span> <span class="token number">1</span> <span class="token operator">:</span> lastLine<span class="token punctuation">,</span> col <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lifeGrid<span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token function">pathOr</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>line <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">?</span> line <span class="token operator">-</span> <span class="token number">1</span> <span class="token operator">:</span> lastLine<span class="token punctuation">,</span> col<span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lifeGrid<span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token function">pathOr</span><span class="token punctuation">(</span>
            <span class="token boolean">false</span><span class="token punctuation">,</span>
            <span class="token punctuation">[</span>line <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">?</span> line <span class="token operator">-</span> <span class="token number">1</span> <span class="token operator">:</span> lastLine<span class="token punctuation">,</span> col <span class="token operator">&#x3C;</span> lastCol <span class="token operator">?</span> col <span class="token operator">+</span> <span class="token number">1</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
            lifeGrid<span class="token punctuation">,</span>
          <span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token function">pathOr</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>line<span class="token punctuation">,</span> col <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">?</span> col <span class="token operator">-</span> <span class="token number">1</span> <span class="token operator">:</span> lastCol<span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lifeGrid<span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token function">pathOr</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>line<span class="token punctuation">,</span> col <span class="token operator">&#x3C;</span> lastCol <span class="token operator">?</span> col <span class="token operator">+</span> <span class="token number">1</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lifeGrid<span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token function">pathOr</span><span class="token punctuation">(</span>
            <span class="token boolean">false</span><span class="token punctuation">,</span>
            <span class="token punctuation">[</span>line <span class="token operator">&#x3C;</span> lastLine <span class="token operator">?</span> line <span class="token operator">+</span> <span class="token number">1</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> col <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">?</span> col <span class="token operator">-</span> <span class="token number">1</span> <span class="token operator">:</span> lastCol<span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
            lifeGrid<span class="token punctuation">,</span>
          <span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token function">pathOr</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>line <span class="token operator">&#x3C;</span> lastLine <span class="token operator">?</span> line <span class="token operator">+</span> <span class="token number">1</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> col<span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> lifeGrid<span class="token punctuation">)</span><span class="token punctuation">,</span>
          <span class="token function">pathOr</span><span class="token punctuation">(</span>
            <span class="token boolean">false</span><span class="token punctuation">,</span>
            <span class="token punctuation">[</span>line <span class="token operator">&#x3C;</span> lastLine <span class="token operator">?</span> line <span class="token operator">+</span> <span class="token number">1</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> col <span class="token operator">&#x3C;</span> lastCol <span class="token operator">?</span> col <span class="token operator">+</span> <span class="token number">1</span> <span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token string">"isAlive"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
            lifeGrid<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 function">filter</span><span class="token punctuation">(</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span> <span class="token operator">=></span> x<span class="token punctuation">)</span><span class="token punctuation">.</span>length<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div>
<h4>Upgrading the Grid</h4>
<div class="remark-highlight"><pre class="language-typescript"><code class="language-typescript"><span class="token keyword">const</span> updateLifeGrid <span class="token operator">=</span> <span class="token punctuation">(</span>lifeGrid<span class="token operator">:</span> LifeGrid<span class="token punctuation">,</span> isBorderLimited<span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">)</span><span class="token operator">:</span> LifeGrid <span class="token operator">=></span>
  lifeGrid<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>line<span class="token punctuation">,</span> lineIndex<span class="token punctuation">)</span> <span class="token operator">=></span>
    line<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span>cell<span class="token punctuation">,</span> colIndex<span class="token punctuation">)</span> <span class="token operator">=></span>
      <span class="token function">generateLifeCell</span><span class="token punctuation">(</span>
        lineIndex<span class="token punctuation">,</span>
        colIndex<span class="token punctuation">,</span>
        <span class="token function">generateFutureAliviness</span><span class="token punctuation">(</span>
          cell<span class="token punctuation">.</span>isAlive<span class="token punctuation">,</span>
          <span class="token function">countCellNeighbors</span><span class="token punctuation">(</span>lineIndex<span class="token punctuation">,</span> colIndex<span class="token punctuation">,</span> lifeGrid<span class="token punctuation">,</span> isBorderLimited<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>
</code></pre></div>
<h4>Evolution Visualization</h4>
<p>We use echarts-for-react to display a line chart tracking the number
of living cells over generations. This provides a visual
representation of the simulation's progress and helps users understand
the dynamics of the cellular automaton.</p>
<div class="remark-highlight"><pre class="language-typescript"><code class="language-typescript"><span class="token keyword">const</span> initialChartOptions <span class="token operator">=</span> <span class="token punctuation">{</span>
  xAxis<span class="token operator">:</span> <span class="token punctuation">{</span>
    type<span class="token operator">:</span> <span class="token string">"category"</span><span class="token punctuation">,</span>
    show<span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
    color<span class="token operator">:</span> <span class="token string">"red"</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  yAxis<span class="token operator">:</span> <span class="token punctuation">{</span>
    type<span class="token operator">:</span> <span class="token string">"value"</span><span class="token punctuation">,</span>
    show<span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>
  tooltip<span class="token operator">:</span> <span class="token punctuation">{</span>
    axisPointer<span class="token operator">:</span> <span class="token punctuation">{</span>
      type<span class="token operator">:</span> <span class="token string">"cross"</span><span class="token punctuation">,</span>
      snap<span class="token operator">:</span> <span class="token boolean">true</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>
  series<span class="token operator">:</span> <span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
      data<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
      showSymbol<span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
      type<span class="token operator">:</span> <span class="token string">"line"</span><span class="token punctuation">,</span>
      lineStyle<span class="token operator">:</span> <span class="token punctuation">{</span> color<span class="token operator">:</span> <span class="token string">"rgba(0, 200, 200, 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>
</code></pre></div>
<h2>Conclusion</h2>
<p>Creating Conway's Game of Life using React and TypeScript was an
exciting and educational journey. The project demonstrates how modern
web development tools can be used to create interactive and visually
appealing applications quite quickly. I hope this project inspires you
to explore the fascinating world of cellular automata and build your
own creations.</p>
<p>Also, revisiting old code can be a valuable exercise for any
developer. Looking back at this project, I see many areas where I
would take a different approach today. This reflection highlights my
growth and development as a programmer. It's a good sign when you can
look at your past work and think, "What was I thinking? This should be
completely different." It means you are continually learning and
improving.</p>
<p><a href="https://lionyxml.github.io/react-game-of-life/">Play the Game of Life
here!</a></p>
<p>Feel free to check out the <a href="https://github.com/LionyxML/react-game-of-life">source code on
GitHub</a> for more
details and to contribute to the project.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/react-game-of-life</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/react-game-of-life</guid>
            <pubDate>Sun, 30 Jun 2024 11:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Github to Codeberg Bulk Migration Script]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Are you considering migrating your GitHub repositories to Codeberg but
finding the process daunting? Look no further! In this blog post, we
introduce a powerful solution: the "Github to Codeberg Bulk Migration
Script." This script offers a nice way to transfer your projects from
GitHub to Codeberg, leveraging automation to simplify the process.</p>
<p>In recent years, the landscape of code hosting platforms has expanded
beyond the traditional giants. Codeberg, a community-driven and
open-source alternative to GitHub, has gained traction among
developers seeking a platform aligned with principles of privacy,
transparency, and community governance. In this blog post, we'll
explore how to migrate your repositories from GitHub to Codeberg using
a simple and efficient migration script.</p>
<h2>Why Codeberg?</h2>
<p>Codeberg is indeed a noteworthy alternative to GitHub, particularly
for those seeking an open-source and community-driven platform. Here's
why Codeberg stands out:</p>
<p>• <strong>Open Source Philosophy:</strong> Codeberg operates on an open-source
philosophy, ensuring transparency and fostering a collaborative
environment where developers can freely contribute to projects.</p>
<p>• <strong>Privacy and Data Sovereignty:</strong> Codeberg prioritizes user privacy and
data sovereignty, providing a platform where users have control over
their data and can trust that it won't be exploited for commercial
purposes.</p>
<p>• <strong>Community and Governance:</strong> Codeberg is community-driven, allowing users
to participate in decision-making processes and shape the direction of
the platform. This democratic approach ensures that the platform
evolves in line with the needs and values of its users.</p>
<p>• <strong>Support for Free and Open Source Software (FOSS):</strong> Codeberg is
committed to promoting and supporting free and open-source software,
providing a home for projects that align with these principles.</p>
<h2>Why Bulk Migration Matters</h2>
<p>Migrating repositories one by one can be a tedious and time-consuming
task, especially if you have numerous projects to transfer. Bulk
migration streamlines this process by allowing you to transfer
multiple repositories simultaneously, significantly reducing the time
and effort required.</p>
<h2>Introducing the Migration Script</h2>
<p>This is a bash script designed to simplify the migration of
repositories from GitHub to Codeberg. It automates the migration
process, making it easy to transfer your projects in bulk while
preserving their metadata and access permissions.</p>
<h2>Key Features</h2>
<ol>
<li>
<p>• <strong>Bulk Migration</strong>: The script allows you to migrate multiple
repositories from GitHub to Codeberg simultaneously, saving you
time and effort.</p>
</li>
<li>
<p>• <strong>Customization Options</strong>: You can customize various aspects of the
migration process, including repository selection and description
prefix, to suit your specific requirements.</p>
</li>
<li>
<p>• <strong>Error Handling</strong>: The script includes error handling mechanisms
to handle any migration failures gracefully, ensuring a smooth and
reliable migration process.</p>
</li>
</ol>
<h2>Preparing the Ground</h2>
<p>Before diving into the migration process, you'll need to obtain API
keys from GitHub and Codeberg. Here's how you can do it:</p>
<h3>Obtaining API Key from GitHub</h3>
<ol>
<li>
<p>• <strong>Visit GitHub Developer Settings</strong>: Go to your GitHub account
settings and navigate to the "Developer settings" section.</p>
</li>
<li>
<p>• <strong>Create a Personal Access Token</strong>: Click on "Personal access
tokens" and then "Generate new token." Provide a descriptive name
for the token and select the desired scopes (e.g., <code>repo</code> for full
access to repositories). Click "Generate token" to create the
token.</p>
</li>
<li>
<p>• <strong>Copy the Token</strong>: Once the token is generated, make sure to copy
it immediately. GitHub will not display the token again for
security reasons.</p>
</li>
</ol>
<h3>Obtaining API Key from Codeberg</h3>
<ol>
<li>
<p>• <strong>Access Codeberg Account Settings</strong>: Log in to your Codeberg
account and navigate to the account settings page.</p>
</li>
<li>
<p>• <strong>Generate Personal Access Token</strong>: In the settings menu, select
"Applications" and then click on "Generate new token." Provide a
name for the token and select the necessary scopes (e.g., <code>repo</code>
for repository access).</p>
</li>
<li>
<p>• <strong>Save the Token</strong>: After generating the token, make sure to save
it securely. Like GitHub, Codeberg will not display the token
again, so it's essential to store it in a safe location.</p>
</li>
</ol>
<p>With your API keys in hand, you're now ready to proceed with the
migration process using the "GitHub to Codeberg Bulk Migration
Script."</p>
<h2>How It Works</h2>
<p>Before proceeding with the migration process, it's crucial to ensure
that you understand the script's functionality and potential
implications. Here's how you can get started:</p>
<ol>
<li>
<p>• <strong>Download the Script</strong>: Begin by downloading the migration script
from the following repository:</p>
<ul>
<li>• <a href="https://codeberg.org/LionyxML/migrate-github-to-codeberg">Codeberg
Repository</a></li>
<li>• <a href="https://github.com/LionyxML/migrate-github-to-codeberg">GitHub
Repository</a></li>
</ul>
</li>
<li>
<p>• <strong>Read the Script</strong>: Once downloaded, take the time to thoroughly
read and understand the script
(<code>migrate_github_to_codeberg.sh</code>). It's essential never to run a
script without comprehending its functionality and potential
effects on your system. While the script is provided as a helpful
tool, it comes with no warranties, and understanding its behavior
is critical for a safe and successful migration. Here's what you'll
find in the user configuration section:</p>
</li>
</ol>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token comment"># User Configuration:</span>
<span class="token comment"># --------------------</span>
<span class="token comment"># GitHub username and personal access token</span>
<span class="token comment"># GITHUB_USERNAME="YourGitHubUsername"</span>
<span class="token comment"># GITHUB_TOKEN="YourGitHubToken"</span>
<span class="token comment">#</span>
<span class="token comment"># Codeberg username and personal access token</span>
<span class="token comment"># CODEBERG_USERNAME="YourCodebergUsername"</span>
<span class="token comment"># CODEBERG_TOKEN="YourCodebergToken"</span>
<span class="token comment">#</span>
<span class="token comment"># Define the REPOSITORIES array with repository names you want to migrate</span>
<span class="token comment"># Leave it blank to migrate all repositories, or create a list of repositories</span>
<span class="token comment"># if you want to select specific ones.</span>
<span class="token comment"># REPOSITORIES=(</span>
<span class="token comment">#     "repository1"</span>
<span class="token comment">#     "repository2"</span>
<span class="token comment">#     "repository3"</span>
<span class="token comment"># )</span>
<span class="token comment">#</span>
<span class="token comment"># Custom prefix for description</span>
<span class="token comment"># DESCRIPTION_PREFIX=""</span>
<span class="token comment"># or something like:</span>
<span class="token comment"># DESCRIPTION_PREFIX="[MIRROR] "</span>
</code></pre></div>
<ol start="3">
<li>
<p>• <strong>Configure User Settings</strong>: Open the script in a text editor and
navigate to the user configuration section. Here, you'll need to
update your GitHub and Codeberg credentials, as well as any other
settings according to your preferences.</p>
</li>
<li>
<p>• <strong>Review Customization Options</strong>: Take advantage of the script's
customization options to tailor the migration process to your
specific needs. You can define the repositories you want to
migrate, specify a description prefix, and adjust other parameters
as required.</p>
</li>
<li>
<p>• <strong>Install Dependencies</strong>: Ensure that the necessary dependencies,
such as <code>curl</code> and <code>jq</code>, are installed on your system to facilitate
the migration process. You can install these dependencies using
your system's package manager.</p>
</li>
<li>
<p>• <strong>Run the Script</strong>: Once you've reviewed and configured the script
to your satisfaction, execute it in your terminal by running
<code>./migrate_github_to_codeberg.sh</code>. Follow the on-screen
instructions to initiate the migration process.</p>
</li>
<li>
<p>• <strong>Monitor Progress and Review Results</strong>: The script will provide
real-time updates on the migration progress, allowing you to
monitor successful migrations and identify any errors
encountered. Once the migration is complete, review the results to
ensure that all desired repositories have been successfully
migrated to Codeberg.</p>
</li>
</ol>
<h2>Some output examples</h2>
<p>Migrating some few repositories with the prefix <code>[MIRROR] </code> to the
description of the repository.</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">----------------------------------------------
    Welcome to Github to Codeberg Migration Script
    ----------------------------------------------

    User on Github          <span class="token builtin class-name">:</span> LionyxML
    User on Codeberg        <span class="token builtin class-name">:</span> LionyxML
    Using description prefix: <span class="token punctuation">[</span>MIRROR<span class="token punctuation">]</span> 
    Migrating repo          <span class="token builtin class-name">:</span> aa
    Migrating repo          <span class="token builtin class-name">:</span> dotfiles
    Migrating repo          <span class="token builtin class-name">:</span> flycheck
    Migrating repo          <span class="token builtin class-name">:</span> my_emacs_config

    If you wish to change this, abort and change this script.



    Press ENTER to continue, C-c to abort.


<span class="token operator">>></span><span class="token operator">></span> Working<span class="token punctuation">..</span>.
<span class="token operator">>></span><span class="token operator">></span> Migrating: aa<span class="token punctuation">..</span>. Error<span class="token operator">!</span> Already exists on Codeberg.
<span class="token operator">>></span><span class="token operator">></span> Migrating: flycheck<span class="token punctuation">..</span>. Success<span class="token operator">!</span>
<span class="token operator">>></span><span class="token operator">></span> Migration complete<span class="token operator">!</span>
</code></pre></div>
<p>Migrating all repositories.</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">Github to Codeberg Migration Script
    ----------------------------------------------

    User on Github          <span class="token builtin class-name">:</span> LionyxML
    User on Codeberg        <span class="token builtin class-name">:</span> LionyxML
    Using description prefix: <span class="token punctuation">[</span>MIRROR<span class="token punctuation">]</span> 
    Migrating repo          <span class="token builtin class-name">:</span> all

    If you wish to change this, abort and change this script.



    Press ENTER to continue, C-c to abort.


<span class="token operator">>></span><span class="token operator">></span> Working<span class="token punctuation">..</span>.
<span class="token operator">>></span><span class="token operator">></span> Migrating: 100_computer_science_concepts<span class="token punctuation">..</span>. Error<span class="token operator">!</span> Already exists on Codeberg.
<span class="token operator">>></span><span class="token operator">></span> Migrating: 10_design_patterns<span class="token punctuation">..</span>. Error<span class="token operator">!</span> Already exists on Codeberg.
<span class="token operator">>></span><span class="token operator">></span> Migrating: aa<span class="token punctuation">..</span>. Error<span class="token operator">!</span> Already exists on Codeberg.
<span class="token punctuation">..</span>.
</code></pre></div>
<p>Notice it can fail for one or other repository (eg.: it is already
migrated from another script run), but it keeps going until the end.</p>
<p>By following these steps and exercising caution throughout the
process, you can safely and efficiently migrate your repositories from
GitHub to Codeberg using the provided script. Remember to always read
and understand scripts before execution, and proceed with care to
ensure a smooth transition.</p>
<h2>Limitations</h2>
<p>While the script offers a convenient solution for transferring
repositories, there are some limitations to be aware of:</p>
<ul>
<li>
<p>• <strong>Repository Quota</strong>: Codeberg limits the number of repositories per
user to 100 by default. If you have more than 100 repositories to
migrate, you'll need to request a higher quota following their
instructions. Additionally, Codeberg mirrors repositories, meaning
that a repository on Codeberg acts as a mirror of the original
repository on GitHub. This may affect certain functionalities, such
as repository forks and pull requests.</p>
</li>
<li>
<p>• <strong>API Changes and Improvements</strong>: As with any script utilizing
external APIs, there's a possibility that API endpoints or
functionalities may change over time. Codeberg may also introduce
new features or improvements to their platform, offering better
options for migration. It's essential to keep this in mind and
periodically review and update the script to align with any changes
or enhancements.</p>
</li>
<li>
<p>• <strong>Local Repository Copies</strong>: The migration script only handles the
transfer of repository metadata and contents to Codeberg. Your local
copies of repositories will remain unaffected by the migration
process. After running the script, you'll need to manually add a new
remote for each repository pointing to Codeberg and push the changes
to both GitHub and Codeberg remotes until you feel confident that
the migration is complete.</p>
</li>
</ul>
<p>To add a new remote for a repository and push to both GitHub and
Codeberg remotes using SSH, follow these steps:</p>
<p>1 . <strong>Navigate to Repository Directory</strong>: Open the terminal and
navigate to the directory of the repository you want to migrate.</p>
<p>2 . <strong>Edit <code>.git/config</code></strong>: Open the <code>.git/config</code> file in a text
editor. Add a new remote entry under the <code>[remote "codeberg"]</code>
section with the SSH URL of your Codeberg repository. Here's an
example of how it might look:</p>
<div class="remark-highlight"><pre class="language-ini"><code class="language-ini"><span class="token section"><span class="token punctuation">[</span><span class="token section-name selector">remote "codeberg"</span><span class="token punctuation">]</span></span>
   <span class="token key attr-name">url</span> <span class="token punctuation">=</span> <span class="token value attr-value">git@codeberg.org:YourUsername/YourRepository.git</span>
   <span class="token key attr-name">fetch</span> <span class="token punctuation">=</span> <span class="token value attr-value">+refs/heads/*:refs/remotes/codeberg/*</span>
</code></pre></div>
<p>3 . <strong>Save and Close:</strong> Save the changes to the .git/config file and
close the text editor.</p>
<p>4 . <strong>Push Changes:</strong> In the terminal, run the following commands to
push changes to both GitHub and Codeberg remotes:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">git</span> push origin master  <span class="token comment"># Push changes to GitHub</span>
<span class="token function">git</span> push codeberg master  <span class="token comment"># Push changes to Codeberg</span>
</code></pre></div>
<p>Of course you could also do it without checking your config with:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">git</span> remote <span class="token function">add</span> codeberg git@codeberg.org:YourUsername/YourRepository.git
</code></pre></div>
<p>Repeat these steps for each repository you've migrated until you feel
confident that the migration process is complete. Or maybe you'll feel
in the mood to hack a script to do it 😉.</p>
<p>As one can see, this script provides a solid foundation for repository
migration, users are encouraged to customize and enhance it according
to their specific use cases and requirements. By leveraging the
script's flexibility, users can optimize the migration process to suit
their individual needs and preferences.</p>
<h2>Deleting API Keys</h2>
<p>After completing the migration process, it's essential to delete the
API keys you generated for GitHub and Codeberg to maintain
security. Follow the respective platforms' instructions to revoke or
delete the API keys from your account settings.</p>
<h2>Conclusion</h2>
<p>The "GitHub to Codeberg Bulk Migration Script" offers a simple and
efficient solution for migrating your repositories from GitHub to
Codeberg in bulk. By automating the migration process, this script
saves you time and effort while ensuring a seamless transition to
Codeberg. Whether you're migrating a handful of projects or an
extensive portfolio of repositories, this script has got you
covered. Say goodbye to manual migration headaches and embrace the
convenience of bulk migration with this powerful script.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/github_to_codeberg</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/github_to_codeberg</guid>
            <pubDate>Sat, 11 May 2024 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Nerd Fonts Installer]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>In the world of programming, where every character counts and
readability is paramount, the choice of font may seem like a minor
detail. Yet, for those who spend countless hours staring at code
editors, terminals, and documentation, the right font can make a
significant difference in productivity and comfort. Enter Nerd Fonts –
the unsung heroes of the programming world.</p>
<p>In this blog post, we'll explore how this installer simplifies the
process of selecting and installing Nerd Fonts, revolutionizing the
way programmers customize their coding environments.</p>
<h2>A quick word about the motivation for this little project</h2>
<p>I was hanging out in the <code>#systemcrafters</code> IRC channel on
<code>libera.chat</code> when <code>David Wilson</code> shared a cool idea: building slides
from scratch using Guile Scheme. The slides looked pretty slick, and
they were using the Iosevka font. Remembering my past fondness for
Iosevka and similar fonts geared towards programming, I thought it
might be time for a reunion.</p>
<p>Curious about what fonts others were into, I asked in the channel. The
folks there, whose names I unfortunately didn't jot down (my bad for
not saving the chat), mentioned they were big fans of Hack, Source
Code Pro, and, of course, Iosevka.</p>
<p>Eager to get Iosevka back on my main machine, I started on a mission,
only to hit a snag: there was no Debian 12 package available. After
some thought and briefly considering creating my own Debian package,
it hit me: Nerd Fonts! A collection of patched fonts I've relied on
across all my apps.</p>
<p>And so, this project was born — a handy solution for grabbing,
installing, and showcasing a range of fonts with minimal hassle.</p>
<h2>Step 1: Obtain the Nerd Fonts Installer</h2>
<p>To begin, download the Nerd Fonts Installer script from its official
<a href="https://github.com/LionyxML/nerd-installer">GitHub repository</a> or the
provided <a href="https://codeberg.org/LionyxML/nerd-installer">mirror
link</a>. This script
serves as a gateway to effortlessly install the entire collection of
Nerd Fonts onto your system.</p>
<h2>Step 2: Review Dependencies</h2>
<p>Before running the installer script, ensure that your system meets the
necessary dependencies. These include:</p>
<ul>
<li><strong>bash</strong>: The Bourne Again Shell, required to execute the script.</li>
<li><strong>wget</strong>: Used to download font files from the internet.</li>
<li><strong>unzip</strong>: Used to extract downloaded zip files.</li>
</ul>
<p>You can install these dependencies using your system's package
manager. For instance, on Debian-based systems like Ubuntu, execute
the following commands:</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> update
<span class="token function">sudo</span> <span class="token function">apt-get</span> <span class="token function">install</span> <span class="token function">bash</span> <span class="token function">wget</span> <span class="token function">unzip</span>
</code></pre></div>
<p>Or on MacOS with the brew package manager:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">brew update
brew <span class="token function">install</span> <span class="token function">bash</span> <span class="token function">wget</span> <span class="token function">unzip</span>
</code></pre></div>
<h2>Step 3: Customize Font Selection (Optional)</h2>
<p>The Nerd Fonts Installer comes pre-configured with a list of fonts to
install. However, if you wish to customize your font selection, you
can do so by modifying the installer script. Simply comment out or
remove the fonts you don't want to install and save the changes.</p>
<p>Please note each font have its own LICENSE, read it on the official
NerdFonts repository, and mark only those you agree with. Also,
marking more fonts, will take more time and disk space, so, be
mindful.</p>
<h2>Step 4: Run the Installer</h2>
<p>Execute the installer script by navigating to the directory where it's
located and running the following command:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">./nerd-installer.sh
</code></pre></div>
<p>The script will download and install the complete Nerd Fonts
collection effortlessly. Sit back and relax as it automates the
process for you.</p>
<h2>Step 5: Verify Installation</h2>
<p>Once the installation is complete, verify that the fonts have been
successfully installed on your system. You can do this by checking
your system's font directory or using font management tools provided
by your operating system.</p>
<h2>Step 6: Integrate with Your IDE or Text Editor</h2>
<p>Now that you've got Nerd Fonts installed, it's time to seamlessly
integrate them into your preferred Integrated Development Environment
(IDE) or text editor. Most modern IDEs and text editors offer
customizable font settings. Simply navigate to the settings menu,
select your desired Nerd Font from the list of available fonts, and
apply the changes.</p>
<p>Here's an additional tip for GUI Emacs users: You can easily list all
available fonts for Emacs using its own font as a reference line with
a custom Elisp function:</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">lemacs/all-available-fonts</span> <span class="token punctuation">(</span><span class="token arguments"></span><span class="token punctuation">)</span></span>
  <span class="token string">"Create and visit a buffer containing a sorted list of available fonts."</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">font-list</span> <span class="token punctuation">(</span><span class="token car">sort</span> <span class="token punctuation">(</span><span class="token car">x-list-fonts</span> <span class="token string">"*"</span><span class="token punctuation">)</span> <span class="token quoted-symbol variable symbol">#'string&#x3C;</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">(</span><span class="token car">font-buffer</span> <span class="token punctuation">(</span><span class="token car">generate-new-buffer</span> <span class="token string">"*Font List*"</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> font-buffer
      <span class="token punctuation">(</span><span class="token car">dolist</span> <span class="token punctuation">(</span><span class="token car">font</span> font-list<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">font-family</span> <span class="token punctuation">(</span><span class="token car">nth</span> <span class="token number">2</span> <span class="token punctuation">(</span><span class="token car">split-string</span> font <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 car">insert</span> <span class="token punctuation">(</span><span class="token car">format</span> <span class="token string">"%s\n"</span> <span class="token punctuation">(</span><span class="token car">propertize</span> font <span class="token quoted-symbol variable symbol">'face</span> <span class="token punctuation">`(</span><span class="token lisp-property property">:family</span> <span class="token splice symbol variable">,font-family</span> <span class="token lisp-property property">:height</span> <span class="token number">110</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">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">setq</span> buffer-read-only <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">pop-to-buffer</span> font-buffer<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Evaluating and calling this function will generate a buffer displaying
all available fonts, providing a visual reference for your font
selection process.</p>
<p><img src="https://rahuljuliato.com/_next/image?url=%2Fassets%2Fblog%2Fposts%2Fnerd-emacs-list.png&w=3840&q=75" alt="wrapped-lines"></p>
<p>However, if you've ever found yourself on a font hunt before, you know
that nothing beats actually seeing how a new font looks in your
codebase. Some fonts offer more vertical space, others provide better
horizontal alignment, and some may contrast better with your color
scheme or monitor settings. Additionally, fonts may have varying
heights, even if set to the same "height."</p>
<p>So, experimentation is key.</p>
<p>If you'd like to try font changes on the fly within Emacs, you can
evaluate something like this:</p>
<div class="remark-highlight"><pre class="language-elisp"><code class="language-elisp"><span class="token punctuation">(</span><span class="token car">set-face-attribute</span> <span class="token quoted-symbol variable symbol">'default</span> <span class="token boolean">nil</span> <span class="token lisp-property property">:family</span> <span class="token string">"JetBrainsMono Nerd Font"</span> <span class="token lisp-property property">:height</span> <span class="token number">100</span><span class="token punctuation">)</span>
</code></pre></div>
<p>Notice how the font name seems a bit odd? That's because patched Nerd
Fonts have slightly altered names. Feeling confused? Check out the
next section for a handy table detailing the names you'll need to use
for your font settings.</p>
<h2>Additional Resources</h2>
<p>For more information about Nerd Fonts and to explore the available
fonts, visit the official website: <a href="https://www.nerdfonts.com/">Nerd
Fonts</a>.</p>
<p>Below is a correlation table between the Nerd Font names and their
corresponding Original Font Names and Repositories:</p>
<div class="remark-highlight"><pre class="language-txt"><code class="language-txt">| Font Name                   | Original Font Name                     |
|-----------------------------|----------------------------------------|
| 0xProto Nerd Font           | 0xProto                                |
| 3270 Nerd Font              | 3270                                   |
| Agave Nerd Font             | Agave                                  |
| AnonymicePro Nerd Font      | Anonymous Pro                          |
| Arimo Nerd Font             | Arimo                                  |
| AurulentSansMono Nerd Font  | Aurulent Sans Mono (Stephen G. Hartke) |
| BigBlueTerminal Nerd Font   | BigBlueTerminal (VileR)                |
| BitstromWera Nerd Font      | Vera Sans Mono (Bitstream Inc)         |
| BlexMono Nerd Font          | IBM Plex Mono                          |
| CaskaydiaCove Nerd Font     | Cascadia Code                          |
| CaskaydiaMono Nerd Font     | Cascadia Mono                          |
| CodeNewRoman Nerd Font      | Code New Roman (Sam Radian)            |
| ComicShannsMono Nerd Font   | Comic Shanns Mono                      |
| CommitMono Nerd Font        | Commit Mono                            |
| Cousine Nerd Font           | Cousine                                |
| D2Coding Nerd Font          | D2Coding                               |
| DaddyTimeMono Nerd Font     | DaddyTimeMono                          |
| DejaVuSansMono Nerd Font    | DejaVu                                 |
| DroidSansMono Nerd Font     | Droid Sans Mono (Ascender Corp)        |
| EnvyCodeR Nerd Font         | Envy Code R                            |
| FantasqueSansMono Nerd Font | Fantasque Sans Mono                    |
| FiraCode Nerd Font          | Fira Code                              |
| FiraMono Nerd Font          | Fira Mono                              |
| GeistMono Nerd Font         | Geist Mono                             |
| GoMono Nerd Font            | Go-Mono                                |
| Gohu Nerd Font              | Gohu TTF, Gohu                         |
| Hack Nerd Font              | Hack                                   |
| Hasklug Nerd Font           | Hasklig                                |
| HeavyDataMono Nerd Font     | HeavyData (Vic Fieger)                 |
| Hurmit Nerd Font            | Hermit                                 |
| iM-Writing Nerd Font        | iA-Writer                              |
| Inconsolata Nerd Font       | Inconsolata                            |
| InconsolataGo Nerd Font     | InconsolataGo                          |
| Inconsolata LGC Nerd Font   | Inconsolata LGC                        |
| IntoneMono Nerd Font        | Intel One Mono                         |
| Iosevka Nerd Font           | Iosevka                                |
| IosevkaTerm Nerd Font       | Iosevka Term                           |
| IosevkaTermSlab Nerd Font   | Iosevka Term Slab                      |
| JetBrainsMono Nerd Font     | JetBrains Mono                         |
| Lekton Nerd Font            | Lekton                                 |
| Literation Nerd Font        | Liberation                             |
| Lilex Nerd Font             | Lilex                                  |
| MartianMono Nerd Font       | MartianMono                            |
| Meslo Nerd Font             | Meslo                                  |
| Monaspice Nerd Font         | Monaspace                              |
| Monofur Nerd Font           | Monofur (Tobias B Koehler)             |
| Monoid Nerd Font            | Monoid                                 |
| Mononoki Nerd Font          | Mononoki                               |
| M+ Nerd Font                | MPlus Fonts                            |
| Noto Nerd Font              | Noto                                   |
| OpenDyslexic Nerd Font      | OpenDyslexic                           |
| Overpass Nerd Font          | Overpass                               |
| ProFont Nerd Font           | ProFont                                |
| ProggyClean Nerd Font       | ProggyClean (Tristan Grimmer)          |
| RecMono Nerd Font           | Recursive Mono                         |
| RobotoMono Nerd Font        | Roboto Mono                            |
| SauceCodePro Nerd Font      | Source Code Pro                        |
| ShureTechMono Nerd Font     | Share Tech Mono                        |
| SpaceMono Nerd Font         | Space Mono                             |
| Terminess Nerd Font         | Terminus TTF                           |
| Tinos Nerd Font             | Tinos                                  |
| Ubuntu Nerd Font            | Ubuntu Font                            |
| UbuntuMono Nerd Font        | Ubuntu Font                            |
| UbuntuSans Nerd Font        | Ubuntu Sans                            |
| VictorMono Nerd Font        | Victor Mono                            |
| ZedMono Nerd Font           | Zed Mono                               |</code></pre></div>
<h2>Conclusion</h2>
<p>Integrating Nerd Fonts into your development environment opens up a
world of customization and aesthetic enhancement. Whether you're
coding in your favorite IDE or text editor, experimenting with
different fonts can greatly impact your coding experience.</p>
<p>So, dive in, explore different fonts, and elevate your coding
experience with Nerd Fonts today!</p>
]]></description>
            <link>https://rahuljuliato.com/posts/nerd-fonts</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/nerd-fonts</guid>
            <pubDate>Sun, 28 Apr 2024 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Zod Quick Tutorial]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Validation is a crucial aspect of any application, ensuring that the
data it operates on meets the necessary criteria. However,
implementing robust validation can often be complex and
time-consuming. Enter ZOD, the lightweight and versatile validation
library that simplifies this process without compromising on
functionality.</p>
<h2>Intro</h2>
<p>According to
<a href="https://zod.dev/?id=introduction">https://zod.dev/?id=introduction</a>,
Zod is a TypeScript-first schema declaration and validation library,
where the term "schema" to broadly refer to any data type, from a
simple string to a complex nested object.</p>
<p>Some great aspects of Zod:</p>
<ul>
<li>
<p>Zero dependencies</p>
</li>
<li>
<p>Works in Node.js, Bun and Deno and all modern browsers</p>
</li>
<li>
<p>Tiny: 8kb minified + zipped</p>
</li>
<li>
<p>Immutable: methods (e.g. .optional()) return a new instance</p>
</li>
<li>
<p>Concise, chainable interface</p>
</li>
<li>
<p>Functional approach: parse, don't validate</p>
</li>
<li>
<p>Works with plain JavaScript too! You don't need to use TypeScript.</p>
</li>
</ul>
<h2>Initializing our playground</h2>
<p>To initialize our playground project we will start by creating a generic typescript
project using Vite <a href="https://vitejs.dev/guide/">https://zod.dev/?id=introduction</a>.</p>
<div class="remark-highlight"><pre class="language-shell"><code class="language-shell"><span class="token function">pnpm</span> create vite
</code></pre></div>
<p>We can choose <code>vanilla</code>, <code>typescript</code>, and <code>zod-testing</code> for our project name.</p>
<p>This will create the following tree:</p>
<div class="remark-highlight"><pre class="language-shell"><code class="language-shell">└── zod-testing
    ├── index.html
    ├── package.json
    ├── public
    │   └── vite.svg
    ├── src
    │   ├── counter.ts
    │   ├── main.ts
    │   ├── style.css
    │   ├── typescript.svg
    │   └── vite-env.d.ts
    └── tsconfig.json
</code></pre></div>
<p>You can go ahead and delete almost all files, leaving just these:</p>
<div class="remark-highlight"><pre class="language-shell"><code class="language-shell">└── zod-testing
    ├── index.html
    ├── package.json
    ├── public
    ├── src
    │   └── main.ts
    └── tsconfig.json
</code></pre></div>
<p>You may also empty the contents of <code>main.ts</code>.</p>
<p>Now, cd into zod-testing and install the dependencies:</p>
<div class="remark-highlight"><pre class="language-shell"><code class="language-shell"><span class="token builtin class-name">cd</span> zod-testing
<span class="token function">pnpm</span> <span class="token function">install</span>
</code></pre></div>
<p>Let's now create a hello world message just to see if everything is
working properly. Inside <code>src/main.ts</code>.</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Hello Zod"</span><span class="token punctuation">)</span>
</code></pre></div>
<p>And on the project root run <code>pnpm dev</code>.</p>
<p>You should see something like:</p>
<div class="remark-highlight"><pre class="language-shell"><code class="language-shell">➜ <span class="token function">pnpm</span> dev

<span class="token operator">></span> zod-testing@0.0.0 dev /home/rmj/Projects/github/zod-tutorial/zod-testing
<span class="token operator">></span> vite



  VITE v5.1.6  ready <span class="token keyword">in</span> <span class="token number">100</span> ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use <span class="token parameter variable">--host</span> to expose
  ➜  press h + enter to show <span class="token builtin class-name">help</span>

</code></pre></div>
<p>Navigate to the URL provided (<code>http://localhost:5173/</code> in my case),
you'll see an empty page, but opening your <code>Developer Tools Console</code>
you will get the hello world message.</p>
<p>We're opting on use your browser developer tools because it probably
shows messages formatted in a better way than directly on the console,
besides providing an running REPL instance of V8 context aware of your
project.</p>
<h2>Installing Zod</h2>
<p>We just set a <code>NodeJS</code> project. If you want to use Zod with Deno or Bun, check Zod Introduction Page to check how to to it:
<a href="https://zod.dev/?id=introduction">https://zod.dev/?id=introduction</a>.</p>
<p>To install zod we can just:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts">pnpm install zod
</code></pre></div>
<p>It might be super quick and need no external dependencies.</p>
<h2>Basic Usage</h2>
<p>Very very simple, you import it and start using it. Let's clean our <code>main.ts</code> file and
add:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span>z<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>
</code></pre></div>
<p>Also, please check that your tsconfig.json has the "strict" option under "compilerOptions"
set to true.</p>
<p>Let's start by defining our first schema. Using it and calling our parser.</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">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 punctuation">;</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span> username<span class="token operator">:</span> <span class="token string">"Rahul"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>What the parse function does is basically ask if the provided data
matches our schema.</p>
<p>We might see on the console:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token punctuation">{</span>
    <span class="token string-property property">"username"</span><span class="token operator">:</span> <span class="token string">"Rahul"</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>If we change our username to an invalid option such as:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token operator">...</span>
	<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span> username<span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token operator">...</span>
</code></pre></div>
<p>We now get an error:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts">zod<span class="token punctuation">.</span>js<span class="token operator">?</span>v<span class="token operator">=</span>72bcbb81<span class="token operator">:</span><span class="token number">479</span> Uncaught ZodError<span class="token operator">:</span> <span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    <span class="token string-property property">"code"</span><span class="token operator">:</span> <span class="token string">"invalid_type"</span><span class="token punctuation">,</span>
    <span class="token string-property property">"expected"</span><span class="token operator">:</span> <span class="token string">"string"</span><span class="token punctuation">,</span>
    <span class="token string-property property">"received"</span><span class="token operator">:</span> <span class="token string">"number"</span><span class="token punctuation">,</span>
    <span class="token string-property property">"path"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      <span class="token string">"username"</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token string-property property">"message"</span><span class="token operator">:</span> <span class="token string">"Expected string, received number"</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">]</span>
    at <span class="token keyword">get</span> <span class="token function">error</span> <span class="token punctuation">(</span>zod<span class="token punctuation">.</span>js<span class="token operator">?</span>v<span class="token operator">=</span>72bcbb81<span class="token operator">:</span><span class="token number">479</span><span class="token operator">:</span><span class="token number">23</span><span class="token punctuation">)</span>
    at _ZodObject<span class="token punctuation">.</span><span class="token function">parse</span> <span class="token punctuation">(</span>zod<span class="token punctuation">.</span>js<span class="token operator">?</span>v<span class="token operator">=</span>72bcbb81<span class="token operator">:</span><span class="token number">578</span><span class="token operator">:</span><span class="token number">18</span><span class="token punctuation">)</span>
    at main<span class="token punctuation">.</span>ts<span class="token operator">:</span><span class="token number">9</span><span class="token operator">:</span><span class="token number">24</span>
</code></pre></div>
<p>And that's great, because we can now get errors based on the
validation of our data.</p>
<p>Another cool feature from Zod that makes it very popular is how easy
it is to integrate it with typescript Types.</p>
<p>We may have the following code:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">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 punctuation">;</span>

<span class="token keyword">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
  username<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> user<span class="token operator">:</span> User <span class="token operator">=</span> <span class="token punctuation">{</span> username<span class="token operator">:</span> <span class="token string">"Rahul"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>See it is almost the same, but we defined the User type.</p>
<p>It's nothing wrong with it, but we defined our type twice: once in the
Schema and once on the type directive.</p>
<p>With Zod what we can do is actually infer the type from the Schema, like:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">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 punctuation">;</span>

<span class="token keyword">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> z<span class="token punctuation">.</span>infer<span class="token operator">&#x3C;</span><span class="token keyword">typeof</span> UserSchema<span class="token operator">></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> user<span class="token operator">:</span> User <span class="token operator">=</span> <span class="token punctuation">{</span> username<span class="token operator">:</span> <span class="token string">"Rahul"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

</code></pre></div>
<p>The <code>z.infer</code> can infer the type for us and we may now maintain only
the Schema, without repeating our selfs.</p>
<p>Another cool thing we can do is using the method <code>safeParse</code>, such as:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">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 punctuation">;</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span> username<span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">safeParse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>This returns:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token punctuation">{</span>
    <span class="token string-property property">"success"</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
    <span class="token string-property property">"error"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token string-property property">"issues"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token punctuation">{</span>
                <span class="token string-property property">"code"</span><span class="token operator">:</span> <span class="token string">"invalid_type"</span><span class="token punctuation">,</span>
                <span class="token string-property property">"expected"</span><span class="token operator">:</span> <span class="token string">"string"</span><span class="token punctuation">,</span>
                <span class="token string-property property">"received"</span><span class="token operator">:</span> <span class="token string">"number"</span><span class="token punctuation">,</span>
                <span class="token string-property property">"path"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
                    <span class="token string">"username"</span>
                <span class="token punctuation">]</span><span class="token punctuation">,</span>
                <span class="token string-property property">"message"</span><span class="token operator">:</span> <span class="token string">"Expected string, received number"</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"ZodError"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token string-property property">"_error"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token string-property property">"issues"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token punctuation">{</span>
                <span class="token string-property property">"code"</span><span class="token operator">:</span> <span class="token string">"invalid_type"</span><span class="token punctuation">,</span>
                <span class="token string-property property">"expected"</span><span class="token operator">:</span> <span class="token string">"string"</span><span class="token punctuation">,</span>
                <span class="token string-property property">"received"</span><span class="token operator">:</span> <span class="token string">"number"</span><span class="token punctuation">,</span>
                <span class="token string-property property">"path"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
                    <span class="token string">"username"</span>
                <span class="token punctuation">]</span><span class="token punctuation">,</span>
                <span class="token string-property property">"message"</span><span class="token operator">:</span> <span class="token string">"Expected string, received number"</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"ZodError"</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>As you can see, we won't raising any errors using <code>safeParse</code>, but we
have an object containing the <code>success</code> property, and if this false,
the <code>error</code> property can be read to show specific what went wrong
during parsing.</p>
<p>Fixing our username to a string:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span> username<span class="token operator">:</span> <span class="token string">"Rahul"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div>
<p>We now have the following result from <code>safeParse</code>:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token punctuation">{</span>
    <span class="token string-property property">"success"</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
    <span class="token string-property property">"data"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token string-property property">"username"</span><span class="token operator">:</span> <span class="token string">"Rahul"</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>As you may see the <code>success</code> property is true and our parsed data is
passed within the <code>data</code> property.</p>
<h2>Primitives</h2>
<p>Delving a bit more into Zod, let's study a bit of the primitives datatypes:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  age<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  birthday<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  isProgrammer<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</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">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span> username<span class="token operator">:</span> <span class="token string">"Rahul"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">safeParse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">.</span>success<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>As we can see, we can test for strings, numbers (also Bigints, and
other forms), dates (several kinds), booleans and so on.</p>
<p>But this code actually returns <code>false</code>, why so?</p>
<p>Because inside of Zod, every single validation is required by default.</p>
<p>We can mark a validation as optional like this if we want to:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  age<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">optional</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  birthday<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">optional</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  isProgrammer<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">optional</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">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span> username<span class="token operator">:</span> <span class="token string">"Rahul"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">safeParse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">.</span>success<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>And now it returns <code>true</code>.</p>
<p>We can also use:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  age<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">optional</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  birthday<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">optional</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  isProgrammer<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">optional</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  test<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">undefined</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>      <span class="token comment">// it must be undefined</span>
  test2<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">null</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>          <span class="token comment">// it must be null</span>
  test3<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">void</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>          <span class="token comment">// it must be void, like the return of a function</span>
  test4<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">any</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>           <span class="token comment">// anything is valid</span>
  test5<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">unknown</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>       <span class="token comment">// anything is valid</span>
  test6<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">never</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>         <span class="token comment">// it should never have this property</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<h2>Basic Validations</h2>
<p>Here we may find a basic example of how to do a validation:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// .max()  .url()  ....</span>
  age<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">gt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  birthday<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  isProgrammer<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</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">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> z<span class="token punctuation">.</span>infer<span class="token operator">&#x3C;</span><span class="token keyword">typeof</span> UserSchema<span class="token operator">></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span>
  username<span class="token operator">:</span> <span class="token string">"Rahul"</span><span class="token punctuation">,</span>
  age<span class="token operator">:</span> <span class="token number">37</span><span class="token punctuation">,</span>
  birthday<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  isProgrammer<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">safeParse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">.</span>success<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>This returns <code>true</code>.</p>
<p>I won't cover every single detail, but as you can see each validation
may have several chainable sub validators, such as <code>min</code>, <code>max</code>,
<code>regex</code>, and so on.</p>
<p>Here we extend a bit our example:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  age<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">gt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  birthday<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  isProgrammer<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  isGamer<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">nullable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// can be null</span>
  isMetalhead<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">nullish</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// can be null OR undefined</span>
  isZen<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  luckyNumber<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">default</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span>random<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">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> z<span class="token punctuation">.</span>infer<span class="token operator">&#x3C;</span><span class="token keyword">typeof</span> UserSchema<span class="token operator">></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span>
  username<span class="token operator">:</span> <span class="token string">"Rahul"</span><span class="token punctuation">,</span>
  age<span class="token operator">:</span> <span class="token number">37</span><span class="token punctuation">,</span>
  birthday<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  isProgrammer<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  isGamer<span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span>
  isMetalhead<span class="token operator">:</span> <span class="token keyword">undefined</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">safeParse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">.</span>success<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>As we can see we now have <code>nullable</code>, that marks a field to be of the
type OR null.  We also have <code>nullish</code> that accepts the parsing type,
null OR undefined. The <code>default</code> method, that actually defines a
fallback value if the parsing fails. The <code>default</code> can also accept a
function, like we did in the example with luckyNumber.</p>
<p>When dealing with a list of possibilities, we can use the <code>enum</code> method to list all
possible values. Note this won't be typed as an enum by <code>infer</code>.</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  age<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">gt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  birthday<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  isProgrammer<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  isGamer<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">nullable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// can be null</span>
  isMetalhead<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">nullish</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// can be null OR undefined</span>
  isZen<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">default</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  luckyNumber<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">default</span><span class="token punctuation">(</span>Math<span class="token punctuation">.</span>random<span class="token punctuation">)</span><span class="token punctuation">,</span>
  preferedHobby<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">enum</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">"Programming"</span><span class="token punctuation">,</span> <span class="token string">"Weight Lifiting"</span><span class="token punctuation">,</span> <span class="token string">"Guitar"</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">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> z<span class="token punctuation">.</span>infer<span class="token operator">&#x3C;</span><span class="token keyword">typeof</span> UserSchema<span class="token operator">></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span>
  username<span class="token operator">:</span> <span class="token string">"Rahul"</span><span class="token punctuation">,</span>
  age<span class="token operator">:</span> <span class="token number">37</span><span class="token punctuation">,</span>
  birthday<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  isProgrammer<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span>
  isGamer<span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">,</span>
  isMetalhead<span class="token operator">:</span> <span class="token keyword">undefined</span><span class="token punctuation">,</span>
  preferedHobby<span class="token operator">:</span> <span class="token string">"Programming"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">safeParse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">.</span>success<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>This returns <code>true</code> and hovering over the <code>User</code> type we get:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
     username<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
    age<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
    birthday<span class="token operator">:</span> Date<span class="token punctuation">;</span>q
    isProgrammer<span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">;</span>
    isGamer<span class="token operator">:</span> <span class="token builtin">boolean</span> <span class="token operator">|</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    isZen<span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">;</span>
    luckyNumber<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
    preferedHobby<span class="token operator">:</span> <span class="token string">"Programming"</span> <span class="token operator">|</span> <span class="token string">"Weight Lifiting"</span> <span class="token operator">|</span> <span class="token string">"Guitar"</span><span class="token punctuation">;</span>
    isMetalhead<span class="token operator">?</span><span class="token operator">:</span> <span class="token builtin">boolean</span> <span class="token operator">|</span> <span class="token operator">...</span> <span class="token number">1</span> more <span class="token operator">...</span> <span class="token operator">|</span> <span class="token keyword">undefined</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<h2>Object Type</h2>
<p>Let's begin by taking a look at this code:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  age<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">gt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  birthday<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  isProgrammer<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  preferedHobby<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">enum</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">"Programming"</span><span class="token punctuation">,</span> <span class="token string">"Weight Lifiting"</span><span class="token punctuation">,</span> <span class="token string">"Guitar"</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">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> z<span class="token punctuation">.</span>infer<span class="token operator">&#x3C;</span><span class="token keyword">typeof</span> UserSchema<span class="token operator">></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span>
  username<span class="token operator">:</span> <span class="token string">"Rahul"</span><span class="token punctuation">,</span>
  age<span class="token operator">:</span> <span class="token number">37</span><span class="token punctuation">,</span>
  birthday<span class="token operator">:</span> <span class="token keyword">new</span> <span class="token class-name">Date</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 builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">partial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>What is happening here is that we now have a partial, really useful to
use with forms and whenever you need partial validation.</p>
<p>Even tough preferedhobby is there on the schema, .partial() usage makes
every field optional.</p>
<p>If we move the <code>.partial()</code> to the schema, like:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  age<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">gt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  birthday<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  isProgrammer<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  preferedHobby<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">enum</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">"Programming"</span><span class="token punctuation">,</span> <span class="token string">"Weight Lifiting"</span><span class="token punctuation">,</span> <span class="token string">"Guitar"</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 function">partial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>We can now check that the type of the UserSchema is turned on all
fields optional:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> UserSchema<span class="token operator">:</span> z<span class="token punctuation">.</span>ZodObject<span class="token operator">&#x3C;</span><span class="token punctuation">{</span>
     username<span class="token operator">:</span> z<span class="token punctuation">.</span>ZodOptional<span class="token operator">&#x3C;</span>z<span class="token punctuation">.</span>ZodString<span class="token operator">></span><span class="token punctuation">;</span>
    age<span class="token operator">:</span> z<span class="token punctuation">.</span>ZodOptional<span class="token operator">&#x3C;</span>z<span class="token punctuation">.</span>ZodNumber<span class="token operator">></span><span class="token punctuation">;</span>
    birthday<span class="token operator">:</span> z<span class="token punctuation">.</span>ZodOptional<span class="token operator">&#x3C;</span>z<span class="token punctuation">.</span>ZodDate<span class="token operator">></span><span class="token punctuation">;</span>
    isProgrammer<span class="token operator">:</span> z<span class="token punctuation">.</span>ZodOptional<span class="token operator">&#x3C;</span>z<span class="token punctuation">.</span>ZodBoolean<span class="token operator">></span><span class="token punctuation">;</span>
    preferedHobby<span class="token operator">:</span> z<span class="token punctuation">.</span>ZodOptional<span class="token operator">&#x3C;</span><span class="token operator">...</span><span class="token operator">></span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">"strip"</span><span class="token punctuation">,</span> z<span class="token punctuation">.</span>ZodTypeAny<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token operator">></span>
</code></pre></div>
<p>We can also use other things from typescript, such as <code>.pick()</code>.</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z
  <span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    age<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">gt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    birthday<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    isProgrammer<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    preferedHobby<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">enum</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">"Programming"</span><span class="token punctuation">,</span> <span class="token string">"Weight Lifiting"</span><span class="token punctuation">,</span> <span class="token string">"Guitar"</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 function">pick</span><span class="token punctuation">(</span><span class="token punctuation">{</span> username<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>And now we only use the <code>username</code> validation;</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
	username<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>We could also use <code>omit()</code>, like:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z
  <span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    age<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">gt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    birthday<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    isProgrammer<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    preferedHobby<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">enum</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">"Programming"</span><span class="token punctuation">,</span> <span class="token string">"Weight Lifiting"</span><span class="token punctuation">,</span> <span class="token string">"Guitar"</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 function">omit</span><span class="token punctuation">(</span><span class="token punctuation">{</span> username<span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>And now everything BUT username is here on the type:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
    age<span class="token operator">:</span> <span class="token builtin">number</span><span class="token punctuation">;</span>
    birthday<span class="token operator">:</span> Date<span class="token punctuation">;</span>
    isProgrammer<span class="token operator">:</span> <span class="token builtin">boolean</span><span class="token punctuation">;</span>
    preferedHobby<span class="token operator">:</span> <span class="token string">"Programming"</span> <span class="token operator">|</span> <span class="token string">"Weight Lifiting"</span> <span class="token operator">|</span> <span class="token string">"Guitar"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>Also, we have <code>.deepPartial()</code> that is the same as partial but makes
objects inside of objects inside of objects... deeply nested, all
partials.</p>
<p>Another thing you can do is "extend" an object with <code>.extend()</code>:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z
  <span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    age<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">gt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    birthday<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    isProgrammer<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    preferedHobby<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">enum</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">"Programming"</span><span class="token punctuation">,</span> <span class="token string">"Weight Lifiting"</span><span class="token punctuation">,</span> <span class="token string">"Guitar"</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 function">extend</span><span class="token punctuation">(</span><span class="token punctuation">{</span> knowsTypescript<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</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>And if we had multiple Schemas we could merge them with:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z
  <span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    age<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">gt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    birthday<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    isProgrammer<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">boolean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    preferedHobby<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">enum</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">"Programming"</span><span class="token punctuation">,</span> <span class="token string">"Weight Lifiting"</span><span class="token punctuation">,</span> <span class="token string">"Guitar"</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 function">merge</span><span class="token punctuation">(</span>
    z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
      name<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      surname<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">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 punctuation">,</span>
  <span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>And now for the last:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</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 punctuation">;</span>

<span class="token keyword">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> z<span class="token punctuation">.</span>infer<span class="token operator">&#x3C;</span><span class="token keyword">typeof</span> UserSchema<span class="token operator">></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span>
  username<span class="token operator">:</span> <span class="token string">"Rahul"</span><span class="token punctuation">,</span>
  alias<span class="token operator">:</span> <span class="token string">"rmj"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">partial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>What should happen here? We defined a key to an object that is not
present on our schema.</p>
<p>Well, we get:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token punctuation">{</span>username<span class="token operator">:</span> <span class="token string">'Rahul'</span><span class="token punctuation">}</span>
</code></pre></div>
<p>By default if allows you to pass something nothing inside the schema,
but it takes the thing of the result object.</p>
<p>You can change this behaviour by passing <code>.passthrough()</code>.</p>
<p>With:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z
  <span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</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 punctuation">.</span><span class="token function">passthrough</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>We now have:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token punctuation">{</span>username<span class="token operator">:</span> <span class="token string">'Rahul'</span><span class="token punctuation">,</span> alias<span class="token operator">:</span> <span class="token string">'rmj'</span><span class="token punctuation">}</span>
</code></pre></div>
<p>You could also add <code>.strict()</code> to the schema, like:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z
  <span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</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 punctuation">.</span><span class="token function">strict</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>This will throw an error, because the extra data is being treated as
not recognized by the schema.</p>
<h2>Array Type</h2>
<p>Take a look at this code:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z
  <span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    friends<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">array</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">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 punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">strict</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> z<span class="token punctuation">.</span>infer<span class="token operator">&#x3C;</span><span class="token keyword">typeof</span> UserSchema<span class="token operator">></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span>
  username<span class="token operator">:</span> <span class="token string">"Rahul"</span><span class="token punctuation">,</span>
  friends<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"Amy"</span><span class="token punctuation">,</span> <span class="token string">"Boris"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">partial</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>We are now declaring a "friends" array of strings.</p>
<p>The type of User is:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
     username<span class="token operator">:</span> <span class="token builtin">string</span><span class="token punctuation">;</span>
    friends<span class="token operator">:</span> <span class="token builtin">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>We can also check the expected type by using <code>shape</code>, like in:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts">UserSchema<span class="token punctuation">.</span>shape<span class="token punctuation">.</span>friends<span class="token punctuation">.</span>element<span class="token punctuation">;</span>
</code></pre></div>
<p>Hovering over <code>element</code> we get:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token punctuation">(</span>property<span class="token punctuation">)</span> ZodArray<span class="token operator">&#x3C;</span>ZodString<span class="token punctuation">,</span> <span class="token string">"many"</span><span class="token operator">></span><span class="token punctuation">.</span>element<span class="token operator">:</span> z<span class="token punctuation">.</span>ZodString 
</code></pre></div>
<p>Now we can add the <code>.nonempty()</code> property to arrays, like:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  friends<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">array</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">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 function">nonempty</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>And now passing an empty array to the <code>friends</code> property raises an
error.</p>
<p>We can also specify things like <code>.min()</code>, <code>.max()</code>, <code>.length()</code>.</p>
<h2>Tuples</h2>
<p>Starting the advanced types, tuples are a fixed lenght array where
each element has a specific type.</p>
<p>Take a look at this example code:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  coords<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">tuple</span><span class="token punctuation">(</span><span class="token punctuation">[</span>z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> z<span class="token punctuation">.</span><span class="token function">number</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">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> z<span class="token punctuation">.</span>infer<span class="token operator">&#x3C;</span><span class="token keyword">typeof</span> UserSchema<span class="token operator">></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span>
  username<span class="token operator">:</span> <span class="token string">"Rahul"</span><span class="token punctuation">,</span>
  coords<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</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 builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>It returns:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token punctuation">{</span>
    <span class="token string-property property">"username"</span><span class="token operator">:</span> <span class="token string">"Rahul"</span><span class="token punctuation">,</span>
    <span class="token string-property property">"coords"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
        <span class="token number">1</span><span class="token punctuation">,</span>
        <span class="token number">2</span><span class="token punctuation">,</span>
        <span class="token number">3</span>
    <span class="token punctuation">]</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>If we change the lenght or types of the provided "coords" data, we now
get an error.</p>
<p>We can also change and combine whatever we want like:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts">coords<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">tuple</span><span class="token punctuation">(</span><span class="token punctuation">[</span>z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> z<span class="token punctuation">.</span><span class="token function">number</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>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts">coords<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">tuple</span><span class="token punctuation">(</span><span class="token punctuation">[</span>z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> z<span class="token punctuation">.</span><span class="token function">number</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">gt</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">int</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>And we can also use <code>.rest()</code> to define a type for the last infinity next numbers of the array, like:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
  coords<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">tuple</span><span class="token punctuation">(</span><span class="token punctuation">[</span>z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> z<span class="token punctuation">.</span><span class="token function">date</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 function">rest</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">number</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>We can now declare a user like:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span>
  username<span class="token operator">:</span> <span class="token string">"Rahul"</span><span class="token punctuation">,</span>
  coords<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"1"</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</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>Union Type</h2>
<p>Let's take a look in the code below:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
 id<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">union</span><span class="token punctuation">(</span><span class="token punctuation">[</span>z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> z<span class="token punctuation">.</span><span class="token function">number</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">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> z<span class="token punctuation">.</span>infer<span class="token operator">&#x3C;</span><span class="token keyword">typeof</span> UserSchema<span class="token operator">></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span>
 id<span class="token operator">:</span> <span class="token string">"abcde"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>We now have a union in our id, meaning the type could be something or other.</p>
<p>An alternative would be using "or" like:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  id<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">or</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">number</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>Another kind of union is a discriminated union, like:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  id<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">discriminatedUnion</span><span class="token punctuation">(</span><span class="token string">"status"</span><span class="token punctuation">,</span> <span class="token punctuation">[</span>
    z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span> status<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">literal</span><span class="token punctuation">(</span><span class="token string">"success"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> data<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">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>
    z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span> status<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">literal</span><span class="token punctuation">(</span><span class="token string">"failed"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> error<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">instanceof</span><span class="token punctuation">(</span>Error<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">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> z<span class="token punctuation">.</span>infer<span class="token operator">&#x3C;</span><span class="token keyword">typeof</span> UserSchema<span class="token operator">></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span>
  id<span class="token operator">:</span> <span class="token punctuation">{</span> status<span class="token operator">:</span> <span class="token string">"success"</span><span class="token punctuation">,</span> data<span class="token operator">:</span> <span class="token string">"asdf"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">safeParse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

</code></pre></div>
<p>This will grant you a conditional parser, testing first the status value
and returning either one or another data.</p>
<p>In this case the snippet returns:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token punctuation">{</span>
    <span class="token string-property property">"id"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token string-property property">"status"</span><span class="token operator">:</span> <span class="token string">"success"</span><span class="token punctuation">,</span>
        <span class="token string-property property">"data"</span><span class="token operator">:</span> <span class="token string">"asdf"</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>If we change our user to:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span>
  id<span class="token operator">:</span> <span class="token punctuation">{</span> status<span class="token operator">:</span> <span class="token string">"failed"</span><span class="token punctuation">,</span> error<span class="token operator">:</span> <span class="token function">Error</span><span class="token punctuation">(</span><span class="token string">"asdfg"</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>We get in return:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token punctuation">{</span>
    <span class="token string-property property">"status"</span><span class="token operator">:</span> <span class="token string">"failed"</span><span class="token punctuation">,</span>
    <span class="token string-property property">"error"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>

</code></pre></div>
<p>Documentation says this is going to have performance gains. So, if
performance is an issue, use a <code>discriminatedUnion</code> when you can.</p>
<h2>Record Type</h2>
<p>Now, what happens when you have like a map of users, like:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token punctuation">{</span>
  <span class="token string-property property">"abcce-asbcde-abd"</span><span class="token operator">:</span> <span class="token string">"User 1"</span><span class="token punctuation">,</span>
  <span class="token string-property property">"ab123-asdkjk-j2k"</span><span class="token operator">:</span> <span class="token string">"User 2"</span><span class="token punctuation">,</span>
  <span class="token operator">...</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>We can use a <code>.record()</code> method to define what we want inside the
record:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserMap <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">record</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">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 keyword">const</span> users <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token string-property property">"abcce-asbcde-abd"</span><span class="token operator">:</span> <span class="token string">"User 1"</span><span class="token punctuation">,</span>
  <span class="token string-property property">"ab123-asdkjk-j2k"</span><span class="token operator">:</span> <span class="token string">"User 2"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserMap<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>users<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

</code></pre></div>
<p>This returns:</p>
<div class="remark-highlight"><pre class="language-shell"><code class="language-shell"><span class="token punctuation">{</span>
    <span class="token string">"abcce-asbcde-abd"</span><span class="token builtin class-name">:</span> <span class="token string">"User 1"</span>,
    <span class="token string">"ab123-asdkjk-j2k"</span><span class="token builtin class-name">:</span> <span class="token string">"User 2"</span>
<span class="token punctuation">}</span>

</code></pre></div>
<p>And if we change our users to:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserMap <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">record</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">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 keyword">const</span> users <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token string-property property">"abcce-asbcde-abd"</span><span class="token operator">:</span> <span class="token string">"User 1"</span><span class="token punctuation">,</span>
  <span class="token string-property property">"ab123-asdkjk-j2k"</span><span class="token operator">:</span> <span class="token number">123</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserMap<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>users<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>We now get an error. This is how we parse "objects" (recors) values.</p>
<p>But what happens if we change our key to, let's say a number?</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserMap <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">record</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">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 keyword">const</span> users <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token string-property property">"abcce-asbcde-abd"</span><span class="token operator">:</span> <span class="token string">"User 1"</span><span class="token punctuation">,</span>
</code></pre></div>
<p>Now we get:</p>
<div class="remark-highlight"><pre class="language-shell"><code class="language-shell"><span class="token punctuation">{</span>
    <span class="token string">"123"</span><span class="token builtin class-name">:</span> <span class="token string">"User 2"</span>,
    <span class="token string">"abcce-asbcde-abd"</span><span class="token builtin class-name">:</span> <span class="token string">"User 1"</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>See? No errors.</p>
<p>If we want to define both key and value datatypes, we define our record with 2
parameters, the first is always the key and the second the value:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserMap <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">record</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> z<span class="token punctuation">.</span><span class="token function">number</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">const</span> users <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token string-property property">"abcce-asbcde-abd"</span><span class="token operator">:</span> <span class="token number">321</span><span class="token punctuation">,</span>
  <span class="token string-property property">"ab123-asdkjk-j2k"</span><span class="token operator">:</span> <span class="token number">123</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserMap<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>users<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>This returns:</p>
<div class="remark-highlight"><pre class="language-shell"><code class="language-shell"><span class="token punctuation">{</span>
    <span class="token string">"abcce-asbcde-abd"</span><span class="token builtin class-name">:</span> <span class="token number">321</span>,
    <span class="token string">"ab123-asdkjk-j2k"</span><span class="token builtin class-name">:</span> <span class="token number">123</span>
<span class="token punctuation">}</span>
</code></pre></div>
<h2>Map Type</h2>
<p>Most times when you're dealing with things with set Keys and set Values types,
you maybe want to use a Map instead of a Record, and Zod has support for it,
example:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserMap <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> z<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span> name<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">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 punctuation">;</span>

<span class="token keyword">const</span> users <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
  <span class="token punctuation">[</span><span class="token string">"abcce-asbcde-abd"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">"John"</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">"321"</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> name<span class="token operator">:</span> <span class="token string">"Mary"</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 builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserMap<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>users<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>That returns:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
    <span class="token punctuation">[</span>
        <span class="token string">"abcce-asbcde-abd"</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
            <span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"John"</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">"321"</span><span class="token punctuation">,</span>
        <span class="token punctuation">{</span>
            <span class="token string-property property">"name"</span><span class="token operator">:</span> <span class="token string">"Mary"</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>Set Type</h2>
<p>We can also work with Sets, a modified array where every value is
unique, like in this example:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserMap <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">number</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">const</span> users <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Set</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserMap<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>users<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>It can also use <code>.min()</code>, <code>.max()</code> and other arrays methods.</p>
<h2>Promise Type</h2>
<p>With Zod we can also validate Promises:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> PromiseSchema <span class="token operator">=</span> z<span class="token punctuation">.</span><span class="token function">promise</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">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 keyword">const</span> p <span class="token operator">=</span> <span class="token builtin">Promise</span><span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token string">"asdf"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>PromiseSchema<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>That returns:</p>
<div class="remark-highlight"><pre class="language-shell"><code class="language-shell">Promise <span class="token punctuation">{</span><span class="token operator">&#x3C;</span>pending<span class="token operator">></span><span class="token punctuation">}</span>
</code></pre></div>
<p>And if we parse another non string info inside resolve or pass
something that is not a promise at all, like a string, we get the
error.</p>
<p>A site note here, the promise validation is actually a 2 step process,
meaning it validades this is a promise and than validates the promise
content.</p>
<h2>Advanced Validation</h2>
<p>You can create your own custom validation with <code>.refine()</code>.</p>
<p>This means we could do something like:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> BrandEmail <span class="token operator">=</span> z
  <span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">email</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">refine</span><span class="token punctuation">(</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span> <span class="token operator">=></span> val<span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span><span class="token string">"@something.com"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
    message<span class="token operator">:</span> <span class="token string">"Email should end with @something.com"</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">const</span> email <span class="token operator">=</span> <span class="token string">"test@something.com"</span><span class="token punctuation">;</span>

<span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>BrandEmail<span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>email<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>Which returns:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts">test<span class="token decorator"><span class="token at operator">@</span><span class="token function">something</span></span><span class="token punctuation">.</span>com
</code></pre></div>
<p>If we test with some email like <code>test@test.com</code> we would get:</p>
<div class="remark-highlight"><pre class="language-shell"><code class="language-shell">Uncaught ZodError: <span class="token punctuation">[</span>
  <span class="token punctuation">{</span>
    <span class="token string">"code"</span><span class="token builtin class-name">:</span> <span class="token string">"custom"</span>,
    <span class="token string">"message"</span><span class="token builtin class-name">:</span> <span class="token string">"Email should end with @something.com"</span>,
    <span class="token string">"path"</span><span class="token builtin class-name">:</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>You can also take this a step further using the method <code>superRefine()</code>,
which we won't cover in here but it is good to know about.</p>
<h2>Error Handling</h2>
<p>Let's get back to this example:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z
  <span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    username<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    coords<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">tuple</span><span class="token punctuation">(</span><span class="token punctuation">[</span>z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> z<span class="token punctuation">.</span><span class="token function">date</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 function">rest</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">number</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 function">strict</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> z<span class="token punctuation">.</span>infer<span class="token operator">&#x3C;</span><span class="token keyword">typeof</span> UserSchema<span class="token operator">></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span>
  username<span class="token operator">:</span> <span class="token string">"rmj"</span><span class="token punctuation">,</span>
  coords<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</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 builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>UserSchema<span class="token punctuation">.</span><span class="token function">safeParse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>As you can see we provided a number 1 to where a string was expected
on coords.</p>
<p>This will output the error:</p>
<div class="remark-highlight"><pre class="language-shell"><code class="language-shell"><span class="token punctuation">{</span>
    <span class="token string">"success"</span><span class="token builtin class-name">:</span> false,
    <span class="token string">"error"</span><span class="token builtin class-name">:</span> <span class="token punctuation">{</span>
        <span class="token string">"issues"</span><span class="token builtin class-name">:</span> <span class="token punctuation">[</span>
            <span class="token punctuation">{</span>
                <span class="token string">"code"</span><span class="token builtin class-name">:</span> <span class="token string">"invalid_type"</span>,
                <span class="token string">"expected"</span><span class="token builtin class-name">:</span> <span class="token string">"string"</span>,
                <span class="token string">"received"</span><span class="token builtin class-name">:</span> <span class="token string">"number"</span>,
                <span class="token string">"path"</span><span class="token builtin class-name">:</span> <span class="token punctuation">[</span>
                    <span class="token string">"coords"</span>,
                    <span class="token number">0</span>
                <span class="token punctuation">]</span>,
                <span class="token string">"message"</span><span class="token builtin class-name">:</span> <span class="token string">"Expected string, received number"</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">]</span>,
        <span class="token string">"name"</span><span class="token builtin class-name">:</span> <span class="token string">"ZodError"</span>
    <span class="token punctuation">}</span>,
    <span class="token string">"_error"</span><span class="token builtin class-name">:</span> <span class="token punctuation">{</span>
        <span class="token string">"issues"</span><span class="token builtin class-name">:</span> <span class="token punctuation">[</span>
            <span class="token punctuation">{</span>
                <span class="token string">"code"</span><span class="token builtin class-name">:</span> <span class="token string">"invalid_type"</span>,
                <span class="token string">"expected"</span><span class="token builtin class-name">:</span> <span class="token string">"string"</span>,
                <span class="token string">"received"</span><span class="token builtin class-name">:</span> <span class="token string">"number"</span>,
                <span class="token string">"path"</span><span class="token builtin class-name">:</span> <span class="token punctuation">[</span>
                    <span class="token string">"coords"</span>,
                    <span class="token number">0</span>
                <span class="token punctuation">]</span>,
                <span class="token string">"message"</span><span class="token builtin class-name">:</span> <span class="token string">"Expected string, received number"</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">]</span>,
        <span class="token string">"name"</span><span class="token builtin class-name">:</span> <span class="token string">"ZodError"</span>
        <span class="token string">"errors"</span><span class="token builtin class-name">:</span> <span class="token punctuation">..</span>.,
		<span class="token string">"formErrors"</span><span class="token builtin class-name">:</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>Using those errors directly can be really dificult, what is
recommended tough is customizing your error messages like:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z
  <span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    username<span class="token operator">:</span> z
      <span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        description<span class="token operator">:</span> <span class="token string">"Must be a String"</span><span class="token punctuation">,</span>
        required_error<span class="token operator">:</span> <span class="token string">"This is REQUIRED"</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token string">"It should be 3 or more"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    coords<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">tuple</span><span class="token punctuation">(</span><span class="token punctuation">[</span>z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> z<span class="token punctuation">.</span><span class="token function">date</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 function">rest</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">number</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 function">strict</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div>
<p>Basically, inside each validation you can pass parameters about what
to show when parsing validation fails.</p>
<p>In this case we could set the username with undefined to see the
required_error message, or provide a number to it, or even a small 2
letters string.</p>
<p>Those would all fail with the previded messages being send after
validation.</p>
<p>As you can see this is not always great to reach for messages, that's the reason
one could recommend a plugin: <code>zod-validation-error</code>.</p>
<p>This will give us really easy validation messages with 1 line of code.</p>
<p>First start by installing it:</p>
<div class="remark-highlight"><pre class="language-shell"><code class="language-shell"><span class="token function">pnpm</span> i zod-validation-error
</code></pre></div>
<p>We can use like this:</p>
<div class="remark-highlight"><pre class="language-ts"><code class="language-ts"><span class="token keyword">import</span> <span class="token punctuation">{</span> z <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod"</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> fromZodError <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"zod-validation-error"</span><span class="token punctuation">;</span>

<span class="token keyword">const</span> UserSchema <span class="token operator">=</span> z
  <span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    username<span class="token operator">:</span> z
      <span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
        description<span class="token operator">:</span> <span class="token string">"Must be a String"</span><span class="token punctuation">,</span>
        required_error<span class="token operator">:</span> <span class="token string">"This is REQUIRED"</span><span class="token punctuation">,</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token punctuation">.</span><span class="token function">min</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">,</span> <span class="token string">"It should be 3 or more"</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
    coords<span class="token operator">:</span> z<span class="token punctuation">.</span><span class="token function">tuple</span><span class="token punctuation">(</span><span class="token punctuation">[</span>z<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> z<span class="token punctuation">.</span><span class="token function">date</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 function">rest</span><span class="token punctuation">(</span>z<span class="token punctuation">.</span><span class="token function">number</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 function">strict</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">type</span> <span class="token class-name">User</span> <span class="token operator">=</span> z<span class="token punctuation">.</span>infer<span class="token operator">&#x3C;</span><span class="token keyword">typeof</span> UserSchema<span class="token operator">></span><span class="token punctuation">;</span>

<span class="token keyword">const</span> user <span class="token operator">=</span> <span class="token punctuation">{</span>
  username<span class="token operator">:</span> <span class="token string">"ab"</span><span class="token punctuation">,</span>
  coords<span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"test"</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</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 keyword">const</span> result <span class="token operator">=</span> UserSchema<span class="token punctuation">.</span><span class="token function">safeParse</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>result<span class="token punctuation">.</span>success<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token builtin">console</span><span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">fromZodError</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>error<span class="token punctuation">)</span><span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div>
<p>And of course, this is not the total best thing to use for everything,
since this is programatically, but it is good enough for most user
responses you can customize.</p>
<h2>Wrap Up</h2>
<p>This is it! Happy Zodding!</p>
]]></description>
            <link>https://rahuljuliato.com/posts/zod-tutorial</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/zod-tutorial</guid>
            <pubDate>Wed, 20 Mar 2024 00:02: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[Rahul's Lab Archives: Navigating Tech and Education]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Explore Rahul's Lab: An archived fusion of tech and educational
insights. Immerse yourself in practical software, hands-on projects,
and more.</p>
<h2>Welcome to Rahul's Lab</h2>
<p>Embark on a journey through the evolution of knowledge and innovation
at Rahul's Lab. Formerly an Electrical Engineer and Teacher for
Associated Degrees in Brazil, I now curate a collection of resources
and projects. This site, accessible in Portuguese from Brazil at
<a href="https://sites.google.com/view/rahuljuliato">Rahul's Lab</a>, is
preserved for historical purposes, as I no longer maintain it. Whether
you're a tech enthusiast, student, or simply curious about software,
Rahul's Lab provides insights into diverse topics.</p>
<h3>SOFTWARE</h3>
<p>Discover a range of educational and practical software solutions, from
a Star Wars API client to a portable algebraic calculator. Each
creation is meticulously crafted for precision and functionality,
exploring the dynamic intersection of creativity and technology.</p>
<h3>ALUNOS (Students)</h3>
<p>Tailored for students, this section offers hands-on projects in
industrial automation, digital systems development, and essential
exercises in electrical basics and mathematics revision.</p>
<h3>ARTIGOS (Articles)</h3>
<p>Journey through insightful articles, exploring topics such as
communication via HID Terminal in PIC microcontrollers, USB
communication with PIC18F4550, and more. Gain valuable insights into
Programmable Logic Controllers, circuit analysis, supervisory systems,
and industrial sensors.</p>
<p>All available here: <a href="https://sites.google.com/view/rahuljuliato">Rahul's
Lab</a>.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/rahuls-lab</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/rahuls-lab</guid>
            <pubDate>Sat, 13 Jan 2024 00:02:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Spicing Up Your PyRadio: Easy Peasy Online Radio Playlists Integration]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>In this article, we'll guide you through enhancing PyRadio using a
Python package that I've developed. This package is designed to
streamline the process of importing m3u files into
PyRadio. Additionally, it offers the convenience of automatically
populating PyRadio with an extensive list of radios using just one
command!</p>
<h2>What is PyRadio?</h2>
<p><strong>PyRadio</strong> stands as a powerful and versatile command-line radio player, offering a unique blend of features that cater to a seamless and customizable radio streaming experience. Here's a closer look at its notable attributes:</p>
<h3>Features:</h3>
<ul>
<li>
<p><strong>Intuitive Navigation:</strong> PyRadio adopts vi-like keys, providing a familiar and efficient navigation experience using arrows, special keys, and vi-like station registers.</p>
</li>
<li>
<p><strong>Station Management:</strong> Enjoy the convenience of a station editor with support for CJK characters, allowing you to effortlessly add or edit stations.</p>
</li>
<li>
<p><strong>Configurability:</strong> Customize PyRadio according to your preferences using the built-in configuration editor, ensuring a personalized and tailored radio environment.</p>
</li>
<li>
<p><strong>Playlist Diversity:</strong> PyRadio supports multiple playlists, enabling you to organize and switch between different sets of your favorite stations effortlessly.</p>
</li>
<li>
<p><strong>Search Functionality:</strong> Seamlessly find your preferred stations with PyRadio's search function, enhancing the overall accessibility of your radio experience.</p>
</li>
<li>
<p><strong>Theming Support:</strong> Personalize the visual aesthetics of PyRadio with theming support, allowing you to tailor the interface to match your style.</p>
</li>
<li>
<p><strong>RadioBrowser Integration:</strong> Benefit from RadioBrowser support, expanding your radio station options and providing a broader spectrum of choices.</p>
</li>
<li>
<p><strong>Remote Control:</strong> PyRadio extends its functionality with remote control capabilities, allowing for enhanced accessibility and control.</p>
</li>
<li>
<p><strong>Compatibility:</strong> PyRadio is designed to run on Linux, macOS, and Windows, offering a versatile solution across different operating systems.</p>
</li>
<li>
<p><strong>Easy Installation:</strong> Install or update PyRadio effortlessly through distribution packages, where available. For cases where distribution packages are not an option, building PyRadio from source ensures a straightforward installation process.</p>
</li>
<li>
<p><strong>Extended Compatibility:</strong> PyRadio interfaces seamlessly with popular multimedia players, requiring MPV, MPlayer, or VLC to be installed and accessible in your system's path.</p>
</li>
<li>
<p><strong>Optional Enhancements:</strong> For users seeking additional features, PyRadio supports optional integration with MKVToolNix (cli files) to insert tags, chapters, and cover to recordings, as well as optional netifaces for enhanced network interface functionality.</p>
</li>
</ul>
<h3>Requirements:</h3>
<ul>
<li>Python 2.7/3.5+</li>
<li>Setuptools</li>
<li>Wheel</li>
<li>Requests</li>
<li>Dnspython</li>
<li>Psutil</li>
<li>Rich</li>
<li>Python-dateutil</li>
<li>Netifaces (optional)</li>
<li>MPV, MPlayer, or VLC installed and in your system's path</li>
<li>MKVToolNix (cli files) for optional advanced features</li>
</ul>
<h3>Installation:</h3>
<p>For optimal installation, use distribution packages when available, such as on Arch Linux and derivatives, where PyRadio can be easily installed from the AUR. In cases where distribution packages are not accessible, building PyRadio from source ensures a smooth installation process, bringing you closer to an enriched command-line radio experience.</p>
<p>For more information, check <a href="https://github.com/coderholic/pyradio">PyRadio's GitHub Repository</a>.</p>
<h2>What is m3u_to_pyradio?</h2>
<p><strong>m3u_to_pyradio</strong> is a versatile Python package designed as a PyRadio playlist generator from m3u playlist files. It addresses the common desire to seamlessly insert extensive m3u playlists into PyRadio or even automate the process of downloading and converting m3u playlists from external sources.</p>
<p>For complete information, check <a href="https://github.com/LionyxML/pyradio-m3u-to-playlist">m3u_to_pyradio_playlist Github Repository</a>.</p>
<h3>How to use it</h3>
<p><strong>Install and Usage:</strong>
To get started, install the package with <code>pip install m3u_to_pyradio_playlist</code>. Once installed, you can utilize the following command-line options:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">m3u_to_pyradio <span class="token punctuation">[</span>-h<span class="token punctuation">]</span> <span class="token punctuation">[</span>-i INPUT <span class="token parameter variable">-o</span> OUTPUT<span class="token punctuation">]</span> <span class="token punctuation">[</span>-d<span class="token punctuation">]</span> <span class="token punctuation">[</span>-a<span class="token punctuation">]</span>

This program converts .m3u files into pyradio playlists.

examples:
   m3u_to_pyradio <span class="token parameter variable">-d</span>    Downloads and creates a huge stations.csv
   m3u_to_pyradio <span class="token parameter variable">-a</span>    Same as <span class="token parameter variable">-a</span> and overrides current pyradio stations
   m3u_to_pyradio <span class="token parameter variable">-i</span> playlist.m3u <span class="token parameter variable">-o</span> playlist.csv
                        Creates playlist.csv <span class="token function">file</span> from your playlist.m3u <span class="token function">file</span>

options:
  -h, <span class="token parameter variable">--help</span>            show this <span class="token builtin class-name">help</span> message and <span class="token builtin class-name">exit</span>
  <span class="token parameter variable">-i</span> INPUT, <span class="token parameter variable">--input</span> INPUT
                        The m3u input <span class="token function">file</span>
  <span class="token parameter variable">-o</span> OUTPUT, <span class="token parameter variable">--output</span> OUTPUT
                        The output CSV <span class="token function">file</span> where playlist will be saved
  -d, --download-super-list
                        Download and convert the complete m3u list from
                        https://github.com/junguler/m3u-radio-music-playlists.
  -a, <span class="token parameter variable">--auto</span>            DANGER: Same as <span class="token parameter variable">-dsl</span> but OVERRIDES your
                        ~/.config/pyradio/stations.csv
</code></pre></div>
<p><strong>Usage Examples:</strong></p>
<p>-- Import a custom m3u file to PyRadio: <code>m3u_to_pyradio -i my_playlist.m3u -o converted.csv</code></p>
<p>-- Automatically download the "everything-full.m3u" playlist and save it as stations.csv: <code>m3u_to_pyradio -d</code></p>
<p>-- Override your current playlist with the downloaded list: <code>m3u_to_pyradio -a</code></p>
<p>The output .csv file is what pyradio actually reads.</p>
<p><strong>Uninstall</strong></p>
<p>To uninstall, use: <code>pip uninstall m3u_to_pyradio_playlist</code></p>
<h3>How to make everything work with one command?</h3>
<p>Achieving a seamless integration of the extensive playlist from the junguler repository into PyRadio, automatically downloading, converting it to PyRadio's custom .csv format, and seamlessly replacing the existing configuration can be effortlessly accomplished by executing:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">m3u_to_pyradio <span class="token parameter variable">-a</span> <span class="token operator">&&</span> pyradio
</code></pre></div>
<p>This single command ensures a streamlined experience, opening PyRadio with all the components seamlessly integrated.</p>
<h2>Conclusion</h2>
<p>In a nutshell, PyRadio just got cooler with "m3u_to_pyradio." This Python package makes importing m3u files a breeze – a quick command, and you're seamlessly integrating extensive playlists, updating configurations, all in one go. It's a perfect match for radio enthusiasts who want a snappy, customized command-line radio experience. Whether you're tinkering with playlists, automating updates, or exploring stations from repositories like junguler's, "m3u_to_pyradio" has your back. Check out the GitHub repository for the inside scoop and to elevate your PyRadio vibes effortlessly. Now, sit back and let the tunes roll! 🎶</p>
<p>Happy listening!</p>
]]></description>
            <link>https://rahuljuliato.com/posts/pyradio-m3u</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/pyradio-m3u</guid>
            <pubDate>Sat, 11 Nov 2023 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[Restoring the "Windows" entry in GRUB]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Reclaiming Your Windows Boot Option: A Comprehensive Step-by-Step
Solution for GRUB Dual-Booters to Restore the Windows Entry and
Achieve Seamless System Switching.</p>
<h2>Problem Statement</h2>
<p>After significant updates, it is not uncommon to encounter an issue
where the "Windows" entry is missing from the GRUB bootloader
menu. Technically, this issue arises when the os-probe utility fails
to run, preventing the automatic addition of extra Operating Systems,
especially in cases of dual-boot configurations.</p>
<h2>Solution</h2>
<p>To resolve this issue and restore the "Windows" entry in the GRUB
bootloader menu, follow these steps:</p>
<ol>
<li>
<p>Open the <code>/etc/default/grub</code> file with root privileges. You can do
this using a text editor like nano or vim.</p>
</li>
<li>
<p>Locate the following line in the file and uncomment it by removing
the # symbol at the beginning of the line:</p>
</li>
</ol>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown"># If your computer has multiple operating systems installed, then you
# probably want to run os-prober. However, if your computer is a host
# for guest OSes installed via LVM or raw disk devices, running
# os-prober can cause damage to those guest OSes as it mounts
# filesystems to look for things.
GRUB_DISABLE_OS_PROBER=false</code></pre></div>
<ol start="3">
<li>
<p>Save the changes to the file and close the text editor.</p>
</li>
<li>
<p>Run the following command to update the GRUB configuration:</p>
</li>
</ol>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">sudo update-grub</code></pre></div>
<p>This command will regenerate the GRUB configuration file with the
necessary changes.</p>
<ol start="5">
<li>After running the update-grub command, you will see output similar
to the following:</li>
</ol>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">Generating grub configuration file ...
Found background image: /usr/share/images/desktop-base/desktop-grub.png
Found linux image: /boot/vmlinuz-6.1.0-13-amd64
Found initrd image: /boot/initrd.img-6.1.0-13-amd64
Found linux image: /boot/vmlinuz-6.1.0-12-amd64
Found initrd image: /boot/initrd.img-6.1.0-12-amd64
Found linux image: /boot/vmlinuz-6.1.0-11-amd64
Found initrd image: /boot/initrd.img-6.1.0-11-amd64
Warning: os-prober will be executed to detect other bootable partitions.
Its output will be used to detect bootable binaries on them and create new boot entries.
Found Windows Boot Manager on /dev/nvme0n1p1@/EFI/Microsoft/Boot/bootmgfw.efi
Adding boot menu entry for UEFI Firmware Settings ...
done</code></pre></div>
<p>This indicates that the Windows partition has been detected, and a new
entry for it has been added to GRUB.</p>
<ol start="6">
<li>Finally, reboot your system using the following command:</li>
</ol>
<div class="remark-highlight"><pre class="language-unknown"><code class="language-unknown">sudo reboot</code></pre></div>
<p>After rebooting, you should see the "Windows" option restored to your
GRUB bootloader menu.</p>
<p>By following these steps, you can efficiently address the issue of the
missing "Windows" entry in GRUB and ensure a smooth dual-boot
experience on your system.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/grub-os-probe</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/grub-os-probe</guid>
            <pubDate>Sun, 08 Oct 2023 00:02:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Resolving Ç (Cedilla) Issue on Debian 12]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Discover how to effortlessly resolve the ç (ce cedilla) issue on your
Debian 12 system with a step-by-step guide that makes keyboard quirks
a thing of the past. From configuring character input to optimizing
your GNOME desktop, this article provides practical solutions for a
more user-friendly experience.</p>
<h2>Problem Statement</h2>
<p>I am encountering an issue with my English US, intl. keyboard,
configured to 'portuguese-br,' where it occasionally outputs <code>ć</code>
instead of <code>ç</code> in certain windows and terminals. This problem persists
on my Debian 12 system with the GNOME desktop environment.</p>
<h2>Solution</h2>
<p>To rectify this issue, you can create or modify the file located at
~/.Xcompose with the following content:</p>
<div class="remark-highlight"><pre class="language-txt"><code class="language-txt"> # UTF-8 (Unicode) compose sequences

 # Overrides C acute with Ccedilla:
 &lt;dead_acute&gt; &lt;C&gt; : &quot;Ç&quot; &quot;Ccedilla&quot;
 &lt;dead_acute&gt; &lt;c&gt; : &quot;ç&quot; &quot;ccedilla&quot;</code></pre></div>
<p>Afterwards, execute the following command in your terminal:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash">gsettings <span class="token builtin class-name">set</span> org.gnome.settings-daemon.plugins.xsettings overrides <span class="token string">"{'Gtk/IMModule': &#x3C;'ibus'>}"</span>
</code></pre></div>
<p>To apply the changes, restart your computer or switch between Wayland and Xorg sessions.</p>
<p>And there you have it! Your issue should now be resolved.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/c-cedilla</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/c-cedilla</guid>
            <pubDate>Thu, 05 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>
        <item>
            <title><![CDATA[Upgrade with Yarn Mindfully]]></title>
            <description><![CDATA[
        <link rel="stylesheet" type="text/css" href="https://rahuljuliato.com/rss-styles.css">
        <p>Have you ever encountered issues when updating your Node.js project?
Learn how to upgrade your packages with care and precision, rather
than blindly.</p>
<h2>Interactive Package Upgrades</h2>
<p>Yarn offers a powerful feature: the ability to upgrade your packages
interactively. This means you can selectively choose which packages to
update while also getting a sneak peek at their compatibility status.</p>
<p>To utilize this feature, run the following command in your terminal:</p>
<div class="remark-highlight"><pre class="language-bash"><code class="language-bash"><span class="token function">yarn</span> upgrade-interactive
</code></pre></div>
<p>This command will display a color-coded list of all available upgrades, where:</p>
<p>Red indicates a major update with potentially backward-incompatible changes.</p>
<ul>
<li>Yellow signifies a minor update, typically introducing backward-compatible features.</li>
<li>Green represents a patch update, often addressing backward-compatible bug fixes.</li>
<li>You can now use the spacebar to select the packages you wish to
upgrade and confirm your selections by pressing Enter.</li>
</ul>
<p>For additional guidance and more information, you can refer to the official documentation <a href="https://classic.yarnpkg.com/lang/en/docs/cli/upgrade-interactive/">here!</a></p>
<p>Upgrading your Node.js project doesn't have to be a daunting
task. With Yarn's interactive package upgrade feature, you can
approach it methodically, ensuring that you only update what you need
while staying informed about compatibility changes. By making use of
this powerful tool, you'll not only streamline your development
process but also reduce the chances of unexpected issues arising
during upgrades. So, remember to upgrade with care and precision, and
let Yarn's interactive upgrades be your trusty companion in
maintaining a healthy and up-to-date Node.js project.</p>
]]></description>
            <link>https://rahuljuliato.com/posts/mindful-upgrades</link>
            <guid isPermaLink="true">https://rahuljuliato.com/posts/mindful-upgrades</guid>
            <pubDate>Mon, 02 Oct 2023 00:00:00 GMT</pubDate>
        </item>
    </channel>
</rss>