870 lines
36 KiB
HTML
870 lines
36 KiB
HTML
<!DOCTYPE html>
|
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="generator" content="pandoc" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
|
<meta name="author" content="Rootiest" />
|
|
<title>7. CUSTOMIZATION</title>
|
|
<style>
|
|
div.sitenav { display: flex; flex-direction: row; flex-wrap: wrap; }
|
|
span.navlink { flex: 1; }
|
|
span.navlink-label { display: inline-block; min-width: 4em; }
|
|
html {
|
|
color: #1a1a1a;
|
|
background-color: #fdfdfd;
|
|
}
|
|
body {
|
|
margin: 0 auto;
|
|
max-width: 36em;
|
|
padding-left: 50px;
|
|
padding-right: 50px;
|
|
padding-top: 50px;
|
|
padding-bottom: 50px;
|
|
hyphens: auto;
|
|
overflow-wrap: break-word;
|
|
text-rendering: optimizeLegibility;
|
|
font-kerning: normal;
|
|
}
|
|
@media (max-width: 600px) {
|
|
body {
|
|
font-size: 0.9em;
|
|
padding: 12px;
|
|
}
|
|
h1 {
|
|
font-size: 1.8em;
|
|
}
|
|
}
|
|
@media print {
|
|
html {
|
|
background-color: white;
|
|
}
|
|
body {
|
|
background-color: transparent;
|
|
color: black;
|
|
font-size: 12pt;
|
|
}
|
|
p, h2, h3 {
|
|
orphans: 3;
|
|
widows: 3;
|
|
}
|
|
h2, h3, h4 {
|
|
page-break-after: avoid;
|
|
}
|
|
}
|
|
p {
|
|
margin: 1em 0;
|
|
}
|
|
a {
|
|
color: #1a1a1a;
|
|
}
|
|
a:visited {
|
|
color: #1a1a1a;
|
|
}
|
|
img {
|
|
max-width: 100%;
|
|
}
|
|
h1, h2, h3, h4, h5, h6 {
|
|
margin-top: 1.4em;
|
|
}
|
|
h5, h6 {
|
|
font-size: 1em;
|
|
font-style: italic;
|
|
}
|
|
h6 {
|
|
font-weight: normal;
|
|
}
|
|
ol, ul {
|
|
padding-left: 1.7em;
|
|
margin-top: 1em;
|
|
}
|
|
li > ol, li > ul {
|
|
margin-top: 0;
|
|
}
|
|
blockquote {
|
|
margin: 1em 0 1em 1.7em;
|
|
padding-left: 1em;
|
|
border-left: 2px solid #e6e6e6;
|
|
color: #606060;
|
|
}
|
|
code {
|
|
font-family: Menlo, Monaco, Consolas, 'Lucida Console', monospace;
|
|
font-size: 85%;
|
|
margin: 0;
|
|
hyphens: manual;
|
|
}
|
|
pre {
|
|
margin: 1em 0;
|
|
overflow: auto;
|
|
}
|
|
pre code {
|
|
padding: 0;
|
|
overflow: visible;
|
|
overflow-wrap: normal;
|
|
}
|
|
.sourceCode {
|
|
background-color: transparent;
|
|
overflow: visible;
|
|
}
|
|
hr {
|
|
background-color: #1a1a1a;
|
|
border: none;
|
|
height: 1px;
|
|
margin: 1em 0;
|
|
}
|
|
table {
|
|
margin: 1em 0;
|
|
border-collapse: collapse;
|
|
width: 100%;
|
|
overflow-x: auto;
|
|
display: block;
|
|
font-variant-numeric: lining-nums tabular-nums;
|
|
}
|
|
table caption {
|
|
margin-bottom: 0.75em;
|
|
}
|
|
tbody {
|
|
margin-top: 0.5em;
|
|
border-top: 1px solid #1a1a1a;
|
|
border-bottom: 1px solid #1a1a1a;
|
|
}
|
|
th {
|
|
border-top: 1px solid #1a1a1a;
|
|
padding: 0.25em 0.5em 0.25em 0.5em;
|
|
}
|
|
td {
|
|
padding: 0.125em 0.5em 0.25em 0.5em;
|
|
}
|
|
header {
|
|
margin-bottom: 4em;
|
|
text-align: center;
|
|
}
|
|
#TOC li {
|
|
list-style: none;
|
|
}
|
|
#TOC ul {
|
|
padding-left: 1.3em;
|
|
}
|
|
#TOC > ul {
|
|
padding-left: 0;
|
|
}
|
|
#TOC a:not(:hover) {
|
|
text-decoration: none;
|
|
}
|
|
code{white-space: pre-wrap;}
|
|
span.smallcaps{font-variant: small-caps;}
|
|
div.columns{display: flex; gap: min(4vw, 1.5em);}
|
|
div.column{flex: auto; overflow-x: auto;}
|
|
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
|
/* The extra [class] is a hack that increases specificity enough to
|
|
override a similar rule in reveal.js */
|
|
ul.task-list[class]{list-style: none;}
|
|
ul.task-list li input[type="checkbox"] {
|
|
font-size: inherit;
|
|
width: 0.8em;
|
|
margin: 0 0.8em 0.2em -1.6em;
|
|
vertical-align: middle;
|
|
}
|
|
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
|
|
</style>
|
|
<style>
|
|
/* ── Catppuccin Latte (light) / Mocha (dark) ─────────────────── */
|
|
:root {
|
|
color-scheme: light dark;
|
|
--bg: #eff1f5;
|
|
--surface: #e6e9ef;
|
|
--overlay: #ccd0da;
|
|
--text: #4c4f69;
|
|
--sub1: #6c6f85;
|
|
--sub0: #8c8fa1;
|
|
--blue: #1e66f5;
|
|
--lavender: #7287fd;
|
|
--sapphire: #209fb5;
|
|
--green: #40a02b;
|
|
--yellow: #df8e1d;
|
|
--peach: #fe640b;
|
|
--mauve: #8839ef;
|
|
--code-bg: #dce0e8;
|
|
--border: #bcc0cc;
|
|
--glow1: rgba(30, 102, 245, 0.05);
|
|
--glow2: rgba(136, 57, 239, 0.04);
|
|
}
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
:root {
|
|
--bg: #1e1e2e;
|
|
--surface: #313244;
|
|
--overlay: #45475a;
|
|
--text: #cdd6f4;
|
|
--sub1: #bac2de;
|
|
--sub0: #a6adc8;
|
|
--blue: #89b4fa;
|
|
--lavender: #b4befe;
|
|
--sapphire: #74c7ec;
|
|
--green: #a6e3a1;
|
|
--yellow: #f9e2af;
|
|
--peach: #fab387;
|
|
--mauve: #cba6f7;
|
|
--code-bg: #181825;
|
|
--border: #45475a;
|
|
--glow1: rgba(137, 180, 250, 0.06);
|
|
--glow2: rgba(203, 166, 247, 0.05);
|
|
}
|
|
}
|
|
|
|
*, *::before, *::after { box-sizing: border-box; }
|
|
|
|
html {
|
|
background-color: var(--bg);
|
|
background-image:
|
|
radial-gradient(ellipse 55% 40% at 10% 5%, var(--glow1) 0%, transparent 100%),
|
|
radial-gradient(ellipse 45% 45% at 90% 95%, var(--glow2) 0%, transparent 100%);
|
|
min-height: 100%;
|
|
}
|
|
|
|
body {
|
|
color: var(--text);
|
|
font-family: system-ui, -apple-system, "Segoe UI", Helvetica, sans-serif;
|
|
font-size: 16px;
|
|
line-height: 1.75;
|
|
max-width: 880px;
|
|
margin: 0 auto;
|
|
padding: 2rem 2.5rem 5rem;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
/* ── Links ─────────────────────────────────────────────────── */
|
|
a { color: var(--blue); text-decoration: none; }
|
|
a:hover { color: var(--lavender); text-decoration: underline; }
|
|
a:visited { color: var(--lavender); }
|
|
|
|
/* ── Headings ──────────────────────────────────────────────── */
|
|
h1, h2, h3, h4, h5, h6 {
|
|
font-family: "JetBrains Mono", "Fira Code", ui-monospace, monospace;
|
|
color: var(--lavender);
|
|
line-height: 1.3;
|
|
margin-top: 2em;
|
|
margin-bottom: 0.5em;
|
|
}
|
|
h1 {
|
|
font-size: 1.9rem;
|
|
color: var(--text);
|
|
border-bottom: 1px solid var(--border);
|
|
padding-bottom: 0.4em;
|
|
margin-top: 1.2em;
|
|
}
|
|
h2 {
|
|
font-size: 1.35rem;
|
|
border-bottom: 1px solid var(--border);
|
|
padding-bottom: 0.2em;
|
|
}
|
|
h3 { font-size: 1.1rem; color: var(--sapphire); }
|
|
h4 { font-size: 0.95rem; color: var(--sub1); }
|
|
|
|
p { margin: 0.8em 0; }
|
|
|
|
/* ── Title block (pandoc-generated cover) ──────────────────── */
|
|
#title-block-header {
|
|
text-align: center;
|
|
padding: 2.5rem 0 2rem;
|
|
margin-bottom: 1.5rem;
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
#title-block-header .title {
|
|
font-family: "JetBrains Mono", "Fira Code", ui-monospace, monospace;
|
|
font-size: 2.6rem;
|
|
letter-spacing: 0.12em;
|
|
color: var(--lavender);
|
|
border: none;
|
|
margin: 0 0 0.75rem;
|
|
}
|
|
#title-block-header .author,
|
|
#title-block-header .date {
|
|
color: var(--sub0);
|
|
font-size: 0.875rem;
|
|
margin: 0.2rem 0;
|
|
}
|
|
|
|
/* ── Inline code ───────────────────────────────────────────── */
|
|
code {
|
|
font-family: "JetBrains Mono", "Fira Code", ui-monospace, monospace;
|
|
background: var(--code-bg);
|
|
color: var(--peach);
|
|
padding: 0.15em 0.4em;
|
|
border-radius: 4px;
|
|
font-size: 0.875em;
|
|
}
|
|
|
|
/* ── Code blocks ───────────────────────────────────────────── */
|
|
pre {
|
|
background: var(--code-bg);
|
|
border: 1px solid var(--border);
|
|
border-left: 3px solid var(--sapphire);
|
|
border-radius: 0 8px 8px 0;
|
|
padding: 1.1em 1.4em;
|
|
overflow-x: auto;
|
|
line-height: 1.55;
|
|
margin: 1.2em 0;
|
|
}
|
|
pre code {
|
|
background: none;
|
|
color: var(--text);
|
|
padding: 0;
|
|
font-size: 0.88em;
|
|
}
|
|
|
|
/* ── Blockquotes ───────────────────────────────────────────── */
|
|
blockquote {
|
|
border-left: 3px solid var(--yellow);
|
|
margin: 1.5em 0;
|
|
padding: 0.75em 1.25em;
|
|
background: var(--surface);
|
|
color: var(--sub1);
|
|
border-radius: 0 6px 6px 0;
|
|
}
|
|
blockquote p { margin: 0.3em 0; }
|
|
|
|
/* ── Tables ────────────────────────────────────────────────── */
|
|
table {
|
|
border-collapse: collapse;
|
|
width: 100%;
|
|
margin: 1.4em 0;
|
|
font-size: 0.93em;
|
|
}
|
|
th, td {
|
|
border: 1px solid var(--border);
|
|
padding: 0.55em 0.9em;
|
|
text-align: left;
|
|
}
|
|
th {
|
|
background: var(--surface);
|
|
color: var(--lavender);
|
|
font-weight: 600;
|
|
font-family: "JetBrains Mono", "Fira Code", ui-monospace, monospace;
|
|
font-size: 0.82em;
|
|
letter-spacing: 0.06em;
|
|
text-transform: uppercase;
|
|
}
|
|
tr:nth-child(even) { background: var(--surface); }
|
|
tr:hover { background: var(--overlay); }
|
|
|
|
/* ── HR ────────────────────────────────────────────────────── */
|
|
hr { border: none; border-top: 1px solid var(--border); margin: 2.5em 0; }
|
|
|
|
/* ── Lists ─────────────────────────────────────────────────── */
|
|
ul, ol { padding-left: 1.6em; }
|
|
li { margin: 0.35em 0; }
|
|
|
|
/* ── Chunk navigation bar (prev / up / next) ───────────────── */
|
|
nav:not(#TOC):not([role="doc-toc"]) {
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-radius: 8px;
|
|
margin: 1.5em 0;
|
|
font-size: 0.875em;
|
|
overflow: hidden;
|
|
}
|
|
nav:not(#TOC):not([role="doc-toc"]) p {
|
|
margin: 0;
|
|
padding: 0.65em 1.2em;
|
|
display: flex;
|
|
gap: 0.4em 1.75em;
|
|
flex-wrap: wrap;
|
|
align-items: center;
|
|
}
|
|
/* JS wraps each "Label: <a>" pair in .nav-item so they flex as a unit */
|
|
.nav-item {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.3em;
|
|
white-space: nowrap;
|
|
}
|
|
.nav-item a { color: var(--blue); }
|
|
.nav-item a:hover { color: var(--lavender); }
|
|
|
|
/* ── Table of contents panel ───────────────────────────────── */
|
|
nav#TOC, nav[role="doc-toc"] {
|
|
display: block;
|
|
background: var(--surface);
|
|
border: 1px solid var(--border);
|
|
border-left: 3px solid var(--lavender);
|
|
border-radius: 0 8px 8px 0;
|
|
padding: 1.2em 1.5em;
|
|
margin: 1.5em 0;
|
|
}
|
|
nav#TOC > h2,
|
|
nav[role="doc-toc"] > h2 {
|
|
font-size: 0.7rem;
|
|
letter-spacing: 0.14em;
|
|
text-transform: uppercase;
|
|
color: var(--sub0);
|
|
border: none;
|
|
margin: 0 0 0.9em;
|
|
padding: 0;
|
|
}
|
|
nav#TOC ul, nav[role="doc-toc"] ul {
|
|
list-style: none;
|
|
padding-left: 1em;
|
|
margin: 0.25em 0;
|
|
}
|
|
nav#TOC > ul, nav[role="doc-toc"] > ul { padding-left: 0; }
|
|
nav#TOC li, nav[role="doc-toc"] li {
|
|
margin: 0.3em 0;
|
|
padding-left: 0.75em;
|
|
border-left: 1px solid transparent;
|
|
transition: border-color 0.12s;
|
|
}
|
|
nav#TOC li:hover, nav[role="doc-toc"] li:hover {
|
|
border-left-color: var(--lavender);
|
|
}
|
|
nav#TOC a, nav[role="doc-toc"] a {
|
|
color: var(--sub1);
|
|
font-size: 0.9em;
|
|
}
|
|
nav#TOC a:hover, nav[role="doc-toc"] a:hover {
|
|
color: var(--lavender);
|
|
text-decoration: none;
|
|
}
|
|
</style>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
/* ── Hide ToC on every page except index.html ───────────── */
|
|
var path = location.pathname;
|
|
var onIndex = path === '/' || path === '' || /\/index\.html(\?.*)?$/.test(path);
|
|
if (!onIndex) {
|
|
var toc = document.getElementById('TOC') ||
|
|
document.querySelector('[role="doc-toc"]');
|
|
if (toc) toc.remove();
|
|
}
|
|
|
|
/* ── Wrap each "Label: <a>" pair in a .nav-item span ───────
|
|
Pandoc emits label text nodes and anchors as siblings;
|
|
flex sees them as separate items, causing labels to split
|
|
from their links when wrapping. Grouping them in a span
|
|
keeps each label+link as a single flex unit. */
|
|
document.querySelectorAll('nav:not(#TOC):not([role="doc-toc"])').forEach(function (nav) {
|
|
var p = nav.querySelector('p');
|
|
if (!p) return;
|
|
var children = Array.from(p.childNodes);
|
|
var pairs = [];
|
|
for (var i = 0; i + 1 < children.length; i++) {
|
|
var cur = children[i];
|
|
var nxt = children[i + 1];
|
|
if (cur.nodeType === Node.TEXT_NODE &&
|
|
/[A-Z][a-z]*:\s*/.test(cur.textContent) &&
|
|
nxt.nodeType === Node.ELEMENT_NODE &&
|
|
nxt.tagName === 'A') {
|
|
pairs.push([cur, nxt]);
|
|
i++; // skip the anchor on the next iteration
|
|
}
|
|
}
|
|
pairs.forEach(function (pair) {
|
|
var span = document.createElement('span');
|
|
span.className = 'nav-item';
|
|
p.insertBefore(span, pair[0]);
|
|
span.appendChild(pair[0]);
|
|
span.appendChild(pair[1]);
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<nav id="sitenav">
|
|
<div class="sitenav">
|
|
<span class="navlink">
|
|
<span class="navlink-label">Up:</span> <a href="index.html" accesskey="u" rel="up">FISH-CONFIG</a>
|
|
</span>
|
|
<span class="navlink">
|
|
<span class="navlink-label">Top:</span> <a href="index.html" accesskey="t" rel="top">FISH-CONFIG</a>
|
|
</span>
|
|
</div>
|
|
<div class="sitenav">
|
|
<span class="navlink">
|
|
<span class="navlink-label">Next:</span> <a href="12-8-fisher-plugins.html" accesskey="n" rel="next">8. FISHER PLUGINS</a>
|
|
</span>
|
|
<span class="navlink">
|
|
<span class="navlink-label">Previous:</span> <a href="10-6-dependency-catalog.html" accesskey="p" rel="previous">6. DEPENDENCY CATALOG</a>
|
|
</span>
|
|
</div>
|
|
</nav>
|
|
<h1 data-number="11" id="7-customization">7. CUSTOMIZATION</h1>
|
|
<h2 data-number="11.1" id="machine-local-configuration">Machine-local
|
|
Configuration</h2>
|
|
<p>Place machine-specific settings that should not be committed to git
|
|
in:</p>
|
|
<pre><code>$__fish_user_dots_path/local.fish</code></pre>
|
|
<p><code>__fish_user_dots_path</code> defaults to
|
|
<code>~/.config/.user-dots/fish</code>. Set a custom location with:</p>
|
|
<pre><code>set -U __fish_user_dots_path /path/to/your/dots/fish</code></pre>
|
|
<p>Typical uses: additional PATH entries, local aliases,
|
|
hostname-specific env vars, work-specific tool configs.</p>
|
|
<h2 data-number="11.2" id="secrets-and-api-keys">Secrets and API
|
|
Keys</h2>
|
|
<pre><code>$__fish_user_dots_path/secrets.fish</code></pre>
|
|
<p>Store API tokens, GPG keys, private credentials here. This file is
|
|
never committed. It is sourced by local.fish directly, not by
|
|
config.fish.</p>
|
|
<p><code>local.fish</code> is sourced at the end of config.fish on every
|
|
interactive session, so it and its companion secrets.fish can override
|
|
anything set earlier.</p>
|
|
<h2 data-number="11.3"
|
|
id="overriding-configuration-variables">Overriding Configuration
|
|
Variables</h2>
|
|
<p>Any variable set in local.fish after the main config loads takes
|
|
effect. Example: to increase the scrollback history limit:</p>
|
|
<pre><code># in local.fish
|
|
set -gx SCROLLBACK_HISTORY_MAX_FILES 200</code></pre>
|
|
<h2 data-number="11.4" id="fish-universal-variables">Fish Universal
|
|
Variables</h2>
|
|
<p>Some settings (fzf colors, theme) are stored in fish_variables via
|
|
<code>set -U</code>. These are machine-local and git-ignored. Do not
|
|
commit fish_variables.</p>
|
|
<h2 data-number="11.5"
|
|
id="opinionated-components-minimal-mode">Opinionated Components (Minimal
|
|
Mode)</h2>
|
|
<p>Every opinionated piece of this config is active by default but can
|
|
be switched off through six category opt-out variables, each evaluated
|
|
via __fish_variable_check. Set a variable to any falsy value (0, false,
|
|
no, off, n) to disable its category; erase it or set a truthy value (1,
|
|
true, yes, on, y) to re-enable. Unset means enabled.</p>
|
|
<p>An explicit per-category truthy value takes precedence over the
|
|
master switch: setting __fish_config_opinionated=0 disables all unset
|
|
categories, but a category with an explicit truthy value remains enabled
|
|
regardless.</p>
|
|
<pre><code>Variable Disables
|
|
------------------------------ ------------------------------------
|
|
__fish_config_op_aliases Command shadows and flag injection:
|
|
ls->eza, cat->bat, cd->zoxide,
|
|
rm->trash, less->ov, top->btop,
|
|
ping->prettyping, ssh->kitten,
|
|
du->duf/dust, mkdir/bash wrappers,
|
|
history timestamps, grep/cp/mv/wget
|
|
flag injection, help intercept, claude
|
|
AGENTS.md auto-link
|
|
__fish_config_op_autoexec Startup side-effects: Fisher
|
|
bootstrap, theme apply, paru/yay
|
|
wrapper generation, auto venv
|
|
activation, WakaTime hook
|
|
__fish_config_op_overrides Key and env overrides: Vi mode,
|
|
exit->smart_exit, PAGER/MANPAGER,
|
|
CDPATH, bang-bang system, autopair,
|
|
puffer, starship prompt, theme
|
|
colors, FZF_DEFAULT_OPTS, right
|
|
prompt
|
|
__fish_config_op_integrations Terminal/tool coupling: Kitty/
|
|
WezTerm window abbreviations, done
|
|
notifications, spwin/tab/split,
|
|
hist, logs, upgrade, WakaTime
|
|
__fish_config_op_logging Logging & capture: scrollback
|
|
capture on exit, paru/yay AUR log
|
|
wrappers, Kitty watcher capture;
|
|
sentinel file coordinates
|
|
cross-process state
|
|
__fish_config_op_greeting Greeting & first-run UI: per-session
|
|
fish_greeting override (defines empty
|
|
function late in config.fish to
|
|
suppress distro greetings such as
|
|
CachyOS fastfetch); first-run welcome
|
|
banner in conf.d/first_run.fish</code></pre>
|
|
<p>Examples:</p>
|
|
<pre><code># Disable command shadows only (rm becomes plain rm again):
|
|
set -U __fish_config_op_aliases off
|
|
|
|
# Full minimal mode — disable all six categories at once:
|
|
set -U __fish_config_opinionated 0
|
|
|
|
# Re-enable everything:
|
|
set -Ue __fish_config_opinionated
|
|
|
|
# Minimal mode but keep the greeting:
|
|
set -U __fish_config_opinionated 0
|
|
set -U __fish_config_op_greeting 1
|
|
# (erase both to go back to full-flavor defaults)</code></pre>
|
|
<p>For an interactive alternative to setting these variables by hand,
|
|
run config-settings — a full-screen TUI that flips any category
|
|
(including C5 logging) on or off, per session or universally. See its
|
|
entry in Section 5.</p>
|
|
<p>Notes:</p>
|
|
<ul>
|
|
<li>Command shadows (rm, cat, ls, ...) react immediately; conf.d-level
|
|
components (bindings, prompt, abbreviations, hooks) take effect in new
|
|
shells.</li>
|
|
<li>With aliases disabled, rm falls back to bare <code>command rm</code>
|
|
— files are deleted permanently, not trashed.</li>
|
|
<li>Disabled integration commands (spwin, tab, split, hist, logs,
|
|
upgrade) print an error naming the variable that disabled them.</li>
|
|
<li>On CachyOS, the distro fish config's own aliases, history override,
|
|
and bang-bang bindings are stripped per category as well.</li>
|
|
</ul>
|
|
<h3 data-number="11.5.1" id="component-reference">Component
|
|
Reference</h3>
|
|
<p>The following tables detail every component in each category. Use
|
|
this reference to understand exactly which behaviors change when you
|
|
toggle a category variable.</p>
|
|
<h4 data-number="11.5.1.1" id="c1--command-shadows">C1 — Command
|
|
Shadows</h4>
|
|
<p>Disabling __fish_config_op_aliases restores standard system behavior
|
|
for all of these commands.</p>
|
|
<pre><code>Command / Alias Active behavior Disabled fallback
|
|
───────────────────────────────────────────────────────────────────────────
|
|
ls eza -l -a --icons --hyperlink system ls
|
|
cat bat syntax-highlighted; dirs → ls /usr/bin/cat
|
|
cd zoxide frecency-based navigation fish builtin cd
|
|
rm moves files to trash (recoverable) command rm (permanent)
|
|
less $PAGER → ov → less → more → cat system less
|
|
du duf (disk overview) or dust (dir tree) system du
|
|
top btop resource monitor system top
|
|
ping prettyping --nolegend animation system ping
|
|
ssh kitten ssh in Kitty terminal system ssh
|
|
rg rg --hyperlink-format=kitty system rg
|
|
mkdir verbose path-tree display on creation mkdir -p silently
|
|
bash XDG bashrc + $SHELL reset on exit system bash
|
|
history timestamps prepended to every entry fish builtin history
|
|
cp / mv forced -i confirmation prompt cp / mv unmodified
|
|
wget forced --continue (resume downloads) system wget
|
|
grep/fgrep/egrep forced --color=auto system grep variants
|
|
dir / vdir forced --color=auto system dir / vdir
|
|
help config intercepts "help config" → config-help fish builtin help
|
|
claude auto-links AGENTS.md as CLAUDE.md before launch command claude
|
|
edit multi-editor launcher (GUI/term + fallbacks) $EDITOR/nvim/nano/vi</code></pre>
|
|
<p>When C1 is disabled, <code>rm</code> uses bare
|
|
<code>command rm</code> with no wrapper — files are permanently deleted,
|
|
not trashed. There is no intermediate safety net.</p>
|
|
<h4 data-number="11.5.1.2" id="c2--startup-side-effects">C2 — Startup
|
|
Side-Effects</h4>
|
|
<p>These run automatically without any user action. Disabling
|
|
__fish_config_op_autoexec prevents all of them.</p>
|
|
<pre><code>Component Trigger What it does
|
|
───────────────────────────────────────────────────────────────────────────
|
|
Fisher bootstrap First shell only Downloads and installs fisher
|
|
Fisher update After bootstrap Installs all fish_plugins entries
|
|
Catppuccin Mocha theme First shell only Applies theme via fish_config
|
|
paru wrapper Every startup Writes ~/.local/bin/paru wrapper
|
|
yay wrapper Every startup Writes ~/.local/bin/yay wrapper
|
|
Python venv activation On every cd Sources .venv/bin/activate.fish
|
|
WakaTime command hook On every command Reports to WakaTime API
|
|
Auto-pull fast-forward On entering a repo Background ff-only git pull</code></pre>
|
|
<p>When C2 is disabled: no Fisher install, no theme application, no
|
|
paru/yay wrapper generation, no automatic venv activation, no WakaTime
|
|
reporting, and no auto-pull (the PWD handler is never registered). The
|
|
first-run completion marker (__fish_config_first_run_complete) is still
|
|
set so the init does not re-run on subsequent shells.</p>
|
|
<p>Python venv activation fires on every directory change. If a
|
|
directory uses direnv (.envrc present), direnv takes priority and
|
|
auto-venv is skipped for that directory.</p>
|
|
<p>Auto-pull fast-forwards opted-in repositories in the background when
|
|
you cd into them. The fish-config repo is always covered; other repos
|
|
are added with the <code>auto-pull</code> command (see its entry in the
|
|
functions reference). It only ever fast-forwards a clean repo whose
|
|
branch has an upstream — never rebases, merges, or overwrites work — so
|
|
it is a no-op on dirty trees, divergent branches, or repos without a
|
|
remote. The handler fires once per repo entry (not on every
|
|
sub-directory cd). The registry is machine-local at
|
|
~/.config/.user-dots/fish/auto-pull.list and is never committed.</p>
|
|
<h4 data-number="11.5.1.3" id="c3--key-and-environment-overrides">C3 —
|
|
Key and Environment Overrides</h4>
|
|
<p>These change fundamental shell behavior: how keys work, which pager
|
|
opens, and what the prompt looks like. Disabling
|
|
__fish_config_op_overrides removes all of them.</p>
|
|
<pre><code>Override What it replaces or sets
|
|
───────────────────────────────────────────────────────────────────────────
|
|
Vi mode fish_vi_key_bindings replaces default Emacs mode
|
|
exit → smart_exit exit wrapper that captures scrollback before closing
|
|
PAGER=ov ov used by git, man, and all $PAGER-aware tools
|
|
MANPAGER=bat pipeline man pages rendered with syntax highlighting
|
|
CDPATH=. ~/projects ~ bare dir names resolve against ~/projects and ~
|
|
Bang-bang system ! and $ keys expand history; !^, !*, !-N, !?str?,
|
|
^old^new abbreviations; six expand_bang_* helpers
|
|
Autopair ( [ { " ' auto-close to (), [], {}, "", ''
|
|
Puffer key intercepts . ! $ * keys intercepted for smart expansion
|
|
Starship prompt fish_prompt replaced by Starship + OSC 133 markers
|
|
Catppuccin colors 30+ fish_color_* variables set to Mocha palette
|
|
FZF_DEFAULT_OPTS FZF themed to Catppuccin Mocha colors
|
|
Right prompt fish_right_prompt: exit code (on failure) + dim timestamp; always rendered; Docker context added when starship+C3 active</code></pre>
|
|
<p>The bang-bang system spans key_bindings.fish, abbr.fish, puffer.fish,
|
|
and six expand_bang_*.fish functions. All are gated together — disabling
|
|
C3 removes the entire bang-expansion system at once.</p>
|
|
<p>When C3 is disabled, <code>exit</code> falls back to
|
|
<code>builtin exit</code> with no scrollback capture, no Kitty IPC, and
|
|
no file I/O on exit. The scrollback capture block is independently
|
|
controlled by C5 (see below).</p>
|
|
<h4 data-number="11.5.1.4" id="c4--terminal-and-tool-integration">C4 —
|
|
Terminal and Tool Integration</h4>
|
|
<p>These features couple the shell to specific external tools. Disabling
|
|
__fish_config_op_integrations disables all of them.</p>
|
|
<pre><code>Component Requires
|
|
───────────────────────────────────────────────────────────────────────────
|
|
~60 Kitty/WezTerm abbrs Active Kitty or WezTerm session
|
|
(:w, :wv, :wh, :t, etc.)
|
|
Done desktop notifications Graphical desktop with a notification daemon
|
|
spwin Kitty or WezTerm
|
|
tab Kitty, WezTerm, or Konsole
|
|
split Kitty or WezTerm
|
|
hist fzf + wl-copy (Wayland clipboard)
|
|
logs fzf + ov; reads from ~/.terminal_history/
|
|
upgrade paru or yay (Arch Linux only)
|
|
WakaTime hook wakatime CLI and a configured API key</code></pre>
|
|
<p>Disabled integration commands (spwin, tab, split, hist, logs,
|
|
upgrade) print a colored error to stderr naming the variable that
|
|
disabled them rather than silently failing.</p>
|
|
<h4 data-number="11.5.1.5" id="c5--logging-and-capture">C5 — Logging and
|
|
Capture</h4>
|
|
<p>Five components capture shell output to disk. Disabling
|
|
__fish_config_op_logging skips all capture and removes the logging
|
|
wrappers.</p>
|
|
<pre><code>Component What it captures
|
|
───────────────────────────────────────────────────────────────────────────
|
|
Scrollback capture Terminal session output saved to:
|
|
~/.terminal_history/scrollback_YYYY-MM-DD_HH-MM-SS.log
|
|
tmux pane capture Continuous pane stream via pipe-pane, saved to:
|
|
~/.terminal_history/tmux_<session>-w<win>-p<pane>_YYYY-MM-DD_HH-MM-SS.log
|
|
zellij pane capture Pane scrollback snapshot on shell exit, saved to:
|
|
~/.terminal_history/zellij_<session>-p<pane>_YYYY-MM-DD_HH-MM-SS.log
|
|
paru wrapper All paru/AUR output captured to:
|
|
~/.terminal_history/paru_YYYY-MM-DD_HH-MM-SS.log
|
|
yay wrapper All yay/AUR output captured to:
|
|
~/.terminal_history/yay_YYYY-MM-DD_HH-MM-SS.log
|
|
Kitty watcher watcher.py captures scrollback when Kitty closes</code></pre>
|
|
<p>The tmux capture starts automatically when fish launches inside any
|
|
tmux pane ($TMUX is set). It uses tmux's native pipe-pane to stream all
|
|
pane output directly to disk without an intermediate process. Each fish
|
|
shell session gets its own log file; a new log is created on each shell
|
|
start (including exec fish and new splits). Before each new log, the
|
|
oldest tmux_*.log files are pruned (by modification time) to keep the
|
|
total within SCROLLBACK_HISTORY_MAX_FILES, matching the paru/yay wrapper
|
|
behaviour.</p>
|
|
<p>The zellij capture works differently: Zellij has no live
|
|
output-streaming facility like pipe-pane, so the log is taken as a
|
|
one-shot snapshot when the shell exits, via
|
|
<code>zellij action dump-screen --full --ansi</code> (the --ansi flag
|
|
preserves color). The dump is captured on the fish process's stdout and
|
|
written to the log file by fish itself (not via <code>--path</code>,
|
|
which would make the zellij server write the file). A fish_exit handler
|
|
(registered whenever $ZELLIJ is set) writes the pane's full scrollback
|
|
and then prunes old zellij_*.log files the same way. Because the capture
|
|
happens at exit, toggling __fish_config_op_logging takes effect on the
|
|
next exit with no restart or sentinel coordination needed — the C5 guard
|
|
is re-checked when the handler fires.</p>
|
|
<p>LIMITATION — zellij capture only fires on a clean shell exit (typing
|
|
<code>exit</code>, Ctrl-D, or a logout), because that is when the
|
|
fish_exit handler runs. It does NOT capture when you close a pane or
|
|
quit zellij through zellij itself:</p>
|
|
<ul>
|
|
<li>Closing a pane signals the shell and tears the pane down
|
|
concurrently, so even if the handler runs, <code>dump-screen</code> may
|
|
find the pane buffer already gone.</li>
|
|
<li>Quitting zellij kills the zellij server, and
|
|
<code>dump-screen</code> needs a live server to read from — there is
|
|
nothing left to snapshot.</li>
|
|
</ul>
|
|
<p>This is a structural difference from tmux, NOT a bug. tmux streams
|
|
pane output to disk continuously via pipe-pane, so whatever was printed
|
|
is already saved no matter how the pane dies. Zellij can only snapshot,
|
|
and the only reliable snapshot point from the shell is a clean exit. To
|
|
guarantee a zellij pane is logged, end the session with
|
|
<code>exit</code> or Ctrl-D rather than zellij's close-pane or quit
|
|
actions.</p>
|
|
<p>The Kitty watcher is managed by the kitty-logging command: it
|
|
installs a version-marked watcher (fish-config-watcher.py) into the
|
|
Kitty config directory and wires it into kitty.conf via a managed block.
|
|
Inside Kitty, a non-blocking per-session reminder points first-time
|
|
users at <code>kitty-logging install</code> until they install or run
|
|
<code>kitty-logging dismiss</code>. Install affects new Kitty windows
|
|
only; runtime disable is still handled by the .logging_disabled
|
|
sentinel.</p>
|
|
<p>Logging coordination via sentinel file</p>
|
|
<p>C5 uses a sentinel file to synchronize state between the shell and
|
|
out-of-process components (the Kitty watcher and all running
|
|
shells):</p>
|
|
<pre><code>~/.config/fish/.logging_disabled</code></pre>
|
|
<p>Disabling __fish_config_op_logging:</p>
|
|
<ol type="1">
|
|
<li>Creates the sentinel immediately in every open shell.</li>
|
|
<li>Removes ~/.local/bin/paru and ~/.local/bin/yay logging wrappers;
|
|
bare /usr/bin/paru and /usr/bin/yay are used instead.</li>
|
|
<li>Kitty's watcher.py reads the sentinel on each save attempt and skips
|
|
capture — no Kitty restart required.</li>
|
|
<li>smart_exit stops saving scrollback logs.</li>
|
|
<li>Stops tmux pipe-pane capture in every open fish shell inside
|
|
tmux.</li>
|
|
</ol>
|
|
<p>Re-enabling __fish_config_op_logging:</p>
|
|
<ol type="1">
|
|
<li>Removes the sentinel in every open shell.</li>
|
|
<li>Regenerates paru/yay logging wrappers in ~/.local/bin/.</li>
|
|
<li>Kitty watcher resumes capture on the next session exit.</li>
|
|
<li>Restarts tmux pipe-pane capture in every open fish shell inside
|
|
tmux.</li>
|
|
</ol>
|
|
<p>Changes propagate to all running shells through an event handler that
|
|
fires whenever __fish_config_op_logging changes — no shell restart
|
|
needed.</p>
|
|
<p>Note: C3 and C5 compose independently. C3 controls whether the
|
|
smart_exit wrapper is active at all; C5 controls only the
|
|
scrollback-capture block inside it. With C3 disabled, exit is plain
|
|
builtin exit regardless of C5.</p>
|
|
<h4 data-number="11.5.1.6" id="c6--greeting-and-first-run-ui">C6 —
|
|
Greeting and First-Run UI</h4>
|
|
<pre><code>Component What it shows
|
|
───────────────────────────────────────────────────────────────────────────
|
|
First-run welcome banner One-time message on first interactive session
|
|
fish_greeting override Empty function defined late in config.fish to
|
|
suppress distro greetings (e.g. CachyOS sets
|
|
fish_greeting to fastfetch by default)</code></pre>
|
|
<p>When C6 is disabled, no greeting is printed by this config. Any
|
|
greeting set by the distro or other configs runs normally — this config
|
|
simply does not override it.</p>
|
|
<h2 data-number="11.6" id="prompt-and-theme">Prompt and Theme</h2>
|
|
<h3 data-number="11.6.1" id="starship">Starship</h3>
|
|
<p>The primary prompt is Starship, initialized by conf.d/starship.fish.
|
|
Configure it via ~/.config/starship.toml.</p>
|
|
<p>conf.d/starship.fish defines a fish_prompt wrapper that only
|
|
activates when starship is in PATH. It emits OSC 133;A (prompt start)
|
|
immediately before Starship renders and OSC 133;B (input start)
|
|
immediately after, placing both markers on the prompt line itself. This
|
|
allows ov to use them as sticky section headers when browsing scrollback
|
|
logs. Without Starship, fish's built-in prompt handles these markers
|
|
automatically.</p>
|
|
<h3 data-number="11.6.2" id="catppuccin-fallback-prompt">Catppuccin
|
|
Fallback Prompt</h3>
|
|
<p>When Starship is absent or C3 overrides are disabled, a built-in
|
|
nim-style two-line prompt activates from functions/fish_prompt.fish. No
|
|
external dependencies — fish builtins only.</p>
|
|
<p>Layout:</p>
|
|
<pre><code>┬─[user@host:~/path] (main)
|
|
╰─>$</code></pre>
|
|
<p>Elements:</p>
|
|
<pre><code>user Yellow (Catppuccin Yellow); red if root
|
|
@host Blue (local) or Teal (SSH)
|
|
~/path prompt_pwd abbreviation (Catppuccin Text)
|
|
(main) Current git branch in Catppuccin Pink; omitted outside repos
|
|
─[V:name] Active Python venv basename; omitted when none
|
|
─[N/I/R/V] Vi-mode indicator when vi bindings are active
|
|
┬─ / ╰─> Connector lines: Catppuccin Green on success, Red on failure</code></pre>
|
|
<p>The right prompt (fish_right_prompt.fish) always renders, regardless
|
|
of C3 state. On failure it shows a red ✘ and the exit code; on success
|
|
it shows only the dim timestamp. When starship is installed and C3 is
|
|
enabled, the active Docker context is also shown (if non-default):</p>
|
|
<pre><code>✘ 1 myctx Fri Jun 12 00:51:21 2026 ← failed, starship+C3 active
|
|
✘ 1 Fri Jun 12 00:51:21 2026 ← failed, fallback prompt
|
|
Fri Jun 12 00:51:21 2026 ← success (no ✘)</code></pre>
|
|
<h3 data-number="11.6.3" id="fzf">FZF</h3>
|
|
<p>FZF is themed to Catppuccin Mocha via FZF_DEFAULT_OPTS set in
|
|
integrations/fzf.fish. The colors applied:</p>
|
|
<pre><code>Background: #1E1E2E (base) #313244 (surface0)
|
|
Foreground: #CDD6F4 (text)
|
|
Highlights: #F38BA8 (red) #CBA6F7 (mauve) #B4BEFE (lavender)</code></pre>
|
|
<p>To customize, override FZF_DEFAULT_OPTS in local.fish.</p>
|
|
<h3 data-number="11.6.4"
|
|
id="catppuccin-mocha-syntax-highlighting">Catppuccin Mocha Syntax
|
|
Highlighting</h3>
|
|
<p>The Catppuccin Mocha theme ships with this config in themes/ and is
|
|
applied on first run via <code>conf.d/first_run.fish</code>. Colors are
|
|
stored in fish_variables (universal). To switch variants, install a
|
|
different theme from themes/:</p>
|
|
<pre><code>fish_config theme save "Catppuccin Latte"</code></pre>
|
|
<hr />
|
|
</body>
|
|
</html>
|