Compare commits

..
622 Commits
Author SHA1 Message Date
rootiest 679a703ab2 Merge pull request 'fix(ci): base64-encode the bot GPG key secret' (#147) from fix/ci-gpg-key-base64 into main 2026-09-10 04:00:24 +00:00
fishconfig-bot ecfcea5106 chore(docs): regenerate manual, man page, and component registry 2026-09-10 03:58:16 +00:00
rootiest 4da176d507 fix(ci): base64-encode the bot GPG key secret
Raw multi-line armored key piped through 'echo | gpg --import' came out
CRC-corrupted (Invalid keyring) on the first real run -- something in the
secret/env round-trip mangles embedded newlines. Regenerated the bot key
(old one is unrecoverable, secrets are write-only) and store it
base64-encoded, decoded with base64 -d before import.
2026-09-09 23:52:40 -04:00
rootiest cc9531f19f Merge pull request 'fix(agy): map -r/--resume with session id to --conversation' (#146) from fix/agy-resume-conversation-syntax into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 1m53s
CI / build-docs (push) Failing after 3m38s
Reviewed-on: #146
2026-09-10 03:37:58 +00:00
rootiest 4ab52329e1 fix(agy): map -r/--resume with session id to --conversation
agy uses different resume syntax than claude: -c/--continue always
resumes the most-recent session, while --conversation takes a
specific session id. Previously -r/--resume was blanket-mapped to
-c/--continue, breaking `agy --resume <id>` and `agy -r=<id>` style
invocations. Now bare -r/--resume (no id following) maps to
-c/--continue; -r/--resume given an id (via =id or a following
non-flag word) maps to --conversation(=id).
2026-09-09 23:24:29 -04:00
rootiest 2597b3ccd3 Merge pull request 'fix(ci): sign docs-regen commits with dedicated bot GPG key' (#145) from fix/ci-commit-signing into main 2026-09-10 02:48:51 +00:00
rootiest a751124b8b fix(ci): sign docs-regen commits with dedicated bot GPG key
actions@gitea was never a verified email on any Gitea account, so the
CI docs-regen commit (git commit && git push, done client-side in the
runner) could never show as verified regardless of server-side
[repository.signing] config -- Gitea only signs commits it generates
itself (merge button, web editor, wiki), never ones a client pushes.

Import a dedicated passphrase-less key for a new fishconfig-bot
account (verified email, no login) from the CI_GPG_PRIVATE_KEY repo
secret and sign with it instead.
2026-09-09 22:16:13 -04:00
rootiest 6732a71eb7 Merge pull request 'fix(git-clean): strip the '+' other-worktree marker too' (#144) from fix/clean-worktree-branch-marker into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 1m58s
CI / build-docs (push) Successful in 3m37s
2026-09-10 01:15:42 +00:00
rootiest e6c6d2533d fix(git-clean): strip the '+' other-worktree marker too
git branch -vv marks column 1 with '+' (not '*') for a branch checked
out in another linked worktree. Only '*' was stripped from $1, so a
gone branch shown with '+' left a bogus "+" entry in $gone_branches
that then failed to delete: error: branch '+' not found.

Add a regression case reproducing the '+'-marked gone-branch line via
the existing git-clean mock handler in tests/test-network-fish.fish.
2026-09-09 21:14:04 -04:00
Gitea Actions 6199caf0d0 chore(docs): regenerate manual, man page, and component registry 2026-09-10 01:11:47 +00:00
rootiest d93cb286ef Merge pull request 'feat(mkrep): add directory + git-repo scaffolding command' (#142) from feat/mkrep-command into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 1m49s
CI / build-docs (push) Successful in 3m35s
2026-09-10 01:01:37 +00:00
rootiest 3c621db727 Merge pull request 'test: expand test coverage across core functions, enforce strict fish_indent linting, and add network isolation harnesses' (#143) from test/network-edge-case-coverage into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m2s
CI / build-docs (push) Successful in 3m34s
2026-09-10 01:00:45 +00:00
rootiest 04edd6de89 test: add core utilities and security test suite 2026-09-09 20:50:21 -04:00
rootiest a1cf06624e fix(security): return full variable name in sponge_filter_secrets 2026-09-09 20:49:16 -04:00
rootiest c7d7cea8ae test: eliminate flakiness in rand_string casing test and improve history cleanup 2026-09-09 20:43:52 -04:00
rootiest ff4f7b3909 test: add string and commandline expansion test suite 2026-09-09 20:39:46 -04:00
rootiest b3082a3313 feat(mkrep): add directory + git-repo scaffolding command
mkcd's create-and-cd behavior plus git init, remote linking, and
optional remote creation via a user-configured command template
($MKREP_REMOTE_CMD, {name}/{user} placeholders).
2026-09-09 20:38:09 -04:00
rootiest d926a632d5 test: enforce fish_indent --check in test runner 2026-09-09 20:32:43 -04:00
rootiest e40d67df59 style: format fish files with fish_indent 2026-09-09 20:27:48 -04:00
rootiest 2dc978e719 fix(docs): align registry generator output with fish_indent 2026-09-09 20:27:21 -04:00
rootiest de6349f2dc test(net): add network isolation harnesses and failure edge case coverage 2026-09-09 19:51:17 -04:00
Gitea Actions b59318e957 chore(docs): regenerate manual, man page, and component registry 2026-09-09 19:59:39 +00:00
rootiest 90aaa6dcda Merge pull request 'feat(config-settings): replace the ANSI renderer with a curses front-end' (#141) from feat/config-settings-curses-tui into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 1m47s
CI / build-docs (push) Successful in 3m45s
Reviewed-on: #141
2026-09-09 19:54:11 +00:00
rootiest 9af0462d29 test(config-settings): cover the empty state dump refusal
The guard added in 208ad95 had no test. This is the failure worth
covering, because it is the one that does not announce itself: with an
empty dump every row renders as DEFAULT, indistinguishable from a config
where nothing is set, so the user toggles from a false baseline.

Reaching the guard needs a real terminal -- the isatty check sits in
front of it -- so the case runs fish under a pty via python3's stdlib
pty module, which this suite already depends on. An empty
__config_settings_state is shadowed in to fake the failure.

The pty reader's 15s deadline is load-bearing rather than defensive: if
the guard regresses, config-settings does not fail, it opens the TUI and
blocks on getch(), so an unbounded read would hang the suite instead of
failing it. Verified both ways -- passes with the guard, and with the
guard removed the deadline fires and the case fails with a legible
excerpt rather than a screenful of escape sequences.
2026-09-09 15:41:39 -04:00
rootiest 208ad95883 fix(config-settings): refuse to open on an empty state dump
An empty dump does not fail loudly: the TUI renders every row as
DEFAULT, which is indistinguishable from a config where nothing is set.
That is a wrong answer rather than a missing one -- the user would be
looking at ON rows reported as DEFAULT -- so the launcher now checks the
dump is non-empty and bails with a message instead. The taxonomy alone
guarantees output on any working checkout. Also guard a failed mktemp,
which would otherwise send the dump to /state and hand an empty path to
rm -rf.

README: mention that / searches sub-categories across every category.
2026-09-09 15:36:40 -04:00
rootiest 983434ffb4 docs(config-settings): drop backticks from the function header
test_concat_section_five_stays_verbatim forbids backticks inside
generated Section 5 entries -- function headers are rendered verbatim, so
inline code markup there breaks the man page.
2026-09-09 14:51:59 -04:00
rootiest 078d01666e feat(config-settings): replace the ANSI renderer with a curses front-end
config-settings is now a launcher for scripts/config-settings-tui.py,
drawn with Python's stdlib curses. The seven fish files that hand-rolled
the ANSI renderer are gone, along with the golden harness that had to pin
their byte-exact output.

The TUI is a child process, so it can neither read the session's global
variables nor write them. State goes in as a dump from the new
__config_settings_state; the edits come back as a fish script that
config-settings sources, which is what lets the Session page's `set -g`
land in the caller's shell instead of in a child that is about to exit.
Every edit is emitted as a call to __config_settings_apply or
__config_settings_set_value, so list splitting, the SCROLLBACK_HISTORY_*
export mirror and the shadow-warning suppression all stay in the fish
layer that already owned them.

The consequence, and the one behaviour change: edits are applied in one
batch on exit rather than on each keypress. The status bar shows a
pending count.

New: `/` filters the current page, and on the Universal and Session pages
it reaches into every category's sub-categories, listing hits as
"Category › Sub" so a sub-category can be toggled without drilling into
its parent first. Also a `?` help overlay, mouse selection, and a
drill-down page that leads with the category's own toggle.

Gone with the renderer: the four width tiers, the wrap-aware erase
arithmetic, the stty/dd/od raw key reader, the panel-height bookkeeping
and the hand-written redraw differ. curses owns all of it, and the alt
screen plus absolute addressing makes the desync class behind 608b022,
4210f3b, 93fc5e0 and 3c4f720 unreachable.

The sub-category taxonomy is NOT duplicated in Python: it travels in the
state dump, still sourced from __config_settings_subcats. The category,
Sponge and Paths row tables move into Python, consolidating the two
copies the fish renderers kept.

Dependency: python3 with curses. Stdlib on Arch, Fedora and a full
Debian/Ubuntu python3; python3-minimal alone lacks _curses. The launcher
checks for both and names what is missing. Called out in the README.

Verified: 416/416 assertions, plus a live end-to-end in a sandbox HOME
confirming the Universal page writes universal scope only (U1/G0) and the
Session page global scope only (U0/G1).
2026-09-09 14:50:26 -04:00
rootiest c5d2624a06 feat(config-settings): curses prototype front-end
Add scripts/config-settings-tui.py, a stdlib-curses prototype of the
config-settings interface, plus a gate that runs its --self-test.

The backend is stubbed: values live in an in-memory dict and nothing is
read from or written to fish variables. This is here to evaluate the
render engine and the interaction model before committing to a rewrite.

Why curses rather than more ANSI arithmetic:

  - No flicker, structurally. curses diffs its virtual screen against the
    physical one and emits only the changed cells, which is what
    __config_settings_diff_redraw.fish reimplements by hand.
  - Alternate screen plus absolute addressing. Stray output cannot desync
    the display, so the bug class behind 608b022 (fish's read prompt),
    4210f3b (a shadow warning on stderr), 93fc5e0 and 3c4f720 (line wrap
    breaking the erase height) cannot occur at all.
  - Resize is a repaint rather than wrap-factor arithmetic.
  - Overlays, panes, live filtering and mouse input cost a few lines each.

The layout departs from the current single panel: a page sidebar with a
live filter on the left, a scrolling detail pane on the right, a help
overlay on '?', and mouse selection. Sub-category drill-down, the
tri-state badges and the Sponge/Paths value rows all carry over.

Dependency note: python3 with the curses module. That is stdlib on Arch,
Fedora and a full Debian/Ubuntu python3; python3-minimal alone does not
carry _curses, so the test asserts the import.

The prototype is not wired into config-settings and nothing existing
changed.
2026-09-09 14:29:40 -04:00
Gitea Actions 69de224cbf chore(docs): regenerate manual, man page, and component registry 2026-09-09 04:49:54 +00:00
rootiest 8e4b719425 fix(docs): title distro code blocks and fix missed shell highlighting (#140)
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m19s
CI / build-docs (push) Successful in 3m46s
2026-09-09 04:43:50 +00:00
rootiest 8f48120ba9 Merge pull request 'docs: strip gitignored AGENTS/ and JOB-BRIEF-FINDINGS references from code comments' (#139) from docs/strip-agents-internal-refs into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 1m57s
CI / build-docs (push) Successful in 3m27s
2026-09-08 16:59:05 +00:00
rootiest 9d7cddf758 docs: strip gitignored AGENTS/ and JOB-BRIEF-FINDINGS references from code comments
Comments in tracked files pointed readers at AGENTS/specs/*.md,
AGENTS.md, and JOB-BRIEF-FINDINGS.md -- all gitignored, transient
dev notes not part of the base repo. Rewrote each to be self-contained
or point at tracked docs (docs/fish-config.md) instead.
2026-09-08 12:54:53 -04:00
Gitea Actions d4c40519e5 chore(docs): regenerate manual, man page, and component registry 2026-09-08 16:50:35 +00:00
rootiest fb454da3bc Merge pull request 'fix(docs): strip backticks from Section 5 verbatim EXIT STATUS/ARGUMENTS lines' (#138) from fix/docs-verbatim-backticks into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m17s
CI / build-docs (push) Successful in 3m56s
2026-09-08 16:44:10 +00:00
rootiest 91dabd565c fix(docs): strip backticks from Section 5 verbatim EXIT STATUS/ARGUMENTS lines
Section 5 (function manpages) is pandoc-rendered verbatim, so a backtick
there is a literal character on the page, not markup. Nine EXIT STATUS/
ARGUMENTS lines across check_fish_deps, lock, cleanup, claude-pr,
claude-docs, dops, ports, screensleep, and steam-dl quoted a command with
backticks; reworded to plain text matching each function's own DESCRIPTION
style.

Fixes docs/verify-manual.py's test_concat_section_five_stays_verbatim,
failing in CI since before this branch (pre-existing on main, confirmed
against the commit before PR #133 merged).
2026-09-08 12:42:30 -04:00
rootiest 453a8500af Merge pull request 'refactor(config-settings): shared frame renderer + line-diff redraw' (#133) from refactor/config-settings-renderer into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m1s
CI / build-docs (push) Failing after 1m6s
Reviewed-on: #133
2026-09-08 16:28:51 +00:00
rootiest afbc3e97d7 Merge remote-tracking branch 'origin/main' into refactor/config-settings-renderer
# Conflicts:
#	functions/__config_settings_draw.fish
#	functions/__config_settings_draw_subcat.fish
#	functions/__config_settings_draw_value.fish
#	tests/functional.fish
2026-09-08 12:19:31 -04:00
rootiest 3c4f720749 fix(config-settings): repair diff-redraw review findings
- Print the missing exit-repaint after the inline editor's
  __cs_dispatch_draw call (was silently changed to capture-only earlier
  in the branch; this call site was missed, blanking the panel on
  commit/cancel of an inline edit).
- Hoist (count $prev_edit_frame) out of a quoted math string in the
  inline editor's per-keystroke redraw -- fish doesn't expand a command
  substitution there, so math silently errored.
- Add a >= 52 column floor to both diff-path guards: below the
  narrowest tier's own 52-column box width, lines wrap and the diff
  path's one-physical-row-per-logical-line walk corrupts the display.
- Reword a stale test comment that described panel_h as mirroring a
  hand-set constant in __cs_dispatch_draw; it derives panel_h from real
  output now.
- Declare prev_edit_frame with -l alongside edit_frame instead of a
  bare set, matching the file's convention.
- Move prev_frame's declaration to its point of use instead of an
  empty top-level placeholder, matching old_h in the same block.
2026-09-08 04:37:27 -04:00
rootiest a0491b2bd1 feat(config-settings): diff redraw in the inline value editor 2026-09-08 04:21:07 -04:00
rootiest fae15b8d55 feat(config-settings): diff redraw in the main navigation loop 2026-09-08 04:17:32 -04:00
rootiest ab14837e39 refactor(config-settings): dispatch captures the frame instead of printing it 2026-09-08 04:13:52 -04:00
rootiest ece3e9dbfb feat(config-settings): add __config_settings_diff_redraw 2026-09-08 04:08:00 -04:00
rootiest 7b02348f64 test(config-settings): lock draw-function line counts to their panel heights 2026-09-08 03:57:26 -04:00
rootiest 4f62710061 Merge pull request 'chore(gitignore): ignore agy's .agents/ cache via shared AI-tool glob' (#137) from fix/gitignore-agy-agents-dir into main
Reviewed-on: #137
2026-09-08 07:02:37 +00:00
rootiest c77a52acd3 chore(gitignore): ignore agy's .agents/ cache via shared AI-tool glob
Root-cause fix in the shared boilerplate template (~/.config/.user-dots/git/gitignore),
same tier as .claude*/.gemini*/.antigrav*. Drops the manual one-off .agents
line; re-stamped this repo's boilerplate block to the new template hash.
2026-09-08 03:00:21 -04:00
rootiest 31b89bbac7 Merge pull request 'refactor(functions): consolidate 198 duplicate color declarations into one helper' (#131) from refactor/shared-color-palette into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 1m59s
CI / build-docs (push) Failing after 1m14s
2026-09-08 05:44:16 +00:00
rootiest b541323949 Merge remote-tracking branch 'origin/main' into refactor/shared-color-palette
# Conflicts:
#	tests/functional.fish
2026-09-08 01:43:01 -04:00
rootiest 6679d19a09 Merge pull request 'fix: split dops/docker, fix header doc gaps from Job 3 findings' (#135) from fix/dops-docker-and-header-gaps into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m2s
CI / build-docs (push) Failing after 1m18s
2026-09-08 05:40:55 +00:00
rootiest 6b2cc3aefc Merge remote-tracking branch 'origin/main' into fix/dops-docker-and-header-gaps 2026-09-08 01:39:44 -04:00
rootiest f2744a9a60 Merge pull request 'feat(help): render --help from function headers; stop 8 functions executing on --help' (#132) from feat/header-driven-help into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m9s
CI / build-docs (push) Failing after 3m59s
2026-09-08 05:39:23 +00:00
rootiest 2e82761b7d Merge remote-tracking branch 'origin/main' into feat/header-driven-help
# Conflicts:
#	tests/functional.fish
2026-09-08 01:38:24 -04:00
rootiest 001c5d3df7 Merge pull request 'fix: tricks.fish double-source and paru/yay wrapper duplication' (#136) from fix/tricks-double-source-and-paru-wrapper-dedup into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 1m46s
CI / build-docs (push) Failing after 4m22s
2026-09-08 05:31:52 +00:00
rootiest 8487f124c7 Merge remote-tracking branch 'origin/main' into fix/tricks-double-source-and-paru-wrapper-dedup 2026-09-08 01:30:43 -04:00
rootiest a994f9e91c Merge pull request 'perf(conf.d): cut shell startup latency by ~30%' (#130) from perf/startup-latency into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 1m49s
CI / build-docs (push) Failing after 3m48s
2026-09-08 05:30:05 +00:00
rootiest 43752aa268 Merge remote-tracking branch 'origin/main' into perf/startup-latency
# Conflicts:
#	tests/functional.fish
2026-09-08 01:28:27 -04:00
rootiest 0a2290640f Merge pull request 'test: unify the test harness, discover suites, fix a real hermeticity leak' (#134) from test/test-harness-overhaul into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 1m49s
CI / build-docs (push) Successful in 3m46s
2026-09-08 05:26:28 +00:00
rootiest 23bf649c5f fix(functions): dedupe conflicting paru/yay wrapper generators
__fish_config_sync_logging carried its own inferior copy of the
paru/yay wrapper generator (tee-based, no PTY, no progress-bar
rendering, hard-coded /usr/bin/paru|yay) alongside the canonical
version-6 generators in conf.d/paru-wrapper.fish and
conf.d/yay-wrapper.fish. Both wrote the same file with different
version markers and the same misattributed provenance comment, so
whichever ran last won and a subsequent C5 toggle would flip it back.
See startup-latency-JOB-BRIEF-FINDINGS.md §2.

__fish_config_sync_logging now delegates entirely to the canonical
generators instead of carrying a copy: they already resolve the real
binary via __fish_real_command (never /usr/bin-assumed) and
independently gate on their own C2/C5 keys, covering both the
enabled-regenerate and disabled-remove cases.

One behavior change falls out of delegating rather than special-casing
around it: a wrapper is no longer generated when C2 (paru-autoexec /
yay-autoexec) is disabled, even if C5 logging is on. The removed
sync-logging copy never checked C2, so it could reinstall a wrapper
the user had explicitly turned auto-exec off for.

Adds functions/_fish_source_scoped.fish: a small helper that runs
source inside its own function-call boundary. source itself runs in
the caller's scope, so a bare return inside a sourced conf.d guard
(both files have several) would otherwise unwind whatever function
called source directly -- verified with a minimal repro before relying
on it. Routing through this helper contains the return to just that
call, so calling paru's generator and then yay's actually reaches the
second call.

Manually verified end-to-end in an isolated HOME/XDG sandbox with a
stubbed paru/yay: enable generates both v6 wrappers, disable removes
both and drops the sentinel, re-enable regenerates them and clears the
sentinel.
2026-09-08 01:22:22 -04:00
rootiest f5c4016fa6 perf(conf.d): stop re-running expensive setup on tricks.fish's second source
tricks.fish is sourced twice per shell on CachyOS: once by the conf.d
autoload, once forced by config.fish to re-win over the distro's own
tricks.fish (measured 4.55ms for the second pass, see
startup-latency-JOB-BRIEF-FINDINGS.md §1). The bang-bang functions,
aliases, and history override further down need to re-run on both
passes since those are what re-assert over the distro config, but the
PATH/MANPAGER setup does not.

Gates fish_add_path and the type -q bat probe behind a once-per-session
global, guarding only that block. Everything else in the file, and the
coupling with config.fish's own cachyos-tricks guard, is unchanged.
2026-09-08 01:22:10 -04:00
rootiest dccf897c9f docs(functions): add missing EXIT STATUS header docs
Fills the gaps recorded in JOB-BRIEF-FINDINGS.md for the functions
converted to header-driven --help: 16 argument-less functions gain an
EXIT STATUS section (check_fish_deps, claude-docs, claude-pr, cleanup,
fast, fzf-update, gip, gip4, hist, limine-edit, lock, ports,
screensleep, steam-dl, swapstat, tmux-clean), and 8 functions that
already document ARGUMENTS gain EXIT STATUS too (lD, lsr, lss, lstree,
lt, ltr, lx, qr).

Not touched: gip6, ld, parur, sudo-toggle, upgrade, the JOB-BRIEF's
'missing ARGUMENTS' group. Re-checked their bodies against that claim
-- none of the five take a positional argument ($argv only appears
forwarded to the --help check), so an ARGUMENTS section would document
something that doesn't exist. All five already have EXIT STATUS.
2026-09-08 01:12:04 -04:00
rootiest 3aa462a2b8 style(functions): remove blank line in sponge_filter_secrets.fish header
The man-page comment header was separated from the function line by a
blank line -- the only file in functions/ with that gap. Cosmetic, no
runtime effect (manualtools and the help-flag renderer both tolerate
it by walking past a blank separator). See JOB-BRIEF-FINDINGS.md §2;
the renderer's tolerance for this case is left in place deliberately,
it is not dead code.
2026-09-08 01:11:56 -04:00
rootiest 23420b3235 fix(functions): split dops.fish into dops and docker
dops.fish defined `docker`, not `dops`. dops was never defined; docker
was only conditionally defined as a side effect of the failed dops
autoload, so its behavior could silently change mid-session. See
JOB-BRIEF-FINDINGS.md §1.

- functions/dops.fish now defines dops: a real enhanced `docker ps`
  listing (custom Names/Image/Status/Ports table), with its own --help.
- functions/docker.fish is a new file holding the ps-redirect wrapper,
  fixed to actually call dops (previously called the still-undefined
  dops from inside itself).
- Bare `docker` with no arguments no longer falls through an
  if-with-no-else (the fish false-zero, AGENTS.md standing gotcha #5)
  and does nothing; it now runs the real docker binary, which prints
  its own usage.
- tests/functional.fish: updated the now-stale comment explaining why
  the help-flag check resolves the real function name instead of the
  file stem.
2026-09-08 01:11:49 -04:00
rootiest a3853a93d8 test: run the config-settings render golden in the test runner
A byte-identity gate CI never runs will rot, and a rotted gate is worse
than no gate. Adds the render harness as Phase 4, in the same shape as the
vault suite: its own process, its own sandbox, no loaded config needed.

Kept to one self-contained block so it can be dropped or re-applied by
hand if the runner is restructured. The functional suite's 317/317 count
is untouched; the render cases report separately.
2026-09-07 20:13:08 -04:00
rootiest 328e30882e test: assert converted functions still emit colour in --help
Runtime escape-presence check over 24 user-facing functions.

Deliberately not a static grep for __fish_palette: measured on a broken
logs.fish whose --help block lost its declarations without gaining a call,
`fish -n` exited 0 and `grep -c __fish_palette` returned 1 while the help
output went 431 B -> 150 B with every escape stripped. The full suite was
green too. Only running the function and looking for an \e byte catches it;
that demonstration is recorded as a comment above the test.

Verified red as well as green -- deleting the __fish_palette call from
functions/mkcd.fish yields:

  --help lost its colour: mkcd
  FAIL  test_functions_keep_their_palette
  16/17 passed

fish_prompt.fish is excluded by name (its own hex palette); qc is excluded
because its --help shells out to aichat, which CI lacks.
2026-09-07 20:12:59 -04:00
rootiest 1f847bfce0 test(guards): cover always/on, always/off and AND via a synthetic registry
14 cases. The production registry has 65 entries all carrying exactly one
tag and no always/* anywhere, so these three documented semantics are
unreachable from real data -- the synthetic keys/values table is the only
way to reach them. Reasoning recorded at the fixture.

Also pins the degenerate no-slash tag and reaches C5 through
__fish_config_op_enabled, which is the path production code takes.
2026-09-07 20:12:22 -04:00
rootiest 7a6a7339dc test(guards): cover op_enabled against the real registry
5 cases: default-on, .fish suffix stripping, category off, subcategory
overriding it, and the documented fail-open on a missing entry.
2026-09-07 20:11:06 -04:00
rootiest 7d815b17e8 refactor: retire drifted palette names in the last five functions
c_rst/c_txt -> c_reset, c_ttl -> c_head, c_bold -> c_cmd, c_primary -> c_arg
across 67 interpolation sites (c_rst 53, c_primary 10, c_bold 2, c_ttl 1,
c_txt 1). Each maps to a variable holding identical bytes, so output is
unchanged. Unlike the 33 structural conversions this edits text that
renders, so it is gated on its own per-file byte-diff against main:

  ok  logs --help         (431 B out, 0 B err)
  ok  mkcd --help         (437 B out, 0 B err)
  ok  qc --help           (936 B out, 0 B err)
  ok  rand_string --help  (883 B out, 0 B err)
  ok  smart_exit --help   (265 B out, 0 B err)
  ok  mkcd                (437 B out, 0 B err)   <- no-args error path

c_accent is deliberately NOT merged into c_ok -- both are (set_color green)
but a role is a semantic slot, not a colour. See JOB-BRIEF-FINDINGS.md.

logs.fish needed two calls (the C4 guard block and the --help block, both at
8-space indentation); it is the only multi-run file in the repository and the
exact trap a depth-deduplicating converter falls into. logs.fish also declared
c_bold without ever interpolating it -- that declaration is simply deleted.
2026-09-07 20:10:43 -04:00
rootiest 2efbcfc53f test(guards): cover registry lookup, including identity:site pairing
5 cases. The wrong-site case pins that the key is the identity:site pair
rather than the identity alone.
2026-09-07 20:10:15 -04:00
rootiest f6ead99f48 feat(help): header-driven --help for development functions, plus the wiring guard
bd-pull, branch, check_fish_deps, claude-docs, claude-pr, fast, poke, qr
and parur take the standard call site. fish-deps instead routes -h/--help
to its existing __fish_deps_help, which previously answered only via the
unknown-subcommand path, printing "Unknown subcommand: --help" and
exiting 1.

This completes the 40 conversions and lands
test_every_user_facing_function_has_help -- acceptance criterion 6, the
check that fails when a new user-facing function ships without help. It
was developed red against the pre-conversion tree and reported exactly
the 40 names of the design's CONVERT table:

    bd-pull bkg branch check_fish_deps claude-docs claude-pr cleanup
    fast fc fish-deps fzf-update gip gip4 gip6 hist lD ld limine-edit
    lock lsr lss lstree lt ltr lx parur poke ports qr sbver screensleep
    split spwin steam-dl sudo-toggle swapstat tab tmux-clean upgrade
    wake-lock

each as "<name>: no -h/--help handling and not in $__help_exempt", with
the guard exiting 1. The count fell 40 -> 32 -> 24 -> 17 -> 10 -> 0
across the conversion commits. It is committed green so every commit on
this branch passes the suite.

$__help_exempt is the single machine-readable exemption record; a second
assertion fails if an exempt name stops being a published function, so a
rename or deletion upstream cannot silently exempt nothing.
2026-09-07 20:09:30 -04:00
rootiest 639d139799 test(guards): pin C5 logging as opt-in, including that the master cannot enable it
8 cases on the real __fish_config_op_logging name. AGENTS.md records this
as a deliberate special case agents keep trying to 'fix' out; three of
these cases exist specifically to turn that into a test failure.

Includes the three subcategory cases proving the opt-in is inherited
through chain[-1] rather than special-cased per subcategory.
2026-09-07 20:09:26 -04:00
rootiest d75bf4f1b4 refactor: use __fish_palette in small utility functions (2/2)
25 duplicated declarations replaced by 7 calls. Completes the 33 structural
conversions: 167 declarations removed, 33 calls added, and --structural
confirms every one of the 33 diffs is declaration removals plus inserted
calls only -- no rendering text touched.

functions/y.fish is the one file in the repo with no trailing newline on
main; its original file ending is preserved rather than normalised.
2026-09-07 20:08:45 -04:00
rootiest 2b1e99ab47 test(guards): cover the cascade's subcategory -> category -> master order
13 cases on invented variable names, so nothing ambient can perturb them:
default-on, explicit truthy/falsy, unrecognized-defers, subcategory
overriding the category in both directions, and the four cases that
together pin the master as an off switch only.
2026-09-07 20:07:37 -04:00
rootiest 3d826c5407 feat(help): header-driven --help for terminal and session functions
spwin, tab, hist, bkg, wake-lock and fc take the standard first-arg-only
call site, so `wake-lock rsync --help` still runs rsync.

split takes --help only: its own ARGUMENTS documents -h as --horizontal,
so a literal test replaces the renderer's own flag check. Verified that
`split -h` still selects a horizontal split and never prints help.
2026-09-07 20:07:25 -04:00
rootiest a8d564803b test(guards): cover __fish_variable_check's four exit codes
21 cases: a precondition asserting the fork's registry is loaded, then
truthy/falsy/unset/empty/unrecognized/no-argument/list.

Runs isolated, which is what lets these cases manipulate real guard
variable names without being able to reach the user's universal variables.
2026-09-07 20:06:42 -04:00
rootiest 3399149cba feat(help): header-driven --help for system-info functions
gip, gip4, gip6, ports, swapstat, sbver and steam-dl. All ignored $argv,
so --help previously ran the query or the launcher. sbver keeps its own
--brief flag: only argv[1] is inspected and --brief is not a help flag,
so the body still runs for it.
2026-09-07 20:06:23 -04:00
rootiest f3f6e6356b refactor: use __fish_palette in small utility functions (1/2)
37 duplicated declarations replaced by 8 calls. Output strings untouched;
byte-identical across 29 harness cases.
2026-09-07 20:06:20 -04:00
rootiest a824005893 refactor(config-settings): draw the value pages through the frame
Width tier, title border, boolean badge, cursor cell and row line now come
from __config_settings_frame. The type badges (PATH/INT/LIST/STR) stay
here -- they are this page's own vocabulary, used nowhere else -- and so
does the STR default arm, which covers a user-settable value rather than
being dead code.

Introduces the `shorten` fit policy: these fields hold arbitrary user
values and want an ellipsis, unlike the toggle page's per-tier text. The
inline editor keeps `pad`, because its field is already length-constrained
and carries a reverse-video caret whose escapes string shorten miscounts.

The panel stays exactly 16 lines -- chrome(6) + nrows + blanks -- so
config-settings.fish's panel_h and its erase are untouched.

Rendering unchanged: 377/377 render cases byte-identical, golden untouched.
Code lines 123 -> 98 (-25).
2026-09-07 20:06:14 -04:00
rootiest b0c6d7f7f5 refactor: use __fish_palette in system and package functions
44 duplicated declarations replaced by 8 calls. Output strings untouched.

fish-deps, upgrade and wake-lock have no --help path and are deliberately
NOT added to the harness case list -- upgrade and wake-lock have side
effects, and runtime coverage is not worth mutating state during tests.
They are covered by --structural, which proves mechanically that no
rendering line changed.
2026-09-07 20:05:23 -04:00
rootiest 71574b5030 feat(help): header-driven --help for listing presets
lD, lsr, lss, lstree, lt, ltr, lx and ld. None shadows a real binary, so
there is no disabled-fallback contract to honour, and `eza --help`
documented eza rather than the preset that is these functions' entire
content. First-arg-only interception leaves `lt -la --help` passing
through to eza untouched.
2026-09-07 20:05:15 -04:00
rootiest 53b353eb7f test: assert conf.d stays lazy in non-interactive shells
Spawns one non-interactive child against the sandboxed config and asserts on
what loaded -- abbreviations, key bindings, bang-expansions, the C5 event
handlers and the tailscale completion machinery must all be absent. Exit
codes name which guard regressed. No wall-clock assertions, so it cannot
flake.
2026-09-07 20:04:47 -04:00
rootiest ad9926861b refactor(config-settings): draw the sub-category page through the frame
Width tier, title border, badge, cursor cell and row line now come from
__config_settings_frame, and the hand-verified title dash count
(iw - L - S - 22) is derived from the segment's visible width instead.

Introduces the `cut` fit policy, which is this page's documented
divergence from the category list: its labels and descriptions are static
data from __config_settings_subcats rather than per-tier authored text,
and several exceed the narrower tiers' fields. `string pad` only ever
grows a string, so they are truncated before padding. That reason now
lives in two places -- the frame's NOTES and each call site -- and the
DESCRIPTION block stating it here is unchanged.

Drops label_w and desc_w, both left assigned and never read once the
frame derives the field width; the comment recording the 13-wide label
field and how the description field absorbs it stays.

Rendering unchanged: 377/377 render cases byte-identical, golden untouched.
Code lines 85 -> 49 (-36).
2026-09-07 20:04:44 -04:00
rootiest 29afe5c89f refactor: use __fish_palette in the config-settings TUI
27 duplicated declarations replaced by 5 calls. Output strings untouched.

Four of these five files have no --help path, so the byte-identity harness
cannot reach them. Covered instead by driving the real TUI under a pty on
both the baseline and converted trees with an identical paced keystroke
feed (down x3, Tab, Enter, Esc, Tab, down, q):

  9 redraws, 15068 bytes, byte-identical on both sides
  c_sel (ESC[35;1m) x9, c_hi (ESC[37;1m) x8, c_head (ESC[36;1m) x9
  all four draw helpers reached -- draw, pagetab, draw_subcat
  ("cascade default", "(category)"), draw_value ("Allow prev")
2026-09-07 20:04:26 -04:00
rootiest 037588ecf6 fix(help): stop eight functions executing on --help
These eight ignore $argv entirely, so passing --help ran the command
instead of describing it. The new check shadows every external binary
they reach with a recording stub on PATH and fails if anything is
invoked. Before the fix it reported, verbatim:

    cleanup --help EXECUTED: pacman -Qtdq
    fzf-update --help EXECUTED: git clone --depth 1 https://github.com/junegunn/fzf.git /tmp/.../.fzf
    limine-edit --help EXECUTED: sudoedit /boot/limine.conf sudo limine-enroll-config sudo limine-mkinitcpio sudo sbctl sign-all
    lock --help EXECUTED: loginctl lock-session
    screensleep --help EXECUTED: busctl --user call org.kde.kglobalaccel ... invokeShortcut s Turn Off Screen
    sudo-toggle --help EXECUTED: sudo stat -c %s /etc/sudoers.d/nofail-toggle sudo tee /etc/sudoers.d/nofail-toggle
    tmux-clean --help EXECUTED: tmux list-sessions -F #{session_name} #{session_attached}
    upgrade --help EXECUTED: paru -Syu --noconfirm

cleanup's log line is the read that precedes `sudo pacman -Rns $orphans`,
which the stub suppressed by returning no orphans; on a real machine with
orphans present the removal ran.

Each now answers --help from its own comment header. The call site is the
first statement of the body, above the C4 guard, so help stays reachable
when the component is disabled and nothing side-effecting runs first.
2026-09-07 20:04:02 -04:00
rootiest 0a9cfebcad refactor(tests): discover suites instead of naming them
run-tests.fish globs tests/test-*.fish and runs each in the mode the suite
declares in its own header. Isolated is the default and no typo can
promote a suite to in-session: detection is case-insensitive so a
near-miss is caught, the value comparison is exact.

In-session suites share one sandboxed session; isolated suites each get a
--no-config child with temp XDG dirs. Counts come back through a file so
output keeps streaming.

functional.fish becomes test-session.fish, its 15 predicates rewritten as
check calls. 332 assertions, unchanged per-phase.
2026-09-07 20:02:59 -04:00
rootiest 889f8e0768 refactor(config-settings): draw the category list through the frame
Width tier, title border, badge, cursor cell and row line now come from
__config_settings_frame. The per-tier description sets stay here -- they
are this page's data, authored to fit each tier's field exactly -- and are
selected by width rather than by re-testing $COLUMNS.

Rows pass the `pad` fit policy explicitly. That is a decision, not a
default: `cut` would be a byte-for-byte no-op on these strings today and
would silently discard the property that they are tuned to their field.

Drops c_hi, which was assigned and never read.

Rendering unchanged: 377/377 render cases byte-identical, golden untouched.
Code lines 114 -> 80 (-34).
2026-09-07 20:02:48 -04:00
rootiest e64e964666 refactor: use __fish_palette in agents and auto-pull functions
34 duplicated declarations replaced by 5 calls. Output strings untouched;
byte-identical across 29 harness cases.
2026-09-07 20:02:15 -04:00
rootiest bca79d3c5a fix(test): exclude __fish_palette.fish from the structural diff check
The helper is a new file, so its diff is entirely additions and can never
be "purely structural". It declares colours rather than rendering any, and
tests/functional.fish asserts its 12 roles directly.
2026-09-07 20:02:09 -04:00
rootiest d49d90a2de chore(docs): regenerate manual
docs/fish-config.1 is left for CI to regenerate: the local pandoc is 3.10.2
against CI's 3.1.3, so rebuilding it here emits ~4700 lines of formatter
churn unrelated to this change. The component registry rebuilt identically.
2026-09-07 20:01:24 -04:00
rootiest 2ac8e5c0d4 feat(config-settings): add __config_settings_frame shared renderer
The width tier, title-border arithmetic, ON/OFF/DEFAULT badge, cursor cell
and table row are currently hand-copied across the three draw functions.
This adds them once, with the two geometry identities derived rather than
hand-maintained: a row's chrome is a fixed 21 columns, so field_w is
iw - 21 - label_w (reproducing both iw-33 and iw-34), and a title border is
dashes = iw - visible(segment) - 1 (reproducing all three of iw-23,
iw-len-3 and iw-L-S-22).

The frame owns no page height. Every verb prints exactly one line or
fragment, so the fixed-16 category and value pages and the dynamic
7+n sub-category page keep their heights, and config-settings.fish's
erase is unaffected.

No caller yet, so rendering cannot move: the golden's existing page
section is byte-identical (verified with cmp -n over its previous size)
and the file only gains frame-verb cases appended after it.
2026-09-07 20:00:59 -04:00
rootiest 85c753aaa6 docs: point tailscale and cheat completions at completions/
Follows the relocation out of conf.d/. The completions/ branch of the file
tree is expanded from the real directory at build time, so it needs no
hand-written children. Generated docs are regenerated separately.
2026-09-07 19:59:53 -04:00
rootiest b424b26700 test(help): pin the renderer's degraded-path contract
A missing or label-less header must still print and exit 0. Returning 1
would hand control back to the caller's body, which for upgrade(1) is a
full system upgrade.

Both fixtures reach the renderer's bottom `count $out -eq 0` fallback,
not the unreadable-source branch. Mutating that fallback to `return 1`
turns the test red with:

    headerless executed its body despite --help
    malformed executed its body despite --help

The mutation was reverted before this commit.
2026-09-07 19:59:50 -04:00
rootiest d3028d7703 refactor(tests): extract the shared assertion core into tests/lib.fish
check/section/report and the counters move out of the vault suite
unchanged. report also writes its counts to $FISH_CONFIG_TEST_COUNTS so a
driver can aggregate without parsing stdout, and ends on an explicit
boolean per AGENTS.md item 5.

All 317 vault assertions and every fixture helper are untouched.
2026-09-07 19:59:23 -04:00
rootiest 52711a42a2 perf(conf.d): skip paru/yay wrapper generation in non-interactive shells
Neither file defines a function or sets a global; their only effect is
writing ~/.local/bin/<tool>, which every interactive session does anyway.
Combined 10.7 ms off every fish -c.
2026-09-07 19:58:10 -04:00
rootiest c998d1b8d7 perf(conf.d): skip C5 logging sync in non-interactive shells
__fish_config_sync_logging ran on every fish -c, mkdir+touching the C5
sentinel on disk from every subshell. Its consumers — the Kitty watcher and
the paru/yay wrappers — are interactive-context, and every interactive shell
still reconciles the state.
2026-09-07 19:56:45 -04:00
rootiest 5fa849fd81 perf(conf.d): skip wakatime hook in non-interactive shells
fish_postexec is emitted only by the interactive reader (verified), so the
handler could never fire in a script. No telemetry behaviour changes.
2026-09-07 15:00:57 -04:00
rootiest a31a46bdc2 feat: add __fish_palette shared output palette helper
Declared --no-scope-shadowing with a bare set, so the 12 colour roles land
in the caller's scope under the same short names the consuming functions
already interpolate. Keeping the names means the conversion never edits an
output string in 33 of the 38 consumers.

No consumer is converted yet; byte-identity harness still reports 29/29.
2026-09-07 15:00:32 -04:00
rootiest 8fc27fa9c2 fix(tests): route the runner's utilities through command
run-tests.fish executes under the config it tests, which shadows cp, rm
and cat. The real hazard is cp: the config aliases it to 'cp -i', which on
a non-empty destination reads EOF in a non-interactive runner, silently
skips the copy and exits 0 -- a sandbox missing config files, reported as
success.

rm -rf and cat were measured and behave correctly as-is (the rm wrapper
bails to command rm on any non-recursive flag, so -rf really deletes and
does not trash). Prefixed anyway: a test runner must not depend on the
configuration under test.
2026-09-07 15:00:10 -04:00
rootiest 2edea59ca3 perf(conf.d): skip auto-pull handler in non-interactive shells
The --on-variable PWD handler backgrounds a git fast-forward. A script that
cd's was firing it, which is also where AGENTS.md Task #4's credential
prompt could surface from a background job.
2026-09-07 15:00:01 -04:00
rootiest 5edfb5b720 perf(conf.d): skip theme colors in non-interactive shells
fish_color_* is consumed only by the syntax highlighter. The guard sits
below the existing cleanup branch so stale-FZF_DEFAULT_OPTS cleanup keeps
running where it does today; the FZF value itself is a persisted universal
and survives regardless.
2026-09-07 14:59:10 -04:00
rootiest 9077d9837e feat(help): add __fish_help_header runtime renderer
Parses a function's own man-page comment header at call time and prints
it as a help menu on stdout, so the documentation that already generates
Section 5 of the manual becomes reachable from the shell.

Reads the .fish source rather than the generated docs/fish-config.md, so
it cannot go stale between a header edit and a docs rebuild. Walks
backwards from the `function` line to collect the header, which resolves
multi-header files (fish-deps, gi, y) without reimplementing
manualtools._block_identity.

Returns 1 only when argv[1] is not a help flag; every other path prints
and returns 0. A return of 1 hands control back to the caller's body.

Nothing calls it yet.
2026-09-07 14:59:05 -04:00
rootiest dd672ded3b fix(tests): isolate the vault suite from the live config and universal variables
The suite ran under a plain `fish`, which loads the user's real
~/.config/fish and their universal variables -- this repo doubles as that
config. A test manipulating a guard variable could erase a real universal
variable out of the running shell.

Override XDG_CONFIG_HOME/XDG_DATA_HOME and pass --no-config. HOME stays
real on purpose: overriding it makes the suite's two hermeticity
assertions vacuous. Reasoning recorded at the call site.

Vault suite still 317/317 with byte-identical stderr.
2026-09-07 14:59:05 -04:00
rootiest 4d6b99fb28 perf(conf.d): skip starship.fish in non-interactive shells
Defines fish_prompt only. The guard precedes the op-guard and the type -q
PATH scan so both are skipped in scripts. Scripts fall back to the repo's
autoloadable functions/fish_prompt.fish, which nothing invokes anyway.
2026-09-07 14:58:18 -04:00
rootiest 51da3e9d83 test: add byte-identity harness for the shared palette
Compares rendered stdout and stderr of 29 colour-bearing cases between a
pristine baseline ref and the working tree, in isolated XDG_CONFIG_HOMEs
that carry the gitignored fish_variables so the opinionated guards resolve.

Two traps this harness exists to avoid, both of which silently produce a
meaningless comparison rather than an error:

  - `git archive main` omits fish_variables because it is untracked. Without
    it __fish_config_op_enabled is unresolvable and every guarded function
    short-circuits, so all cases render empty and trivially "match".
  - `qc --help` shells out to aichat and never reaches its colour path
    unless aichat is on PATH; the harness stubs it.
2026-09-07 14:57:07 -04:00
rootiest bb5b6b361a perf(conf.d): skip key_bindings.fish in non-interactive shells
fish_user_key_bindings is invoked only by the interactive reader.
2026-09-07 14:57:02 -04:00
rootiest 13d415db2b perf(conf.d): skip bash_expands.fish in non-interactive shells
The six expand_* functions are only ever reached through abbr --function,
which fires during interactive expansion.
2026-09-07 14:56:16 -04:00
rootiest c3a2b6fa0c perf(conf.d): skip abbr.fish in non-interactive shells
61 abbreviations were declared on every fish -c. Abbreviations expand only
in the line editor, so nothing outside an interactive session can use them.
2026-09-07 14:55:31 -04:00
rootiest 3d8d6a4468 refactor(conf.d): move cheat completions to completions/
Thirteen lines, every one a `complete -c cheat` registration, sourced on
every shell start from the wrong directory. Startup cost was already ~0
because its command substitutions are lazy, but completions/ is where fish
expects the file and the move is free.
2026-09-07 14:54:38 -04:00
rootiest fb21fa550a perf(completions): drop tailscale self-priming completion call
The Cobra-generated block ran `complete --do-complete "tailscale "` to flush
pre-existing completions before erasing them, which executed the tailscale
binary. From completions/ it has no job: fish autoloads only the first match
on $fish_complete_path and the repo's completions/ precedes the vendor dir,
so the vendor file is never sourced.

Verified byte-identical completion output across four probes with the vendor
file present. A comment at the deletion site records the reasoning.
2026-09-07 14:53:35 -04:00
rootiest 321b80f1f8 perf(conf.d): load tailscale completions lazily from completions/
conf.d/tailscale.fish is 252 lines of Cobra-generated completion that fish
sourced on every shell start, and its self-priming block executed the
tailscale binary to warm the completion cache. completions/ is the directory
fish autoloads on first <TAB>.

Measured: 19.2 ms off both interactive and non-interactive startup.
2026-09-07 07:32:03 -04:00
rootiest 574b235b6f test(config-settings): add byte-exact golden-output render harness
The three config-settings draw functions are hand-tuned layout code whose
field widths, dash counts and pad targets are arithmetic on the width tier.
Any refactor of them has to be byte-identical, and nothing until now could
prove that.

Renders all 356 page/width/scope/cursor-row combinations -- every page at
COLUMNS 100/88/84/70, both scopes, cursor on every row, plus the inline
editor -- and byte-compares against a committed baseline.

The golden holds raw output: set_color escapes and box drawing exactly as
emitted, plus the wrap-aware \e[<N>A\e[J erase config-settings.fish would
emit for each panel, and per case the declared panel height against the
measured line count. Nothing is normalized; the gate is cmp(1) and a
one-space change anywhere fails it. Proven by four deliberate mutations,
one per draw function plus a panel-height change, each caught and reverted.

Runs entirely inside a throwaway HOME/XDG_CONFIG_HOME sandbox: the fixtures
must be real universal variables, and this repo doubles as a live
~/.config/fish. fish --no-config cannot be used, as -N silently degrades
set -U to global scope. Every utility is called through `command`, since
the config itself shadows rm, cat and mkdir and aliases cp -i.
2026-09-07 07:28:45 -04:00
rootiest 8a2731d411 revert: untrack the spec
AGENTS/ is gitignored upstream; a tracked file there pollutes
git diff main..work, which is what the user reads when choosing
which job to merge. Spec stays on disk, browsable, out of history.
2026-09-07 07:22:51 -04:00
rootiest 21a02fd0e4 docs(specs): add header-driven --help design
Design for making the man-page-style comment header above each function
reachable at runtime via -h/--help, instead of hand-writing 40 more menus.

One renderer (__fish_help_header) parses the .fish source at call time and
prints the header to stdout; each call site is a single line. Audits all 79
published functions that lack help today into 35 shadow/pass-through exempt,
4 prompt-hook exempt, and 40 to convert, with a one-line reason each.

Corrects the baseline counts (109 published functions, 30 with menus, 79
without) and records two pre-existing defects found while auditing.

Note: AGENTS/ is gitignored upstream, so this file is force-added.
2026-09-07 03:06:30 -04:00
Gitea Actions 08e66c81ca chore(docs): regenerate manual, man page, and component registry 2026-09-04 21:28:58 +00:00
rootiest c009bbf257 Merge pull request 'feat(docs): GitHub mirror icon, README-sourced doc sections, auto-generated TOC' (#129) from feat/docs-readme-sections into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 2m0s
CI / build-docs (push) Successful in 3m54s
Reviewed-on: #129
2026-09-04 21:23:06 +00:00
rootiest e6d3fd80b3 style(docs): add fish to logo icon 2026-09-04 17:14:17 -04:00
rootiest 54375a9530 style(docs): match Gitea icon size to GitHub's 24px (1.5rem) 2026-09-04 16:50:16 -04:00
rootiest 2ee2806e01 fix(docs): make the Gitea icon override actually apply, tune GitHub to 1.5x
UnoCSS's .i-pajamas:gitea rule is unlayered CSS; our override lived in
@layer starlight.core, and unlayered rules always beat layered ones
regardless of specificity or source order. The Gitea icon has silently
stayed at UnoCSS's 1em default since it was first added -- confirmed via
computed style in the browser, not just reading the stylesheet source.
!important restores the override across the layer boundary.

Also drops the GitHub icon from 2x to 1.5x per visual feedback.
2026-09-04 16:49:04 -04:00
rootiest 23cae4bd10 chore(docs): regenerate man page
pandoc wasn't available when this branch's earlier commit ran
build-manual.py --concat; regenerate docs/fish-config.1 from the
current docs/fish-config.md now that it is.
2026-09-04 16:43:27 -04:00
rootiest 8c21d34943 style(docs): double the Gitea/GitHub header icon size
--sl-nav-height is a fixed CSS var, not driven by icon content, so both
icons can grow without changing the header bar's height.
2026-09-04 16:43:27 -04:00
rootiest 4912c4052f feat(docs): add GitHub mirror icon, README-sourced doc sections, auto-generated TOC
Adds a GitHub social icon to the docs site header alongside the existing
Gitea one, and documents in the README's Contributing section that
git.rootiest.dev is the base repo while the GitHub copy is a one-way
mirror, so forks/issues/PRs should go through Gitea.

Adds Testing, Contributing, Attribution, and License sections to the
manual/man page/site, sourced directly from README.md via a new
`<!-- README: Heading -->` placeholder mechanism in build-manual.py, so
the README stays the single source of truth for those sections instead
of a hand-maintained copy drifting out of sync.

Also converts docs/manual/00-table-of-contents.md from a hand-typed list
to a generated one (mt.walk()-driven), fixing a numbering drift where
Components Reference was omitted and every section after it was off by
one relative to its own manTitle.
2026-09-04 16:34:22 -04:00
Gitea Actions c5bbbf06e3 chore(docs): regenerate manual, man page, and component registry 2026-09-04 02:52:27 +00:00
rootiest 76afcd5e13 Merge pull request 'feat(privacy): add DO_NOT_TRACK and DISABLE_TELEMETRY env vars under C3 privacy' (#128) from feat/do-not-track-privacy-env into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 1m53s
CI / build-docs (push) Successful in 9m30s
Reviewed-on: #128
2026-09-04 02:40:53 +00:00
rootiest 28a88a9bdf feat(privacy): add DO_NOT_TRACK and DISABLE_TELEMETRY env vars under C3 privacy 2026-09-03 22:35:05 -04:00
Gitea Actions d278a47b32 chore(docs): regenerate manual, man page, and component registry 2026-09-03 23:52:10 +00:00
rootiest dc3236fddb Merge pull request 'test(agents-vault): make the suite hermetic against git configuration' (#127) from fix/vault-test-git-identity into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 1m58s
CI / build-docs (push) Successful in 9m19s
Reviewed-on: #127
2026-09-03 23:40:56 +00:00
rootiest 73d41da07d test(agents-vault): inject failures in a way that survives uid 0
Five fixtures forced a failure with chmod 500 on a parent directory. That
is silently useless for root: uid 0 bypasses the mode bits, the operation
succeeds, and a test asserting a failure path then reports the tool as
broken rather than the injection as ineffective.

CI runs the suite as root inside a container, so 21 checks failed there
while passing for every developer and every reviewer -- the same shape as
the git-identity gap in the previous commit. A fixture that quietly stops
injecting is worse than one that never existed: it reads as coverage.

Shim the single command each failure hinges on, matched by a path fragment
so nothing else in the run is disturbed. A command that exits 1 on purpose
does so for every uid. Which command matters: ensure_symlink removes an
existing link before it creates the new one, so the two adopt fixtures
have to fail at that rm to leave the live link in place, and shimming ln
would be too late. The restore fixture deletes the link first and so does
hinge on ln, and the failing --remote fixture hinges on git set-url.

The one remaining chmod 500 asserts a success, not a failure, and its real
proof is the direct assertions on where the stash landed.

Reproduce the root case locally without a container:
  unshare -r fish tests/test-agents-vault.fish

Verified: 296/317 as root before, 317/317 after; 317/317 unchanged as an
ordinary user; and neutering the shims reproduces exactly 296/317, the
count CI reported.
2026-09-03 19:34:01 -04:00
rootiest 75fbfa1e16 test(agents-vault): make the suite hermetic against git configuration
The suite was hermetic against $HOME and ~/.claude but not against git
config. new_repo set an identity on the repos the tests create; nothing
set one on the repos the tool creates -- the scaffolded vault and the
AGENTS/ sub-repo. Those inherited a global user.name/user.email on a
developer machine and committed fine, so the gap was invisible to every
local run and every review; on a runner with no gitconfig they died with
"Author identity unknown", and the suite reported the tool own correct
"nothing recorded" handling as 71 failures.

Supply the identity through the environment, which reaches the git calls
inside agents-vault and agents-init as well as the ones the tests make.

Pin commit.gpgsign off for the mirror-image reason: a developer with
signing enabled would otherwise have tool-created repos reach for a key,
and a hardware token would prompt for a touch partway through the run.

Pin init.defaultBranch because the rebase fixtures build an upstream and a
clone and need the two to agree on a branch name. A global saying main and
a bare default of master disagree, and the fixture then fails to create the
rebase the test is about, reporting a tool failure that never happened.

Verified with GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_SYSTEM=/dev/null:
267/317 before, 317/317 after; unchanged at 317/317 with a normal config.
2026-09-03 19:20:11 -04:00
rootiest 3c967c0cee Merge pull request 'feat(agents-vault): back up curated agent memory to a host-scoped vault repo' (#126) from feat/agent-memory-vault into main
CI / github-mirror (push) Skipped
CI / test (push) Failing after 1m19s
CI / build-docs (push) Skipped
Reviewed-on: #126
2026-09-03 23:09:55 +00:00
rootiest f9d400699f fix(agents-vault): keep the user's ssh command and drop the quadratic walk
The connect bound was delivered by injecting GIT_SSH_COMMAND, and an
environment variable outranks git's core.sshCommand -- so the guard,
which read only the environment, did not merely miss a configured ssh
command, it overruled one. A vault remote reachable only as
`ssh -i ~/.ssh/vault_key` failed to authenticate on every push, autopush
and --push alike, for the sake of a ten-second timeout. Both spellings
now count, and `set -qx` rather than `set -q` on the environment side so
an unexported fish variable -- which git never sees -- does not leave the
push with neither the user's ssh command nor a bound.

The agy knowledge walk appended each find with `set -a`, which rewrites
the whole variable every time; 500 files cost 21ms but 20,000 cost 58s,
on a path that runs in front of every agent launch. The walk now prints
NUL-separated and the list is built once, which is flat: the same 20,000
files take 707ms. NUL rather than newline because a filename may legally
contain one. What the walk collects, and its symlink and dot-led
semantics, are byte-for-byte unchanged.

Autopush is bounded by timeout(1) alone, so without it the launch path
was quietly back to an open-ended network call. It now says so and skips
the push instead; --push was never wrapped and is unaffected.
2026-09-03 18:56:47 -04:00
rootiest d9b56790c5 fix(agents-vault): keep the knowledge walk and the launch push inside their bounds
The agy knowledge allowlist walked the store with `**` and copied with
plain cp, so a symlink inside the store was both followed and dereferenced.
The extension rule still bounded what kind of file was collected, but not
whose: a link to a home directory hands over settings.json, CLAUDE.md and
every cached .json in it, and those reached a commit. A link to / made the
walk itself unbounded, on the path that runs before every agent launch.
The tree is now walked a level at a time and nothing that is a symlink is
followed or copied.

Autopush had the same shape one layer out. Neither GIT_TERMINAL_PROMPT nor
GIT_ASKPASS closes a socket, and git has no connect timeout to set: against
a blackholed address a push took 135s with http.lowSpeedLimit and
http.lowSpeedTime set as well as without them. ssh can time itself out and
is now told to; the autopush pull and push are additionally capped with
timeout(1). An explicit --push stays uncapped, since it is watched and has
to report what a real transfer really did.

Also: scaffold /.migrate-stash into .gitignore beside /.adopt-stash, which
the comment already claimed was covered; and drop the live memory path
during a slug migration only when it is a link. Reached from the
path-derived fallback candidate it can be a real populated directory, where
rm -f correctly refuses -- but said so in rm's voice, so a --silent run that
had succeeded printed what read as an error.
2026-09-03 18:56:46 -04:00
rootiest 16ea31289d fix(agents-vault): repair slug migration, keep the network off the launch path
Six findings from the whole-branch review, all of which end in the same
place: a backup tool reporting success while nothing was backed up.

Slug migration nested the old entry inside the new one. The clear before
the rename was gated on the destination's claude/memory subdirectory
rather than on the destination itself, so an entry that exists without
one survived, `git mv A B` moved A *inside* B, and the mkdir below
fabricated a fresh empty memory directory for the live link to point at.
The real memory ended up one level deeper than --status and --restore
ever look, and the run returned 0. That shape is not exotic: git cannot
track an empty directory, so an entry committed while its memory was
empty comes back from a clone as projects/<slug>/origin and nothing
else -- and cloning the vault is this feature's own recovery path. The
destination is now moved aside the way --adopt already does it rather
than deleted (widening the rm -rf would have destroyed the clone's
origin log), its provenance is folded into the migrated entry, and every
failure path rolls back and reports.

The launch path pulled over the network. Both wrappers call agents-vault
synchronously before starting an agent, and the pull in the shared sync
helper was unguarded once an upstream existed: against a blackholed
remote it blocked the launch indefinitely and then aborted the commit,
so an offline laptop silently stopped being backed up at all. Committing
never needed a remote, so the pull moved to the push path, which was
already opt-in for exactly this reason. A failure there now distinguishes
a real rebase conflict (rebase-merge/ or rebase-apply/ present) from an
unreachable remote instead of calling both a conflict, and both network
calls set GIT_TERMINAL_PROMPT=0 and GIT_ASKPASS so they fail fast rather
than prompt with nobody watching. The helper still refuses to commit a
rebase in progress, and leaves it standing rather than aborting one it
did not start. This also restores agents-init's pre-refactor ability to
commit while offline.

The agy knowledge copy was unfiltered. The allowlist held at the agy root
and nowhere below it, so a planted .credentials.json inside knowledge/
was committed verbatim while the documentation promised nothing new
upstream added could leak in. Only *.md and *.json are copied now --
which is what the store actually holds -- so lock files, transcripts and
conversation databases are excluded by having no business in a backup
rather than by being known about. The scaffolded .gitignore also ignored
only the SQLite sidecars and not the databases, which is worse than
ignoring neither: a torn database landed in history with the write-ahead
log that would have completed it deliberately excluded. Both changes are
template-only, on a feature that has never shipped.

agents-init reported success when nothing was committed. It ended on a
branchless `if` with no arm for a failed commit, which fish resolves to
0 -- the same false zero already fixed in agents-vault, left in the
function the refactor was rewriting. It now has the arm and an explicit
final status.

The --adopt forward-failure path with no stash left a raw coreutils `mv:`
line and no statement that the adopt had been abandoned cleanly; it is
branded like every other error exit in the function.

Tests: the suite now clones a vault with git and runs agents-vault
against the clone, instead of trusting hand-built fixtures to have shapes
git can actually produce -- that blind spot shipped both of the merge
blockers. The "present but empty" migration fixture is rebuilt as the
origin-only directory a clone leaves behind, with the hand-built shape
kept as a separate case. Reverting each fix drops the suite from 285 to
279 (migration), 261 (network), 275 (knowledge allowlist) and 283
(agents-init status).
2026-09-03 18:56:46 -04:00
rootiest 2ad5bf75d2 feat(agents-vault): sync the vault from the claude and agy wrappers
Both wrappers stay behind the C1 guard, so disabling
__fish_config_op_aliases still passes straight through to the real binary.

Launch commits but never pushes, keeping the network and any credential
prompt off the critical path; pushing is left to the Claude Code SessionEnd
hook. agy has no such hook, so its memory lands one launch later.
2026-09-03 18:56:46 -04:00
rootiest 11f4551fa5 fix(agents-vault): repair the adopt rollback and see dot-led entries
The adopt rollback restored the worktree but not the index. Every move it
makes is a plain rename as far as git is concerned -- the stash move out
from under the index most of all -- so a rolled-back adopt left a
half-applied rename staged against a clean vault. No bytes were at risk
and the next ordinary run's `git add -A` healed it, but a hand
`git commit` in that window recorded the half-applied state. Both
rollback sites now re-read projects/ once the worktree is whole again,
the stash restore included. projects/ is named whole rather than the two
entries, because `git add` refuses a pathspec that matches nothing --
which one of the two always is, once it has been moved back -- and then
stages neither.

The stash itself moves from the vault root into .git/, where neither the
entry walk nor `git add -A` can reach it, so a crash between the two
moves can no longer leave junk at the vault root for the next run to
commit. A vault whose .git is not a directory falls back to the root,
which the scaffolded .gitignore now covers.

--status and --restore walked the vault with a fish glob, which does not
match dot-led names. A dot-led slug is both reachable and sanctioned: the
sibling-bare-mirror idiom (`git remote add origin ../mirror.git`) keys as
..-mirror, a dot-led host keys as .hidden.example.com-o-r, and --adopt
accepts a leading dot on purpose. Such an entry is scaffolded, linked,
committed and pushed normally, yet --status under-reported it and batch
--restore left that project unlinked, both without saying so. Both walks
now list the directory instead. The --adopt completion gains -A for the
same reason: an entry that cannot be completed reads as one that is not
there.

The now-fatal push failure is painted as an error rather than a warning,
matching its sibling on the commit path.

The header notes that --adopt does not pin a name. The slug is re-derived
on every run, so the next ordinary run migrates the adopted entry back to
the canonical key, memory and live link following. Behaviour unchanged;
only the documentation gap is closed.

Tests, 173 -> 209 checks. The whole stash branch of --adopt was
uncovered, because the existing atomicity test adopts onto a slug with no
entry at all: a successful stash-adopt and a stash-adopt whose relink
fails are both pinned now, the latter asserting an empty
`git status --porcelain` and a still-reachable live memory. The stash
location is pinned by making the vault root unwritable for the duration,
which only a stash at the root would need. agents-vault's own propagation
of a failed sync had no test at all -- the third recurrence of fish's
branchless-`if` false zero here -- so both ways it can fail are now
driven end to end: a rejecting pre-commit at the vault's own
core.hooksPath, and a real rebase conflict against a bare remote. A
dot-led entry is asserted in --status and in --restore.
2026-09-03 18:56:46 -04:00
rootiest 090779ae5d fix(agents-vault): make push failure fatal and adopt atomic
A push that fails against a configured remote warned on stderr and then
fell through to the trailing branchless `if`, which resolves to 0, so
`--push` reported a successful backup while nothing had left the machine.
That is the exact loss the vault exists to prevent. It now returns
non-zero, verified against a real unreachable remote rather than a mock.

The same audit found two more false zeros in this function, both fixed:
the commit block warned about a rebase conflict and walked past it, and
swallowed a hook-rejected commit entirely (neither branch of its if/else
if matched, since the error goes to stderr rather than stdout); and
--restore reported a relink failure and then returned 0 regardless. All
three now feed one flag and the function ends on an explicit status
rather than on whatever the last branchless `if` left behind.

--adopt is now atomic. A rename that landed while the relink failed left
the memory intact at the new slug but unreferenced: the next ordinary run
found no live link, recomputed the old slug, found nothing there, and
fabricated a fresh empty entry, so the agent wrote history-less memory
from then on. No bytes were lost, but continuity was, with no automated
recovery. The live link is no longer removed first -- ensure_symlink
repins a link that points elsewhere on its own -- a contentless target
entry is moved aside rather than deleted, the origin note is appended
only after the relink succeeds, and a failed relink rolls the rename back
so the vault is exactly as it was.

The --adopt validator no longer refuses a leading dot. _agents_repo_slug
legitimately emits one for a dot-led subdomain, so refusing it made such
an entry impossible to adopt; inside projects/ it is a hidden directory,
not an escape. The traversal cases are still refused: no slash survives
the charset, and "." and ".." are refused by name.

Adds the RETURNS section the header was missing. --status prints a
structured report, which this repo's convention treats as return value
rather than as progress output.
2026-09-03 18:56:46 -04:00
rootiest 45f0fb9688 feat(agents-vault): add status, restore, adopt, remote, and push
--status reports link health, orphaned entries, and how far the vault is
ahead of its remote, which is how an unpushed backup gets noticed. --adopt
rebinds a machine-specific local-* entry by hand. --push is explicit;
autopush stays opt-in via __fish_agent_vault_autopush.

Three corrections to the planned shape:

--status is dispatched ahead of the scaffold instead of behind it. As
planned it sat after the tool install, the agy knowledge copy, and the
global memory link, so asking for a report would first sync global state
and claim ~/.claude/memory. It is now read-only and reports a missing
vault rather than creating one. The global-state block moved below the
mode dispatch so it runs only on a default or --link run; the mutating
modes still need the vault repo, so they sit between the scaffold and it.

--adopt validates its slug before using it. It is interpolated into
"$vault/projects/$slug" and handed to `git mv`, so --adopt=../../../etc
walked straight out of the vault. Only the charset the slug formula emits
is accepted, with no slash and no leading dot.

--remote captures the git exit status explicitly rather than chaining an
`or` off the block terminator. That construct does work in fish, but it
reads as the silent-false-success shape that a hook-rejected commit once
produced here, and it stops working the moment the `else` goes away.

Also pins the dangling-global-symlink case the suite never covered: for a
broken ~/.claude/memory link both -d and -e are false, so the -L disjunct
in the global-memory guard is the only thing that notices it. That is the
state a buggy earlier run left on a real machine; the test asserts it is
detected, repinned into the vault, and exits 0.
2026-09-03 18:56:46 -04:00
rootiest 4c7334c46e fix(agents-vault): keep a global-state fault from aborting project backup
The global block runs before the per-project link and the commit, but its
mkdir and link failures returned 1 outright. Global memory is optional and
frequently absent, so a stray file or a permission problem at
~/.claude/memory would abort the per-project memory backup and its commit
for every project, on every agent launch -- a fault in the secondary
feature killing the primary one.

Both failures now warn to stderr and continue, matching the treatment the
agy copy already had; the whole global block is best-effort by design.
Continuing is safe because _agents_repo_ensure_symlink validates and
refuses before mutating anything. $changed is set only when the link
actually succeeded, and nothing is recorded that would make a later run
believe the global memory is linked when it is not.

The live-side test widens from -d to -e so a stray regular file where the
global memory directory belongs is reported on every run instead of being
silently skipped and mistaken for the absent-by-default case.

Also documents that the agy knowledge copy is merge-only: a fact deleted
upstream persists in the vault and a restore brings it back. Whether the
vault should mirror deletions is a retention decision for the repo owner;
the gap is worth stating either way.
2026-09-03 18:56:46 -04:00
rootiest 1c9cedb8f3 feat(agents-vault): back up agy and global Claude state
agy partitions by conversation UUID rather than by workspace, so it has no
per-project slice and is tracked globally. Its knowledge store is copied
rather than symlinked because it sits beside SQLite databases with WAL
sidecars. Claude's global memory directory is symlinked into the vault the
same way per-project memory is, including the emergent-restore direction.

Paths are allowlisted so credentials, transcripts, and session state cannot
be swept in.

Two variables keep the tests off the real home: the new
__fish_agent_vault_claude_home overrides ~/.claude (whose memory/
subdirectory is the global one), distinct from the existing
__fish_agent_vault_claude_root, which overrides ~/.claude/projects.
Without it a test run on a machine that has a real global memory directory
would move it into a mktemp vault and leave a dangling symlink behind. The
suite now points every run at a throwaway home by default and asserts the
real paths are untouched.

cp cannot report whether anything actually differed, so the copy is only
counted as a change when it leaves the vault's global/agy/ subtree dirty.
Marking it changed unconditionally would print a --quiet summary line on
every agent launch and make the flag meaningless.
2026-09-03 18:56:45 -04:00
rootiest a018d7997c fix(agents-vault): dedupe local-slug formula, drop dead code, widen migration coverage
The slug-migration fallback (used when there is no live symlink to read
the previous slug from) recomputed the local-* candidate by lowercasing
the basename only, while _agents_repo_slug sanitizes it. The two formulas
had drifted, so the fallback silently found nothing for any project
directory whose basename needed sanitizing.

Extract the formula into a single private helper,
_agents_repo_local_slug, and have both _agents_repo_slug's no-remote
branch and agents-vault's migration fallback call it, so there is one
place left to drift.

Also drop two dead lines the review flagged: an unused  local,
and an unreachable mkdir -p (path dirname ...) — slugs never contain a
path separator, so dirname always resolves to a directory that already
exists by that point.

Widen migration test coverage: the current-entry-present-but-empty case,
a remote URL rewrite, a remote removal, and a dirty-basename fallback
test that fails without the sanitization fix and passes with it.
2026-09-03 18:56:45 -04:00
rootiest b7ff4e0981 feat(agents-vault): migrate entries when a project's slug changes
Adding a remote to a previously remote-less project changes its slug. Left
unhandled, the link step repinned the live memory symlink to a fresh empty
entry and orphaned the real memory.

The previous slug is read from the live symlink target rather than guessed,
which covers a remote being added, rewritten, or removed. When both the old
and new entries hold content the migration is ambiguous, so nothing moves
and the user is directed to --adopt.
2026-09-03 18:56:45 -04:00
rootiest 2d8db42b12 docs(fish-config.index): index the agent memory vault variables
config-help resolves keywords through this hand-maintained index; the
new "Agent Memory Vault" section in 07-customization.md had no entries
here yet. Adds agent-vault, __fish_agent_vault_dir, and
__fish_agent_vault_autopush, following the __fish_scrollback_history_dir
precedent (bare variable names as keys).
2026-09-03 18:56:45 -04:00
rootiest 19126316a7 fix(agents-vault): always link the current project's memory
The guard around the symlink step only linked when the live Claude
project directory already existed, which is exactly backwards for the
clone-onto-a-new-machine restore case: a freshly cloned vault entry
would be silently left unlinked and a starting agent would write fresh,
history-less memory instead. _agents_repo_ensure_symlink already makes
its own parent directories and is idempotent, so nothing depended on
the guard; it is removed and the link is now attempted unconditionally.

Also stop swallowing a refused or failed link as success: the helper's
exit status is now checked, and agents-vault reports its own error and
exits 1 instead of silently continuing with no link in place.

Smaller fixes from the same review pass:
- check the exit status of _agents_repo_install_tools and the
  core.hooksPath git config write, instead of discarding both
- give the vmem mkdir failure a stderr message like every other fatal
  in the function
- guard hostname with type -q and add it to DEPENDENCIES
- .version creation now sets changed, so --link (which skips the
  commit step) reports it in --quiet mode
- reword --link's help/doc text: it still scaffolds the vault and
  links memory, it only skips the final commit
- drop the unused c_dim color variable
- move the __fish_agent_vault_dir / __fish_agent_vault_autopush
  documentation below Opinionated Components so its NOTE: callout
  (now flush-left so it actually renders as a Starlight Aside, per
  review) doesn't become the first Note aside in the page and steal
  the existing test's assertions about the original 4-bullet one

Adds two tests: pre-seeded vault entry with no live directory at all
(the restore path the guard was breaking), and a forced link failure
asserting agents-vault now exits 1 instead of 0.
2026-09-03 18:56:45 -04:00
rootiest 2c185f7e23 feat(agents-vault): scaffold the vault and link project memory
Creates the vault repo on demand, reusing the AGENTS version bumper and
hook shims, then links the current project's live memory directory into
its slug-keyed entry and commits.

Because the live directory becomes a symlink into the vault, backup and
restore are the same operation: a cloned vault relinks itself on the next
run in each project, with no manifest and no batch restore step.

Also fixes _agents_repo_install_tools' progress messages, which hardcoded
the literal "AGENTS/.agents-tools/" even for callers writing elsewhere:
they now name repo_dir's own basename, so agents-vault reports its own
directory instead of a false AGENTS/ path.
2026-09-03 18:56:45 -04:00
rootiest b0585d00ad refactor(agents-init): use the shared repo helpers
Renames _agents_init_install_tools to _agents_repo_install_tools now that
the vault shares it, collapses the two duplicated root-symlink blocks into
one loop, and routes the auto-commit through _agents_repo_sync so a failed
rebase can no longer be committed as conflict markers.
2026-09-03 18:56:45 -04:00
rootiest b5d2c9ba87 fix(agents-vault): surface commit-hook rejection as exit 1
_agents_repo_sync fell off the end of its final if-block when git commit
failed, e.g. a pre-commit or commit-msg hook rejecting it (this repo runs
ggshield and Git-LFS hooks). fish's if construct sets status 0 when the
condition is false and there is no else branch, so a rejected commit was
being reported as success rather than as the documented "not a git
repository" exit 1 it was assumed to fall through to.

Add an explicit else branch that emits a stderr diagnostic and returns 1,
and widen the EXIT STATUS/DESCRIPTION docs to cover this path under the
existing code 1 rather than adding a fourth code, since later tasks
already consume the 0/1/2 contract.
2026-09-03 18:56:44 -04:00
rootiest 51543cb7ca feat(agents-vault): add sync helper that refuses to commit conflicts
agents-init currently swallows a failed rebase and then stages and commits
whatever is in the tree, which records conflict markers under a routine
message. No AGENTS repo has a remote today so the pull never runs, but the
vault gives these repos remotes and arms it.

The shared helper aborts the rebase, commits nothing, and returns 2. It
also redirects git's own stdout during the pull/abort: git prints
"CONFLICT (content): ..." to stdout, not stderr, so without this the
message would leak into the helper's own stdout instead of staying
diagnostic-only.

The conflict fixture commits "ours" locally before diverging, since an
uncommitted worktree change has nothing for --autostash's rebase step to
replay -- it fast-forwards cleanly and only the stash pop would conflict.
2026-09-03 18:56:44 -04:00
rootiest 3fd9476fbc feat(agents-vault): add directory-only symlink helper
Enforces the rails the vault depends on: only directories are linked
(agent editing tools refuse to write through a symlinked file), a missing
target is refused rather than turned into a dangling link, and adopting a
populated live directory copies without clobbering.

Also fixes slug sanitization in _agents_repo_slug to apply the same
[^a-z0-9._-] → - mapping to the fallback (no-remote) branch, ensuring
local project slugs are filesystem-safe and won't leak special chars like
spaces or exclamation marks.
2026-09-03 18:56:44 -04:00
rootiest 1dc0e5293d feat(agents-vault): derive vault slugs from normalized remote URLs
Keys a project by its remote rather than its path so the key survives a
machine change or a directory rename. Falls back to a path-derived
local-* key when no remote exists.

Adds a hermetic test harness that builds throwaway repos under mktemp.
2026-09-03 18:56:44 -04:00
rootiest 335fdff433 Merge pull request 'feat(ci): sync the label taxonomy to the GitHub mirror automatically' (#125) from ci/sync-mirror-labels into main
Sync labels to mirror / sync-labels (push) Successful in 26s
2026-09-01 03:37:16 +00:00
rootiest a78c6a604d Merge pull request 'docs(contributing): add issue templates and define the labeling standard' (#124) from docs/issue-templates-and-labels into main 2026-09-01 03:36:02 +00:00
rootiest aed37d5a75 docs(contributing): note that mirror labels now sync automatically
The mirror section told contributors a label added on Gitea "must be
created on the mirror too -- no automation does it for you." That's no
longer true, and a stale instruction to do something by hand is worse than
none, since it invites a manual edit that the next scheduled sync would
overwrite anyway.

Describe what the sync actually does: what it creates, updates, and prunes,
that an in-use label is never deleted, the --dry-run and --self-test flags,
and the rename caveat that follows from matching labels by name. Also
record the GH_MIRROR_TOKEN secret the workflow needs and its exact scopes,
since that's the one part of this that can't be automated.

The exclusive-labels caveat below it is unaffected and stays as written.
2026-08-31 23:32:16 -04:00
rootiest cff4f7b414 feat(ci): sync the label taxonomy to the GitHub mirror automatically
Labels don't travel with a mirror push -- mirroring copies files, not
repository settings -- but they matter on the GitHub side anyway, because
GitHub reads the same .github/ISSUE_TEMPLATE/ files and silently drops a
labels: entry naming a label it doesn't have. Until now the only thing
keeping the two sets aligned was remembering to do it by hand, which is
exactly the kind of thing that gets forgotten and then fails invisibly.

Add scripts/sync-labels.py and a workflow that runs it daily, on any change
to the script itself, and on manual dispatch. Gitea stays the source of
truth: labels are managed there and GitHub is made to match.

- **Creates and updates** anything missing or drifted. Colors and
  descriptions are normalized before comparison -- Gitea returns colors
  bare, GitHub sometimes with a leading '#', and a description may be null
  on one side and "" on the other -- so a steady state is a true no-op
  rather than a rewrite of all 33 labels every run.
- **Deletes only unused extras.** An extra label on the mirror is removed
  only when no issue or PR there carries it; one in use is reported with
  its count and left alone. An unattended scheduled job must not be able to
  strip a label off somebody's issue.
- **Refuses to run on an empty source**, since treating that as truth would
  propose deleting every label on the mirror.
- **--dry-run** prints the plan and changes nothing; **--self-test** checks
  the diff logic offline against fixtures, and gates the sync step in CI so
  a broken diff can't mutate anything.

Stdlib only, so the CI step installs nothing beyond python3. The job is
gated with the same github.server_url check ci.yml uses -- without it the
mirror would queue this forever against a runner that only exists on Gitea.

Labels are matched by name, so a rename reads as delete-plus-create; the
new name is created and the old is pruned only if unused. The two forges
share no stable label ID, so a rename can't be tracked across them.
2026-08-31 23:32:16 -04:00
rootiest 877c973e87 docs(contributing): make the issue templates work on the GitHub mirror too
The templates were written against Gitea's schema alone, but the mirror
serves the same .github/ISSUE_TEMPLATE/ files to GitHub, where two of them
would have silently failed:

- **config.yaml -> config.yml.** Gitea accepts either spelling
  (modules/structs/issue.go: `base == "config.yaml" || base == "config.yml"`),
  GitHub only recognizes config.yml. Under the old name the mirror's
  template chooser would have shown neither the contact links nor the
  blank-issue setting.
- **bug.yaml `about:` -> bug.yml `description:`.** GitHub requires
  `description` on a YAML issue form; Gitea's IssueTemplate.About carries
  the comment "Using description in a template file is compatible" and
  falls back to it at modules/issue/template/unmarshal.go:126. So
  `description` is the one spelling both forges accept. The markdown
  templates keep `about:`, which is correct for their format on both.

Both files now carry a comment explaining the constraint, so neither gets
"tidied" back into a broken state.

Also add a contact link pointing at the canonical Gitea tracker, so someone
arriving from the mirror is steered to the right place before they file,
and document mirror parity in CONTRIBUTING.md: the labels must be created
on both sides by hand, since mirroring copies files rather than repository
settings and GitHub drops a labels: entry naming a label it doesn't have.
Note too that GitHub has no exclusive labels, so the one-of rule on
Priority/, Reviewed/, and Status/ holds only by convention there.
2026-08-31 23:16:41 -04:00
rootiest ce3c44a053 docs(contributing): define the issue and PR labeling standard
The repo carried Gitea's stock label set with no written rule for applying
it, so labels were effectively unused. Establish the standard: every issue
and PR carries exactly one Kind/ and at least one Area/, and document what
each group means, which are exclusive, and who applies them.

Extend the taxonomy to make that workable:

- **Kind/Refactor, Kind/Chore, Kind/Performance** — the stock Kind/ group
  couldn't describe a refactor, a chore, or a perf change, which is much of
  this repo's history. The group now maps one-to-one onto the Conventional
  Commits types already in use, so a PR's label and title agree.
- **A new non-exclusive Area/ group** over the ten subsystems (functions,
  completions, config, docs, tests, CI, integrations, prompt & theme,
  components, scripts). This is what makes the tracker searchable by
  subsystem; Kind/ alone can't answer "what's outstanding in the docs
  pipeline?".
- **good first issue and help wanted**, deliberately unscoped rather than
  under Status/. Status/ is exclusive, and an issue is often both blocked
  and open for someone to pick up; keeping these outside the group lets
  them coexist with a real status.

Priority/, Reviewed/, and Status/ are documented as exclusive and
maintainer-applied, with the rules that keep them meaningful — no
Priority/ label means ordinary priority, Reviewed/Confirmed means actually
reproduced, and a Status/ label is removed once it stops being true.

Also add labeling to the standing PR rules in Branching & Pull Requests,
so it's visible where the rest of the PR checklist lives.
2026-08-31 23:09:01 -04:00
rootiest af764903e7 docs(contributing): add issue templates for bugs, features, and docs
Issues had no template at all, so a report arrived in whatever shape the
reporter chose — most often without a fish version, a reproduction, or the
full error text, which is what actually stalls a bug.

Add three templates under .github/ISSUE_TEMPLATE/, beside the PR template
so the GitHub mirror offers the same set:

- **bug.yaml** — a Gitea issue form rather than markdown. Version, OS,
  area, reproduction, expected and actual behavior are required fields, so
  an unactionable report can't be submitted in the first place. The Area
  dropdown exists because contributors without push access can't set an
  Area/ label themselves.
- **feature.md** and **docs.md** — comment-guided markdown in the same
  house style as PULL_REQUEST_TEMPLATE.md, since what they ask for is
  open-ended prose. feature.md carries `## Acceptance criteria`, the
  issue-side counterpart to a PR's `## Verification`. docs.md insists on
  the docs/manual/** source rather than the generated page, which the next
  CI run would overwrite.
- **config.yaml** — keeps blank issues enabled for what the three don't
  cover, and links the contributing guide and the customization docs.

Each template pre-applies its Kind/ label. Document the set, the plain-
description title convention (an issue states a problem; the conventional
subject belongs on the PR that closes it), and the triage split in a new
CONTRIBUTING.md § Issues.
2026-08-31 23:07:44 -04:00
rootiest fcb9e0c468 Merge pull request 'docs(contributing): add PR description template and convention' (#123) from docs/pr-template into main
Reviewed-on: #123
2026-09-01 02:42:37 +00:00
rootiest 1dc86b9ff0 docs(contributing): document the WIP: title prefix for in-progress PRs
Gitea treats a `WIP:` title prefix as a draft marker and refuses to merge
while it's present. Verified empirically against this instance by
temporarily retitling PR #123: the API flipped `draft` to true and
`mergeable` to false, and both reverted when the prefix was removed.

The distinction from the verification merge gate is the point, so it's
stated explicitly in both files: `WIP:` means more code changes are
coming, NOT "finished but unverified". A complete branch with unticked
`## Verification` boxes is an ordinary PR — that case is already covered
by the merge gate and does not want the prefix. The two signals are
independent and can occur in any combination.

Documented as a merge rule under Branching & Pull Requests, next to the
verification gate, and in the template's title guidance where an author
picking a title will actually encounter it.
2026-08-31 22:41:12 -04:00
rootiest ea8b13b38a docs(contributing): rename Manual Verification to Verification, make it a merge gate
The old name implied the list was only for by-hand steps, which sat badly
with the fact that most entries in practice are programmatic — the test
suite, `fish_indent`, `docs/verify-manual.py`, CI. Dropping "Manual" lets
one list carry both kinds, and gives the checkbox state real meaning:

- **Checked** — verified, whether it ran programmatically or the author
  performed it by hand.
- **Unchecked** — an outstanding manual check the reviewer still has to
  perform. Left visible rather than dropped.
- **The list is the merge gate.** A PR isn't merged until every box is
  checked; added as an explicit rule under Branching & Pull Requests
  alongside the other merge rules.

Because unchecked boxes now block the merge, the guidance also states that
only resolvable checks belong here — one nobody can run would block the PR
indefinitely. Genuinely unverifiable caveats and assumptions go in
`## Notes`, which already existed in the optional-sections list.

Incidentally realigns with PRs 121-122, which had already shortened the
heading to `## Verification`; that part of the recent drift was right.
2026-08-31 22:35:30 -04:00
rootiest 2f49960149 docs(contributing): establish Closes #N issue-linking convention
The repo has no issue-tracking history yet — a grep across all 122 prior
PRs found zero `Closes #N` references — so this is forward-looking rather
than derived from precedent. Establishing it now means the first PR that
does close an issue has a rule to follow instead of inventing one.

- Placement is a trailing line at the end of `## Summary`, not the bottom
  of the body, because `## Manual Verification` is always last.
- `Fixes`/`Resolves` noted as equivalent; `Refs #N` for a related issue
  that should stay open.
- Guidance calls out that the keyword must be repeated per issue, since a
  bare `#43` after a comma links without closing.
- Lives in the template's HTML comments, so a PR with no associated issue
  leaves no stray `Closes #` behind.

Also drops an unverified claim that the GitHub mirror pre-loads the
template; PRs are opened on Gitea, and the mirror is push-only.
2026-08-31 22:32:52 -04:00
rootiest f52bfaa55e docs(contributing): add PR description template and convention
Codifies the PR body format the repo has converged on across its first
122 pull requests, which until now lived only as an implicit pattern
agents and contributors had to reverse-engineer from prior PRs.

- **`.github/PULL_REQUEST_TEMPLATE.md`** — `## Summary`, optional `##`
  sections, then `## Manual Verification` as a checkbox list. Gitea falls
  back to `.github/` when `.gitea/` is absent, and the GitHub mirror reads
  the same path, so one file covers both.
- **`CONTRIBUTING.md`** — new "Pull request descriptions" subsection under
  Branching & Pull Requests, documenting the same three-part structure.

Section names were chosen by frequency across all 122 PRs: `## Summary`
(86) and `## Manual Verification` (63) are the clear majority. The later
`## Manual Verification Checklist` (12, PRs 90-113), `## Test plan` (11)
and `## Verification` (3, PRs 121-122) variants are drift away from that
baseline, not a newer standard, so the template restores the dominant
form. Checkboxes ship unchecked but are meant to be checked before the
PR opens, matching the 585-to-12 ratio of `[x]` to `[ ]` in merged PRs.
2026-08-31 22:27:26 -04:00
Gitea Actions dfb353af09 chore(docs): regenerate manual, man page, and component registry 2026-09-01 02:16:32 +00:00
rootiest 5328529e18 Merge pull request 'fix(help): full index audit and singular/plural keyword matching' (#122) from docs/index-full-audit into main
CI / github-mirror (push) Skipped
CI / test (push) Successful in 49s
CI / build-docs (push) Successful in 3m35s
2026-09-01 02:11:53 +00:00
rootiest 81d26e095a Merge pull request 'feat(help): render code spans in the pager instead of printing backticks' (#121) from feat/consistent-code-spans-in-concat into main
CI / github-mirror (push) Skipped
CI / build-docs (push) Canceled after 0s
CI / test (push) Canceled after 40s
2026-09-01 02:11:27 +00:00
rootiest 6cf690e637 fix(help): resolve singular and plural section keywords
The heading scan matches a keyword contained in a heading, so a plural
could never reach a singular heading: `customization` found "7.
CUSTOMIZATION" and `customizations` found nothing at all. The index
lookup was exact-match, so it could not cover the gap either without an
alias per word.

Both now try the keyword as typed first, then its singular/plural
forms. Each variant is tried against every heading before the next one
is considered, so a loose plural cannot beat an exact hit further down
the document.
2026-08-31 22:07:06 -04:00
rootiest f7a9ff9d23 chore(docs): regenerate manual
The man page is left to CI, which has pandoc.
2026-08-31 22:02:41 -04:00
rootiest 577ad993ea feat(help): render inline code spans instead of printing backticks
config-help pipes the manual through bat, which dims the backticks and
leaves the span content the same colour as the prose around it -- so a
delimiter carried no information and every span cost the reader two
literal characters. 1236 of them across the document.

Each span is now rendered bold and the delimiters dropped, in every
branch of the viewer chain:

- ov + bat, and ov alone, style the spans (bat's output wraps each
  backtick in its own SGR sequence; raw Markdown is matched directly)
- bat alone flattens them on the way in instead, because bat escapes
  any SGR sequence handed to it as input
- less and cat style them, less gaining -R to render the result
- man -l needs nothing; pandoc consumed the backticks at build time

Both substitutions are line-preserving, so the tail-slice that opens
the pager on a requested section still lands on it.
2026-08-31 22:02:37 -04:00
rootiest f0de5378fe docs(manual): keep backticks out of verbatim blocks and off line breaks
Two shapes reach a reader as literal punctuation rather than markup:

A backtick inside a four-space block. The block is verbatim in every
renderer -- pandoc sets it monospace, prettify() fences it for the site
-- so the backtick is a character on the page. Twelve such lines are
cleaned; each sat at the start of its column, so the alignment of the
C5 capture table and the component summaries is unchanged.

A span split over a line break. Markdown pairs it happily, but
config-help pairs backticks one line at a time, so `fish-deps\nupdate`
showed both halves. The sentence is reflowed.

Both are now enforced, the first by test_concat_section_five_stays_
verbatim and the second by test_concat_code_spans_never_straddle_a_line.
2026-08-31 22:02:28 -04:00
rootiest b01124f99d feat(docs): run codespans over the man-page pipeline too
A token was typeset by whichever pipeline happened to render it: the
site marked tmux and local.fish through codespans, while the man page
and config-help marked only what the SSOT had backticked by hand. Run
the same pass in build_concat() so prose is marked identically wherever
it is rendered (549 -> 662 spans in the concat).

codespans now treats a four-space block as code. The site never meets
one -- prettify() has already turned it into a fence by then -- but the
concat keeps the indented form pandoc wants, and its contents are
verbatim: without this the table of contents alone would come out with
ov, bat, less and cat wrapped inside a code block. Section 5 is
unaffected for the same reason; its entries arrive as indented blocks
that pandoc already sets in a monospace font.

test_codespans_is_site_only asserted the opposite guarantee and was
passing only because its example, -r/--resume, sits inside one of those
newly-protected blocks. It is replaced by tests for what is now true:
indented blocks stay verbatim, prose spans reach the concat, and
section 5 carries no backticks.

The man page is left for CI to regenerate; pandoc is not needed to
build the concat.
2026-08-31 21:56:55 -04:00
rootiest 2ce8bebf29 docs(functions): drop backticks from doc-headers
CONTRIBUTING states doc-headers are written as plain text -- the header
is read as-is by config-help, by funcsave, and by anyone opening the
file, and docs/codespans.py adds the site's inline code spans at render
time. 22 files had drifted from that, carrying 41 hand-written spans
that reached config-help and the man page as literal backtick
characters inside an otherwise verbatim block.

The one span whose content ended in a space is requoted rather than
dropped, so "read> " keeps reading as a prompt string.
2026-08-31 21:56:45 -04:00
rootiest 618ce00f9e docs(index): full audit of the config-help keyword index
Cover the ~50 previously-unindexed headings (function reference entries
like play-media, steam-dl, bd-pull, cffetch/ffetch, config-toggle, dops,
rand_string, fish_prompt/fish_mode_prompt/fish_right_prompt, lD, mv, p,
fast/fast-cli, gip4/gip6, fzf-update, sponge_filter_secrets,
fzf_configure_bindings, ld; the C1-C6 component sub-category headings
filesystem/network/monitor/shell-tools/dev-tools,
plugin-management/pkg-wrappers/venv/telemetry/sync,
key-bindings/environment/prompt, terminal-abbrs/window-mgmt/
notifications/history-logs/pkg-upgrade, terminal-capture/
multiplexer-capture/pkg-logs, first-run/greeting-message; plus
Config Variables' "Other", the Integrations "Scrollback History", the
dependency catalog's Optional/Terminal Emulators tiers, the C0/always
override note, and "Reading the source directly").

Expanded aliases for existing headings: play-media also reachable as
video/audio/mpv/vlc, steam-dl as steam, cffetch/ffetch share fetch/
fastfetch/neofetch/sysinfo, rand_string as random/password/randomword,
gip4/gip6 as ipv4/ipv6, dops as docker-ps, ld as lazydocker, bd-pull as
beads, fast-cli as speedtest, sponge_filter_secrets as secret-filter.

Fixed two pre-existing duplicate normalized keys (key-bindings/
keybindings and man-page/manpage both collapsed to a single entry) and
repointed config-toggle from the generic config-settings heading to its
own dedicated "### config-toggle" heading now that one exists.

Judgment calls on ambiguous/repeated heading text (left unindexed, or
indexed via a distinguishing keyword instead of the literal name):
- "### Sub-categories" repeats 7 times (once per opinionated-components
  overview and once per C1-C6 page); an index entry pointing at that
  text always resolves to the first occurrence, so none of the 7 are
  indexed under that name. Each parent (C1-C6, and the Minimal Mode
  section) already has its own keyword.
- "### search" appears twice: the pkg search subcommand (kept, existing
  `search` key) and the C1 command-shadow sub-category. The C1 one
  isn't separately reachable for the same reason.
- "## Integrations" appears twice (Section 1 integrations writeup and
  the Dependency Catalog's Integrations tier table); only the first
  (already indexed) is reachable.
- Where a C1-C6 sub-category heading text collides after normalization
  with an existing higher-value keyword (key-bindings, network,
  notifications, venv), the new entry uses a distinguishing keyword
  (bindings-toggle, network-shadow, notifications-toggle, venv-toggle)
  instead of contesting the existing one.
- `prompt` now points at the fuller "## Prompt and Theme" section
  rather than the one-line C3 sub-category blurb; the latter is
  reachable via `prompt-toggle`.
2026-08-31 21:56:15 -04:00
rootiest 1aef0ffca8 Merge pull request 'fix(ci): skip queued-forever jobs on the GitHub mirror' (#120) from ci/skip-duplicate-run-on-github-mirror into main
Reviewed-on: #120
2026-09-01 00:21:20 +00:00
rootiest a89a5576a3 fix(ci): skip queued-forever jobs on the GitHub mirror
The test/build-docs jobs target a self-hosted runner (racknerd-mini)
that only exists on the Gitea instance. When GitHub re-runs this same
workflow on the mirror, those jobs sit queued forever with no matching
runner, so the commit never gets a completed status.

Gate both jobs to skip when github.server_url is github.com, and add a
trivial github-mirror job (runs-on: ubuntu-latest, which GitHub does
provide) that only runs on the mirror, so the check completes instead
of hanging.
2026-08-31 20:19:40 -04:00
rootiest b754709f02 docs(site): add inline code spans to generated Starlight pages
CI / test (push) Successful in 1m4s
CI / build-docs (push) Successful in 3m57s
Function doc-headers are authored as plain text -- `config-help`,
`funcsave` and anyone opening the `.fish` file read them as-is -- so they
carry no backticks. The site inherited that and rendered `-a/--all` and
`__fish_config_op_aliases` as ordinary prose.

docs/codespans.py adds the spans at render time, as the last step of
prettify(), so only the site sees them; build_concat() (man page,
config-help) is byte-for-byte unchanged.

Recognised shapes: flags and flag pairs, `$vars`, SCREAMING_SNAKE env
vars, snake_case identifiers, paths and filenames, key chords, command
shadow chains (`ls->eza`), runs of tool names, whole command lines in a
table column of command lines, and known command names -- drawn from the
`_fdc_*` catalog in functions/_fish_deps_catalog.fish, the functions/
listing, and a standard-command list, minus the names that also read as
English.

Fenced blocks, existing code spans, headings, link targets, URLs,
component markup and <FileTree> bodies are passed through untouched, and
every rule bails out rather than guess.
2026-08-31 20:04:19 -04:00
Gitea Actions f7cfad559c chore(docs): regenerate manual, man page, and component registry 2026-08-25 05:54:10 +00:00
rootiest e97b3ee6ab Merge pull request 'fix(docs): reformat Prompt and Theme section and fix MDX code-block bug' (#119) from docs/customization-prompt-theme-formatting into main
CI / test (push) Successful in 52s
CI / build-docs (push) Successful in 3m38s
Reviewed-on: #119
2026-08-25 05:49:37 +00:00
rootiest d44dbd3564 Merge branch 'main' into docs/customization-prompt-theme-formatting 2026-08-25 05:49:26 +00:00
rootiest 2aad1aca98 Merge pull request 'feat(docs): expand functions/ and completions/ in the Starlight home tree' (#118) from feat/docs-filetree-dynamic-listing into main
CI / test (push) Successful in 49s
CI / build-docs (push) Successful in 3m7s
Reviewed-on: #118
2026-08-25 05:35:32 +00:00
rootiest 9969f43ba3 fix(docs): reformat Prompt and Theme section and fix MDX code-block bug
Verified every claim in the Prompt and Theme section against the actual
source and corrected several inaccuracies: the Starship wrapper's missing
C3 gate, the fallback prompt's vi-mode states and segment order, the FZF
theme's real location (conf.d/theme.fish, not integrations/fzf.fish) and
color set, and the Catppuccin theme-switch example using the wrong
fish_config subcommand (choose, not save). The right-prompt Docker-context
example was rewritten to show that it's independent of exit status.

While reformatting, found that any block build-manual.py couldn't classify
as shell/table/tree fell back to plain 4-space markdown indentation, which
silently renders as squashed, unreadable paragraph text on any page that
also contains an <Aside> or <FileTree> — MDX has no indented-code-block
syntax, unlike plain Markdown. This affected 07-customization.mdx plus four
other pages. Fixed the fallback to emit a fenced ```text block instead,
since fences work in both MDX and plain Markdown; this also gives every
affected block Starlight's normal code-block styling instead of a bare grey
slab.

docs/fish-config.md is intentionally left stale here — CI regenerates and
auto-commits it from docs/manual/** on push to main.
2026-08-25 01:28:18 -04:00
rootiest 82d78d19f5 feat(docs): expand functions/ and completions/ in the Starlight home tree
List every file in functions/ and completions/ inline under the home
page's file tree instead of a one-line summary. The listing is read
live off disk during --site generation, so it never needs manual
upkeep, and only affects the Starlight build — the plain-text
manual/man page (--concat) still renders the compact summary.
2026-08-25 01:07:07 -04:00
rootiest 38924d5c3c docs(readme): link to CONTRIBUTING.md 2026-08-22 01:01:12 -04:00
rootiest 057d9913b9 Merge pull request 'docs(contributing): add CONTRIBUTING.md formalizing repo standards' (#117) from docs/contributing-guide into main
Reviewed-on: #117
2026-08-22 04:58:07 +00:00
rootiest 62167a439e docs(contributing): clarify fork workflow for outside contributors
The branch-directly-off-main workflow assumes push access to the
repo; contributors without it should fork and PR from there instead.
2026-08-22 00:54:20 -04:00
rootiest f4c4922f0e docs(contributing): add CONTRIBUTING.md formalizing repo standards
Documents the branching/PR workflow, commit conventions, fish function
doc-header and colored --help conventions, the docs generation
pipeline, testing, and the secrets/machine-config placement rule, so
these practices live somewhere durable instead of only in commit
history and conversation memory.
2026-08-22 00:53:54 -04:00
rootiest 857faebeba Merge pull request 'feat(help): standardize colored --help output across functions' (#116) from feat/colored-help-text into main
CI / test (push) Successful in 56s
CI / build-docs (push) Successful in 3m26s
Reviewed-on: #116
2026-08-22 04:24:44 +00:00
rootiest b1a0c6c488 Merge pull request 'fix(scrub): restore missing line continuation in aggressive_patterns' (#115) from fix/scrub-aggressive-patterns-backslash into main
CI / build-docs (push) Canceled after 0s
CI / test (push) Canceled after 22s
Reviewed-on: #115
2026-08-22 04:24:30 +00:00
rootiest 500dd8a735 feat(help): standardize colored --help output across functions
Add the established c_head/c_cmd/c_flag/c_dim/c_arg color scheme to
--help (or usage-on-error) output in play-media and 13 other functions
that lacked it or used an ad hoc scheme: bkg, detach, replay, p, y,
spark, wake-lock, open-url, repo-open, dng2avif, dockup, fish-deps
(__fish_deps_help), and scrub.

Also tweak the standard itself:
- c_cmd now uses plain `set_color --bold` instead of `--bold white`,
  so the command name adapts to the terminal's foreground instead of
  forcing white text that washes out on light-background themes.
  Applied across all functions already using the pattern.
- jobrunner's reset variable renamed from c_rst to c_reset to match
  the naming used everywhere else.
2026-08-22 00:19:43 -04:00
rootiest 9e74cb8f0a fix(scrub): restore missing line continuation in aggressive_patterns
A missing trailing backslash after the Thumbs.db:encryptable pattern
terminated the `set -l aggressive_patterns` array early. The AI-tool
patterns (.gemini*, .claude*, .antigravity*, .remember*) were then
executed as a bogus command instead of being appended to the array,
so scrub -a never actually purged them, and every scrub invocation
printed a spurious "Unknown command" error.
2026-08-22 00:18:55 -04:00
Gitea Actions 4006a2f855 chore(docs): regenerate manual, man page, and component registry 2026-08-21 06:57:00 +00:00
rootiest 8b9d0ac1f4 Merge pull request 'feat(media): add play-media fzf picker for audio/video files' (#114) from feat/play-media-fzf-picker into main
CI / test (push) Successful in 1m0s
CI / build-docs (push) Successful in 3m37s
2026-08-21 06:52:23 +00:00
rootiest 51fc669c02 feat(media): add play-media fzf picker for audio/video files
Fuzzy-filters audio/video files under the current directory via fd,
previews them with thumbnails pulled from the freedesktop thumbnail
cache (or ffprobe metadata as a fallback), and plays the selection
through the best available player: --player flag, $play_media_player,
xdg-mime default, then a short mpv/vlc fallback list. Adds mpv/vlc as
optional fish-deps entries.
2026-08-21 02:47:45 -04:00
rootiest c25bb3b105 Merge pull request 'fix(ci): use working-directory instead of cd everywhere' (#113) from fix-ci-deploy-step-group-label into main
Reviewed-on: #113
2026-08-21 05:39:42 +00:00
rootiest 4d7ad64c3a fix(ci): drop remaining cd for working-directory consistency
The only other cd left in the workflow mixed two working directories
in one step: docs/build-manual.py --site runs from the repo root, then
npm ci/astro build need docs/site. Split into two steps so each can
use working-directory instead, keeping the whole file cd-free and
consistent with the Cloudflare deploy step's fix.
2026-08-21 01:23:34 -04:00
rootiest 3c27e52ada fix(ci): use working-directory instead of cd for Cloudflare deploy
Gitea/GitHub Actions auto-groups a multi-line run: script under
"Run <first line>". With `cd docs/site` as the first line, the
collapsed log tree showed that instead of the actual wrangler deploy
command. Moving the directory change to the step's working-directory
key drops cd from the script entirely, so the group label now reflects
the command that's actually running.
2026-08-21 01:21:29 -04:00
rootiest 70b5868e3e Merge pull request 'fix(ci): reduce apt-get noise/fragility and allow per-job dispatch' (#112) from ci-robustness-and-dispatch into main
Reviewed-on: #112
2026-08-21 05:10:01 +00:00
rootiest c47b51cd6e feat(ci): allow triggering test or build-docs individually
workflow_dispatch already ran the whole pipeline manually, but there
was no way to fire just one job (e.g. re-run docs generation without
re-running the fish test suite) the way the old standalone
build-docs.yml let you. Add a job choice input (all/test/build-docs,
defaulting to all) and gate each job on it via `if:`, while leaving
the push-triggered path's needs: test gating untouched.
2026-08-21 00:58:30 -04:00
rootiest c4e225b007 fix(ci): retry apt-get update and skip recommended packages
Two more sources of CI noise/fragility alongside the debconf frontend
fix: fish's install pulls in man-db/groff-base/xsel as recommends,
triggering a slow mandb rebuild for tooling nothing here uses;
--no-install-recommends skips that. apt-get update had no retry
policy, so a transient blip against the PPA mirror failed the whole
job; -o Acquire::Retries=3 gives it a few chances first.
2026-08-21 00:54:54 -04:00
rootiest f7598e5e23 fix(ci): set DEBIAN_FRONTEND=noninteractive for apt-get installs
apt-get install was probing for a Dialog then Readline debconf frontend
before falling back to Teletype on the non-interactive CI runner,
adding noise and failed-negotiation log lines to every run. Passing
DEBIAN_FRONTEND=noninteractive directly on the sudo command line (env
vars set via step-level `env:` don't survive sudo's env_reset) skips
the negotiation and goes straight to the frontend that actually works
here.
2026-08-21 00:52:55 -04:00
rootiest a5cc8cbd36 Merge pull request 'feat(fzf): add preview, dirs, and image support to @@ inline picker' (#110) from enhance-fzf-inline-picker-preview into main
CI / test (push) Successful in 54s
CI / build-docs (push) Successful in 3m34s
Reviewed-on: #110
2026-08-21 04:47:16 +00:00
rootiest 616596726d feat(fzf): add preview, dirs, and image support to @@ inline picker
The @@ picker only listed files with no preview. It now lists both
files and directories via fd (matching _fzf_search_directory), and
shows a bat-highlighted or image-rendered preview through
_fzf_preview_file. Image previews use a kitty-graphics-protocol,
chafa, viu, timg fallback chain via the new _fzf_preview_image
helper, benefiting the Ctrl+F directory search and git-status
pickers as well since they share the same preview helper.
2026-08-21 00:46:29 -04:00
rootiest 7466188d35 chore(ci): rename build-docs.yml to ci.yml
The workflow now runs the fish config test suite before building and
publishing docs, so "build-docs" no longer describes its full scope.
2026-08-20 01:15:10 -04:00
rootiest 2608a6cd72 Merge pull request 'test(ci): add fish config test suite and gate docs build on it' (#109) from ci-fish-config-tests into main
Generate documentation / test (push) Successful in 56s
Generate documentation / build-docs (push) Successful in 3m28s
Reviewed-on: #109
2026-08-20 05:04:20 +00:00
rootiest 642c981e4b test(ci): add fish config test suite and gate docs build on it
Adds tests/run-tests.fish (syntax lint over every .fish file, plus a
sandboxed interactive load) and tests/functional.fish (10 checks
covering XDG/PATH/CDPATH setup, key bindings, abbreviations, core
functions, exit rewiring, and the opinionated-component registry).

The sandbox copies config-relevant files into a scratch HOME/XDG tree
rather than symlinking the checkout, since this repo also serves as a
live ~/.config/fish and a symlink would let universal-variable writes
leak into the real fish_variables file.

Wires the suite into build-docs.yml as a `test` job that `build-docs`
now depends on, so a broken config can no longer get published to the
docs site. Documents the workflow in the README's new Testing section.
2026-08-20 01:03:40 -04:00
Gitea Actions 451097d384 chore(docs): regenerate manual, man page, and component registry 2026-08-20 04:44:19 +00:00
rootiest 1ec69309cf Merge pull request 'fix(bindings): trigger fzf inline picker with a lookbehind @ instead of a @@ chord' (#108) from fix-fzf-picker-at-key-delay into main
Generate documentation / build-docs (push) Successful in 3m46s
Reviewed-on: #108
2026-08-20 04:40:38 +00:00
rootiest 27f780e733 docs(manual): use cat as the token-boundary example for @@ 2026-08-20 00:38:22 -04:00
rootiest 9368a4864c fix(bindings): trigger fzf inline picker with a lookbehind @ instead of a @@ chord
Binding the raw @@ chord made a lone @ an ambiguous prefix, so fish
(with fish_sequence_key_delay_ms unset) held every typed @ indefinitely
until a disambiguating keystroke arrived, breaking things like
`ssh user@host`. Binding the single @ key instead and checking whether
the current token is already a bare @ removes the ambiguity entirely:
plain @ always self-inserts instantly, and a second consecutive @
triggers the picker in place, with no forced delimiter before you can
keep typing. Vi's normal/visual modes are left unbound, matching their
existing (no-op) @ behavior.
2026-08-20 00:38:02 -04:00
rootiest 6689e69ece fix(ci): install fish from the official 4.x PPA
Ubuntu 24.04's default repo only carries fish 3.7, but
docs/manual/06-dependency-catalog.md states fish >= 4.0 as a
project dependency. ppa:fish-shell/release-4 is the fish-shell
maintainers' own PPA and explicitly supports 24.04.
2026-08-18 22:03:23 -04:00
Gitea Actions 5f55438581 chore(docs): regenerate manual, man page, and component registry 2026-08-19 01:58:54 +00:00
rootiest 0ef99e4874 fix(verify-manual): use a real temp file instead of /dev/stdin for the registry round-trip test
Generate documentation / build-docs (push) Successful in 3m30s
fish 3.7 (Ubuntu 24.04's packaged version, used in CI) rejects
'source /dev/stdin' when it's backed by a pipe, with
"'/dev/stdin' is not a file" -- fish 4.8 (local dev) accepts it.
Writing the generated registry to a real temp file sources
identically across fish versions.
2026-08-18 21:55:23 -04:00
rootiest df929c5335 fix(ci): install fish in build-docs workflow
Generate documentation / build-docs (push) Failing after 50s
The registry round-trip test spawns a real fish subprocess to verify
conf.d/__fish_config_op_registry.fish sources correctly, but the
runner image has no fish binary, so the workflow failed with
FileNotFoundError.
2026-08-18 21:50:43 -04:00
rootiest 6ef0859e43 perf(logo-svg): further optimized logo SVG image 2026-08-18 21:49:13 -04:00
rootiest 01f4e376ae Merge pull request 'feat(config): add sub-category granularity to opinionated components' (#107) from worktree-opinionated-subcategories into main
Generate documentation / build-docs (push) Failing after 43s
2026-08-19 01:42:25 +00:00
rootiest 31d04a2fe0 chore(ci): reflect registry regeneration in auto-commit message 2026-08-18 21:37:12 -04:00
rootiest 8866236bda fix(config-settings): align Enter continuation line in --help output
The wrapped description for the Enter key was indented one column past
every other description in the Navigation block. Drop the extra leading
space so it lines up at column 17 with the rest.
2026-08-18 18:13:01 -04:00
rootiest f7b207aaf4 fix(verify-manual): move assertion-free check to warn_*, exclude guard infra from false-positive warning
test_c0_tags_never_combine_with_contradiction_unwarned could never fail (its
own docstring said so) yet inflated the test_* pass count. Rename it to
warn_c0_tags_never_combine_with_contradiction, matching the file's existing
warn_* convention, and call it explicitly from main() alongside the other
three warn_* checks.

warn_functions_without_component also permanently false-positived on
functions/__fish_config_op_enabled.fish: the file's own function signature
and EXAMPLE prose contain the literal guard name, tripping the "calls the
guard" substring check against itself. Exclude the guard's own supporting
infrastructure files (__fish_config_op_enabled.fish,
__fish_config_op_cascade.fish, __fish_config_op_registry_lookup.fish) by
name -- an EXAMPLE-section-only exclusion wouldn't have worked here since
the false match is the function's own `function __fish_config_op_enabled`
definition line, not just its EXAMPLE block.
2026-08-18 18:12:57 -04:00
rootiest 1cb6f37b5b fix(registry): quote keys, dedupe tags, and document sourcing order; CI commits regenerated registry
- Quote both keys and values in the generated __fish_config_op_registry.fish
  keys array so a future identity/tag containing a glob-special character
  (*, ?, [) can't be silently dropped by fish's set, desyncing the
  positionally-paired keys/values arrays.
- Deduplicate the tag list per site in build_registry() so an identity
  collision across sources (e.g. auto-pull tagged autoexec/sync in both
  functions/auto-pull.fish and conf.d/auto-pull.fish) no longer produces a
  duplicated tag in the committed registry.
- Add a comment to the generated file's header noting it must sort first
  among conf.d/*.fish guard-callers, since that ordering is currently
  implicit in the filename rather than stated anywhere.
- CI's auto-commit step now also stages conf.d/__fish_config_op_registry.fish
  alongside the docs it already regenerates, so a # COMPONENT header change
  pushed without a manual __fish_config_op_registry_rebuild self-heals
  instead of silently drifting from what CI just regenerated.
2026-08-18 18:12:49 -04:00
rootiest a8468f3402 docs(manual): document sub-categories in customization, reference index, and troubleshooting
Sub-categories were previously undocumented outside README and the
per-category reference pages. Add a paragraph to 07-customization.md (the
canonical opinionated-components page) explaining the sub-category cascade,
a short note to the 08-components-reference index pointing readers at each
category's sub-category list, and a troubleshooting note that
__fish_config_op_<category>_<subcategory> variables follow the same
check/reset pattern as category variables.
2026-08-18 18:12:41 -04:00
rootiest 040c98c0a7 fix(config-settings,docs): address final whole-branch review findings
Bundled fix wave for six findings from the sub-category-granularity
whole-branch review:

- config-settings: reset in_subcat on Tab/Shift-Tab so up/down keep
  routing to cur_row instead of freezing on the Sponge/Paths pages
  after a drill-down
- verify-manual: _parsed_components() now delegates to
  generate_component_registry.collect_components() instead of a
  lossy dict.update() merge, closing a taxonomy-check blind spot on
  identity collisions
- verify-manual: add test_committed_registry_matches_headers to
  catch the committed registry drifting from current # COMPONENT
  headers
- build-docs workflow: trigger on conf.d/** and config.fish edits,
  not just functions/**
- __config_settings_draw_subcat: show (Universal)/(Session) in the
  drill-down title so the persistence scope is visible before toggling
- __config_settings_draw / config-settings: mention the Enter
  sub-category drill-down in the on-screen hint and --help text
- generate_component_registry: send the "wrote ..." progress line to
  stderr so it no longer corrupts --concat's stdout output
2026-08-18 16:46:46 -04:00
rootiest 3c0bba1737 fix(config-settings): fix silent varname resolution failure and stale panel_h in sub-category drill-down
Two bugs invisible to single-frame rendering, only reachable via the
interactive event loop:

- right/l and left/h resolved the sub-category variable name with
  "$toggle_vars[(math ...)]"_(...) inside a quoted string -- fish
  cannot expand a command-substitution index there ("Invalid index
  value"), so the set never ran and varname silently kept the parent
  category variable. Every arrow-key press on a sub-category row
  toggled the parent category instead. Fixed by hoisting the category
  variable into a plain local first, the same technique the down/j
  case already used for its page index.

- __cs_dispatch_draw left panel_h fixed at 16 regardless of what it
  actually drew, but the new sub-category page is n+7 lines (9-13,
  always < 16). Every redraw/cleanup erase computed its height from
  the stale constant, erasing too many rows and corrupting whatever
  was above the panel. Fixed by having the dispatcher record the
  actual printed height into panel_h after every draw, including
  resetting it back to 16 on the value pages even when in_subcat is
  stale from a Tab away without an intervening Escape.
2026-08-18 03:22:19 -04:00
rootiest 489e3cc7de feat(config-settings): render and toggle sub-categories in the drill-down page
Adds __config_settings_draw_subcat.fish, rendering a category's own
toggle plus its sub-category rows, sized dynamically from
__config_settings_subcats instead of the fixed 6-row category layout.
Wires the real per-category row count into config-settings.fish's
up/down handling (replacing Task 17's stub) and adds the
hyphen-to-underscore sub-category variable resolution to the
left/right toggle handlers, mirroring the translation the guard
function already applies.

Two box-drawing bugs surfaced while adapting the design doc's draft to
the real static sub-category data and were fixed rather than
transcribed: the title-dashes offset was off by 5, and several real
sub-category labels/descriptions (e.g. "Notifications", 13 chars;
several descriptions past 30 chars) exceed the narrower width tiers'
fixed field widths, so both fields are now defensively truncated
before padding to keep every row exactly iw+2 wide regardless of
content length.
2026-08-18 03:11:17 -04:00
rootiest 7ad3b90503 feat(config-settings): add sub-category drill-down navigation state 2026-08-18 03:01:22 -04:00
rootiest db21efee0c fix(config): split tricks.fish overrides-tricks into manpager/bang sites
overrides-tricks conflated two distinct C3 concerns under one shared site
(overrides/environment), so __fish_config_op_overrides_key_bindings off
left tricks.fish's bang-bang bindings active while abbr.fish/puffer.fish/
config.fish's equivalent sites correctly disabled -- a half-dismantled
bang-bang system per docs/manual's own atomic-gating claim. Split into
tricks-manpager (overrides/environment, matches PAGER/EDITOR/CDPATH) and
tricks-bang (overrides/key-bindings, matches abbr.fish/puffer.fish/
config.fish's bang-related sites, per
docs/manual/08-components-reference/03-c3-key-and-environment-overrides.md).

Also fixes stale prose in config.fish's top-of-file comment: the guard
signature is now <identity> [<site>], not <category>.
2026-08-18 02:56:35 -04:00
rootiest 207540c093 fix(config): restore cachyos-tricks site to its documented overrides category
The site was mistagged aliases/filesystem in the prior commit. The original
code's own comment above the guarded block ("Surgically overriding the
distro config is opinionated (C3 overrides): skip it entirely when
overrides are disabled") documents this as an overrides decision, and it
gated __fish_config_op_overrides pre-migration. Retag to
overrides/environment (matching tricks.fish's own sibling site for the
equivalent action) so aliases=on/overrides=off keeps skipping
tricks.fish/ls/lt/cleanup/copy, as originally documented -- no silent
user-facing behavior change.
2026-08-18 02:45:32 -04:00
rootiest 6b2d3bf491 refactor(config): migrate multi-category files and config.fish to named sites
Adds multi-site `# COMPONENT` headers and converts every guard call site in
conf.d/tricks.fish, conf.d/abbr.fish, functions/smart_exit.fish,
conf.d/yay-wrapper.fish, conf.d/paru-wrapper.fish, conf.d/wakatime.fish,
conf.d/first_run.fish, and config.fish (9 sites across 3 categories) to the
self-identifying `(status current-function|basename) <site>` calling
convention. Regenerates conf.d/__fish_config_op_registry.fish.
2026-08-18 02:39:47 -04:00
rootiest c3a2e35465 refactor(config): migrate C5 logging call sites to self-identifying guard 2026-08-18 02:22:31 -04:00
rootiest e02919de21 fix(config): translate hyphens to underscores in sub-category guard variable names
__fish_config_op_enabled built the sub-category override variable name by
concatenating the tag's slug verbatim, e.g. __fish_config_op_integrations_window-mgmt.
Fish variable names cannot contain hyphens, so any hyphenated sub-category
slug (14 of the 24 in the taxonomy) silently could never be overridden --
an unset such variable safely fell through via set -q, but attempting to
set it always errored with "invalid variable name", masking the defect
since no prior smoke test exercised an explicit sub-category-level toggle.
The registry tag itself (as authored in # COMPONENT headers and the
taxonomy docs) stays hyphenated; only the derived fish variable name is
translated.
2026-08-17 21:53:48 -04:00
rootiest 516b2ba26c refactor(config): migrate C4 integrations call sites to self-identifying guard 2026-08-17 21:49:45 -04:00
rootiest a981fa7f0a refactor(config): migrate C3 overrides call sites to self-identifying guard 2026-08-17 21:37:35 -04:00
rootiest 760b8e68fd refactor(config): migrate C2 autoexec call sites to self-identifying guard 2026-08-17 21:23:12 -04:00
rootiest 04fd832974 refactor(config): migrate C1 aliases call sites to self-identifying guard 2026-08-17 21:12:56 -04:00
rootiest 77c68558b2 docs(readme): mention sub-category toggles 2026-08-17 21:07:25 -04:00
rootiest 0554a3dddc fix(docs): tighten taxonomy slug regex to exclude the Sub-categories heading 2026-08-17 21:04:06 -04:00
rootiest fbb6b6e740 feat(docs): validate # COMPONENT tags against the sub-category taxonomy 2026-08-17 21:02:11 -04:00
rootiest 2cf61b0590 docs: author the sub-category taxonomy and C0 explanation 2026-08-17 20:55:36 -04:00
rootiest d748289c11 feat(docs): regenerate component registry before building the manual 2026-08-17 20:49:42 -04:00
rootiest d2e07effc1 feat(config): add manual registry-rebuild command 2026-08-17 20:46:55 -04:00
rootiest 9d6923f225 fix(docs): merge, not overwrite, COMPONENT lines on identity collision
collect_components() used dict.update(), which let conf.d silently
overwrite functions/ (or vice versa) when the same bare identity
appears in both, e.g. functions/auto-pull.fish and
conf.d/auto-pull.fish. The runtime guard can only ever look up the
bare status current-function/basename string, so both call sites
genuinely share one identity and their raw COMPONENT lines must be
concatenated, not replaced.
2026-08-17 20:42:04 -04:00
rootiest c0628dbd4c feat(docs): add component registry generator 2026-08-17 20:34:48 -04:00
rootiest 31b47ddfc5 feat(docs): parse # COMPONENT headers in manualtools 2026-08-17 20:29:02 -04:00
rootiest 9642cd69db feat(config): rewrite guard as self-identifying with C0 and site support 2026-08-17 20:23:49 -04:00
rootiest 7fa5ca2568 feat(config): add component registry lookup helper 2026-08-17 20:19:42 -04:00
rootiest 94a4fbe45f feat(config): add sub-category cascade evaluator 2026-08-17 20:15:29 -04:00
rootiest 04a02d089f style(docs-site): size the Gitea header icon up to 1.5rem
Generate documentation / build-docs (push) Successful in 3m26s
At the default 1em (16px) it read as noticeably smaller than the
other header controls, especially next to the logo. Bumped to a fixed
1.5rem — well within the nav bar's existing content height, so the
header itself doesn't grow.
2026-08-17 16:18:02 -04:00
rootiest 3ef83d1747 Merge pull request 'docs(site): use real Gitea logo for header social link' (#106) from feat-starlight-gitea-icon into main
Generate documentation / build-docs (push) Successful in 3m43s
Reviewed-on: #106
2026-08-17 20:05:56 +00:00
rootiest f865ad766d perf(docs-site): minify header logo SVG
logo.svg was 56KB of unminified, high-precision path data with no
embedded raster. Running it through SVGO (default preset, multipass)
cuts it to ~20KB with no visual difference.

perf(docs-site): further minify header logo SVG. Cut to ~8.9KB with no visual difference.
2026-08-17 16:03:05 -04:00
rootiest f32e0d0ce5 feat(docs-site): add starlight-plugin-icons, use real Gitea logo in header
The header social link used Starlight's generic `code-branch` icon.
Wires up starlight-plugin-icons + UnoCSS (Iconify) and overrides
SocialIcons to render `pajamas:gitea` for the Gitea link instead, while
falling back to Starlight's default icon set for anything else. Sidebar
and codeblock icon support are enabled but unused for now.
2026-08-17 15:30:42 -04:00
Gitea Actions 8a937124d3 chore(docs): regenerate manual and man page 2026-08-17 19:12:59 +00:00
rootiest d8feaf7143 Merge pull request 'docs(fisher-plugins): clarify sponge's history-purge security model, link plugin repos' (#105) from docs-sponge-privacy-clarity into main
Generate documentation / build-docs (push) Successful in 3m34s
Reviewed-on: #105
2026-08-17 19:09:27 +00:00
rootiest 22dcd31c05 docs(fisher-plugins): clarify sponge's history-purge security model, link plugin repos
Explains that a matched command is actively deleted from history and
force-saved within about one prompt cycle by default, not deferred to
shell exit, and calls out sponge_purge_only_on_exit as the setting that
would change that (a killed/crashed session never triggers fish_exit).
Also hyperlinks the Fisher-managed and bundled plugin names to their
upstream repos on the Starlight site.
2026-08-17 15:06:19 -04:00
Gitea Actions cbce46b63f chore(docs): regenerate manual and man page 2026-08-14 20:47:11 +00:00
rootiest 8ab69f53ed Merge pull request 'feat(deps): add Optional/Terminal Emulator tiers, fix docker prompt hang and ov install path' (#104) from feat-fish-deps-optional-tiers into main
Generate documentation / build-docs (push) Successful in 3m8s
Reviewed-on: #104
2026-08-14 20:44:10 +00:00
rootiest c17f6663db feat(deps): add Optional/Terminal Emulator tiers, fix docker prompt hang and ov install path
Reworks fish-deps' dependency classification from three tiers to five:
Required, Recommended, Optional, Terminal Emulators, and Integrations.

- Add an Optional tier for single-purpose wrapper conveniences that only
  matter if you already use that specific tool (btop, dust, duf,
  prettyping, go, lazygit, lazydocker, docker, yt-dlp, screen). Skipped by
  `fish-deps install`/`sync` by default.
- Split kitty/wezterm into their own Terminal Emulators tier, since only
  the one matching $TERM is ever relevant to a given user.
- Add --optional, --terminals, and --all flags to `install`/`sync` to
  opt back into the skipped tiers, with a summary of how many were
  skipped and which flag restores them.
- Fix `_fish_deps_status` marking missing Integrations as critical (red)
  the same as Required — only Required is red now; Recommended stays
  yellow, everything else renders as a neutral dim note.

Also fixes two bugs surfaced during dependency testing on a fresh
install:

- `fish_right_prompt` called `docker context show` on every prompt with
  no `type -q docker` guard, unlike every other optional integration in
  this config — on a system without docker this printed a visible
  "Unknown command: docker" block on every single prompt render. Added
  the missing guard, and hardened the `ld` wrapper with explicit
  docker/lazydocker presence checks.
- `ov`'s catalog entry offered `cargo install ov` as its preferred
  install method, but crates.io's `ov` is an unrelated crate, not the
  noborus/ov pager — cargo would silently install the wrong package.
  Removed the cargo path; `ov` now prefers `go install
  github.com/noborus/ov@latest` (ahead of the system PM) when go is
  available, since not all distros package `ov` in their base repos,
  and falls back to the system PM otherwise.
2026-08-14 16:42:37 -04:00
Gitea Actions 20adb8f75c chore(docs): regenerate manual and man page 2026-08-14 20:05:59 +00:00
rootiest 0e63b4fbb7 Merge pull request 'fix(mv): bring header and completions up to repo conventions' (#103) from fix-mv-header-conformance into main
Generate documentation / build-docs (push) Successful in 3m15s
Reviewed-on: #103
2026-08-14 20:02:53 +00:00
rootiest adbcd1d3c0 fix(mv): bring header and completions up to repo conventions
The EXIT STATUS block used a single space before the ">0" row's
description, which falls below the doc pipeline's 2-space column
threshold and silently degrades the rendered site page from a table
(like rm's) to a plain indented block. Pad it to match. Also strip
trailing whitespace from two DESCRIPTION lines and add --wraps='mv'
so fish inherits real mv's completions, matching the bash/top wrapper
convention.
2026-08-14 16:02:07 -04:00
rootiest 9e037f2a08 Merge pull request 'feat(docs): publish llms.txt for AI agent consumption' (#102) from feat-docs-llms-txt into main
Generate documentation / build-docs (push) Successful in 3m12s
Reviewed-on: #102
2026-08-14 19:58:10 +00:00
rootiest 96df21444b feat(docs): publish llms.txt for AI agent consumption
Add the starlight-llms-txt plugin so the docs build emits llms.txt,
llms-full.txt, and llms-small.txt alongside the regular pages, making
the manual queryable by MCP-compatible agents without depending on a
third-party indexing service.

Also bump js-yaml, nanoid, and sharp in docs/site to clear three
high-severity advisories (quadratic YAML omap parsing, a zero-size
nanoid loop, and inherited libvips CVEs) flagged by npm audit while
touching the same lockfile.
2026-08-14 15:50:21 -04:00
Gitea Actions 7875b83a94 chore(docs): regenerate manual and man page 2026-08-14 19:28:36 +00:00
rootiest 0765a2726a Merge pull request 'feat(mv): wrap the mv command to facilitate moving a directory up the tree' (#101) from mv-up-tree into main
Generate documentation / build-docs (push) Successful in 3m15s
Reviewed-on: #101
2026-08-14 19:25:28 +00:00
rootiest 80d4f5d9fa feat(mv): wrap the mv command to facilitate moving a directory up the tree 2026-08-14 15:24:40 -04:00
rootiest 391e2b6750 chore: ignore auto-generated uv env vars 2026-08-14 15:22:04 -04:00
Gitea Actions fc420fad72 chore(docs): regenerate manual and man page 2026-08-06 20:32:45 +00:00
rootiest dfdc1063ba Merge pull request 'docs(manual): format plugins and installation pages' (#100) from docs-format-plugins-installation into main
Generate documentation / build-docs (push) Successful in 3m32s
Reviewed-on: #100
2026-08-06 20:29:18 +00:00
rootiest 4ff120cc5d docs(manual): format plugins and installation pages 2026-08-06 16:28:13 -04:00
Gitea Actions 7c99b475e3 chore(docs): regenerate manual and man page 2026-08-06 20:14:19 +00:00
rootiest 262b53c6c4 Merge pull request 'docs: dynamic abbreviations with markdown tables' (#99) from feature/dynamic-abbreviations-docs into main
Generate documentation / build-docs (push) Successful in 3m30s
Reviewed-on: #99
2026-08-06 20:10:55 +00:00
rootiest 0ff6be3f81 Merge branch 'main' into feature/dynamic-abbreviations-docs 2026-08-06 20:10:18 +00:00
rootiest 86d20105e5 ci: move workflow to .github to increase hosting compatibility 2026-08-06 16:09:57 -04:00
rootiest 6790bf1430 ci: remove obsoleted docs-drift workflow 2026-08-06 16:09:28 -04:00
rootiest e76668d3b1 docs: fix abbreviations file ordering and capitalization for tests 2026-08-06 16:07:08 -04:00
rootiest 204b13781d docs: use indented text tables for abbreviations and strip CardGrid from concat 2026-08-06 16:00:48 -04:00
Gitea Actions 0b9cf5a928 chore(docs): regenerate manual and man page 2026-08-06 19:48:00 +00:00
rootiest 93831564a8 Merge pull request 'feat: implement __rand_string generator and update jobrunner backend' (#98) from feature/rand-string-generator into main
Generate documentation / build-docs (push) Successful in 3m44s
Offline docs drift reminder / remind (push) Successful in 15s
Reviewed-on: #98
2026-08-06 19:44:25 +00:00
rootiest 82d761b026 docs: restructure abbreviations into individual pages for sidebar 2026-08-06 15:38:15 -04:00
rootiest 742fd7941d docs: use markdown tables for abbreviations
Generates actual markdown tables instead of indented text blocks to ensure MDX/Starlight correctly renders abbreviations.
2026-08-06 15:04:06 -04:00
rootiest cb74cd84e2 fix: change jobrunner auto-naming to adjective-animal 2026-08-02 05:47:29 -04:00
rootiest 89fdfc8e72 refactor: use -n flag for explicit jobrunner names 2026-08-02 05:45:35 -04:00
rootiest 0e9c3b4b27 feat: implement jobrunner auto-naming fallback 2026-08-02 05:41:48 -04:00
rootiest d5535a38ad feat: add verb dictionary and preserve literal string casing in rand_string 2026-08-02 05:37:06 -04:00
rootiest 01553b71fd refactor: drop __ prefix and add -h flag to rand_string 2026-08-02 05:32:33 -04:00
rootiest ffff95f3b9 feat: implement __rand_string generator and update jobrunner to use tmux 2026-08-02 05:21:29 -04:00
rootiest 674a50ea05 feat(jobrunner): add named background job manager backed by GNU screen
Adds jobrunner (short alias jr) for running, listing, inspecting,
re-attaching to, and terminating detached background tasks. Unlike bkg
and detach, which discard output, a jobrunner job keeps a live terminal
that survives closing the shell and can be restored later with attach.

Includes the __jobrunner_sessions parser shared by the function and its
completions, dynamic job-name completions, and screen in the fish-deps
catalog.
2026-08-02 04:40:07 -04:00
Gitea Actions a2d52e1ec2 chore(docs): regenerate manual and man page 2026-07-28 07:37:49 +00:00
rootiest 84c6e9b79d Merge pull request 'fix(bindings): restore directory segment autosuggestion on ctrl-right' (#97) from fix-autosuggestion-ctrl-right into main
Generate documentation / build-docs (push) Successful in 2m59s
Reviewed-on: #97
2026-07-28 07:34:49 +00:00
rootiest 2d84bcdf7e docs(bindings): document Ctrl+Right autosuggestion behavior 2026-07-28 03:34:02 -04:00
rootiest 935ba904bd fix(bindings): restore directory segment autosuggestion on ctrl-right 2026-07-28 03:29:52 -04:00
Gitea Actions 8b0b5ee85a chore(docs): regenerate manual and man page 2026-07-28 07:14:10 +00:00
rootiest a1297a417e Merge pull request 'refactor(deps): demote zoxide to recommended tier' (#96) from feat-demote-zoxide into main
Generate documentation / build-docs (push) Successful in 3m13s
Reviewed-on: #96
2026-07-28 07:11:02 +00:00
rootiest 5c54ede483 refactor(deps): demote zoxide to recommended tier 2026-07-28 03:09:08 -04:00
rootiest f9086bd2ca ci(build-docs): fix baseless non-critical warnings in build log
Generate documentation / build-docs (push) Successful in 5m27s
- Eliminate the warning about the generic 404 page being replaced, it
was intentional.
- Add a flag to the cloudflare deploy task to approve pushes from dirty
git repos, it was intentional for the dynamic build.
2026-07-28 00:20:16 -04:00
Gitea Actions f9dfc4ca4c chore(docs): regenerate manual and man page 2026-07-28 04:02:20 +00:00
rootiest a899448fda Merge pull request 'docs(site): restore Categories table and fix markdown table syntax' (#95) from fix-categories-table into main
Generate documentation / build-docs (push) Successful in 3m28s
Reviewed-on: #95
2026-07-28 03:59:01 +00:00
rootiest 429c407548 chore(docs): rebuild config-help artifacts from SSoT 2026-07-27 23:58:42 -04:00
rootiest 2fb8e3718b docs(home): add button for components alongside functions button 2026-07-27 23:58:10 -04:00
rootiest 11097e32de docs(site): restore Categories table and fix markdown table syntax 2026-07-27 23:47:40 -04:00
Gitea Actions 9d1acf0fb3 chore(docs): regenerate manual and man page 2026-07-28 03:31:21 +00:00
rootiest 7d95e7854c Merge pull request 'docs(site): UI improvements and Starlight integration fixes' (#94) from docs-site-improvements into main
Generate documentation / build-docs (push) Successful in 3m22s
Reviewed-on: #94
2026-07-28 03:28:05 +00:00
rootiest 1972ea5bb9 docs(site): improve UI, add catppuccin theme, fix MDX bugs 2026-07-27 23:27:09 -04:00
Gitea Actions 2b9b8e495c chore(docs): regenerate manual and man page 2026-07-28 01:37:54 +00:00
rootiest 231162bd03 ci(build-docs): watch functions dir as they are dynamically documented now
- Also enables manual trigger to rebuild and publish docs
2026-07-27 21:34:05 -04:00
rootiest 94e4e0dfab feat(function): add a --resume flag to the agy function
The agy tool uses -c and --continue natively. It does not recognize -r
or --resume. This commit allows -r and --resume to be used by
translating them to -c and --continue respectively.
2026-07-27 21:28:40 -04:00
Gitea Actions 7dca813556 chore(docs): regenerate manual and man page 2026-07-28 00:55:44 +00:00
rootiest 0fe183c93e Merge branch 'docs-layout-rework' into fix-xdg-overrides
Generate documentation / build-docs (push) Successful in 3m1s
2026-07-27 20:52:32 -04:00
rootiest dd28fc784b docs: restructure customization and components reference into nested directories 2026-07-27 20:49:40 -04:00
rootiest 7183ed712b fix(config): adjust XDG and EDITOR/GPG gates and sync docs 2026-07-27 20:32:58 -04:00
rootiest d91c0c8deb Merge pull request 'docs(functions): add category metadata to undocumented functions' (#91) from feat-function-categories into main
Reviewed-on: #91
2026-07-28 00:07:20 +00:00
rootiest d2f3da4a23 docs(functions): add category metadata to undocumented functions 2026-07-27 20:04:37 -04:00
Gitea Actions 0d8a2110cf chore(docs): regenerate manual and man page 2026-07-27 23:59:49 +00:00
rootiest 7ca9d19b93 docs(logging): add note to logging customization section regarding existing logs
Generate documentation / build-docs (push) Has been cancelled
2026-07-27 19:56:47 -04:00
rootiest 29daf01b95 Merge pull request 'feat(site): add starlight logo and favicon' (#90) from feat-site-logo into main
Generate documentation / build-docs (push) Successful in 2m54s
Reviewed-on: #90
2026-07-27 23:35:16 +00:00
Gitea Actions 4202be5d3a chore(docs): regenerate manual and man page 2026-07-27 23:33:57 +00:00
rootiest 05db9b57d7 feat(site): add starlight logo and favicon 2026-07-27 19:33:16 -04:00
rootiest a690e814eb Merge pull request 'feat(logging)!: make C5 session logging opt-in' (#89) from feat/c5-logging-opt-in into main
Generate documentation / build-docs (push) Successful in 2m53s
Offline docs drift reminder / remind (push) Successful in 17s
Reviewed-on: #89
2026-07-27 23:31:11 +00:00
rootiest f2874bf890 feat(logging)!: make C5 session logging opt-in
Session logging is the one opinionated category that writes a persistent
record of terminal output to disk, and those logs can contain secrets.
Silent-by-default is the wrong posture for it, so C5 now defaults to off:
__fish_config_op_logging must be set to an explicit truthy value to enable
capture, and the master switch cannot enable it on its own.

Implemented as a single special case in __fish_config_op_enabled, so all
five capture components, the sentinel file, the paru/yay wrappers, the
Kitty watcher, and the config-settings TUI pick it up with no other code
changes. The existing startup sync in conf.d/logging-events.fish
reconciles the sentinel and removes the generated wrappers on the first
shell after upgrading.

BREAKING CHANGE: users relying on the previous default must now run
`set -U __fish_config_op_logging on`. Existing logs in ~/.terminal_history
are left untouched.
2026-07-27 19:17:05 -04:00
Gitea Actions d085d5c597 chore(docs): regenerate manual and man page 2026-07-27 21:21:05 +00:00
rootiest 4a00bc5492 docs: adjust wording in features list to reflect current behavior
Generate documentation / build-docs (push) Successful in 3m5s
- Slight formatting tweak to CAUTION note
2026-07-27 17:17:58 -04:00
Gitea Actions 5b1d90c59d chore(docs): regenerate manual and man page 2026-07-27 21:10:19 +00:00
rootiest 11a9db5fad Merge pull request 'docs: revamp minimal mode troubleshooting section' (#88) from fix/docs-troubleshooting-formatting into main
Generate documentation / build-docs (push) Successful in 3m1s
Reviewed-on: #88
2026-07-27 21:07:22 +00:00
rootiest 12ee2bac89 docs(troubleshooting): add link to personalization page for local.fish 2026-07-27 17:04:45 -04:00
rootiest 6feaa0ea9e build: fix md parsing for file paths with variables
Updated the python site builder's regex to correctly parse file paths containing shell variables like $__fish_user_dots_path in comment titles. Also added fish_default_key_bindings to the known shell-heads list so those examples are correctly wrapped in a fenced code block rather than falling through to plain text and getting parsed as MDX headings.
2026-07-27 16:59:04 -04:00
rootiest 7bbd705d0f docs: replace slash in uninstall heading to sidestep slug bugs
Renamed 'Uninstalling / Reverting to Backup' to 'Uninstalling and Reverting to Backup' to avoid the edge cases where forward slashes cause Starlight top navigation cards to break when generating the heading slug.
2026-07-27 16:50:41 -04:00
rootiest d9c8000f68 fix(docs): update python slugifier to match starlight/github rules
Modified build-manual.py to strip punctuation and properly handle spaces/hyphens during link slug generation. This ensures top navigation link cards generated by the script actually match Starlight's URL format. Also fixed a few manual markdown links that mistakenly contained double dashes.
2026-07-27 16:45:39 -04:00
rootiest 8dba8a31fe docs: revamp minimal mode troubleshooting section
Replaced the minimal mode troubleshooting section with a new 'What's with the C1-C6 stuff?' heading. Included a quick-reference table for the six opinionated categories with links to their detailed customization sections, and updated the documentation index.
2026-07-27 16:33:00 -04:00
Gitea Actions 6b484599ae chore(docs): regenerate manual and man page 2026-07-27 20:11:58 +00:00
rootiest 6e6f276896 Merge pull request 'docs: fix formatting and links in troubleshooting' (#87) from fix/docs-troubleshooting-formatting into main
Generate documentation / build-docs (push) Successful in 3m20s
Reviewed-on: #87
2026-07-27 20:08:45 +00:00
rootiest bbe8aaf88d build: strip internal markdown links from terminal manual
Modified build-manual.py to strip relative markdown links when concatenating fish-config.md, ensuring that terminal viewers (man, config-help) display clean text instead of un-clickable URLs. Starlight build logic remains untouched.
2026-07-27 16:05:40 -04:00
rootiest f62404c692 docs: fix formatting and links in troubleshooting
Converted plain text references to Markdown links across the troubleshooting documentation and index.md. Converted commands to properly formatted inline code blocks, and ensured code blocks conform to the SSOT's indented-block requirements.
2026-07-27 16:01:14 -04:00
rootiest 1192e62eaf Merge pull request 'docs: update documentation URL to fish.rootiest.fyi' (#86) from feat/override-path-and-xdg into main
Generate documentation / build-docs (push) Successful in 3m45s
Offline docs drift reminder / remind (push) Successful in 17s
Reviewed-on: #86
2026-07-27 05:39:11 +00:00
rootiest 2c624d1a28 Merge branch 'main' into feat/override-path-and-xdg 2026-07-27 05:38:54 +00:00
Gitea Actions 69e59806df chore(docs): regenerate manual and man page 2026-07-27 05:37:37 +00:00
rootiest ba6146c343 docs: update documentation URL to fish.rootiest.fyi
Replaced all instances of fish-config.rootiest.fyi with the new domain fish.rootiest.fyi across the codebase.
2026-07-27 01:37:34 -04:00
rootiest 8951644c75 Merge pull request 'feat: gate XDG and PATH behind overrides toggle' (#85) from feat/override-path-and-xdg into main
Generate documentation / build-docs (push) Successful in 3m26s
Offline docs drift reminder / remind (push) Successful in 18s
Reviewed-on: #85
2026-07-27 05:34:19 +00:00
rootiest e180e8d452 feat: gate XDG and PATH behind overrides toggle
Wrapped the XDG variables and PATH setup in config.fish with the C3 overrides toggle so users can fully opt out. Updated the documentation (07-customization.md, 02-path-setup.md, README.md) to reflect this. Also added a Home link to the 404 page and removed a leftover test_sidebar.js file.
2026-07-27 01:33:21 -04:00
Gitea Actions 3155449ef6 chore(docs): regenerate manual and man page 2026-07-27 05:26:34 +00:00
rootiest 528ce2a984 docs(site): update 404 text tagline
Generate documentation / build-docs (push) Successful in 3m47s
Updated the 404 page tagline to say 'That page doesn't exist' as requested, and fixed YAML parsing error.
2026-07-27 01:21:31 -04:00
rootiest afad1c9933 docs(site): add custom 404 page with navigation links
Generate documentation / build-docs (push) Has been cancelled
Created a custom Starlight 404 page (docs/manual/404.md) that includes LinkCards pointing to common sections (Installation, Troubleshooting, Function Reference). Also updated build-manual.py to prevent '404' from appearing in the generated sidebar.
2026-07-27 01:20:21 -04:00
rootiest ea66507c76 docs(site): rename Overview sidebar labels to fix pagination
Generate documentation / build-docs (push) Has been cancelled
Renamed the root 'Overview' entry under 'Functions Reference' to 'Categories'. Also renamed the inner category 'Overview' entries to '{Category} Overview'. Because Starlight uses the sidebar label for the 'Next/Previous' pagination buttons at the bottom of pages, having multiple pages labeled just 'Overview' caused the button text to ambiguously say 'Next: Overview' even when linking to a new category.
2026-07-27 01:08:24 -04:00
rootiest 3e00f4e321 docs: rename PATH Setup and format as table
Generate documentation / build-docs (push) Has been cancelled
Renamed the 'Path Setup' section to 'PATH Setup', formatted the prepended directories list as a Markdown table, and added a NOTE acknowledging that these paths will shadow existing system binaries of the same name. Updated verify-manual.py test since 02-path-setup now contains an Aside and gets correctly promoted to .mdx.
2026-07-27 01:02:42 -04:00
Gitea Actions 78f957b211 chore(docs): regenerate manual and man page 2026-07-27 04:59:58 +00:00
rootiest d6c37fe0ad docs: reformat catalog/vars to standard markdown and add intros
Generate documentation / build-docs (push) Successful in 3m16s
Fixed tables and text formatting in the Dependency Catalog and Configuration Variables pages so they render properly as markdown instead of flat code blocks. Added introductory sentences to Troubleshooting and Customization so the Starlight sub-heading navigation cards get injected at the top of the page rather than jumping below the first heading.
2026-07-27 00:55:41 -04:00
rootiest e63fd8b525 docs(site): add Home entry to Starlight sidebar
Generate documentation / build-docs (push) Successful in 3m26s
The sidebar previously started with 'Configuration Variables' which felt abrupt. Add a 'Home' link at the top pointing to the landing page (the one with install/functions-ref buttons). Seeded the sidebar list in build_site() so it persists across --site rebuilds.
2026-07-27 00:14:32 -04:00
Gitea Actions c770afa6c4 chore(docs): regenerate manual and man page 2026-07-27 04:07:58 +00:00
rootiest 49e487ac3b Merge pull request 'fix(docs): update verify-manual test for section renumber' (#84) from fix/troubleshooting-ci-verification into main
Generate documentation / build-docs (push) Successful in 3m8s
2026-07-27 04:04:49 +00:00
rootiest 911e656e5e fix(docs): update verify-manual test for section renumber and regenerate concat
The troubleshooting section renumbered Viewing This Manual from 11 to
12, but verify-manual.py still hardcoded the old filename
(11-viewing-this-manual.mdx) in the site promotion test. Update both
references to 12-viewing-this-manual.mdx.

Also regenerate docs/fish-config.md so the concat roundtrip test passes
with the new section ordering.
2026-07-27 00:04:03 -04:00
rootiest 0f02def439 Merge pull request 'docs: add Section 11 — Troubleshooting' (#83) from docs/add-troubleshooting-section into main
Generate documentation / build-docs (push) Failing after 51s
Reviewed-on: #83
2026-07-27 03:59:43 +00:00
rootiest 24cdfe4129 docs: add Section 11 — Troubleshooting
Add a new Troubleshooting section to the manual with 9 concise how-to
subsections covering uninstall/revert, Fish version requirements,
disabling logging, changing the greeting, secrets/local config, the
return sentinel gotcha, missing dependencies, Vi mode keybindings,
and minimal mode.

Renumber Viewing This Manual from Section 11 to Section 12 to place
troubleshooting before it. Update TOC and help index accordingly.

All verify-manual.py checks pass.
2026-07-26 23:55:28 -04:00
Gitea Actions 1b69ff9a7f chore(docs): regenerate manual and man page 2026-07-27 03:34:24 +00:00
rootiest 0ba43b6226 Merge branch 'fix-docs-overview'
Generate documentation / build-docs (push) Successful in 3m2s
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
2026-07-26 23:31:27 -04:00
rootiest b898cf1030 docs: escape mdx tag in installation manual 2026-07-26 23:30:53 -04:00
rootiest ce1722d97f Merge pull request 'docs: fix overview pages and button styling' (#82) from fix-docs-overview into main
Generate documentation / build-docs (push) Failing after 2m10s
Reviewed-on: #82
2026-07-27 03:24:08 +00:00
rootiest f02714416c docs: add dynamic CardGrids to overview pages and fix button text color 2026-07-26 23:20:31 -04:00
Gitea Actions cd08c0782e chore(docs): regenerate manual and man page 2026-07-27 03:01:07 +00:00
rootiest 927d28c01a Merge pull request 'docs: use aside syntax for caution block and update intro text' (#81) from docs-index-tweaks into main
Generate documentation / build-docs (push) Successful in 3m26s
Reviewed-on: #81
2026-07-27 02:57:48 +00:00
rootiest 25fb02b7ac build(docs): strip LinkButton from concatenated terminal output 2026-07-26 22:55:12 -04:00
rootiest c126296935 docs: add LinkButton call-to-actions to the manual index 2026-07-26 22:52:35 -04:00
rootiest 48e6a96c6d docs: use aside syntax for caution block and update intro text 2026-07-26 22:43:24 -04:00
rootiest a5e6efc761 style(docs): keep root file tree folder open by default
Generate documentation / build-docs (push) Successful in 3m39s
2026-07-26 22:33:16 -04:00
Gitea Actions ca130ff612 chore(docs): regenerate manual and man page 2026-07-27 02:29:43 +00:00
rootiest 51f2c020d1 Merge pull request 'style(docs): prevent file tree wrapping and collapse by default' (#80) from style-file-tree into main
Generate documentation / build-docs (push) Successful in 3m6s
Reviewed-on: #80
2026-07-27 02:26:44 +00:00
rootiest 5b43f3bbd3 style(docs): prevent file tree wrapping and collapse by default 2026-07-26 22:24:49 -04:00
Gitea Actions 19e5225254 chore(docs): regenerate manual and man page 2026-07-27 02:08:37 +00:00
rootiest c2506bdf9c Merge pull request 'fix(docs): allow multi-level nesting in Starlight file trees' (#79) from fix-starlight-file-tree into main
Generate documentation / build-docs (push) Successful in 3m24s
Reviewed-on: #79
2026-07-27 02:05:17 +00:00
rootiest c4980a15b1 fix(docs): allow multi-level nesting in Starlight file trees 2026-07-26 22:04:02 -04:00
Gitea Actions ddaaf35c85 chore(docs): regenerate manual and man page 2026-07-27 01:42:32 +00:00
rootiest 7a0e1f0930 Merge pull request 'feat(docs): Starlight asides and file-tree conversions (site-build-only)' (#78) from starlight-asides-and-filetree into main
Generate documentation / build-docs (push) Successful in 3m7s
Reviewed-on: #78
2026-07-27 01:39:33 +00:00
rootiest ef384b9c7c fix(docs): scope aside regression test to its contents, reject nested file trees
- test_customization_notes_render_as_aside now asserts the four NOTE
  bullets live inside the <Aside> tags, not merely anywhere on the
  page — a re-wrapped bullet previously still passed because the
  bullet text leaked into an untouched sibling paragraph.
- TREE_BRANCH_RE no longer matches an indented/continuation branch
  line (dropped the leading `[│ ]*`), so a second-level tree falls
  through to verbatim rendering instead of being silently flattened
  to one level. Added test_as_file_tree_rejects_deeper_trees to guard it.
2026-07-26 21:20:34 -04:00
rootiest fe59a7c22c chore(docs): regenerate manual and man page 2026-07-26 21:04:37 -04:00
rootiest 1c671d71ac feat(docs): promote pages with asides or file trees to .mdx 2026-07-26 20:43:07 -04:00
rootiest 819a3b1541 docs(customization): convert Notes: list to a NOTE: callout paragraph 2026-07-26 20:38:33 -04:00
rootiest 6ac647e0c1 test(docs): forbid Aside, FileTree, and ::: markers in the manual SSOT 2026-07-26 20:33:20 -04:00
rootiest 690bfd64d0 feat(docs): add _as_file_tree detector for box-drawing trees 2026-07-26 20:29:42 -04:00
rootiest d972de3df5 feat(docs): render flat LABEL: paragraphs as Starlight asides in prettify() 2026-07-26 20:25:51 -04:00
rootiest 413b8d8fa1 feat(docs): add _as_aside detector for LABEL: callout paragraphs 2026-07-26 19:51:44 -04:00
Gitea Actions 27b6b22f6a chore(docs): regenerate manual and man page 2026-07-26 20:48:03 +00:00
rootiest b6034114ad Merge pull request 'docs(functions): split RETURNS into EXIT STATUS and stdout RETURNS' (#77) from docs-exit-status-returns into main
Generate documentation / build-docs (push) Successful in 3m14s
Reviewed-on: #77
2026-07-26 20:44:29 +00:00
rootiest e651566e14 docs(functions): split RETURNS into EXIT STATUS and stdout RETURNS
RETURNS previously conflated fish's $status exit code with genuine
stdout/printed output, e.g. rm listing "0/1" as if they were print
values rather than exit codes. Rename RETURNS to EXIT STATUS across
all 83 documented functions, and reintroduce RETURNS as a distinct
label reserved for the 15 functions that actually print to stdout.

Update build-manual.py's ENTRY_HEADS to render Exit Status before
Returns, manualtools.py's SECTIONS constant, and AGENTS.md's label
order and label-usage guidance to match. Add two verify-manual.py
regression tests: EXIT STATUS bodies must never contain stray
stdout/printed language, and Returns: must always render after
Exit Status: when both are present. Regenerate docs/fish-config.md.
2026-07-26 16:41:57 -04:00
Gitea Actions f6a3ba0453 chore(docs): regenerate manual and man page 2026-07-26 20:14:37 +00:00
rootiest cd08403416 docs(manual): standardize ruled-table rule style on a solid dash run
Generate documentation / build-docs (push) Successful in 3m4s
Every ruled table in the SSOT used one solid rule under the header
except the "Fish Universal Variables" table, which used the other
(per-column, RST-style) convention build-manual.py just learned to
also accept. Two conventions for the same thing with no reason for
the split, so convert the outlier to match the other six.

The parser keeps supporting both — the per-column style stays a
useful fallback for anyone still authoring that way — this just
makes our own SSOT consistent.
2026-07-26 16:11:38 -04:00
rootiest 4ca008836c fix(docs): recognize RST-style per-column dashed rules as tables
Generate documentation / build-docs (push) Successful in 3m22s
_as_ruled_table() only matched a single solid run of dashes under the
header row. The "Fish Universal Variables" table in
07-customization.md uses the other common convention instead: one
dash run per column, gapped the same as the header (RST simple-table
style) — e.g. "------  ----------". That line failed RULE_RE's
whole-line match, so the table still fell through to a code block.

Split the rule line on the same CELL_SPLIT boundary used for data
rows and require every resulting group to be a solid dash run, which
accepts both conventions without adding a second code path.

No SSOT changes needed — the source table was already well-formed,
docs/fish-config.md round-trips unchanged, confirming this is a
site-only fix.
2026-07-26 16:06:36 -04:00
Gitea Actions 980834e961 chore(docs): regenerate manual and man page 2026-07-26 20:01:35 +00:00
rootiest f2f4d4ef49 Merge pull request 'fix(docs): render Component Reference tables as real Markdown tables' (#76) from docs-ruled-tables into main
Generate documentation / build-docs (push) Successful in 3m19s
Reviewed-on: #76
2026-07-26 19:58:21 +00:00
rootiest 05ba0a4f10 fix(docs): render Component Reference tables as real Markdown tables
_as_table() only detects tables whose data rows are indented deeper
than a ":"-terminated label. The "Component Reference" tables use a
different convention (header, dashed rule, rows all at the same
indent), so they never matched and fell through to a plain indented
code block on the Starlight site.

Add _as_ruled_table() to recognize that header+rule+rows shape. It
supports N columns, folds word-wrapped continuation lines into the
previous row, and backtick-escapes cells containing "<" or "{" instead
of rejecting the table outright (unlike _as_table's stricter guard,
which those tables would otherwise trip on for angle-bracket
placeholders and brace globs).

Also fixes four ambiguous rows in 07-customization.md where two
columns had collapsed to a single space, making them indistinguishable
from a word-wrapped continuation.
2026-07-26 15:55:48 -04:00
Gitea Actions 49c8191037 chore(docs): regenerate manual and man page 2026-07-26 19:37:26 +00:00
rootiest ab030d7ec0 docs: update site title and canonical URL
Generate documentation / build-docs (push) Successful in 3m14s
Offline docs drift reminder / remind (push) Successful in 16s
Rename the Starlight site to "Rootiest Fish Config" and switch its
canonical URL from the Cloudflare Pages subdomain to
fish-config.rootiest.fyi (now aliased in Cloudflare). Updates all
references in README, config-help, open-url, and the manual, and
regenerates the concat/man-page artifacts to match.
2026-07-26 15:34:08 -04:00
Gitea Actions 4f00b5a0f4 chore(docs): regenerate manual and man page 2026-07-26 09:32:37 +00:00
rootiest 5c21788c8f Merge pull request 'docs(site): replace starter README and title code fences throughout the manual' (#75) from docs-option-tables into main
Generate documentation / build-docs (push) Successful in 3m8s
Reviewed-on: #75
2026-07-26 09:29:25 +00:00
rootiest 625a58fa9f docs(site): title Examples fences and auto-title file-scoped snippets
Function EXAMPLE blocks now render as their own fish fence titled
"Examples" (matching the existing "Usage" title on the Synopsis fence),
triggered by a flat Example: label line mirroring the Synopsis: prefix.

Prose pages get two new generic titling signals in _render_para: a bare
indented path ending in a known extension is titled by its basename, and
a leading "# in <file>" / "# <file>" comment on a shell paragraph is
promoted to the fence title and stripped from the body. This picks up
local.fish/secrets.fish path displays and override examples in
07-customization.md for free, plus a bonus .logging_disabled hit.

10-personalization.md's secrets.fish block gets an explicit "# secrets.fish"
comment to title it the same way. The four local.fish examples keep their
existing descriptive comments rather than a redundant local.fish title.
2026-07-26 05:27:26 -04:00
rootiest e20cff41d4 docs(site): replace starter README and title synopsis fences
Swap the Starlight scaffold README for one describing this project's
two-source SSOT and dev/deploy workflow. Give the generated function
synopsis fence a Starlight filename title (`fish title="name.fish"`)
so it reads as a snippet of the function it documents.
2026-07-26 05:01:01 -04:00
Gitea Actions 5c24d2c72d chore(docs): regenerate manual and man page 2026-07-26 08:44:24 +00:00
rootiest 92bcc49962 Merge pull request 'docs: generate the Functions Reference from function comment headers' (#74) from docs-option-tables into main
Generate documentation / build-docs (push) Successful in 3m29s
Offline docs drift reminder / remind (push) Successful in 16s
Reviewed-on: #74
2026-07-26 08:41:01 +00:00
rootiest 4197e7faec Merge remote-tracking branch 'origin/main' into docs-option-tables
# Conflicts:
#	docs/fish-config.md
#	docs/manual/05-functions/14-miscellaneous.md
2026-07-26 04:37:55 -04:00
rootiest daf81bf0a4 docs(functions): publish dops and fzf-update
Both carry complete headers and are user-facing, but had no # CATEGORY
so generated no entry. Surfaced by the new verify-manual.py warning,
which is exactly what it is there for.

The 8 that still warn are correct exclusions: fast is a self-described
placeholder, the rest are bundled plugin and prompt internals.
2026-07-26 04:16:31 -04:00
rootiest cbd5faa66c docs: document the two-source SSOT split
Function documentation now comes from functions/*.fish comment headers;
everything else stays in docs/manual/**. Records that split in the three
places a contributor looks:

- AGENTS.md "Documentation Policy" and Coding Convention #4, which now
  spells out the full label set and flags CATEGORY as required-to-publish.
- Manual section 11, which pointed readers at docs/manual/ for everything.
- README, same.
2026-07-26 04:15:21 -04:00
rootiest a65e05b661 feat(docs): generate Section 5 from function comment headers
The man-page-style comment header above each function in functions/*.fish
becomes the SSOT for that function's documentation. Writing a new function
and documenting it are now the same act.

- manualtools.parse_functions() parses every header carrying a # CATEGORY;
  absence of one is the opt-in, keeping bundled-plugin and prompt internals
  out of the manual with no exclusion list to maintain.
- build-manual.py generates entries for both --concat and --site, with
  **Dependencies:** rendered as links and a **Used by:** reverse index
  computed in one pass. Cross-category links are the navigation win.
- docs/manual/05-functions/*.md reduced to frontmatter-only stubs. Every
  intro measured zero words, so the category files were pure entry
  containers; ordering, titles, and helpKeywords routing are untouched.
- _first_sentence() unwraps the leading hard-wrapped paragraph and skips
  the whole Synopsis block, not just its label line. Site cards no longer
  truncate mid-clause or show a synopsis as their description.

Verification, per the design spec:
- test_concat_roundtrips_original scoped to sections 0-4 and 6-11. It
  guarded a format migration; this is a content migration.
- replaced by structural checks: one entry per categorised function, the
  required sections present, every category resolving to a stub with no
  stub empty, and every declared dependency resolving to a real function
  or a type -q-guarded binary.
- public functions lacking # CATEGORY warn rather than fail, so a new
  user-facing function going undocumented stays visible in CI.

24/24 checks pass. 94 entries generated from 94 parsed headers.

Also drops a stale claim from open-url's NOTES: config-help --html calls
xdg-open directly and has never called open-url.
2026-07-26 04:12:48 -04:00
rootiest 00f70e8558 docs(functions): merge remaining manual-only facts into headers
Word-level diff of every manual entry against its generated counterpart
surfaced 546 tokens present in the manual and absent from the header —
losses reconcile.py missed, because it compared description length and
these headers are longer overall thanks to ARGUMENTS/RETURNS.

Merged the substantive ones (546 -> 202 residual tokens, the remainder
being synonym drift). Notable real fixes:

- git-clean: -f/--force was missing from ARGUMENTS entirely
- pkg: per-package-manager query table
- qc: cli-role rationale, role paths, --role passthrough
- config-help: site URL, xdg-open, man page path, case-insensitivity
- agents-init: idempotency, .gitignore paths, upstream pull, wrapper callers
- smart_exit: exit-builtin wiring note, $SCROLLBACK_HISTORY_DIR

The manual's claim that claude/agy pass `agents-init --agents` is stale;
both pass `--quiet` (full setup). Header wins, manual dropped.
2026-07-26 04:02:57 -04:00
rootiest 8d6ca1797a docs(functions): merge remaining manual prose into function headers
Folds the last seven manual entries whose description exceeded their header
back into the source-of-truth comment blocks: config-settings (Sponge/Paths
page detail, list-value parsing, width tiers, navigation keys), fish-deps
(install-method priority, dependency tiers), logs (fzf keybindings, ov
viewer behavior), kitty-logging (symlink wording, C5 inert-vs-uninstalled),
config-update (exec fish reload), yt-dlp (C1 guard). Drops duplicate example
lines left by the previous merge.
2026-07-26 03:52:02 -04:00
rootiest 02c46ebea7 docs(functions): merge manual-only examples and notes into headers
Folds the examples Section 5 carried but the headers did not into each
function's `# EXAMPLE`, and moves the three lines that only looked like
examples -- the two typo-abbreviation notes and rm's /usr/bin/rm fallback --
into `# NOTES`, the label already in use.

Also corrects gi's synopsis, which omitted -l, and documents yt-dlp's
--no-embed-thumbnail in `# ARGUMENTS`.
2026-07-26 03:47:25 -04:00
rootiest 5f4306b6ca docs(functions): add man-page headers to branch, fc, gitup, sudo-toggle
These four were the only documented functions with no comment header,
carrying just a one-line description. Content is merged from their manual
entries plus what the implementations actually do (fc's vi fallback and
empty-buffer abort, sudo-toggle's credential-cache clear), so the headers
are a superset of Section 5 rather than a copy of it.
2026-07-26 03:45:03 -04:00
rootiest 4c51ef7a33 docs(functions): add # CATEGORY to documented function headers
Records each documented function's manual category in its own header, so
Section 5 can later be generated from source instead of hand-maintained
alongside it. Values reproduce the current grouping in
docs/manual/05-functions/ exactly; no documentation changes meaning here.

Four functions are skipped because they have no header at all yet
(branch, fc, gitup, sudo-toggle); they get one in the merge that follows.
2026-07-26 03:44:03 -04:00
rootiest 67fb29687c docs(site): render aligned option blocks as markdown tables
Two-column option and subcommand blocks in the manual were falling through
to the indented-code fallback, rendering as an unhighlighted grey slab on
the site. `_as_table` detects a contiguous, column-aligned indented run and
emits a headerless GFM table instead; anything it cannot prove is tabular
still takes the old path.

15 blocks convert, 20 are correctly left alone. The concat and man-page
outputs are untouched — `prettify` is site-only, and the byte-exact
round-trip test stays green.
2026-07-26 03:38:07 -04:00
rootiest b4a58af23c Merge pull request 'docs: remove hard-coded URL mention from config-update documentation' (#73) from fix-hardcoded-url-docs into main
Generate documentation / build-docs (push) Successful in 3m15s
Reviewed-on: #73
2026-07-26 05:18:28 +00:00
rootiest 073dbd9b14 docs: remove hard-coded URL mention from config-update documentation 2026-07-26 01:15:45 -04:00
rootiest 6cd0de7ccf fix(docs-site): publish function pages under /reference/
Generate documentation / build-docs (push) Successful in 2m59s
Cloudflare Pages reserves a top-level `functions/` directory in the deploy
output for Pages Functions (server-side handlers) and strips it from the
static-asset upload. The wrangler log for run 812 shows the collision
exactly: 159 files uploaded, which is precisely the number of files in
dist/ outside functions/ — all 108 files under it were dropped.

Nothing failed loudly. Astro built all 120 pages, wrangler reported
success, and the site worked under `astro preview`; only the deployed
copy 404'd on every function entry and category index.

Move the generated tree to /reference/ and add a test asserting the site
output never emits a name Pages reserves.
2026-07-26 00:48:26 -04:00
Gitea Actions d23cbfc733 chore(docs): regenerate manual and man page 2026-07-26 04:33:41 +00:00
rootiest 1bfcd519b8 Merge pull request 'docs: migrate the manual to a Starlight documentation site' (#72) from docs-starlight-site into main
Offline docs drift reminder / remind (push) Successful in 16s
Generate documentation / build-docs (push) Successful in 3m26s
Reviewed-on: #72
2026-07-26 04:27:26 +00:00
rootiest e684eb6134 style(docs-site): use green as the primary accent instead of mauve
Swaps the two usages: green now carries the site title, H2 headings, and
the card hover accent; mauve moves to the tip aside it displaces.
2026-07-26 00:15:13 -04:00
rootiest ab2f03213b feat(docs-site): syntax-highlight examples and restyle the site
The manual is authored man-page style: every synopsis, example, option
table, and description sits in one 4-space-indented block. On the site
that renders as a single unhighlighted grey slab, because an indented
block declares no language.

Split each block into its paragraphs at site-build time and classify
them: synopsis and shell examples become ```fish fences, descriptions
become real prose, and column-aligned reference tables keep their
indentation. 175 blocks now highlight; the 412 lines of genuine tables
are left alone.

The transform is site-only. docs/manual/** keeps the indented form the
pandoc man-page pipeline and config-help depend on, and a test enforces
that no fence is ever written back to the SSOT.

Also:
- Point Expressive Code at the bundled Catppuccin Mocha/Latte themes so
  code blocks match the palette in catppuccin.css.
- Build the functions sidebar group explicitly. `autogenerate` labelled
  it with the raw directory slug and republished the directory index as
  a child of the group it already titled, producing the duplicate
  "Functions Reference" row.
- Skip `Synopsis:` lines when deriving card descriptions; they restated
  the calling convention the card already shows as its title.
- Widen the palette: tinted heading levels, inline code, links, card
  hover accents, aside accents, and table headers.

Fixes a bug where _split_entries stripped the leading indentation of an
entry's first line, detaching `Synopsis:` from the block it opens.
2026-07-26 00:12:33 -04:00
rootiest 16e969ee15 chore(docs): retire wiki, chunked HTML, and split-manual pipeline
docs/manual/** plus the Astro Starlight site (https://fish-config-docs.pages.dev/)
replace the Gitea wiki (docs/wiki/) and chunked offline HTML (docs/html/,
docs/html-style.html) as the published documentation surface. Retires the
now-unused docs/split-wiki.py and docs/split-manual.py generators alongside them.

- config-help --html now opens the published site root instead of resolving
  a local sitemap anchor; when a keyword was given it prints a note that deep
  links aren't available yet and to use the site's search box.
- open-url and docs/manual/05-functions/14-miscellaneous.md examples
  repointed from docs/html/index.html to the site URL.
- docs/manual/11-viewing-this-manual.md rewritten to document the four
  access paths: the website, the man page, in-terminal pager, and reading
  docs/manual/** directly. fish-config.index updated to match the new
  headings.
- README.md documentation section and Zoxide attribution link repointed at
  the site; corrected the stale "single source file" claim about
  fish-config.md.
- Regenerated docs/fish-config.md via build-manual.py --concat.
2026-07-25 23:33:26 -04:00
rootiest 936f13f712 ci(docs): build and deploy the Starlight site to Cloudflare Pages
Adds Node setup, an Astro site build, and a wrangler Pages deploy step
to the existing docs workflow, gated on docs/site/** via the paths
trigger. Also fixes astro.config.mjs's site: URL to match the
fish-config-docs Cloudflare Pages project name (it previously pointed
at fish-config.pages.dev, which is not the project being deployed).
2026-07-25 23:10:54 -04:00
rootiest 3bb534f20b feat(docs): configure Starlight site with Catppuccin theme 2026-07-25 22:59:11 -04:00
rootiest a4054de4f6 feat(docs): generate Starlight content from the manual tree
Add build_manual.build_site(), which walks docs/manual and emits the
Astro Starlight content collection: plain pages copied with pipeline-only
frontmatter (man/site/manTitle/helpKeywords) stripped, and *-functions/
category files exploded into one page per function plus a CardGrid/LinkCard
overview. Writes src/sidebar.json for astro.config.mjs to import. Wires
--site alongside the existing --concat flag.

Fixes two latent defects found while building the real site against the
strict content.config.ts schema:
- _split_entries now tracks fenced code blocks (like
  manualtools.shift_headings does) so a `## ` inside a fence can't be
  mistaken for an entry boundary.
- LinkCard title/description are escaped for JSX attribute context, since
  shell synopses routinely contain `<placeholder>` angle brackets that
  would otherwise open unterminated MDX/JSX parsing.

Also fixes the generated sidebar shape for the functions category: Starlight
0.39+ dropped support for a bare `autogenerate` sibling of `label` on a
top-level group, so the autogenerate config now nests inside `items`.

Verified with a full `astro build` (temporarily pointing astro.config.mjs
at the generated sidebar.json, then reverted since replacing that config
is a later task's deliverable): 120 pages built cleanly, no
content-collection/frontmatter/MDX errors.
2026-07-25 22:44:28 -04:00
rootiest c096433b5d feat(docs-site): scaffold Astro Starlight site
Scaffold docs/site/ via `npm create astro@latest ... --template
starlight`. Extend the docs collection schema in
src/content.config.ts with the four custom frontmatter fields (man,
site, manTitle, helpKeywords) needed by the generator in a later
task, using z.strictObject so unrecognized keys fail the build
instead of being silently stripped by Zod's default behavior.

Ignore generated site output (node_modules, dist, .astro, generated
content, and sidebar.json) in .gitignore.
2026-07-25 22:27:55 -04:00
rootiest 36a03202c6 fix(ci): regenerate docs before verifying manual integrity
build-docs.yml ran verify-manual.py before regenerating
docs/fish-config.md, so test_concat_roundtrips_original compared a
fresh concat of docs/manual/** against the stale, pre-push copy on
disk. Any ordinary edit under docs/manual/** — the exact trigger for
this workflow's paths filter — failed the job before it ever
regenerated anything.

Swap the "Generate concatenated markdown" and "Verify manual
integrity" steps so regeneration runs first. Verification still gates
pandoc and the auto-commit step. Also add docs/verify-manual.py to the
paths filter so edits to the integrity checker itself retrigger the
job.
2026-07-25 22:12:48 -04:00
rootiest e4ef26fe03 ci(docs): build man page from the manual tree 2026-07-25 22:01:42 -04:00
rootiest 424a3c76ab fix(docs): make manual round-trip test byte-exact
test_concat_roundtrips_original previously compared through
_normalise(), which strips trailing whitespace and drops blank lines.
Mutation testing showed it still passed after joining chunks with a
single newline, deleting all 635 blank lines, and appending trailing
double-spaces to every line. Blank lines are load-bearing for pandoc
(blank_before_header defaults on), so losing them merges paragraphs
and stops headings being headings while the test stays green.

Compare the raw got/want text directly to decide pass/fail. Keep
_normalise only to build the diff shown on failure, normalising both
sides first so whitespace noise doesn't swamp the real difference. If
the exact compare fails but the normalised sides match, say so
explicitly in the assertion message instead of emitting an empty diff.
2026-07-25 21:53:04 -04:00
rootiest beb89e406a fix(docs): move pandoc metadata out of index.md frontmatter
index.md is both the man-page LANDING section and a Starlight content
page. Astro errors on any frontmatter key outside the fixed
man/site/manTitle/helpKeywords schema, so folding the source
fish-config.md pandoc header (title/section/header/date/author) onto
index.md under a fifth "pandoc" key would break the docs-site build
the moment it's scaffolded.

Relocate that block to docs/manual/_pandoc.yml: a plain, fence-free
YAML file that Astro content collections ignore (leading underscore).
split-manual.py now extracts it as raw text (no yaml.safe_load/
safe_dump round-trip) so build-manual.py's --concat re-emits it
byte-for-byte instead of merely "verbatim" in comment only. Also guard
build_concat against a manual/ tree with no _pandoc.yml/index.md,
removing the unconditional index.md parse that previously raised
FileNotFoundError on such a tree.

Regenerated docs/manual/ via split-manual.py; concat output remains
byte-identical to the pre-migration docs/fish-config.md.
2026-07-25 21:52:54 -04:00
rootiest 63e71ac9dd feat(docs): generate fish-config.md from the manual tree
Adds docs/build-manual.py (--concat) and a round-trip test in
verify-manual.py that reproduces the pre-migration fish-config.md
exactly from docs/manual/.

Fixes found by the round-trip check, applied in split-manual.py and
re-run to regenerate docs/manual/:
- NAME/SYNOPSIS/TABLE OF CONTENTS had no sidebar.order, so they sorted
  after every numbered section instead of interleaving with DESCRIPTION
  in original document order. All manual pages now get sidebar.order
  from a single position counter matching source order.
- split_h1/split_h2 used .strip() on section bodies, which also ate
  leading indentation on the first body line, corrupting the 4-space
  indented code blocks that open SYNOPSIS and TABLE OF CONTENTS.
- The source's leading pandoc metadata block (title/section/header/
  date/author) was discarded entirely by the splitter. It's now parsed
  off via manualtools.parse and stashed on index.md under a "pandoc"
  key; build-manual.py re-emits it verbatim ahead of the first heading.
2026-07-25 21:39:48 -04:00
rootiest 61a82540fb feat(docs): split fish-config.md into docs/manual SSOT tree 2026-07-25 21:21:37 -04:00
rootiest 3ccc5d2210 fix(docs/manualtools.py): use removeprefix instead of lstrip for frontmatter parsing
Replace .lstrip('\n') with .removeprefix("\n") to preserve body text that
legitimately starts with blank lines. The serialize() function inserts exactly
one separator newline; removing only that one newline (via removeprefix) rather
than all leading newlines (via lstrip) maintains parse/serialize roundtrip
losslessness.

Adds regression test to verify bodies with leading blank lines roundtrip
correctly.
2026-07-25 21:11:40 -04:00
rootiest efa86e8eda feat(docs): add manualtools library for SSOT frontmatter and ordering 2026-07-25 21:06:22 -04:00
Gitea Actions 83e8c52298 chore(docs): regenerate man page, HTML docs, and wiki 2026-07-21 18:11:30 +00:00
rootiest f674ae303c Merge pull request 'refactor(kitty-logging): move watcher to scripts/ and symlink it' (#71) from refactor-kitty-watcher-symlink into main
Generate documentation / build-docs (push) Successful in 49s
Offline docs drift reminder / remind (push) Successful in 14s
Reviewed-on: #71
2026-07-21 18:10:41 +00:00
rootiest 29b69c7b03 refactor(kitty-logging): move watcher to scripts/ and symlink it
Relocate the Kitty scrollback watcher out of the single-purpose kitty/
directory into scripts/kitty-fish-config-watcher.py, and change the
installer to symlink it into the Kitty config directory instead of
copying it.

The symlink always tracks the canonical source, which removes the
version-staleness comparison and the copy-vs-refresh messaging. uninstall
now removes a symlink (including a dangling one) or a legacy copied file.
Existing installs migrate automatically on the next `kitty-logging install`.

Docs (README, docs/fish-config.md, wiki) updated to match.
2026-07-16 02:39:41 -04:00
Gitea Actions 8c869cc1b9 chore(docs): regenerate man page, HTML docs, and wiki 2026-07-16 06:19:50 +00:00
rootiest fcc2f6ccc2 Merge pull request 'feat(functions): add qc quick-chat wrapper around aichat' (#70) from feat-qc-aichat-wrapper into main
Generate documentation / build-docs (push) Successful in 44s
Reviewed-on: #70
2026-07-16 06:19:05 +00:00
rootiest 38bce499bd fix(ls): pass --hyperlink=auto to eza for consistent OSC 8 behavior 2026-07-16 01:51:08 -04:00
rootiest f3533835be feat(functions): add qc quick-chat wrapper around aichat
Defaults to the bundled 'cli' role (concise, terminal-friendly output),
installed on first use by symlinking scripts/cli-agent.md into the aichat
config dir. Inherits all aichat flags and completions via --wraps; passing
--role/-r forwards unchanged. Only defined when aichat is installed.
--help prepends a banner and rewrites aichat's own help to qc.

Docs: fish-config.md 5.12 + index keywords.
2026-07-16 01:51:00 -04:00
Gitea Actions 68eb3b0092 chore(docs): regenerate man page, HTML docs, and wiki 2026-07-04 06:36:42 +00:00
rootiest 3362c33339 Merge pull request 'feat(config): user-dots convenience symlink with config-settings toggle' (#69) from feat-user-dots-symlink into main
Generate documentation / build-docs (push) Successful in 35s
Offline docs drift reminder / remind (push) Successful in 10s
Reviewed-on: #69
2026-07-04 06:36:09 +00:00
rootiest ec47b0671c feat(config-settings): add Dots link toggle for user-dots symlink
Extract the user-dots symlink logic into the __fish_user_dots_link helper and
add a dedicated __fish_user_dots_symlink toggle, surfaced as a 'Dots link' bool
row on the config-settings Paths page. Unlike the opinionated categories it has
no universal/session split — it acts on a literal path.

Setting it falsy (or toggling off) stops symlink generation and removes any
existing link immediately, honoured regardless of the C2 master switch.
Creation remains a C2 startup side-effect. config.fish now calls the helper.

Docs: README, fish-config.md (C2 table, Paths page, machine-local section),
and fish-config.index updated.
2026-07-04 02:34:20 -04:00
rootiest 8495cbaa24 feat(config): auto-manage user-dots convenience symlink
Point $__fish_config_dir/user-dots at $__fish_user_dots_path on interactive
startup so the private overlay can be browsed from the fish config dir. The
link is created if missing and repointed if the path variable changes, only
ever managing a symlink (never clobbering a real file/dir). Gated as a C2
startup side-effect (__fish_config_op_autoexec) and git-ignored.

Docs: README overlay section and fish-config.md C2 table updated.
2026-07-04 02:24:37 -04:00
rootiest fe3eb818ba Merge pull request 'fix(help): repair 'help config' wrapper for Fish 4.x embedded help' (#68) from fix-help-config-fish4-embedded into main
Reviewed-on: #68
2026-07-04 06:13:24 +00:00
Gitea Actions 5930514847 chore(docs): regenerate man page, HTML docs, and wiki 2026-07-04 06:13:06 +00:00
rootiest 8068dcb312 Merge pull request 'feat(functions): add open-url and repo-open browser helpers' (#67) from feat-open-url-and-repo-open into main
Generate documentation / build-docs (push) Successful in 37s
Offline docs drift reminder / remind (push) Successful in 12s
Reviewed-on: #67
2026-07-04 06:12:30 +00:00
rootiest 7afb470a42 fix(help): repair 'help config' wrapper for Fish 4.x embedded help
Fish 4.x ships the native `help` function embedded in the binary
(embedded:functions/help.fish) with no on-disk file. The old
functions/help.fish tried to `source $__fish_data_dir/functions/help.fish`
to back up the native help before shadowing it — that path no longer exists,
so the first `help config ...` call errored:

    source: No such file or directory
    functions: Function 'help' does not exist

The backup cannot happen from functions/help.fish at all: an autoload shadow
of that name makes `help` resolve to our own wrapper (or nothing, mid-load),
so `functions -c help` can never capture the embedded original.

Move the wrapper to conf.d/help.fish, sourced at startup before any shadow
exists, where `functions -c help __original_help` copies the embedded native
help. Behavior is otherwise unchanged: 'help config' delegates to config-help,
all other topics fall through to __original_help, and the C1 opinionated guard
still applies. Delete the obsolete functions/help.fish.
2026-07-04 02:11:17 -04:00
rootiest 4761c48d96 feat(functions): add open-url and repo-open browser helpers
Extract the browser-detection and launch logic out of config-help into a
reusable open-url function, then build repo-open on top of it to open the
current repo's origin remote in a browser.

- open-url: resolve the best graphical browser (fish_help_browser -> BROWSER
  -> xdg-mime https handler -> known binaries -> xdg-open) and launch it
  backgrounded. Silent by default; -v/--verbose reports the browser, -s/--silent
  is accepted explicitly. Browser console chatter is discarded.
- repo-open: normalize the origin URL from HTTPS and SSH/scp forms, deep-link
  to the current branch (falling back to the remote default) and sub-directory.
  Provider layout resolved via git config browse.provider, hostname heuristic
  (github/gitlab/gitea/bitbucket, codeberg->gitea), then github default.
  -p/--print emits the URL, -r/--root ignores the sub-directory.
- config-help: replace the inlined browser block with an open-url call.
- abbr: add open-repo and url-open abbreviations that expand to the canonical
  command names on space/enter.
- docs: document both functions in the SSoT (fish-config.md + index) and add a
  repo-open row to the README doc-browsing table.
2026-07-04 02:02:28 -04:00
Gitea Actions 0a83bd425c chore(docs): regenerate man page, HTML docs, and wiki 2026-07-04 05:28:39 +00:00
rootiest 83d5bd2d40 Merge pull request 'feat(config-settings): four-page TUI (Universal · Session · Sponge · Paths)' (#66) from feat/config-settings-pages into main
Offline docs drift reminder / remind (push) Successful in 13s
Generate documentation / build-docs (push) Successful in 39s
Reviewed-on: #66
2026-07-04 05:26:10 +00:00
rootiest de349a423e fix(config-settings): list values accept comma and/or whitespace separators
Previously list rows (Extra secret, OK codes) split on spaces only, so
'KOPIA, TEST' produced the malformed token 'KOPIA,'. Collapse any run of
commas/whitespace to a single space before splitting, so 'A,B', 'A, B' and
'A B' all yield the same entries.
2026-06-24 11:17:45 -04:00
rootiest 0250669306 feat(config-settings): inline in-field value editor (no fish read prompt)
Replace the fish `read` prompt (which showed an unstyled `read>` and left the
prompt line behind on redraw) with an in-place editor built on the raw key
reader. The value is edited directly in its UI field with a block caret; the
panel redraws each keystroke and cleans up on exit. Pre-fills the current value;
Backspace deletes, Enter saves (empty reverts to default), Esc cancels.

- __config_settings_read_key: decode Backspace (bytes 8/127)
- __config_settings_draw_value: edit-mode field with caret + edit hint line
- config-settings: inline edit loop replaces the read-based prompt block
2026-06-24 11:14:01 -04:00
rootiest 7caf75b940 fix(config-settings): blank/cleared sponge values revert to default, never unset
A blank or escaped inline edit, and the ← clear, previously erased the variable.
sponge reads sponge_delay / sponge_purge_only_on_exit / sponge_allow_previously_
successful with no fallback, so an unset value crashed the prompt
('test: Missing argument'). Fixes:

- Value rows reset to a per-row default value (sponge_delay→2, exit_codes→0) or
  erase only when the var tolerates unset (paths, extra-sensitive list).
- Blank/escaped Enter reverts to that default instead of writing empty.
- Sponge booleans are now a 2-state true/false (sponge's convention), never unset.
- Defensive set -q;or set -l fallbacks added to the sponge consumer functions so
  a transiently-unset var can never error the prompt.
2026-06-24 10:47:00 -04:00
rootiest 453b5f1d50 fix(config-settings): sponge bools use true/false; hint width; set -- hardening
- C1: sponge_purge_only_on_exit / sponge_allow_previously_successful are 'bool'
  rows that write true/false (sponge's convention), not on/off; badge maps
  true->ON, false->OFF, unset->DEFAULT
- I1: shorten value-page hint to 49 cols so it fits the 50-wide tier
- M1: set -U -- before the var name guards typed values beginning with a dash
2026-06-24 00:49:23 -04:00
rootiest 5cf5ca07c5 docs: document multi-page config-settings (sponge + paths)
- §1 Scrollback History: __fish_scrollback_history_* source-of-truth + exported
  mirror, and the no-global-shadow rationale
- §Sponge History Filtering: __fish_sponge_extra_sensitive name tokens (--entire
  match) and the tuning vars surfaced on the Sponge page
- config-settings function reference: four-page model, Tab/Shift-Tab, value rows
- index + README updated
2026-06-24 00:34:57 -04:00
rootiest fbfc52e675 feat(config-settings): four-page model with sponge and paths value editors 2026-06-24 00:31:06 -04:00
rootiest b791010e48 refactor(config-settings): toggle page uses 4-page tab, drops Dots-Path row 2026-06-24 00:17:22 -04:00
rootiest c6c13c2e99 feat(config-settings): value-page renderer for sponge and paths 2026-06-24 00:08:34 -04:00
rootiest b82166872f feat(config-settings): shared four-page tab header helper 2026-06-24 00:04:35 -04:00
rootiest ec99ceb018 feat(config-settings): decode Shift-Tab as backtab 2026-06-24 00:02:50 -04:00
rootiest a422400d72 fix(config): don't create global shadow for scrollback source vars
A global __fish_scrollback_history_dir/_max_files would shadow the universal
that config-settings writes, defeating live mirror updates and stale-displaying
the value until restart. Export the default, override from the universal only
if set.
2026-06-24 00:01:57 -04:00
rootiest 2772b26704 feat(config-settings): value-row set/get backend helpers 2026-06-23 23:58:10 -04:00
rootiest 180ea9337f feat(sponge): user-extensible sensitive var names via __fish_sponge_extra_sensitive 2026-06-23 23:55:31 -04:00
rootiest 72920c04ce feat(config): fish-style scrollback vars mirrored to exported env vars 2026-06-23 23:45:19 -04:00
Gitea Actions 614c064524 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-24 03:09:52 +00:00
rootiest 5ee09bf13e Merge pull request 'fix(auto-pull): respect $__fish_user_dots_path for registry location' (#65) from fix/auto-pull-user-dots-path into main
Generate documentation / build-docs (push) Successful in 35s
Reviewed-on: #65
2026-06-24 03:09:15 +00:00
rootiest 390072e919 fix(auto-pull): respect $__fish_user_dots_path for registry location
Both the auto-pull function and the PWD event handler hardcoded
$XDG_CONFIG_HOME/.user-dots/fish as the registry directory. They now
resolve $__fish_user_dots_path first, falling back to the same default,
so a custom path set via config-settings is honoured.
2026-06-23 23:07:46 -04:00
Gitea Actions cd240f4460 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-23 18:28:57 +00:00
rootiest f6fd093850 Merge pull request 'feat(config-settings): rename config-toggle → config-settings; add __fish_user_dots_path UI' (#64) from feat/config-settings-rename-path-var into main
Generate documentation / build-docs (push) Successful in 30s
Offline docs drift reminder / remind (push) Successful in 11s
Reviewed-on: #64
2026-06-23 18:28:29 +00:00
rootiest 67f22c8a60 docs(config-settings): fix remaining stale config-toggle ref in draw helper description 2026-06-23 14:17:40 -04:00
rootiest 6f8fd855e4 docs(config-settings): fix stale __config_toggle_* references in helper docstrings 2026-06-23 14:16:04 -04:00
rootiest 93829285d8 docs: update fish-config.index for config-toggle → config-settings rename 2026-06-23 14:10:59 -04:00
rootiest 533ab60321 docs: rename config-toggle to config-settings in SSOT, README, and AGENTS.md 2026-06-23 14:07:48 -04:00
rootiest 43b3cf51f6 feat(config-settings): add path row event handling (Enter edit, LEFT clear, RIGHT no-op)
- Add __fish_user_dots_path as 8th entry in vars list
- Update panel_h from 14 to 16 (matches draw function's 16-line output)
- Clamp cur_row down to min(7, ...) to allow navigation to path row
- Add did_redraw flag (reset per iteration) to skip double-redraw after Enter
- Add Enter handler for row 7: erases panel, prompts for path, sets or clears
  __fish_user_dots_path universally, redraws, sets did_redraw
- Special-case RIGHT on row 7 as no-op (path is set via Enter only)
- Special-case LEFT on row 7 to clear path var via apply DEFAULT
- Add Enter key hint to --help navigation section
- Fix EXAMPLE block in __config_settings_draw docstring to include 8th arg
2026-06-23 14:02:03 -04:00
rootiest 26b90ecc72 feat(config-settings): add path row for __fish_user_dots_path in draw function 2026-06-23 12:17:55 -04:00
rootiest b506f2aa39 feat(config-settings): support arbitrary string values in apply helper 2026-06-23 12:14:35 -04:00
rootiest 7a1a213add fix(config-settings): update stale help body text after rename 2026-06-23 12:11:15 -04:00
rootiest 98a5cb4c7c feat(config-settings): rename config-toggle to config-settings; add deprecated alias 2026-06-23 12:08:21 -04:00
rootiest 93554695dc refactor(config-settings): rename __config_toggle_* helpers to __config_settings_* 2026-06-23 12:03:16 -04:00
Gitea Actions 8852ed3108 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-23 15:34:43 +00:00
rootiest 47487ddcc0 Merge pull request 'feat(config): introduce __fish_user_dots_path universal variable' (#63) from feat/user-dots-path-variable into main
Generate documentation / build-docs (push) Successful in 38s
Offline docs drift reminder / remind (push) Successful in 11s
Reviewed-on: #63
2026-06-23 15:34:05 +00:00
rootiest 2a5aef2a64 feat(config): introduce __fish_user_dots_path universal variable
Allow users to customize the location of their private overlay directory
via `set -U __fish_user_dots_path /your/path`. Falls back to the previous
hardcoded default of `$XDG_CONFIG_HOME/.user-dots/fish` when unset.

Simplify the sourcing model: config.fish now sources only local.fish,
which is responsible for sourcing its own secrets.fish companion. The
redundant direct sourcing of secrets.fish from config.fish is removed.

Update docs/fish-config.md (Sections 1, 7, 10) and README.md to
document the new variable, the custom-path override pattern, and the
simplified sourcing model.
2026-06-23 03:21:02 -04:00
rootiest bdf4581b28 Merge pull request 'fix(fish-deps): show real binary path + drop hardcoded /usr/bin in paru/yay wrappers' (#62) from fish-deps-real-binary-resolution into main
Reviewed-on: #62
2026-06-22 06:18:29 +00:00
rootiest f92ac6ac37 fix(paru/yay-wrapper): resolve real binary instead of assuming /usr/bin
The generated PTY-logging wrappers hardcoded /usr/bin/{paru,yay} both for
the presence check and as the command the wrapper shells out to, breaking
on any host where the binary lives elsewhere. Resolve the real path via
__fish_real_command (which skips our own shim) and embed that. Bump the
wrapper version 5 -> 6 so existing installs regenerate.
2026-06-22 02:16:41 -04:00
rootiest cb30f19c32 feat(fish-deps): resolve real binary past our generated wrapper shims
Add __fish_real_command, which walks all PATH matches for a name and
returns the first that is NOT one of this config's generated wrappers
(identified by the "# <name>-wrapper-version:" marker; grep -I treats
real ELF binaries as no-match so only our text shims are skipped). It
never returns one of our own wrappers, so a caller embedding the result
can't build a shim that recurses into itself.

Use it for the fish-deps status "(Found at ...)" path so paru/yay show
the real binary instead of the ~/.local/bin logging shim.
2026-06-22 02:16:40 -04:00
rootiest 4a5536aeb6 feat(completions): add copilot CLI tab completions
Generated via `copilot completion fish`.
2026-06-22 00:59:25 -04:00
Gitea Actions 5103ddc43d chore(docs): regenerate man page, HTML docs, and wiki 2026-06-22 04:57:45 +00:00
rootiest 29637799f6 Merge pull request 'feat(yt-dlp): wrapper with sane defaults + fish-deps shadow-detection fix' (#61) from yt-dlp-wrapper-and-deps-fix into main
Generate documentation / build-docs (push) Successful in 33s
Reviewed-on: #61
2026-06-22 04:57:12 +00:00
rootiest ec1f00320b chore(gitignore): ignore ggshield cache directory
Exclude /.cache_ggshield, the local GitGuardian secret-scanner cache.
2026-06-22 00:55:39 -04:00
rootiest 878bc360d9 fix(fish-deps): detect tools with command -q so wrappers don't mask missing binaries
Status, install, and update resolved catalog entries with `type -q`,
which also matches wrapper functions that shadow a tool name (rg, rm,
yt-dlp). A shadowed-but-uninstalled tool was reported "installed",
skipped by `install`, and skipped by `update`. Switch these catalog-bin
probes to `command -q`/`command -s` (PATH only). PM/build-tool probes
(cargo, uv, paru, yay, ...) and the fisher check (a fish function) keep
`type -q`.
2026-06-22 00:55:30 -04:00
rootiest 6bd6436c81 feat(yt-dlp): add wrapper with embedding + SponsorBlock defaults
Add functions/yt-dlp.fish, shadowing yt-dlp to prepend sane defaults
(--sponsorblock-remove all, --embed-subs, --embed-metadata,
--embed-thumbnail). Each default is suppressed when the user already
passes that flag, its alias (--add-metadata), its negation
(--no-embed-thumbnail), the --opt=value form (--sponsorblock-remove=...),
or the global --no-sponsorblock kill. User args pass through last so an
explicit flag wins on precedence. Gated as a C1 opinionated alias;
falls back to bare `command yt-dlp` when disabled.

Register yt-dlp as a recommended (rec tier) dependency in the fish-deps
catalog and document the function (§5.13) and dependency in the SSOT
and index.
2026-06-22 00:55:12 -04:00
Gitea Actions a76e4de605 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-19 06:58:05 +00:00
rootiest cf8dc8d7e1 Merge pull request 'feat(auto-pull): opt-in background fast-forward for registered repos' (#60) from feat-auto-pull-registry into main
Generate documentation / build-docs (push) Successful in 38s
Offline docs drift reminder / remind (push) Successful in 13s
Reviewed-on: #60
2026-06-19 06:57:25 +00:00
rootiest d3851fcddc docs(auto-pull): document auto-pull command, C2 behavior, and registry
Add the auto-pull function entry (5.4 Git) and index entry, a C2 component
reference row plus explanatory paragraph in fish-config.md, and update the
README C2 disable-list. (AGENTS.md C2 table, file tree, and task #12 are
tracked in the git-ignored AGENTS/ dir.)
2026-06-19 02:23:35 -04:00
rootiest 261e663e97 feat(auto-pull): opt-in background fast-forward for registered repos
Add a C2-guarded PWD handler that background fast-forwards the fish-config
repo (baseline) plus any repos in a machine-local registry. Safety is
guaranteed by _auto_pull_sync: clean tree + has-upstream + --ff-only, else
no-op. Never rebases, merges, or overwrites work.

- conf.d/auto-pull.fish: --on-variable PWD handler, throttled to fire once
  per repo entry; spawns a --no-config child to run the worker
- functions/_auto_pull_sync.fish: the ff-only worker (safe on any branch)
- functions/auto-pull.fish: add/remove/list/status registry management,
  usable even when C2 is disabled
- completions/auto-pull.fish: subcommand + registered-repo completions

Registry lives at ~/.config/.user-dots/fish/auto-pull.list (machine-local,
never committed).
2026-06-19 02:21:21 -04:00
Gitea Actions 83abb5b6c6 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-19 05:58:55 +00:00
rootiest 1433844c2b Merge pull request 'feat(edit): multi-editor launcher with GUI/terminal fallbacks' (#59) from feat-edit-multi-editor-launcher into main
Generate documentation / build-docs (push) Successful in 36s
Offline docs drift reminder / remind (push) Successful in 12s
2026-06-19 05:58:20 +00:00
rootiest 034ebade0d feat(edit): stop forcing VISUAL to the terminal editor
VISUAL was hardwired to $EDITOR (nvim), so 'edit --visual' would launch a
terminal editor detached with no tty. Comment it out so --visual falls
through to the GUI fallback chain, and let users set a real GUI editor via
local.fish. Update the editor-variable docs to match.
2026-06-19 01:56:58 -04:00
rootiest 8dfbc2a9be Merge branch 'main' into feat-edit-multi-editor-launcher 2026-06-19 05:54:18 +00:00
rootiest ed8de40d46 feat(edit): replace edit wrapper with multi-editor launcher
Rewrite functions/edit.fish as a flexible launcher supporting GUI and
terminal editors with rich fallback chains, clipboard/text temp files,
new-window flags, and verbose/silent output control.

- --visual/--terminal force mode; default auto-detects via tty
- GUI chain: zed → antigravity-ide → code → kate → kwrite → gnome-text-editor → gedit
- Terminal chain: nvim → vim → micro → nano → vi
- --clipboard reuses the existing p function; --text opens a literal string
- --new maps to per-editor new-window flags (best-effort)
- C1 guard falls back to legacy bare-editor behavior when disabled

Docs: update fish-config.md function entry + C1 table, README and AGENTS C1 shadow lists.
2026-06-19 00:58:40 -04:00
Gitea Actions d87582253c chore(docs): regenerate man page, HTML docs, and wiki 2026-06-18 03:02:57 +00:00
rootiest 7079319a09 docs: fix CAUTION callout rendering and list scripts/agents-tools in structure tree
Generate documentation / build-docs (push) Successful in 32s
2026-06-17 23:02:22 -04:00
Gitea Actions 3fcc8a3ab5 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-18 02:45:47 +00:00
rootiest fdd0733b3f Merge pull request 'fix(agents): chain AGENTS git hooks to global core.hooksPath' (#58) from fix-agents-hooks-chain-global into main
Generate documentation / build-docs (push) Successful in 35s
Reviewed-on: #58
2026-06-18 02:45:12 +00:00
rootiest c3e39b7a96 fix(agents): chain AGENTS git hooks to global core.hooksPath
The local core.hooksPath override set by agents-init shadowed the user's
global hooks (ggshield, Git LFS) since git honors only one hooksPath. Each
shim now execs the global/system hook of the same name after running
version-bump, so global hooks still run after version increment. Bumped the
agents-tools version marker to 2 so existing AGENTS repos refresh.
2026-06-17 22:39:18 -04:00
rootiest c7d1e642e5 fix(cat): terminate string match options to handle --- frontmatter
A file whose first lines contain a bare '---' (e.g. YAML frontmatter)
caused 'string match -qr' to parse the line as an option flag, raising
'string match: ---: unknown option'. Add '--' to end option parsing.
2026-06-17 22:14:31 -04:00
Gitea Actions 3bdc712fa9 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-18 02:10:46 +00:00
rootiest b81cbd3b02 Merge pull request 'feat(agents): AGENTS/ structure versioning + plans/specs/devlogs consolidation' (#57) from feat/agents-version-tracking into main
Generate documentation / build-docs (push) Successful in 35s
Reviewed-on: #57
2026-06-18 02:10:08 +00:00
rootiest 7474760525 fix(agents-init): guard install helper against silent failures 2026-06-17 21:51:54 -04:00
rootiest 70f1ec2eeb docs: document AGENTS/ structure versioning and current layout 2026-06-17 21:42:36 -04:00
rootiest 46dd6cd3a9 feat(agents-init): scaffold .version + commit-time version hooks, pull before commit 2026-06-17 21:40:40 -04:00
rootiest 58e21eba95 fix(agents-tools): never block commits on missing bumper; robust .version parse 2026-06-17 21:38:03 -04:00
rootiest 5cbb01497c fix(agents-tools): harden version-bump test (CDPATH + hooks isolation), drop LFS band-aid 2026-06-17 21:29:05 -04:00
rootiest 7d277e52bd test(agents-tools): cover version-bump prepmsg suffix 2026-06-17 21:17:44 -04:00
rootiest dda63a05ff feat(agents-tools): add version-bump precommit logic 2026-06-17 20:58:08 -04:00
Gitea Actions 399f481adb chore(docs): regenerate man page, HTML docs, and wiki 2026-06-17 20:32:07 +00:00
rootiest 6a6eff2d00 Merge pull request 'chore: remove AI session save/resume helpers' (#56) from chore/remove-ai-session-save into main
Generate documentation / build-docs (push) Successful in 36s
Reviewed-on: #56
2026-06-17 20:31:28 +00:00
rootiest a9190cf7ec chore: remove AI session save/resume helpers
Drop the save-session/resume system entirely:

- functions/save_claude_session.fish, save_antigravity_session.fish
  (session-start hook scripts)
- functions/claude-resume.fish, antigravity-resume.fish, code-resume.fish
  (consumers of the .claude_session/.antigravity_session files)

Also updates docs/fish-config.md (removes the three function sections,
drops the session-helper mention from the python3 dependency note) and
docs/fish-config.index (removes the orphaned keyword entries). Generated
html/wiki/man are rebuilt by build-docs.yml on merge.

External hook registrations were removed from ~/.claude/settings.json and
~/.gemini/settings.json (the latter pointed at an already-deleted
save_gemini_session.fish); those files live outside this repo.
2026-06-17 16:21:25 -04:00
Gitea Actions 0c7f7df4ec chore(docs): regenerate man page, HTML docs, and wiki 2026-06-16 19:15:54 +00:00
rootiest 70b4492986 Merge pull request 'fix(zellij): repair scrollback logging on shell exit' (#55) from fix/zellij-logging-dump-screen into main
Generate documentation / build-docs (push) Successful in 31s
Offline docs drift reminder / remind (push) Successful in 12s
Reviewed-on: #55
2026-06-16 19:15:22 +00:00
rootiest 1aac43af62 docs(index): expand help-index coverage and fix stale targets
Add tool-name synonyms whose names appear in no heading (so the
fallback substring scan can't reach them): eza/exa/lsd, trash, btop,
prettyping, duf/dust, kitten, bat. Add integration and topic keywords
(zoxide, direnv, venv/virtualenv, wakatime, tailscale, done/notify,
pager-hierarchy, shell-aliases, kitty-logging/watcher, agy,
antigravity-ide, html/browser, wiki).

Fix stale entries pointing at renamed/removed headings:
- antigravity -> ### antigravity-resume (### antigravity was removed)
- man-page/manpage -> ## As a man page (dropped '(if compiled)')
- disambiguate duplicate 'secrets' key: secrets.fish is now secrets-file
2026-06-16 15:14:40 -04:00
rootiest 68a9cd17bf docs(index): add zellij/tmux logging keywords to help index
Point zellij, zellij-logging, tmux-logging, pipe-pane, and dump-screen
lookups at the C5 logging section. tmux=tmux-clean stays for the function.
2026-06-16 15:10:40 -04:00
rootiest 7564604c53 fix(zellij): repair scrollback logging on shell exit
The zellij wrapper (functions/zellij.fish) rewrote every `zellij`
invocation as `zellij options --theme catppuccin-mocha <args>`, which is
only valid for launching a new session. This mangled every subcommand,
including the `zellij action dump-screen` call inside _zellij_dump_log,
so no logs were ever produced. The theme is already set in config.kdl,
making the wrapper redundant — remove it.

Also harden _zellij_dump_log:
- dump-screen takes the file via stdout redirect, not a positional arg
  (rejected by zellij 0.44) nor --path (server-side write, flaky)
- add --ansi to preserve color in the logs
- discard empty dumps instead of leaving junk files

Document the structural limitation: zellij can only snapshot on a clean
shell exit, unlike tmux's continuous pipe-pane stream. Closing a pane or
quitting zellij tears down the pane/server before it can be dumped.
2026-06-16 15:05:41 -04:00
Gitea Actions 548df81c08 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-16 18:36:50 +00:00
rootiest b4bac6a562 Merge pull request 'feat(c5): own the Kitty scrollback watcher (kitty-logging)' (#54) from feat/kitty-watcher-ownership into main
Generate documentation / build-docs (push) Successful in 38s
Offline docs drift reminder / remind (push) Successful in 13s
Reviewed-on: #54
2026-06-16 18:36:09 +00:00
rootiest 2ff553f7b6 docs(kitty): document kitty-logging command and watcher reminder 2026-06-16 10:03:14 -04:00
rootiest 914613c751 feat(kitty): add per-session watcher setup reminder 2026-06-16 10:00:19 -04:00
rootiest 78df24cba1 fix(kitty): harden kitty-logging install/uninstall/dismiss
- abort install if the watcher copy fails (was wiring a block pointing at
  a missing file and reporting success)
- handle dismiss before the kitty guard so it works without kitty installed
- require both managed-block markers before the uninstall range-delete to
  prevent deleting to EOF on a malformed block
2026-06-16 09:58:19 -04:00
rootiest 4f266f691b feat(kitty): add kitty-logging install/uninstall/status/dismiss command 2026-06-16 02:12:47 -04:00
rootiest ca0a35e8c7 feat(kitty): add kitty-logging resolver/inspection helpers 2026-06-16 02:09:52 -04:00
rootiest c2ec031af2 feat(kitty): add canonical version-marked scrollback watcher 2026-06-16 02:07:23 -04:00
Gitea Actions 3990bd13b4 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-16 05:30:46 +00:00
rootiest 429ccc3876 Merge pull request 'feat(c5): multiplexer session logging (tmux + zellij)' (#53) from feat/tmux-logging into main
Generate documentation / build-docs (push) Successful in 42s
Offline docs drift reminder / remind (push) Successful in 14s
Reviewed-on: #53
2026-06-16 05:30:02 +00:00
rootiest a7e6ae4d21 docs(c5): feature session logging prominently with transparency callout
Add a Session Logging section and a CAUTION callout to the README, and a
matching privacy notice to docs/fish-config.md, making clear that this
config logs terminal sessions (Kitty/tmux/zellij/paru/yay) to
~/.terminal_history by default. Point users at both the
__fish_config_op_logging variable and the interactive config-toggle TUI
for opting out.
2026-06-16 01:27:47 -04:00
rootiest 5b74fbe427 feat(c5): add zellij exit-capture logging and shared prune helper
Zellij has no live-stream facility like tmux pipe-pane, so capture is a
one-shot 'zellij action dump-screen --full' run from a fish_exit handler
(conf.d/zellij-logging.fish -> functions/_zellij_dump_log.fish). The C5
guard is checked inside the helper at exit time, so toggling logging
needs no sync_logging coordination — there is no persistent stream.

Extract pruning into functions/_prune_terminal_logs.fish, shared by both
the tmux and zellij helpers. This also fixes a latent bug in the tmux
helper: globbing tmux_*.log directly errored with 'No matches for
wildcard' on the first log in an empty dir. The shared helper globs via
'set' (tolerates no-match) and uses command ls/rm to bypass the eza and
trash C1 shadows.
2026-06-16 01:16:22 -04:00
rootiest b998cc652e feat(c5): prune old tmux logs and share pipe-pane helper
Extract the tmux pipe-pane setup into functions/_tmux_pipe_log.fish,
called by both conf.d/tmux-logging.fish (startup) and
__fish_config_sync_logging (C5 re-enable). The helper prunes the oldest
tmux_*.log files by mtime to stay within SCROLLBACK_HISTORY_MAX_FILES,
matching the paru/yay wrappers.

Uses 'command ls' to bypass the eza ls shadow, which injects OSC-8
hyperlink escapes into paths and corrupted the filenames passed to rm.
2026-06-16 01:03:54 -04:00
rootiest 2e1750b5a4 fix(c5): use fish-valid variable concatenation in tmux log filename
Fish does not support bash-style ${var} brace syntax. Build the
log file path in a dedicated variable using quote-splicing instead.
2026-06-16 00:55:53 -04:00
rootiest 764f2253f6 fix(c5): update sync_logging function description to mention tmux 2026-06-16 00:53:44 -04:00
rootiest 2e6abec499 feat(c5): add tmux pipe-pane session logging
Starts tmux pipe-pane capture for the current pane whenever fish
launches inside a tmux session. Each shell gets a timestamped log
in SCROLLBACK_HISTORY_DIR. Toggling __fish_config_op_logging stops
or restarts the pipe in all open fish shells via the existing
--on-variable event handlers.
2026-06-16 00:52:59 -04:00
Gitea Actions 5c3d169572 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-13 04:27:04 +00:00
rootiest 50e4d92249 Merge pull request 'feat(agents-init): scaffold AGENTS/ sub-repo with symlinks, plugin dirs, and AI wrapper integration' (#52) from feat/agents-init into main
Generate documentation / build-docs (push) Successful in 37s
Reviewed-on: #52
2026-06-13 04:26:24 +00:00
rootiest a5966fd982 chore(agents-init): fix formatting and alignment 2026-06-13 00:24:18 -04:00
rootiest 976f46757c fix(agents-init): quiet only on change, add -v/--verbose flag
- quiet mode now outputs one summary line only when something actually changed;
  idempotent re-runs produce no output
- add -v/--verbose flag as an explicit alias for the default verbose behavior
- gitignore helper output captured to detect changes without printing in quiet mode
- drop eager "Initializing…" header in favour of end-of-run conditional summary
2026-06-13 00:19:11 -04:00
rootiest 2a7cb0f5cb feat(agents-init): add -a/--agents and -p/--plugins short flags 2026-06-13 00:05:31 -04:00
rootiest 8f845f7cf2 feat(agents-init): add --quiet and --silent flags; wrappers use --quiet 2026-06-13 00:03:11 -04:00
rootiest 69384f6427 fix(agents-init): use command cp -rn to bypass interactive wrapper and skip existing files 2026-06-12 23:51:30 -04:00
rootiest 9f9248deb1 fix(agents-init): fix gitignore duplicate entries, add block comment style
- Strip leading / from pattern before git check-ignore so root-anchored
  patterns like /AGENTS.md are checked as repo-relative paths (AGENTS.md)
  and correctly match existing rules — fixes duplicates on every run
- Rework helper to accept multiple patterns and write them as a single
  labeled block with project-style header/footer comment rather than
  appending bare patterns one at a time
- Move gitignore calls out of per-plug loop in --plugins mode so all
  three docs/ patterns are checked and written in one block
- Remove 5 duplicate bare entries left in .gitignore by the broken runs
2026-06-12 23:30:12 -04:00
rootiest 3a054021cf fix(agents-init): migrate plugin dirs, smarter CLAUDE.md handling, wrappers run full init
- Move plugin dir creation into --plugins mode (not 'Always') so --agents
  alone no longer creates empty AGENTS/plugins/ dirs
- Wrappers (claude, agy) now call plain agents-init (both modes) so plugin
  dirs in docs/ are migrated on the first AI launch, not just --agents
- Rewrite --agents CLAUDE.md logic: detect which root files are real vs
  symlinks and handle all four cases (both/agents-only/claude-only/neither)
  without ever losing content
- AGENTS/CLAUDE.md is now its own file in AGENTS/ (real file when both
  existed, symlink → AGENTS.md for single-source cases)
- Root CLAUDE.md now points to AGENTS/CLAUDE.md instead of AGENTS/AGENTS.md;
  readlink checks auto-fix existing symlinks with the wrong target
- New empty setups get AGENTS/AGENTS.md pre-populated with the agent
  directive warning editors not to write through the root symlinks
2026-06-12 23:05:40 -04:00
rootiest 015daec928 chore: update ag/ag. abbreviations and docs to point to agy instead of antigravity 2026-06-12 22:27:34 -04:00
rootiest d68bedef95 chore: remove antigravity wrapper (filtered error no longer exists, use agy directly) 2026-06-12 22:26:56 -04:00
rootiest e96f874469 feat(agy): wrap agy with agents-init --agents, same as claude wrapper 2026-06-12 22:25:47 -04:00
rootiest 178214c812 docs: add SYNOPSIS/DESCRIPTION doc blocks to session hook scripts and index entries 2026-06-12 22:13:31 -04:00
rootiest 45cba3a15b fix(agents-init): address final review issues (CLAUDE.md safety, rm-rf guard, gitignore anchoring, worktree detection) 2026-06-12 22:09:44 -04:00
rootiest 11dc584104 docs: add agents-init entry and update claude description in fish-config.md 2026-06-12 22:04:12 -04:00
rootiest 0167370823 refactor(claude): delegate symlink logic to agents-init --agents 2026-06-12 22:01:50 -04:00
rootiest 8d0f425b10 feat(agents-init): add auto-commit step for AGENTS/ sub-repo 2026-06-12 21:59:02 -04:00
rootiest a483c30c05 fix(agents-init): use fish-idiomatic command substitution in --plugins mode 2026-06-12 21:55:05 -04:00
rootiest 3befc07887 feat(agents-init): add --plugins mode (docs/ move + symlinks + gitignore) 2026-06-12 21:53:32 -04:00
rootiest 2a9a7ed2ff fix(agents-init): add error checks and CLAUDE.md move to --agents mode 2026-06-12 21:51:05 -04:00
rootiest d1949953df feat(agents-init): add --agents mode (AGENTS.md move + symlinks + gitignore) 2026-06-12 21:48:25 -04:00
rootiest 7463d894f2 fix(agents-init): address code quality issues in skeleton 2026-06-12 21:46:59 -04:00
rootiest 1e1c2003f3 feat(agents-init): scaffold function with argparse, help, and sub-repo init 2026-06-12 21:42:58 -04:00
rootiest e6de825fb1 fix(agents-init): move argv assignments after guard in gitignore helper 2026-06-12 21:41:14 -04:00
rootiest b6ed77d8f9 fix(agents-init): add write-error check and arg validation to gitignore helper 2026-06-12 21:40:27 -04:00
rootiest 522fd03c12 feat(agents-init): add gitignore helper function 2026-06-12 21:38:26 -04:00
Gitea Actions d68f68bec7 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-12 23:43:51 +00:00
rootiest a92847e6ed Merge pull request 'fix(first-run): move fish-config.1 symlink install to first-run' (#51) from fix/manpage-symlink-move-to-first-run into main
Generate documentation / build-docs (push) Successful in 34s
Reviewed-on: #51
2026-06-12 23:43:13 +00:00
rootiest 682e93c794 docs: update man page symlink description to reflect first-run timing 2026-06-12 19:37:58 -04:00
rootiest 953aafd055 fix(first-run): move fish-config.1 symlink install to first-run
Startup side-effects that modify the filesystem belong in first-run, not
in a recurring conf.d fragment. The symlink is now created once (like a
real install step) instead of being checked on every shell launch.

MANPATH addition stays in tricks.fish — that's an env var that must be
set each session.
2026-06-12 19:37:30 -04:00
Gitea Actions 39688b28f4 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-12 23:28:18 +00:00
rootiest 654503062b docs: shorten clean_progress_log.py description to single line
Generate documentation / build-docs (push) Successful in 34s
2026-06-12 19:27:38 -04:00
Gitea Actions 9d2a498089 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-12 23:19:42 +00:00
rootiest 64c559dbab Merge pull request 'feat(config-toggle): adaptive width, centering, and resize handling' (#50) from feat/config-toggle-adaptive-width into main
Generate documentation / build-docs (push) Successful in 34s
Offline docs drift reminder / remind (push) Successful in 11s
Reviewed-on: #50
2026-06-12 23:19:05 +00:00
rootiest 93fc5e0517 feat(config-toggle): adaptive width, centering, and resize handling
Panel now selects from four width tiers based on $COLUMNS (with a 6-col
buffer per side before stepping up): 52-wide (default), 70, 74, or 78.
Each tier carries richer category descriptions sized to fit the layout.
The box is horizontally centered on every draw via a left-padding prefix.

Key reader switches from stty min 1 to min 0 / time 3, giving a 0.3 s
poll interval so COLUMNS changes are detected without a keypress. The
erase formula is now wrap-aware: prev_max_line_width / COLUMNS gives the
wrap factor, ensuring old wider panels are fully cleared after narrowing.
Idle timeout ticks that detect no resize are skipped entirely.
2026-06-12 19:17:49 -04:00
Gitea Actions 1253f67c9c chore(docs): regenerate man page, HTML docs, and wiki 2026-06-12 21:46:31 +00:00
rootiest 045f141e30 Merge pull request 'feat: add claude wrapper that auto-links AGENTS.md as CLAUDE.md' (#49) from feat/claude-wrapper-agents-link into main
Generate documentation / build-docs (push) Successful in 40s
Reviewed-on: #49
2026-06-12 21:45:49 +00:00
rootiest f76a45e273 feat: add claude wrapper that auto-links AGENTS.md as CLAUDE.md
New functions/claude.fish wraps the claude CLI. Before launch it checks the
current directory and the git project root; when CLAUDE.md is absent but
AGENTS.md is present, it creates a relative symlink CLAUDE.md -> AGENTS.md so
Claude Code picks up shared agent instructions without duplicating the file.
Arguments are forwarded verbatim.

Implemented as a C1 command shadow: when __fish_config_op_aliases (or the
master __fish_config_opinionated) is disabled, the call passes through to the
bare claude binary unchanged. Link-creation notices print to stderr in green.

Documents the new shadow in docs/fish-config.md (section 5.12 AI tools, C1
component reference table, and C1 summary list) and adds a claude-cli anchor
to docs/fish-config.index.
2026-06-12 17:44:40 -04:00
rootiest 95f2ad9112 Merge pull request 'fix: suppress fish shadow warning corrupting config-toggle redraw' (#48) from fix/config-toggle-shadow-warning-redraw into main
Reviewed-on: #48
2026-06-12 21:41:21 +00:00
rootiest 4210f3b445 fix: suppress fish shadow warning corrupting config-toggle redraw
When a category variable is set explicitly in both universal and session
scope, interactive fish prints a one-line stderr warning ("successfully set
universal 'X'; but a global by that name shadows it") on each `set -U`/`set
-g`. That stray line landed between the apply and the in-place panel redraw,
pushing the cursor down one row so the `\e[14A` cursor-up no longer reached
the top border — leaving it behind to stack on every toggle and persist
after exit.

Suppress stderr on the six set commands in __config_toggle_apply. The
warning is expected noise here since config-toggle edits both scopes
independently. The warning only fires in a real interactive TTY (not under
`fish -ic`), which is why it was easy to miss when testing.
2026-06-12 17:40:18 -04:00
Gitea Actions 8b9bd248fd chore(docs): regenerate man page, HTML docs, and wiki 2026-06-12 04:58:11 +00:00
rootiest b323fedf49 Merge pull request 'feat: add catppuccin nim-style fallback prompt and overhaul right prompt' (#47) from feat/catppuccin-fallback-prompt into main
Generate documentation / build-docs (push) Successful in 33s
Offline docs drift reminder / remind (push) Successful in 11s
Reviewed-on: #47
2026-06-12 04:57:36 +00:00
rootiest 4f8c45c4ef fix: restore docker context behind starship+C3 guard, use long date format in right prompt 2026-06-12 00:51:55 -04:00
rootiest 16394da0d9 docs: mention catppuccin fallback prompt in README overview 2026-06-12 00:49:28 -04:00
rootiest 7527f01a2b fix: use jobs -c in background loop, reset color after loop, clean up right_prompt 2026-06-12 00:47:27 -04:00
rootiest 0670fbbdad docs: document catppuccin fallback prompt and update component reference 2026-06-12 00:43:42 -04:00
rootiest b5513ccbde fix: overhaul fish_right_prompt — exit code, dim time, remove docker dep 2026-06-12 00:41:53 -04:00
rootiest 4c77f3b0af fix: add operator vi-mode case and # prefix to hex palette in fish_prompt 2026-06-12 00:40:51 -04:00
rootiest eb828a09d5 feat: add catppuccin nim-style fallback fish_prompt 2026-06-12 00:38:22 -04:00
rootiest ab284641a5 fix: add RETURNS block and remove blank line in fish_mode_prompt docstring 2026-06-12 00:36:30 -04:00
rootiest fefcb9034b feat: add empty fish_mode_prompt stub to suppress vi-mode prefix 2026-06-12 00:35:26 -04:00
Gitea Actions e90cdeb259 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-12 03:55:18 +00:00
rootiest 3eec6c3f89 Merge pull request 'fix(deps): clean up dependency catalog tiers and remove dead installer code' (#46) from fix/deps-catalog-uv-pipx into main
Generate documentation / build-docs (push) Successful in 37s
Reviewed-on: #46
2026-06-12 03:54:36 +00:00
rootiest 36a303f7d4 fix(deps): demote cargo/starship to rec, remove fisher from catalog
Required tier is now fish, fzf, and zoxide only — the tools the config
meaningfully can't function without. Everything else degrades gracefully.

- cargo: only used by fish-deps to install Rust tools or build fish from
  source; all paths are already gated on type -q cargo
- starship: type -q guard in conf.d/starship.fish; shell falls back to
  fish's built-in prompt without it
- fisher: auto-bootstrapped by first_run.fish; no need for users or
  fish-deps to manage it. Remove from catalog and clean up the now-dead
  fisher-bootstrap/special-fisher installer cases.

Catalog arrays verified aligned at 26 entries each.
2026-06-11 23:50:37 -04:00
rootiest 5c224694ec fix(deps): demote direnv to recommended
direnv integration is fully guarded with type -q direnv in config.fish.
The auto-venv script checks $DIRENV_DIR (set at runtime), not the binary.
Without direnv installed the hook simply never loads and venv activation
fires normally. No functionality breaks.
2026-06-11 23:36:50 -04:00
rootiest bc0b67a498 fix(docs): correct paru/yay tier — catalog already has them as rec
paru and yay were already classified as rec in _fish_deps_catalog.fish
(they've always been position 9-10 in the tiers array with rec values)
but docs/fish-config.md still listed them under Required. Non-Arch
systems have had silent guards throughout, so they were never truly
required. This syncs the docs with what the catalog already says.
2026-06-11 23:30:12 -04:00
rootiest a3b60718de fix(deps): demote uv to recommended, remove dead pipx installer code
uv is only used in the fish-deps fish-from-source build path
(uv run --no-managed-python cargo install --path .) and is not required
by the config at runtime. All consumers degrade gracefully without it.

pipx appeared in the installer's method-building and execution switch
blocks but no catalog entry ever sets special=pipx, making both branches
permanently unreachable dead code. The docs listed pipx as install
priority #6 which was equally misleading.

- _fish_deps_catalog: change uv tier from req → rec
- _fish_deps_install: remove case pipx method-builder and
  special-pipx / special-pip execution cases
- docs/fish-config.md: move uv from Required to Recommended catalog
  entry with accurate description; drop pipx from install priority
  list and tier summary
2026-06-11 23:28:33 -04:00
Gitea Actions 7744f4f569 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-12 03:24:46 +00:00
rootiest 4eea14576c Merge pull request 'feat(deps): catalog python3 as a recommended dependency' (#45) from feat/python3-dependency into main
Generate documentation / build-docs (push) Successful in 34s
Reviewed-on: #45
2026-06-12 03:24:09 +00:00
rootiest 681a48f3c5 feat(deps): catalog python3 as a recommended dependency
python3 is used unguarded by the AI session helpers and (guarded) by the
paru/yay log cleaner, but was absent from the dependency catalog and docs.
uv does not provide python3 on PATH, and Arch's base omits it, so it is
tracked separately rather than assumed via uv.

- Add python3 (recommended tier, pm: python) to _fish_deps_catalog.fish
- Guard python3 calls in save_claude_session/save_antigravity_session with
  `type -q python3`, emitting valid empty JSON when absent (Convention §6)
- Document python3 in docs/fish-config.md (§5.6 tiers + catalog entry)
2026-06-11 23:15:17 -04:00
Gitea Actions 965d72230c chore(docs): regenerate man page, HTML docs, and wiki 2026-06-12 03:02:58 +00:00
rootiest 71aa38c7ca Merge pull request 'fix(logging): restore AUR progress bars and render clean colored logs' (#44) from fix/aur-wrapper-pty-progress-bars into main
Generate documentation / build-docs (push) Successful in 37s
Reviewed-on: #44
2026-06-12 03:02:20 +00:00
rootiest 499bf672f8 chore(gitignore): add python patterns to gitignore 2026-06-11 22:57:30 -04:00
rootiest 477a4ab265 fix(logging): render AUR progress animations to clean logs via terminal emulator
pacman/paru download progress is a multi-line terminal animation: it
repaints lines in place using ANSI cursor-movement (ESC[<n>A) and
erase-line (ESC[K) sequences, not just carriage returns. The previous
line-wise regex approaches could not reconstruct this — frames either
concatenated into one giant line (CR removed) or collapsed to blanks
(CR kept), discarding the final 100% frame.

Add scripts/clean_progress_log.py, a small dependency-free terminal
screen-buffer emulator that replays the cursor movements against an
in-memory grid and dumps the final static frame, preserving SGR color
so logs still render with color in ov/bat/less -R. It also drops the
script(1) header/footer.

Both wrappers now pipe the raw PTY capture through this cleaner (bumped
to version 5), falling back to stripping only the script(1) header when
python3 is unavailable. Document the scripts/ dir and mechanism in
AGENTS.md and docs/fish-config.md.
2026-06-11 22:48:02 -04:00
rootiest bd0eac8413 fix(logging): fix CR-collapse and script header filtering in AUR log post-processing
col -bp is designed for backspace-overstriking (man pages), not ANSI
terminal animations; it mangled escape sequences and garbled overprinted
progress bar text. Replace with a perl -ne one-liner that:
  1. Skips Script started/done header lines (next if matches, with -ne
     so next truly suppresses print, unlike -pe which still auto-prints)
  2. Strips trailing \r from PTY \r\n line endings
  3. Collapses CR-redrawn progress bar frames to their final state
  4. Preserves all ANSI color codes so ov renders them correctly
Bump wrapper version to 4 to force regeneration.
2026-06-11 22:23:38 -04:00
rootiest fc63b4f1b0 fix(logging): use col -bp to collapse progress bar redraws in AUR logs
script(1) captures every \r-redrawn frame of the pacman progress bar
as raw bytes. The previous sed pass only stripped ANSI codes, leaving
all intermediate frames concatenated in the log. col -bp semantically
replays the carriage-return overwrites and retains only the final state
of each line; the sed pass then strips residual ANSI codes and the
"Script started/done" header that script(1) writes to the file even
under -q. Bump wrapper version to 3.
2026-06-11 22:10:19 -04:00
rootiest 0cbb7c6892 fix(logging): run paru/yay wrappers in PTY to restore progress bars
Piping through tee caused libalpm to detect a non-TTY stdout and
suppress download progress bars. Switch to script(1) with -q -e -c
which allocates a pseudo-TTY so paru/yay see a real terminal, then
strip ANSI escape sequences from the captured log for readability.
Bump wrapper version to 2 to force regeneration on next shell start.
2026-06-11 22:02:56 -04:00
rootiest 35e86dcd6e docs(readme): lead Minimal Mode with the config-toggle TUI
Offline docs drift reminder / remind (push) Successful in 11s
Promote config-toggle to a callout at the top of the Minimal Mode
section so users see the interactive UI before the variable table,
and drop the now-redundant tip at the bottom.
2026-06-11 03:31:34 -04:00
rootiest 4bfea67cc5 chore(gitignore): ignore and untrack superpowers planning artifacts
Add docs/plans, docs/specs, docs/superpowers, and .superpowers to
.gitignore and stop tracking the two config-toggle artifacts that were
committed before the ignore rules existed. The files are kept on disk
(now ignored), only removed from version control.
2026-06-11 03:29:04 -04:00
Gitea Actions 85a7889c5c chore(docs): regenerate man page, HTML docs, and wiki 2026-06-11 07:20:34 +00:00
rootiest 97f783e9a8 Merge pull request 'feat(config-toggle): add interactive TUI for toggling opinionated component settings' (#43) from feat/config-toggle into main
Generate documentation / build-docs (push) Successful in 39s
Offline docs drift reminder / remind (push) Successful in 11s
Reviewed-on: #43
2026-06-11 07:19:54 +00:00
rootiest 764a9d35e5 feat(config-toggle): right-align ON badge to mirror value direction
The badge now positions each state by where it sits on the scale: OFF
left-aligned, DEFAULT centered, ON right-aligned. This makes the
OFF ← DEFAULT → ON ordering visible at a glance and reinforces the
direction the ←→/h l keys move.
2026-06-11 03:16:33 -04:00
rootiest cfd4749e72 feat(config-toggle): drop Space, add vim h/l for value changes
Directional arrows fully cover value changes, so the Space cycle is
removed. Add h/l as vim-style aliases for ←/→ (matching the existing
j/k for up/down), keeping the whole keymap hjkl-consistent. Update the
in-panel hint, help text, docstrings, and offline docs accordingly.
2026-06-11 03:10:50 -04:00
rootiest bddb068ec0 feat(config-toggle): add Left/Right arrows for directional value changes
Left/Right now adjust the highlighted value one step along the
OFF ← DEFAULT → ON scale, clamped at the ends (no wrap), complementing
Space which cycles through all states and wraps. Right steps toward ON,
Left toward OFF.

Extract the set/erase side-effect into __config_toggle_apply so Space,
Left, and Right share one implementation of the scope-aware
set -U/-g/-Ue/-eg logic. Update the in-panel keybind hint (now
width-padded via string pad so the border stays aligned) and the help
text and offline docs to cover the new keys.
2026-06-11 03:07:17 -04:00
rootiest 608b0227cb fix(config-toggle): read keys via raw tty, fixing arrows/Tab/redraw/prompt
fish's `read` invokes its interactive line editor on a TTY, which (1)
prints a `read> ` prompt below the panel, (2) intercepts Tab and arrow
keys for its own line editing so they never reach the switch, and (3)
shifts the cursor down a line, throwing off the `\e[14A` redraw so top
borders stacked on every keypress. Plain keys (j/k/q/space) passed
through, masking the problem.

Add __config_toggle_read_key: puts the terminal in raw, no-echo mode
(`stty raw -echo min 1 time 1`), reads one keypress from /dev/tty, and
returns a normalized token (up/down/left/right/tab/space/escape/quit or
the literal char) by decoding the bytes via od. Arrow keys and Tab now
work, there is no stray prompt, and the redraw stays aligned. Ctrl-C in
raw mode arrives as byte 3 and maps to quit; bare Esc exits after the
0.1s inter-byte timer.

Rewrite the event loop to consume these tokens and restore Esc to the
help text.
2026-06-11 03:03:32 -04:00
rootiest 5a018fe975 fix(config-toggle): use valid -n read flag, stopping the busy redraw loop
The event loop used `read -k 1`, but `-k` is not a valid fish read option
(it errors with "unknown option", status 2). read therefore returned
instantly every iteration without consuming a keypress, so the loop
redrew the panel as fast as the terminal could render and ignored all
input. The nchars flag is `-n`, not `-k`.

Switch to `read -s -n 1` (one char, silent so keystrokes don't garble the
panel) and add `or break` so a read failure (EOF / non-tty stdin) exits
cleanly instead of spinning. Applies to the primary read and both escape
sequence continuation reads.
2026-06-11 02:56:12 -04:00
rootiest cc14f7fb3d fix(config-toggle): replace read -k 3 with read -k 1 + ESC sequence detection
fish's read -k N waits for exactly N bytes; single-char keys ('q', 'j',
Space, Tab) were blocking indefinitely waiting for 2 more bytes, causing
the input loop to appear unresponsive. Random 3-key bundles were then
processed as unrecognised input, triggering infinite redraws.

Switch to read -k 1 (one raw byte per call). Arrow keys still work: the
terminal sends ESC+[+A/B as a burst, so after reading ESC the two
continuation bytes are already in the TTY buffer and the follow-up reads
return immediately. Bare ESC now passes the next keypress through as the
effective key rather than exiting (q/Q remain the exit keys).
2026-06-11 02:51:01 -04:00
rootiest bff084db07 fix(config-toggle): exit on Ctrl-C via flag variable, add README tip 2026-06-11 01:29:28 -04:00
rootiest f75d64bf9c docs(config-toggle): add config-toggle entry to offline docs and index 2026-06-11 01:20:55 -04:00
rootiest 43fd36f5ea feat(config-toggle): add Space cycling with immediate apply 2026-06-11 01:18:09 -04:00
rootiest 9a820fc3e6 fix(config-toggle): use read -k 3 for ESC sequences, clear INT trap on exit
Replace two-read-k-1 ESC handling with a single read -k 3 so that a bare
ESC returns immediately instead of blocking the shell indefinitely waiting
for a second byte.  Add trap - INT in the cleanup block so the signal
handler does not leak into the global session after config-toggle exits.
2026-06-11 01:16:41 -04:00
rootiest d20f7f8d7b feat(config-toggle): add event loop with navigation and scope switching 2026-06-11 01:11:04 -04:00
rootiest a4f6ee26cb feat(config-toggle): add function skeleton and help flag 2026-06-11 01:07:15 -04:00
rootiest c9174f9d4a feat(config-toggle): add panel renderer helper 2026-06-11 01:01:19 -04:00
rootiest c372c96dd7 feat(config-toggle): add scope-specific variable reader helper 2026-06-11 00:52:11 -04:00
rootiest aa8e4437ec docs(plans): add config-toggle implementation plan
6-task plan: scope-value reader, panel renderer, skeleton/help,
event loop + navigation, cycling + immediate apply, docs update.
2026-06-11 00:49:41 -04:00
rootiest 87960cc8cc docs(specs): add config-toggle design spec
Interactive TUI for toggling opinionated component categories and master
variable. Tabbed Universal/Session scope, arrow-key navigation, Space to
cycle ON/OFF/DEFAULT with immediate apply.
2026-06-11 00:31:49 -04:00
Gitea Actions a9d1d6ac4d chore(docs): regenerate man page, HTML docs, and wiki 2026-06-11 03:38:01 +00:00
rootiest fc17c9fd61 Merge pull request 'docs(catalog): migrate opinionated component catalog into fish-config.md' (#42) from docs/migrate-opinionated-catalog into main
Generate documentation / build-docs (push) Successful in 34s
Reviewed-on: #42
2026-06-11 03:37:26 +00:00
rootiest 780bda7ab7 docs(catalog): migrate opinionated component catalog into fish-config.md
Promotes the internal opinionated_catalog.md (git-ignored dev reference)
to first-class user documentation in docs/fish-config.md Section 7.

- Add per-category component tables (C1–C6) under a new "Component
  Reference" subsection in "Opinionated Components (Minimal Mode)"
- Document the C5 sentinel-file coordination mechanism and how
  __fish_config_logging_changed propagates changes to all open shells
- Document C3/C5 composition (smart_exit wrapper vs capture block)
- Document bang-bang system atomicity across its multiple source files
- Add rg function entry to Section 5.1 (Kitty hyperlink wrapper)
- Update fish-config.index with keywords for all new headings
2026-06-10 23:36:24 -04:00
Gitea Actions e4bcbd3da2 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-11 03:10:26 +00:00
rootiest 4bef8f9c91 Merge pull request 'feat(guards): per-category variable overrides master in __fish_config_op_enabled' (#41) from feat/per-category-master-override into main
Generate documentation / build-docs (push) Successful in 34s
Offline docs drift reminder / remind (push) Successful in 10s
Reviewed-on: #41
2026-06-11 03:09:51 +00:00
rootiest e776e7fba6 docs(guards): document per-category master override in fish-config.md 2026-06-10 23:02:16 -04:00
rootiest a170d82086 docs(guards): document per-category master override in README Minimal Mode 2026-06-10 23:00:23 -04:00
rootiest c04c1a4bc2 docs(guards): fold no-arg edge case into RETURNS status-1 line 2026-06-10 22:59:49 -04:00
rootiest 4c989a45c1 refactor(guards): remove what-comments; document no-arg edge case in RETURNS 2026-06-10 22:59:11 -04:00
rootiest cccef17031 feat(guards): category variable overrides master in __fish_config_op_enabled 2026-06-10 22:57:01 -04:00
361 changed files with 44628 additions and 15442 deletions
-48
View File
@@ -1,48 +0,0 @@
name: Generate documentation
on:
push:
branches:
- main
paths:
- "docs/fish-config.md"
jobs:
build-docs:
runs-on: racknerd-mini
steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.GITEA_TOKEN }}
- name: Install pandoc
run: sudo apt-get update -qq && sudo apt-get install -y pandoc
- name: Compile man page
run: |
pandoc --standalone \
--from markdown \
--to man \
docs/fish-config.md \
-o docs/fish-config.1
- name: Generate chunked HTML docs
run: |
rm -rf docs/html/
pandoc -f gfm -t chunkedhtml --split-level=1 --toc \
--include-in-header docs/html-style.html \
docs/fish-config.md \
-o docs/html/
- name: Generate wiki markdown
run: python3 docs/split-wiki.py
- name: Commit generated docs
run: |
git config user.name "Gitea Actions"
git config user.email "actions@gitea"
git add docs/fish-config.1 docs/html/ docs/wiki/
git diff --cached --quiet && echo "No changes to commit" && exit 0
git commit -m "chore(docs): regenerate man page, HTML docs, and wiki"
git push
-45
View File
@@ -1,45 +0,0 @@
name: Offline docs drift reminder
on:
push:
branches:
- main
paths:
- "README.md"
jobs:
remind:
runs-on: racknerd-mini
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Check whether offline doc changed in same push
id: drift
run: |
if git diff --name-only HEAD~1 HEAD | grep -q '^docs/fish-config\.md$'; then
echo "synced=true" >> "$GITHUB_OUTPUT"
else
echo "synced=false" >> "$GITHUB_OUTPUT"
fi
- name: Open drift reminder issue
if: steps.drift.outputs.synced == 'false'
env:
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
SERVER_URL: ${{ github.server_url }}
REPO: ${{ github.repository }}
SHA: ${{ github.sha }}
BRANCH: ${{ github.ref_name }}
run: |
curl -s -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${SERVER_URL}/api/v1/repos/${REPO}/issues" \
-d "{
\"title\": \"docs: README updated — review docs/fish-config.md for drift\",
\"body\": \"README.md was modified in commit ${SHA} but \`docs/fish-config.md\` (the offline manual) was not updated in the same push.\n\nPlease review the README diff and update the offline documentation if any functions, keybindings, abbreviations, or configuration options were added, removed, or changed.\n\nCommit: ${SHA}\nBranch: ${BRANCH}\",
\"labels\": [\"Kind/Documentation\"]
}"
+151
View File
@@ -0,0 +1,151 @@
# The key below is `description`, NOT `about`.
#
# GitHub requires `description` on a YAML issue form and rejects the
# template without it; Gitea wants `about` but explicitly accepts
# `description` as a compatible alias. `description` is therefore the
# only spelling that works on both the canonical repo and the mirror.
# The markdown templates beside this one still use `about`, which is
# correct for their format on both forges.
name: Bug report
description: Something in the config is broken or behaves unexpectedly
labels:
- Kind/Bug
body:
- type: markdown
attributes:
value: |
Thanks for filing a bug.
**Title it as a plain description of the problem**, not as a
conventional-commit subject — `mv clobbers a symlink when the target
exists`, not `fix(mv): ...`. The commit format belongs on the PR that
fixes this; the `Kind/` and `Area/` labels carry type and scope here.
Before filing, please confirm the problem survives a fresh shell
(`exec fish`) — a stale function definition in a long-lived session is
the single most common false alarm.
- type: input
id: fish-version
attributes:
label: fish version
description: Output of `fish --version`. This config targets fish 4.x.
placeholder: fish, version 4.0.2
validations:
required: true
- type: input
id: os
attributes:
label: Operating system
description: Distribution and version, or macOS release.
placeholder: Arch Linux (CachyOS), kernel 6.12.4
validations:
required: true
- type: input
id: terminal
attributes:
label: Terminal emulator
description: >-
Only matters for rendering, key bindings, and color problems. Leave it
blank if the bug has nothing to do with those.
placeholder: kitty 0.42.1
validations:
required: false
- type: dropdown
id: area
attributes:
label: Area
description: >-
Which part of the config is affected? Pick the closest match — a
maintainer translates this into the matching `Area/` label at triage,
since contributors without push access can't set labels themselves.
Choose "Not sure" rather than guessing.
options:
- Not sure
- Functions (functions/)
- Completions (completions/)
- Config and startup (config.fish, conf.d/)
- Docs (docs/manual/, man page, docs site)
- Tests (tests/)
- CI (.github/workflows/)
- Integrations (integrations/)
- Prompt and theme (themes/)
- Opinionated components (C1-C6 toggles)
- Scripts (scripts/)
validations:
required: true
- type: textarea
id: summary
attributes:
label: What's broken
description: One or two sentences. Name the function or file if you know it.
placeholder: >-
`mv` replaces an existing symlink instead of prompting, so the link
target is lost with no confirmation.
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: Steps to reproduce
description: >-
Exact commands, starting from a fresh shell, that someone else can
paste and run. Include any setup needed to reach the broken state.
render: fish
placeholder: |
exec fish
mkdir -p /tmp/repro; cd /tmp/repro
touch real; ln -s real link
mv real link
validations:
required: true
- type: textarea
id: expected
attributes:
label: Expected behavior
description: What you thought those commands would do.
validations:
required: true
- type: textarea
id: actual
attributes:
label: Actual behavior
description: >-
What happened instead. Paste the complete output, including any error
text and stack traces — truncated errors are the usual reason a bug
report stalls in Status/Need More Info.
render: text
validations:
required: true
- type: checkboxes
id: preflight
attributes:
label: Pre-flight
options:
- label: I searched the existing issues and this isn't already reported.
required: true
- label: I reproduced this in a fresh shell (`exec fish`), not a long-lived session.
required: true
- label: I ran `fish tests/run-tests.fish` and noted the result below (or in the output above).
required: false
- type: textarea
id: context
attributes:
label: Additional context
description: >-
Anything else worth knowing: a private overlay in
`~/.config/.user-dots/fish/` that may be involved, opinionated
components you've disabled, the last commit where it worked. Never
paste credentials, tokens, or machine-specific paths you'd rather not
publish.
validations:
required: false
+21
View File
@@ -0,0 +1,21 @@
# Read by both Gitea (the canonical repo) and GitHub (the mirror).
#
# The .yml extension is required: Gitea accepts config.yaml or config.yml,
# but GitHub only recognizes config.yml and silently ignores config.yaml.
# Don't "tidy" this back to .yaml — the chooser on the mirror stops working.
#
# Blank issues stay enabled deliberately: the three templates cover bugs,
# features, and docs, and anything else (a chore, a refactor, a question)
# is better served by an empty box than by a template that doesn't fit.
blank_issues_enabled: true
contact_links:
- name: Canonical repository and issue tracker
url: https://git.rootiest.dev/rootiest/fish-config/issues
about: fish-config is developed on Gitea. If you came from the GitHub mirror, please file here instead — the mirror is read-only and issues opened there are easy to miss.
- name: Contributing guide
url: https://git.rootiest.dev/rootiest/fish-config/src/branch/main/CONTRIBUTING.md
about: Branch naming, commit conventions, coding standards, and the label taxonomy.
- name: Customization and personal overrides
url: https://git.rootiest.dev/rootiest/fish-config/src/branch/main/docs/manual/07-customization.md
about: Want to change behavior on just your machine? Use your private overlay — no issue needed.
+80
View File
@@ -0,0 +1,80 @@
---
name: Documentation issue
about: Something in the manual, man page, config-help, or docs site is wrong, missing, or unclear
labels:
- Kind/Documentation
---
<!--
Title this as a plain description of the problem:
config-help shows literal backticks in the customization section
not `docs(help): ...`. See CONTRIBUTING.md § Labels.
Docs in this repo are GENERATED. docs/manual/** plus the doc-header
comments above each function are the single source of truth;
docs/fish-config.md and docs/fish-config.1 are build output and are never
hand-edited. So a fix always lands in the source, not in the page where you
saw the problem — the Location section below asks for both.
Delete these comments as you fill it in.
-->
## Location
<!--
Where you saw it, and where it actually comes from.
- **Where you saw it** — the docs site URL, the `config-help <topic>` you
ran, `man fish-config`, or the README section.
- **Source file** — the docs/manual/** page, or the function whose
doc-header feeds it (e.g. `functions/mv.fish`). If you're not sure which,
say so and leave it to triage rather than guessing.
If the problem appears in one output but not the others — correct on the
site, broken in the pager — say which, since that usually points at the
rendering pass (docs/codespans.py) rather than the source text.
-->
## Problem
<!--
What's wrong. Quote the current text so it can be found and compared.
Common shapes, if it helps you place yours:
- **Wrong** — documents behavior the code doesn't have.
- **Stale** — described a flag or path that has since changed.
- **Missing** — a function, flag, or setting with no entry at all. Note
that a function with no `# CATEGORY` header is omitted from the manual
deliberately, so "missing" may be an intentional opt-out.
- **Unclear** — accurate, but a reader can't act on it. Say what you
expected to learn and what you concluded instead.
- **Renders wrong** — a broken code span, a mangled table, a bad anchor.
-->
## Suggested fix
<!--
Proposed wording or structure, if you have one — a diff-shaped
before/after is ideal, but a rough sketch is welcome too. "I don't know
what it should say, only that this confused me" is a legitimate and useful
report; keep the heading and say that.
Two constraints on any text under docs/manual/, both enforced by
docs/verify-manual.py:
- No backticks inside an indented block.
- No backtick span wrapped across a line break.
Doc-headers in .fish files take no backticks at all — docs/codespans.py
adds code spans when it renders. See CONTRIBUTING.md § Documentation
Pipeline.
-->
## Notes
<!--
Anything else — related issues (`Refs #42`), the commit that introduced the
problem, other pages with the same mistake. Drop this heading if empty.
-->
+111
View File
@@ -0,0 +1,111 @@
---
name: Feature or enhancement request
about: Propose new functionality, or an improvement to something that already exists
labels:
- Kind/Feature
---
<!--
Title this as a plain description of what you want, NOT as a
conventional-commit subject:
A picker for switching themes without editing config.fish
not `feat(theme): add theme picker`. That format belongs on the PR that
implements this; here, the Kind/ and Area/ labels carry type and scope.
See CONTRIBUTING.md § Labels.
This template applies Kind/Feature. If you're proposing an improvement to
something that already exists rather than genuinely new functionality, say
so in the Summary — a maintainer will swap the label to Kind/Enhancement
at triage. Contributors without push access can't set labels directly.
Keep every heading below except Alternatives considered and Notes, which
you can drop if they'd be empty. Delete these comments as you go.
-->
## Summary
<!--
What you want, in one or two sentences. Lead with the capability, not the
implementation — "a way to preview a theme before committing to it" rather
than "add a --preview flag to theme-set".
-->
## Problem
<!--
What's awkward, slow, or impossible today. Be concrete about the situation
that led you here: the sequence of commands you run now, what you have to
remember, or what goes wrong. A proposal is only as good as the problem it
names, and this section is what a reviewer weighs the cost against.
-->
## Proposed behavior
<!--
The concrete shape of the thing. Where they apply:
- The command or function name, and its flags.
- What it prints on success, and what it does on the error paths.
- What happens with no arguments, or with a missing dependency.
- Whether it's interactive, and what it falls back to when it isn't.
A short usage sketch in a ```fish block is worth several paragraphs.
-->
## Alternatives considered
<!--
Other approaches you weighed and why you set them aside — including
"solve it in my own ~/.config/.user-dots/fish/local.fish instead", which is
the right answer for anything genuinely specific to one machine or one
person's taste. See CONTRIBUTING.md § Secrets & Machine-Specific Config.
Drop this heading if there were no real alternatives.
-->
## Scope
<!--
Answer these — they determine how the change has to be built, and getting
them wrong late is expensive:
- Does this shadow a builtin or an existing command?
- Does it run at startup, or bind a key, or set an environment variable?
- Does it need a new external dependency, and what should happen when that
dependency is missing?
- Is it opinionated enough that users should be able to turn it off? If any
of the above is yes, it likely needs a `# COMPONENT` header and an
`__fish_config_op_enabled` guard — see CONTRIBUTING.md § Opinionated
Components.
- Does it need a manual entry (a `# CATEGORY` header), and under which of
the docs/manual/05-functions/ categories?
-->
## Acceptance criteria
<!--
What must be true for this issue to close, as a checkbox list. This is the
issue-side counterpart to a PR's ## Verification: it's the shared
definition of done, agreed before the work starts rather than argued about
after.
- One observable outcome per line — behavior a reader could check, not
implementation steps.
- Cover the error and fallback paths, not just the happy one.
- Include the docs and tests the change will owe.
Leave the boxes unchecked; they get ticked as the work lands.
-->
- [ ]
- [ ]
## Notes
<!--
Anything else: prior art in other shells or dotfiles, links to the relevant
upstream tool's docs, related issues (`Refs #42`). Drop this heading if
there's nothing to add.
-->
+109
View File
@@ -0,0 +1,109 @@
<!--
PR title: Conventional Commits — type(scope): description
e.g. fix(mv): bring header and completions up to repo conventions
Lowercase after the colon, imperative mood, no trailing period.
Append `!` after the scope for a breaking change: feat(logging)!: ...
Types in use: feat, fix, docs, test, chore, perf, refactor, style.
See CONTRIBUTING.md § Commit Conventions.
Still writing code? Prefix the title with `WIP:` —
WIP: feat(media): add play-media fzf picker
Gitea recognizes the prefix, marks the PR a draft, and blocks merging
until you remove it. The prefix goes before the whole conventional
subject, and comes off when the branch is complete.
`WIP:` means MORE CHANGES ARE COMING. It is not for a finished branch
waiting on verification — that is what an unchecked box in Verification
already signals. A complete branch with open checkboxes is a normal PR,
not a WIP.
Keep the two headings below, in this order, and delete these comments.
Optional sections may be added between them (see the note above
"Verification").
-->
## Summary
<!--
What changed and why. A short prose paragraph, 2-5 bullets, or a
paragraph followed by bullets — whichever fits the change.
- Name concrete paths and identifiers in backticks (`functions/mv.fish`,
`$__fish_config_op_autoexec`), not vague descriptions.
- Lead a bullet with a **bold phrase** when it covers a distinct file or
behavior, so the list scans at a glance.
- Explain the reasoning, not just the diff — a reader should understand
why this approach over the obvious alternative.
- Say so explicitly when there is no behavioral change, when a file is
generated by the docs pipeline, or when the change is scoped to the
site build only.
If this PR resolves a tracked issue, close it with a trailing line at the
end of this section — not at the very bottom, since Verification is
always last:
Closes #42
Gitea and GitHub both auto-close the issue on merge. `Fixes #N` and
`Resolves #N` work identically; pick whichever reads correctly. Use one
line per issue (`Closes #42, closes #43` — the keyword must be repeated,
a bare `#43` after a comma is only a link and will NOT close). For an
issue that is related but should stay open, reference it without a
keyword: `Refs #42`. Omit all of this entirely when no issue is involved
— do not leave an empty `Closes #` behind.
-->
<!--
OPTIONAL SECTIONS — add any `##` heading here that the change actually
needs, and skip them entirely for a straightforward one. Used in this
repo, roughly in order of frequency:
## Root cause — for a bug fix, what was actually wrong
## Why — motivation, when it isn't obvious
## How it works — mechanism, for a non-trivial new feature
## Behavior — user-visible behavior before/after
## Changes — a longer breakdown than Summary can carry
## Docs — documentation touched by this change
## Notes — caveats, follow-ups, deferred work
## Scope note — what this deliberately does NOT cover
## Opinionated guard (C1-C6)
— which tier gates this, and behavior when off
## ⚠️ Breaking Change — required whenever the title carries `!`;
state the break and the migration path
A "Why not <alternative>?" heading is also common when a reviewer would
reasonably ask why the obvious approach was rejected.
-->
## Verification
<!--
Every check this change needs, as a checkbox list. Always the last
section.
A CHECKED box means verified — either it ran programmatically (test
suite, linter, docs verifier, CI) or the author performed it by hand and
confirmed the result. Check these off before opening the PR.
An UNCHECKED box is an outstanding manual check the reviewer still has to
perform. Leave anything you could not verify yourself unchecked rather
than dropping it, so it stays visible.
**This list is the merge gate: the PR does not merge until every box is
checked.** So only put things here that can actually be resolved — a
check nobody is able to run blocks the PR forever. Genuinely unverifiable
caveats, assumptions, and known limitations belong in a `## Notes`
section instead, where they inform the review without gating it.
- One check per line, imperative, with the exact command in backticks
and the expected result stated.
- Cover the regression path, not just the happy path: the old behavior
still working, the opinionated toggle disabled, the error branch.
- Include the repo's standing gates when the change touches what they
guard: `fish -n <file>`, `fish_indent`, `python3 docs/verify-manual.py`,
`python3 docs/build-manual.py --site`, `fish tests/run-tests.fish`.
- Reset any universal variable you set during a check.
-->
- [ ]
- [ ]
+169
View File
@@ -0,0 +1,169 @@
name: CI
on:
push:
branches:
- main
paths:
- "docs/manual/**"
- "docs/build-manual.py"
- "docs/manualtools.py"
- "docs/verify-manual.py"
- "docs/site/**"
- "functions/**"
- "conf.d/**"
- "config.fish"
- "completions/**"
- "integrations/**"
- "tests/**"
workflow_dispatch:
inputs:
job:
description: "Job to run"
required: false
default: all
type: choice
options:
- all
- test
- build-docs
jobs:
# This workflow file is mirrored to GitHub as-is, but the runner label
# below (racknerd-mini) only exists on the Gitea instance -- on GitHub
# the job just sits queued forever with no matching runner, so the
# mirror never gets a completed status. Gate the real jobs to Gitea and
# let the github-mirror job below stand in on GitHub instead.
test:
if: |
github.server_url != 'https://github.com' &&
(github.event_name != 'workflow_dispatch' || github.event.inputs.job == 'all' || github.event.inputs.job == 'test')
runs-on: racknerd-mini
steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.GITEA_TOKEN }}
- name: Install fish
run: |
sudo apt-get -o Acquire::Retries=3 update -qq
sudo DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y software-properties-common
sudo add-apt-repository -y ppa:fish-shell/release-4
sudo apt-get -o Acquire::Retries=3 update -qq
sudo DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y fish
- name: Run fish config tests
run: fish tests/run-tests.fish
build-docs:
needs: test
if: |
github.server_url != 'https://github.com' &&
always() &&
(github.event.inputs.job == 'build-docs' ||
((github.event_name != 'workflow_dispatch' || github.event.inputs.job == 'all') &&
needs.test.result == 'success'))
runs-on: racknerd-mini
steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.GITEA_TOKEN }}
- name: Install dependencies
run: |
sudo apt-get -o Acquire::Retries=3 update -qq
sudo DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y software-properties-common
sudo add-apt-repository -y ppa:fish-shell/release-4
sudo apt-get -o Acquire::Retries=3 update -qq
sudo DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y pandoc python3-yaml fish
- name: Generate concatenated markdown
run: python3 docs/build-manual.py --concat -o docs/fish-config.md
# Regeneration MUST run before verification: verify-manual.py's
# test_concat_roundtrips_original compares a freshly-built concat
# against docs/fish-config.md on disk. Before this step ran, that
# file was still the stale pre-push copy, so any ordinary edit under
# docs/manual/** failed the round-trip check before anything was
# regenerated. Do not reorder this back — verification still gates
# pandoc and the auto-commit below, it just no longer requires a
# contributor to hand-sync the generated file before pushing.
- name: Verify manual integrity
run: python3 docs/verify-manual.py
- name: Compile man page
run: |
pandoc --standalone \
--from markdown \
--to man \
docs/fish-config.md \
-o docs/fish-config.1
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: "24"
- name: Generate site content
run: python3 docs/build-manual.py --site
- name: Build documentation site
working-directory: docs/site
run: |
npm ci
npx astro build
- name: Deploy to Cloudflare Pages
working-directory: docs/site
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
run: |
npx --yes wrangler pages deploy dist/ \
--project-name=fish-config-docs \
--branch=main \
--commit-dirty=true
- name: Commit generated docs
env:
BOT_GPG_KEY: ${{ secrets.CI_GPG_PRIVATE_KEY }}
run: |
# actions@gitea was never a verified email on any account, so
# these commits could never show as signed/verified regardless
# of server config. fishconfig-bot is a dedicated Gitea account
# (verified email, no login) that owns this key; the private
# key lives only in the CI_GPG_PRIVATE_KEY repo secret.
#
# Secret is base64-encoded: a raw multi-line armored key piped
# through `echo "$VAR" | gpg --import` came out CRC-corrupted
# ("Invalid keyring") the first time this ran -- something in
# the secret/env round-trip mangles embedded newlines. Base64
# collapses it to one line immune to that.
export GNUPGHOME="$(mktemp -d)"
chmod 700 "$GNUPGHOME"
echo "pinentry-mode loopback" > "$GNUPGHOME/gpg.conf"
echo "allow-loopback-pinentry" > "$GNUPGHOME/gpg-agent.conf"
command -v gpg >/dev/null || sudo apt-get install -y --no-install-recommends gnupg
echo "$BOT_GPG_KEY" | base64 -d | gpg --batch --import
git config user.name "Gitea Actions Bot"
git config user.email "fishconfig-bot@git.rootiest.dev"
git config user.signingkey CAA082C2F3467E1F7217AD492075C120312D23F4
git config commit.gpgsign true
git add docs/fish-config.md docs/fish-config.1 conf.d/__fish_config_op_registry.fish
git diff --cached --quiet && echo "No changes to commit" && exit 0
git commit -m "chore(docs): regenerate manual, man page, and component registry"
git push
# Stand-in for the GitHub mirror so the commit gets a completed status
# instead of the real jobs above sitting queued forever for a
# self-hosted runner that only exists on the Gitea instance.
github-mirror:
if: github.server_url == 'https://github.com'
runs-on: ubuntu-latest
steps:
- name: Note that CI runs on Gitea
run: |
echo "This repository mirrors from Gitea (git.rootiest.dev), where CI actually runs."
echo "See the commit's status on the Gitea instance for the real test/build-docs results."
+71
View File
@@ -0,0 +1,71 @@
name: Sync labels to mirror
# Labels do not travel with a mirror push -- mirroring copies files, not
# repository settings -- but they matter on the GitHub side anyway, because
# GitHub reads the same .github/ISSUE_TEMPLATE/ files and silently drops a
# labels: entry naming a label it does not have. Gitea is the source of
# truth; this makes the mirror match.
on:
schedule:
# 06:00 UTC daily. Label churn is rare, so a slower cadence than this
# would leave the mirror wrong for most of a working day after an edit.
- cron: "0 6 * * *"
push:
branches:
- main
paths:
# Exercise the sync as soon as its own logic changes, rather than
# waiting for the next scheduled run to find out it is broken.
- "scripts/sync-labels.py"
- ".github/workflows/sync-labels.yml"
workflow_dispatch:
inputs:
dry_run:
description: "Report the plan without changing anything"
required: false
default: false
type: boolean
jobs:
sync-labels:
# This file is mirrored to GitHub as-is. The runner label below only
# exists on the Gitea instance, so on GitHub the job would sit queued
# forever against a runner that will never pick it up -- the same
# problem the github-mirror stand-in in ci.yml exists to solve. A
# skipped job costs nothing and produces no stuck status.
if: github.server_url != 'https://github.com'
runs-on: racknerd-mini
steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.GITEA_TOKEN }}
- name: Install Python
run: |
sudo apt-get -o Acquire::Retries=3 update -qq
sudo DEBIAN_FRONTEND=noninteractive apt-get install \
--no-install-recommends -y python3
# Cheap, offline, and no token needed. Catches a broken diff before
# anything is allowed to mutate labels on the mirror.
- name: Check the diff logic
run: python3 scripts/sync-labels.py --self-test
- name: Sync labels
env:
GH_MIRROR_TOKEN: ${{ secrets.GH_MIRROR_TOKEN }}
run: |
if [ -z "$GH_MIRROR_TOKEN" ]; then
echo "::error::GH_MIRROR_TOKEN is not set in this repository's Actions secrets."
echo "Create a fine-grained GitHub token scoped to rootiest/fish-config with"
echo "Issues: read and write, plus Pull requests: read, and add it as"
echo "GH_MIRROR_TOKEN under Settings -> Actions -> Secrets."
exit 1
fi
if [ "${{ inputs.dry_run }}" = "true" ]; then
python3 scripts/sync-labels.py --dry-run
else
python3 scripts/sync-labels.py
fi
+204 -2
View File
@@ -1,6 +1,6 @@
# GitIgnore for Fish-config # GitIgnore for Fish-config
# id: gitig-boilerplate-7f0528027e23f210196ae4583c408e5b # id: gitig-boilerplate-a27b89403ff9f0bb3340ede87b42f93e
# ╭──────────────────────────────────────────────────────────╮ # ╭──────────────────────────────────────────────────────────╮
# │ GitIgnore Boilerplate Template │ # │ GitIgnore Boilerplate Template │
# ╰──────────────────────────────────────────────────────────╯ # ╰──────────────────────────────────────────────────────────╯
@@ -60,7 +60,10 @@
# ──────────────────── Planning Artifacts ─────────────────── # ──────────────────── Planning Artifacts ───────────────────
# Catalog files generated by pre-implementation analysis passes # Catalog files generated by pre-implementation analysis passes
opinionated_catalog.md opinionated_catalog.md
.superpowers
docs/superpowers docs/superpowers
docs/specs
docs/plans
# ──────────────────── Runtime State Files ─────────────────── # ──────────────────── Runtime State Files ───────────────────
# Sentinel file written/removed at runtime to coordinate logging state # Sentinel file written/removed at runtime to coordinate logging state
@@ -90,8 +93,9 @@ functions/sponge_*.fish
[Aa][nN][Tt][Ii][Gg][Rr][Aa][Vv][Ii][Tt][Yy].[Mm][Dd] [Aa][nN][Tt][Ii][Gg][Rr][Aa][Vv][Ii][Tt][Yy].[Mm][Dd]
.[Aa][Nn][Tt][Ii][Gg][Rr][Aa][Vv]* .[Aa][Nn][Tt][Ii][Gg][Rr][Aa][Vv]*
# Matches AGENTS.md, .remember, etc. # Matches AGENTS.md, .agents/ (agy), .remember, etc.
[Aa][Gg][Ee][Nn][Tt][Ss].[Mm][Dd] [Aa][Gg][Ee][Nn][Tt][Ss].[Mm][Dd]
.[Aa][Gg][Ee][Nn][Tt][Ss]*
.[Rr][Ee][Mm][Ee][Mm][Bb][Ee][Rr] .[Rr][Ee][Mm][Ee][Mm][Bb][Ee][Rr]
# ────────────────────────────────────────────────────────────── # ──────────────────────────────────────────────────────────────
@@ -107,3 +111,201 @@ fish_variables
config.local.fish config.local.fish
# End of https://www.toptal.com/developers/gitignore/api/fish # End of https://www.toptal.com/developers/gitignore/api/fish
# id: gi-patterns-e390e9c720b3dda36906a2b4cb76ffdd
# Created by https://www.toptal.com/developers/gitignore/api/python
# Edit at https://www.toptal.com/developers/gitignore?templates=python
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
### Python Patch ###
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
poetry.toml
# ruff
.ruff_cache/
# LSP config files
pyrightconfig.json
# End of https://www.toptal.com/developers/gitignore/api/python
# ──────────────── Added by agents-init ──────────────────
# agents-init --agents
AGENTS/
# ────────────────────────────────────────────────────────
# ──────────────── Added by agents-init ──────────────────
# agents-init --plugins
docs/devlogs
# ────────────────────────────────────────────────────────
/.cache_ggshield
user-dots
# ──────────────────── Generated Docs Site ───────────────────
docs/site/node_modules/
docs/site/dist/
docs/site/.astro/
docs/site/src/content/docs/
docs/site/src/sidebar.json
/conf.d/uv.env.fish
+568
View File
@@ -0,0 +1,568 @@
# Contributing to fish-config
This is a personal dotfiles repo, but it's run with practices meant to scale
to a team of contributors, not just one person's solo habits. This document
formalizes those practices so they live somewhere durable instead of only in
commit history and conversation memory. It will grow as the project does —
treat it as a living document, not a final word.
## Table of Contents
- [Getting Started](#getting-started)
- [Issues](#issues)
- [Branching & Pull Requests](#branching--pull-requests)
- [Labels](#labels)
- [Commit Conventions](#commit-conventions)
- [Fish Coding Standards](#fish-coding-standards)
- [Opinionated Components](#opinionated-components)
- [Documentation Pipeline](#documentation-pipeline)
- [Testing](#testing)
- [Secrets & Machine-Specific Config](#secrets--machine-specific-config)
- [License](#license)
---
## Getting Started
You'll need [fish 4.x](https://fishshell.com/). Clone the repo and run the
test suite to confirm your environment is sane:
```fish
fish tests/run-tests.fish
```
If you're touching anything under `docs/manual/`, you'll also want `pandoc`,
`python3-yaml`, and Node 24+ to exercise the full doc-build pipeline locally
(see [Documentation Pipeline](#documentation-pipeline)) — otherwise CI will
catch problems on push.
## Issues
Issues live on the Gitea repo. Three templates cover the common cases, each
pre-applying its `Kind/` label; blank issues stay enabled for everything else
— a chore, a refactor, a question, a tracking issue.
| Template | Format | Use it for | Applies |
|---|---|---|---|
| **Bug report** | web form | Something is broken or behaves unexpectedly | `Kind/Bug` |
| **Feature or enhancement request** | markdown | New functionality, or an improvement to what exists | `Kind/Feature` |
| **Documentation issue** | markdown | The manual, man page, `config-help`, or docs site is wrong, missing, or unclear | `Kind/Documentation` |
They live in `.github/ISSUE_TEMPLATE/`, next to the PR template, so the
GitHub mirror offers the same set. The bug report is a Gitea *issue form*
a real web form with required fields — because a bug report missing its
version, reproduction, or full error text can't be acted on, and a form
refuses to submit without them. The other two are markdown templates in the
same comment-guided style as `.github/PULL_REQUEST_TEMPLATE.md`, since what
they ask for is open-ended prose that structure would only get in the way of.
GitHub reads these same files on the mirror, and its schema differs from
Gitea's in two places, so both are pinned to the spelling that works on both
and each file says so in a comment: the chooser config must be `config.yml`
(GitHub ignores `config.yaml`), and `bug.yml` declares `description:` rather
than `about:` (GitHub requires it; Gitea accepts it as an alias). The two
markdown templates keep `about:`, which is correct for their format on both.
### Issue titles
**Issue titles are plain descriptions of the problem, not Conventional
Commits subjects.**
```text
mv clobbers a symlink when the target exists ← yes
fix(mv): prompt before replacing an existing symlink ← no
```
An issue states a problem; a commit states a change. The type and scope that
`fix(mv):` would carry are already on the issue as its `Kind/` and `Area/`
labels, and the conventional subject belongs on the PR that closes it, where
it becomes the commit message. Writing the fix into the title also presumes
one, which is the wrong end to start from for anything still being diagnosed.
### What an issue owes
- **A bug** needs a reproduction someone else can paste and run, starting
from a fresh shell, plus the complete error output. A stale function
definition in a long-lived session is the most common false alarm, so
confirm it survives `exec fish` first. `Status/Need More Info` is where
reports without a reproduction end up.
- **A feature** needs `## Acceptance criteria` — the checkbox list of what
must be true for the issue to close. It is the issue-side counterpart to a
PR's `## Verification`: a definition of done agreed before the work starts
rather than argued about after, and the PR's checks usually grow out of it.
- **A docs issue** needs to name the `docs/manual/**` source, not just the
page where the problem showed up. `docs/fish-config.md` and
`docs/fish-config.1` are generated, and a fix applied there is overwritten
by the next CI run — see [Documentation
Pipeline](#documentation-pipeline).
### Triage
Reporters aren't expected to label anything. Contributors without push access
can't, and the templates apply the `Kind/` label by themselves; the rest is
the maintainer's job when the issue is triaged — add the `Area/` label (the
bug form's **Area** dropdown is how a reporter tells you, since no forge can
map a form field to a label), set a `Priority/` if it isn't ordinary, and
apply `Reviewed/Confirmed` once a bug actually reproduces. See
[Labels](#labels).
When a PR resolves an issue it closes it with a trailing `Closes #N` line —
see [Pull request descriptions](#pull-request-descriptions).
## Branching & Pull Requests
**If you don't have push access to this repo**, fork it and open your PR
from a branch on your fork back to `main` here — everything below about
branch naming and commit hygiene still applies, it just happens on your
fork instead of a branch of this repo directly. The rest of this section
assumes you *do* have push access (maintainers, regular contributors).
- **Branch off `main` before starting work.** Don't accumulate uncommitted
changes directly on `main`. (If you already started editing before
branching, that's fine — create the branch now, before your first commit;
branching doesn't touch the working tree.)
- **Merge target is `main`, via PR.** Contributors open the PR; the repo
owner merges it. Don't merge your own PR.
- **Label every PR.** At minimum one `Kind/` and one `Area/`, same as an
issue — see [Labels](#labels). If you can't set labels, say what the
change is in the description and a maintainer applies them.
- **Don't merge until the `## Verification` checklist is fully checked.**
Unchecked boxes are outstanding manual checks, not decoration. See
[Pull request descriptions](#pull-request-descriptions) below.
- **Prefix in-progress PRs with `WIP:`.** If the branch still has code
changes coming, open it as `WIP: type(scope): description`. Gitea
recognizes the prefix, flags the PR as a draft, and refuses to merge it
until the prefix is removed; drop it once the branch is complete.
`WIP:` signals **more changes are coming** — not "done but unverified".
A finished branch waiting on manual checks is an ordinary PR whose
`## Verification` boxes aren't all ticked yet; that's already the merge
gate above and doesn't need the prefix. The two are independent: a PR
can be WIP with everything ticked, or complete with checks outstanding.
- **Keep feature branches focused.** If you stumble onto something unrelated
to your current task while working (a pre-existing bug, a stray cleanup),
don't fold it into the same commit or PR. Handle it with one of these,
in order of preference:
1. **Separate branch, separate PR, merged to `main` independently.** The
default for anything that doesn't overlap the code your current branch
touches. The two PRs review and merge independently, in either order.
2. **Separate branch and PR, then sync `main` back into your feature
branch** once it merges. Use this only when the unrelated fix actually
touches the same file/function as your feature branch, or your feature
branch depends on the corrected behavior to work or test correctly.
3. **Commit directly to `main`.** Reserved for changes too small to
justify a branch, or genuinely urgent fixes. **Always ask for explicit
approval before doing this** — there's no standing exception, no matter
how trivial the change looks.
### Pull request descriptions
Fill in `.github/PULL_REQUEST_TEMPLATE.md` — Gitea pre-loads it into the
description box when you open a PR. Every PR carries, in this order:
- **`## Summary`** — what changed and why, as a short paragraph, 2-5
bullets, or both. Name concrete paths and identifiers in backticks, and
explain the reasoning rather than restating the diff.
- **Optional `##` sections** — add what the change actually needs
(`Root cause`, `Why`, `How it works`, `Behavior`, `Docs`, `Notes`,
`Scope note`, `Opinionated guard (C1-C6)`), and skip them entirely for a
straightforward change. A breaking change (title ending in `!` before
the colon) must include `## ⚠️ Breaking Change` with the migration path.
- **`## Verification`** — always last. Every check this change needs, as a
checkbox list, each with the exact command and its expected result.
A **checked** box means verified, whether programmatically (test suite,
linter, docs verifier, CI) or by hand; check those off before opening the
PR. An **unchecked** box is an outstanding manual check the reviewer
still has to perform — leave anything you couldn't verify yourself
unchecked rather than dropping it.
**This list is the merge gate: a PR isn't merged until every box is
checked.** Only list checks that can actually be resolved — one nobody
can run blocks the PR indefinitely. Put genuinely unverifiable caveats,
assumptions, and known limitations in `## Notes` instead, where they
inform the review without gating it.
When a PR resolves a tracked issue, close it with a trailing `Closes #42`
line at the end of `## Summary` — not at the very bottom of the body, since
`## Verification` is always last. `Fixes #N` and `Resolves #N` behave
identically. Repeat the keyword for each issue (`Closes #42, closes #43`); a
bare `#43` is only a link and won't close anything. To point at a related
issue that should stay open, drop the keyword and use `Refs #42`. Leave the
line out entirely when no issue is involved.
## Labels
**Every issue and every pull request carries exactly one `Kind/` label and at
least one `Area/` label.** Everything else is optional, and most of it is
applied by a maintainer at triage rather than by whoever opened the thing.
Labels are scoped: the `Group/Name` form renders as a two-tone chip in Gitea,
and for the three *exclusive* groups below Gitea enforces one-at-a-time by
swapping the old label out when you apply a new one.
### `Kind/` — what this is
Required, and by convention exactly one. Gitea doesn't enforce one-of here,
so pick the dominant character of the change instead of stacking two.
| Label | For |
|---|---|
| `Kind/Bug` | Something is not working |
| `Kind/Feature` | New functionality |
| `Kind/Enhancement` | Improves functionality that already exists |
| `Kind/Documentation` | Documentation changes |
| `Kind/Testing` | The test suite itself |
| `Kind/Refactor` | Restructures code without changing behavior |
| `Kind/Chore` | Tooling, dependencies, housekeeping |
| `Kind/Performance` | Makes existing behavior faster or lighter |
| `Kind/Security` | A security issue |
These deliberately mirror the Conventional Commits types in [Commit
Conventions](#commit-conventions), so a PR's label and its title agree:
`fix``Kind/Bug`, `feat``Kind/Feature` or `Kind/Enhancement`, `docs`
`Kind/Documentation`, `test``Kind/Testing`, `refactor`
`Kind/Refactor`, `chore``Kind/Chore`, `perf``Kind/Performance`.
### `Area/` — what it touches
Required, and non-exclusive on purpose: a change that adds a function, its
completions, and a manual entry gets all three.
| Label | Covers |
|---|---|
| `Area/Functions` | `functions/` |
| `Area/Completions` | `completions/` |
| `Area/Config` | `config.fish`, `conf.d/` — startup and environment |
| `Area/Docs` | `docs/manual/` and the generated manual, man page, and site |
| `Area/Tests` | `tests/` |
| `Area/CI` | `.github/workflows/` and repository automation |
| `Area/Integrations` | `integrations/` |
| `Area/Prompt & Theme` | `themes/` and prompt appearance |
| `Area/Components` | The opinionated-component system (C1-C6) |
| `Area/Scripts` | `scripts/` |
`Area/` is what makes the tracker searchable: it answers "what's still
outstanding in the docs pipeline?" in a way `Kind/` never can. Two edges
worth naming — `Area/Docs` covers the documentation *and its pipeline*, so
`README.md` and this file count even though they sit outside `docs/`; and
`Area/Components` is for the C1-C6 machinery itself, not for every function
that happens to carry a `# COMPONENT` header.
### `Compat/Breaking`
Applied to **any PR whose title carries `!` before the colon**, and to any
issue proposing a change that would. It travels with the `## ⚠️ Breaking
Change` section that such a PR must already include — see [Pull request
descriptions](#pull-request-descriptions).
### `Priority/` — exclusive, maintainer-applied
`Priority/Critical`, `Priority/High`, `Priority/Medium`, `Priority/Low`.
**No priority label means ordinary priority.** Labeling everything defeats
the point, so leave it off unless the item is genuinely more or less urgent
than the rest of the queue.
### `Reviewed/` — exclusive, maintainer-applied
`Reviewed/Confirmed` goes on a bug that has actually been reproduced —
that's the signal separating a report from a known defect.
`Reviewed/Duplicate`, `Reviewed/Invalid`, and `Reviewed/Won't Fix` accompany
closing an issue, always with a comment saying why; a close with only a
label on it is not an explanation.
### `Status/` — exclusive, maintainer-applied
`Status/Blocked`, `Status/Need More Info`, `Status/Abandoned`. These describe
the item's current state, so remove one as soon as it stops being true — a
stale `Status/Need More Info` on an issue that got its answer is worse than
no label, because it reads as still waiting.
### `good first issue` and `help wanted`
Invitations to contributors, applied by a maintainer. Both are deliberately
**unscoped**: they'd be a natural fit under `Status/`, but that group is
exclusive, and an issue is quite often both blocked on something *and* open
for someone to pick up. Keeping them outside the group lets them coexist
with a real status.
Use `good first issue` for work that is genuinely self-contained — a clear
acceptance criterion, one or two files, no need to understand the
opinionated-component system first.
### The GitHub mirror
The repo is mirrored to
[github.com/rootiest/fish-config](https://github.com/rootiest/fish-config),
and **the mirror carries the same labels, by the same names**. That isn't
cosmetic: GitHub reads the same `.github/ISSUE_TEMPLATE/` files, and a
`labels:` entry naming a label that doesn't exist on that side is silently
dropped rather than reported.
Mirroring copies files, not repository settings, so labels don't travel with
a push. **`.github/workflows/sync-labels.yml` closes that gap**: it runs
`scripts/sync-labels.py` on a daily schedule, and again whenever the script
itself changes, to make GitHub match Gitea. Manage labels here, in the Gitea
UI, and the mirror catches up within a day — or dispatch the workflow by
hand for it to happen now. Nothing needs doing on the GitHub side.
The sync creates what's missing and corrects color or description drift,
and it deletes an extra label on the mirror **only when no issue or PR there
carries it**; one that's in use is reported with its count and left for a
human to decide about. Run the script with `--dry-run` to see the plan
without changing anything, or `--self-test` to check its diff logic offline
— both are useful before editing it. Because labels are matched by name,
renaming one on Gitea reads as a delete plus a create: the new name appears
on the mirror, and the old one is pruned only if it's unused.
The workflow needs a GitHub token in this repo's Actions secrets as
`GH_MIRROR_TOKEN`, scoped to the mirror with **Issues: read and write**
(GitHub files labels under Issues) and **Pull requests: read** (so the
in-use check sees labels on PRs). The job fails with an explicit message if
it's missing rather than quietly doing nothing.
One behavioral difference to keep in mind: **GitHub has no exclusive
labels.** Gitea enforces one-at-a-time on `Priority/`, `Reviewed/`, and
`Status/` by swapping the old label out; on the mirror those are ordinary
labels and nothing stops two of a group coexisting, so there the one-of rule
holds by convention alone.
Issues and pull requests belong on the canonical Gitea repo — the template
chooser links there first, on both sides. The mirror's tracker stays open so
that a report which lands there anyway isn't lost, not because it's a second
supported front door.
## Commit Conventions
Commit subjects follow [Conventional Commits](https://www.conventionalcommits.org/):
```
type(scope): description
```
Types currently in use in this repo: `feat`, `fix`, `docs`, `test`, `chore`,
`perf`. The scope is usually the function, component, or subsystem touched
(e.g. `feat(help): ...`, `fix(scrub): ...`, `chore(docs): ...`). Look at
`git log` for recent examples before picking a type/scope for something
novel.
## Fish Coding Standards
### File header
Every hand-authored `.fish` file starts with:
```fish
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
```
(A few completion scripts adapted directly from a tool's own upstream
completions keep that tool's original attribution comment instead of this
header — match whichever convention the specific file already follows. New
files use the standard header above.)
### Public function documentation header
Every user-facing function gets a machine-parsed comment header directly
above its `function` line. This header is the single source of truth for
the generated manual (`docs/fish-config.md` / the man page / the docs
site) — see [Documentation Pipeline](#documentation-pipeline) for how it
gets consumed. The parser (`docs/manualtools.py`) recognizes these labels,
all optional except where noted:
| Label | Purpose |
|---|---|
| `CATEGORY` | **Required to appear in the manual at all** — see below. |
| `COMPONENT` | Only for functions gated by the [opinionated-component system](#opinionated-components). |
| `DEPENDENCIES` | Other functions this one calls that a reader may want to look up. |
| `SYNOPSIS` | One-line usage form. |
| `DESCRIPTION` | Prose description; can span multiple paragraphs. |
| `ARGUMENTS` | Flags/positional args, one per line. |
| `EXIT STATUS` | Exit codes and what they mean. |
| `RETURNS` | For functions used for their output/return value rather than exit status. |
| `EXAMPLE` | One or more realistic invocations. |
| `NOTES` | Anything else worth flagging (fallback behavior, caveats, gotchas). |
A full example (`functions/claude.fish`):
```fish
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 12-ai-and-developer-tools
#
# COMPONENT
# aliases/dev-tools
#
# DEPENDENCIES
# agents-init
#
# SYNOPSIS
# claude [ARGS...]
#
# DESCRIPTION
# Wrapper for the claude CLI that ensures the AGENTS/ sub-repository is
# initialized and any agent-made changes are committed before launch.
# ...
```
**`CATEGORY` is the opt-in gate for the manual:** a function with no
`# CATEGORY` line produces no manual entry at all — this is how bundled
plugin internals and prompt guts stay out of user-facing docs without an
exclusion list. `CATEGORY` must exactly match one of the existing
`docs/manual/05-functions/NN-*.md` stubs:
```
01-file-and-directory 08-terminal-management
02-navigation 09-clipboard
03-editors-and-viewers 10-network
04-git-and-version-control 11-pager-and-logging
05-package-management 12-ai-and-developer-tools
06-dependency-management 13-media-and-utilities
07-system-and-monitoring 14-miscellaneous
```
If your function genuinely doesn't fit any of these, add a new
`docs/manual/05-functions/NN-your-category.md` stub (with frontmatter
matching its siblings) rather than force-fitting it into an existing one.
### Private/internal helper functions
Functions named with a leading `_` (e.g. `_agents_init_ensure_gitignore`,
`__fish_config_op_enabled`) are excluded from the manual unconditionally,
regardless of whether they carry a `CATEGORY` line — so they generally don't
have one. They should still carry the standard file header, and a lighter
`SYNOPSIS`/`DESCRIPTION` comment is encouraged wherever the function's
purpose or calling convention isn't obvious from its body, matching the
convention already used across `__fish_config_op_*.fish` and similar files.
### Function declaration
Give every function a `--description`, since it's what shows up in `fish -c
'functions'`/completions and other introspection:
```fish
function my_function --description 'Short, imperative description'
```
### Colored `--help` output
Every function with a `-h`/`--help` flag uses this standardized color
palette (established across the codebase 2026-08-22):
```fish
set -l c_head (set_color --bold cyan) # section headers
set -l c_cmd (set_color --bold) # the command name itself (theme-adaptive)
set -l c_flag (set_color yellow) # flags
set -l c_arg (set_color cyan) # required-argument placeholders
set -l c_dim (set_color brblack) # optional-argument placeholders
set -l c_ok (set_color green) # success/positive status
set -l c_warn (set_color yellow) # warnings
set -l c_err (set_color red) # errors
set -l c_reset (set_color normal)
```
Not every function needs every variable — pull in only the ones your help
text actually uses. Structure the usage block as `Usage:`, then sections
for arguments/flags/examples as needed; see `functions/rand_string.fish` or
any recently-touched function for a full worked example.
## Opinionated Components
Some functionality in this config is classified into one of six toggleable
categories (C1C6: aliases, autoexec, overrides, integrations, logging,
greeting) plus sub-categories, so users can disable pieces of it via
`config-settings` or universal variables. If you're adding something that
shadows a builtin, runs at startup, overrides a key binding/environment
variable, or otherwise falls under an existing category, tag it with a
`# COMPONENT` header (`<category>/<subcategory>`, e.g.
`overrides/key-bindings`) and guard it with `__fish_config_op_enabled`. See
the [README's Minimal Mode section](README.md#minimal-mode) for the full
category list and toggle semantics. Most new functions are *not*
opinionated components — only tag something if it fits an existing
category; this isn't something to force.
## Documentation Pipeline
`docs/manual/` is the single source of truth for the user manual, man page,
and documentation site. **Never hand-edit `docs/fish-config.md` or
`docs/fish-config.1`** — they're generated by `docs/build-manual.py` from
`docs/manual/**` plus every function's doc-header (see above), verified by
`docs/verify-manual.py`, and auto-committed by CI on push to `main`
(`chore(docs): regenerate manual, man page, and component registry`).
If you're changing something under `docs/manual/` directly, or adding a
function whose `CATEGORY`/`COMPONENT` header should surface new content, you
can build and check it locally before pushing:
```fish
python3 docs/build-manual.py --concat -o docs/fish-config.md
python3 docs/verify-manual.py
```
CI runs the same verification and regenerates the site/man page — a broken
manual won't get published, but running it locally saves a round trip.
Write doc-headers as plain text — no backticks. `-a/--all`,
`__fish_config_op_aliases` and `~/.config/fish/config.fish` are typed
bare, because the header is also read as-is by `config-help` and by
anyone opening the file. `docs/codespans.py` adds the inline code spans
when it renders, so the SSOT never carries them; see
`docs/site/README.md` for which shapes it recognises. That pass runs for
every output — the site, the man page and `config-help` — so a token is
typeset the same way wherever it is read.
Two rules apply to backticks you write under `docs/manual/` as well:
- **Never inside an indented block.** A four-space block is verbatim in
every renderer, so a backtick there is a literal character on the page
rather than markup.
- **Never wrapped across a line break.** Markdown accepts a span split
over two lines, but `config-help` pairs backticks one line at a time
and would show the halves literally. Reflow the sentence instead.
`docs/verify-manual.py` enforces both.
## Testing
```fish
fish tests/run-tests.fish
```
Runs before every push and gates the documentation build in CI. Two phases:
1. **Syntax lint** — every tracked `.fish` file (`config.fish`, `functions/`,
`conf.d/`, `completions/`, `integrations/`) is checked with `fish -n`.
2. **Sandboxed functional checks** — the config is copied into a throwaway
`HOME`/`XDG_CONFIG_HOME` sandbox (never this checkout itself, since it
doubles as a real `~/.config/fish`) and loaded as an isolated interactive
session. `tests/functional.fish` then runs against foundational behavior:
XDG/PATH/CDPATH setup, key bindings, abbreviations, core functions, the
opinionated-component registry, and more.
To add a new functional check, add a `test_*` function to
`tests/functional.fish` — it's picked up automatically by
`functional_test_main`, no registration needed. Return 0 on pass, non-zero
on fail; print a short diagnostic on failure.
## Secrets & Machine-Specific Config
**Nothing containing credentials, tokens, personal identifiers, or a
specific machine's paths belongs in this repo — not even in a PR.** That
kind of thing lives in each user's own private overlay
(`~/.config/.user-dots/fish/secrets.fish` and `local.fish`), which is
git-ignored by design. If you're writing something that needs a secret or a
machine-specific path, source it from there rather than hardcoding it.
Everything else — general-purpose, reusable across machines — belongs in
the tracked repo as normal. See [README's Personalization
section](README.md#personalization) and
[`docs/manual/07-customization.md`](docs/manual/07-customization.md) for the
full mechanics.
## License
This project is licensed under AGPL-3.0-or-later (see `LICENSE`). Every new
hand-authored file needs the SPDX header shown in [File
header](#file-header) above.
+197 -27
View File
@@ -5,13 +5,18 @@ built around a Catppuccin Mocha aesthetic with a curated set of modern
CLI tool integrations, smart shell functions, and a heavily customized CLI tool integrations, smart shell functions, and a heavily customized
abbreviation system for keyboard-driven workflows. abbreviation system for keyboard-driven workflows.
📖 **[Documentation site](https://fish.rootiest.fyi/)**
## Table of Contents ## Table of Contents
- [Overview](#overview) - [Overview](#overview)
- [Session Logging](#session-logging)
- [Documentation](#documentation) - [Documentation](#documentation)
- [Installation](#installation) - [Installation](#installation)
- [Personalization](#personalization) - [Personalization](#personalization)
- [Minimal Mode](#minimal-mode) - [Minimal Mode](#minimal-mode)
- [Testing](#testing)
- [Contributing](#contributing)
- [Attribution](#attribution) - [Attribution](#attribution)
- [License](#license) - [License](#license)
@@ -22,24 +27,131 @@ abbreviation system for keyboard-driven workflows.
This config layers on top of the CachyOS base Fish configuration and adds: This config layers on top of the CachyOS base Fish configuration and adds:
- **Catppuccin Mocha** theming throughout (prompt, FZF, syntax highlighting) - **Catppuccin Mocha** theming throughout (prompt, FZF, syntax highlighting)
- **Starship** prompt with VI key bindings - **Starship** prompt with VI key bindings; Catppuccin Mocha nim-style fallback prompt when Starship is absent or C3 overrides are disabled
- **Fisher** plugin manager bootstrapped automatically; manages `sponge` (failed-command history filter); FZF bindings, Catppuccin theme, done, autopair, and puffer-fish are bundled directly with the config as customized versions - **Fisher** plugin manager bootstrapped automatically; manages `sponge` (failed-command history filter); FZF bindings, Catppuccin theme, done, autopair, and puffer-fish are bundled directly with the config as customized versions
- **Smart CLI wrappers** that prefer modern tools (`eza`, `bat`, `btop`, `dust`, `prettyping`) with graceful fallbacks - **Smart CLI wrappers** that prefer modern tools (`eza`, `bat`, `btop`, `dust`, `prettyping`) with graceful fallbacks
- **Auto Python venv** activation on directory change (direnv-aware) - **Auto Python venv** activation on directory change (direnv-aware)
- **Kitty terminal** deep integration for splits, tabs, and SSH - **Kitty terminal** deep integration for splits, tabs, and SSH
- **Named background jobs** — `jobrunner` (short: `jr`) starts, lists, inspects, re-attaches to, and kills detached tasks via `tmux` or GNU `screen`, so long-running work survives closing the shell
- **Optional session logging** — terminal scrollback, multiplexer panes (tmux/zellij), and AUR-helper output can be captured to `~/.terminal_history`; **off by default**, opt in when you want it (see the caution below and [Session Logging](#session-logging))
- **AI workflow** helpers for Claude and Antigravity session management - **AI workflow** helpers for Claude and Antigravity session management
- **WakaTime** shell activity tracking - **WakaTime** shell activity tracking
- **Opt-out toggles** for every opinionated component — see [Minimal Mode](#minimal-mode) - **Opt-out toggles** for every opinionated component — see [Minimal Mode](#minimal-mode)
> [!CAUTION]
> **This configuration *can* log your terminal sessions to disk.** Logging is
> **off by default** — but once enabled it silently captures terminal output to
> `~/.terminal_history`: Kitty scrollback when a window closes, live tmux pane
> streams, zellij pane snapshots on exit, and full `paru`/`yay` output. These
> logs can contain command output, file contents, and anything else printed to
> your terminal. Nothing is sent off your machine, but the files persist
> locally until pruned.
>
> To turn logging on, set the C5 category variable:
>
> ```fish
> set -U __fish_config_op_logging on
> ```
>
> Or run **`config-settings`** for an interactive menu to flip logging (and any
> other opinionated category) on or off — no variable names to remember.
>
> This takes effect immediately in every open shell. See [Session Logging](#session-logging)
> for exactly what is captured and where, and [Minimal Mode](#minimal-mode) for the
> full set of opt-out toggles.
---
## Session Logging
This config can capture terminal output to `~/.terminal_history` (override with
`$SCROLLBACK_HISTORY_DIR`) so you can search back through past sessions. It is
**off by default** — opt in with `set -U __fish_config_op_logging on`. Once
enabled, five sources feed it:
| Source | When it captures | Log file |
|---|---|---|
| Kitty scrollback | When a Kitty window/tab closes | `scrollback_<timestamp>.log` |
| tmux pane | Continuously while the pane is open (`pipe-pane`) | `tmux_<session>-w<win>-p<pane>_<timestamp>.log` |
| zellij pane | Snapshot taken on **clean** shell exit (`dump-screen`) | `zellij_<session>-p<pane>_<timestamp>.log` |
| `paru` wrapper | Every `paru` invocation | `paru_<timestamp>.log` |
| `yay` wrapper | Every `yay` invocation | `yay_<timestamp>.log` |
Old logs are pruned automatically to stay within `$SCROLLBACK_HISTORY_MAX_FILES`
(default 100) per source, and empty/trivial captures are discarded.
> **zellij caveat:** zellij has no continuous pipe like tmux, so its pane is
> snapshotted only on a clean shell exit (`exit`/Ctrl-D). Closing a pane or
> quitting zellij directly tears down the pane/server before it can be dumped,
> so those sessions are not logged. End with `exit` to guarantee a log.
**These logs can contain secrets** — anything printed to your terminal (command
output, file dumps, tokens echoed to stdout) ends up in them. They never leave
your machine, but treat `~/.terminal_history` as sensitive.
All of it is controlled by a single universal variable:
```fish
set -U __fish_config_op_logging on # enable; takes effect in every open shell
set -U __fish_config_op_logging off # disable again
set -Ue __fish_config_op_logging # erase — back to the default (off)
```
Unlike the other categories, C5 is opt-in: an unset variable means off, and
`__fish_config_opinionated` cannot turn it on for you.
Prefer an interactive interface? Run **`config-settings`** for a full-screen
picker that flips logging — and every other opinionated category — on or off
per session or universally, without memorizing variable names.
Disabling (or leaving it unset) also removes the generated `paru`/`yay` log
wrappers and tells the Kitty watcher to skip capture via a sentinel file — no
shell or terminal restart required. Logging is category **C5** in
[Minimal Mode](#minimal-mode); `set -U __fish_config_opinionated 0` keeps it
off along with everything else.
The Kitty scrollback capture is provided by a watcher script that fish-config can
install and manage for you. Inside Kitty, if it isn't set up yet, you'll see a
one-time-per-session reminder. Manage it with:
| Command | Action |
|---|---|
| `kitty-logging install` | Symlink the watcher into your Kitty config and wire it into `kitty.conf` |
| `kitty-logging uninstall` | Remove the managed block and the watcher symlink |
| `kitty-logging status` | Show whether it's wired, the watcher version, and C5 state |
| `kitty-logging dismiss` | Stop the per-session reminder without installing |
`install` adds a clearly-marked managed block to `kitty.conf` and comments out
any conflicting `watcher` line. It affects **new** Kitty windows (existing
windows keep their current watcher until restarted). With C5 logging off the
watcher is inert without needing to be uninstalled, and the reminder stays
silent until you enable logging.
--- ---
## Documentation ## Documentation
### [📖 Full Documentation Wiki](docs/wiki/index.md) ### [📖 Documentation Site](https://fish.rootiest.fyi/)
A multi-page Markdown wiki auto-generated from the single source file `docs/fish-config.md` A Starlight-powered site rebuilt on every push to `main`. It covers
on every push to `main`. It covers configuration variables, key bindings, abbreviations, configuration variables, key bindings, abbreviations, all functions, the
all functions, the dependency catalog, customization, and more. dependency catalog, customization, and more, with full-text search. Also
published as [`llms.txt`](https://fish.rootiest.fyi/llms.txt) (with
`llms-full.txt` and `llms-small.txt` variants) for AI agents and other
LLM tooling.
Contributing to the docs? There are two sources, split by content type:
- **Function documentation** comes from the man-page-style comment header
above each function in `functions/*.fish`. Edit the function; the entry
and its site page are generated from the header.
- **Everything else** lives under `docs/manual/**`.
- **Testing, Contributing, Attribution, and License** are pulled straight
from this README (the sections below) rather than authored twice — edit
them here and the manual, man page, and site all pick up the change.
Never edit the generated `docs/fish-config.md` — it's rebuilt from all
three sources and any hand-edits are discarded.
To browse the docs from the terminal: To browse the docs from the terminal:
@@ -47,10 +159,10 @@ To browse the docs from the terminal:
|---|---| |---|---|
| `help config` | Open the terminal manual in the best available pager | | `help config` | Open the terminal manual in the best available pager |
| `help config <keyword>` | Jump directly to a section matching the keyword | | `help config <keyword>` | Jump directly to a section matching the keyword |
| `help config --html` | Open the pre-built HTML docs in the default browser | | `help config --html` | Open the documentation site in the default browser |
| `help config <keyword> --html` | Open HTML docs at the matching section anchor |
| `help config --man` | Open the compiled man page via `man -l` | | `help config --man` | Open the compiled man page via `man -l` |
| `help config <keyword> --man` | Open the man page jumping to the nearest match | | `help config <keyword> --man` | Open the man page jumping to the nearest match |
| `repo-open` | Open this repo's web page in the browser (deep-links to the current branch and sub-directory) |
The pager falls back through: **ov****bat****man -l****less****cat**. The pager falls back through: **ov****bat****man -l****less****cat**.
@@ -72,7 +184,9 @@ git clone https://git.rootiest.dev/rootiest/fish-config.git ~/.config/fish
Then open a new Fish shell — Fisher will be installed automatically on first launch and the Catppuccin Mocha theme will be applied. All plugin functionality is bundled directly with this config and requires no additional installation. Then open a new Fish shell — Fisher will be installed automatically on first launch and the Catppuccin Mocha theme will be applied. All plugin functionality is bundled directly with this config and requires no additional installation.
A [chezmoi](https://www.chezmoi.io/) dotfile manager is also configured — secrets are sourced from `~/.config/.user-dots/fish/secrets.fish` and excluded from version control. A [chezmoi](https://www.chezmoi.io/) dotfile manager is also configured — secrets are kept in a private overlay directory (see [Personalization](#personalization)) and excluded from version control.
**External requirements.** Everything degrades gracefully if a tool is missing, with two exceptions worth calling out. `python3` is required by the documentation pipeline and by `config-settings`, whose TUI is drawn with the stdlib `curses` module. That module ships with CPython on Arch, Fedora and a full Debian/Ubuntu `python3`; `python3-minimal` alone does **not** carry `_curses`, so install the complete `python3` package there. `config-settings` checks for both and tells you which is missing rather than failing inside the renderer.
> [!IMPORTANT] > [!IMPORTANT]
> `config.fish` ends with a `return` sentinel guard. Any lines appended **after** it by a tool's setup command will silently have no effect. Many tools (starship, zoxide, mise, etc.) offer a setup command that appends an `init | source` line to your `config.fish` — all integrations are managed through `conf.d/` files instead. If you add a new tool and its shell integration appears to do nothing, check whether its setup command appended an init line to the bottom of `config.fish` and create a `conf.d/<tool>.fish` file for it instead. > `config.fish` ends with a `return` sentinel guard. Any lines appended **after** it by a tool's setup command will silently have no effect. Many tools (starship, zoxide, mise, etc.) offer a setup command that appends an `init | source` line to your `config.fish` — all integrations are managed through `conf.d/` files instead. If you add a new tool and its shell integration appears to do nothing, check whether its setup command appended an init line to the bottom of `config.fish` and create a `conf.d/<tool>.fish` file for it instead.
@@ -91,12 +205,18 @@ Pull the latest changes from upstream without needing a configured git remote:
## Personalization ## Personalization
Sensitive credentials and machine-specific paths are kept out of version control via a secondary private directory at `~/.config/.user-dots/fish/`. Two files are sourced automatically by `config.fish` if they exist: Sensitive credentials and machine-specific paths are kept out of version control via a private overlay directory. The path defaults to `~/.config/.user-dots/fish/` but can be changed by setting a universal variable:
```fish
set -U __fish_user_dots_path /path/to/your/dots/fish
```
`config.fish` sources `local.fish` from that directory. `local.fish` is responsible for sourcing its own `secrets.fish` companion:
``` ```
~/.config/.user-dots/fish/ $__fish_user_dots_path/
├── secrets.fish # API keys, tokens, passwords, personal identifiers ├── secrets.fish # API keys, tokens, passwords, personal identifiers
└── local.fish # Machine-specific paths and environment variables └── local.fish # Machine-specific paths, env vars, and sourcing secrets
``` ```
### secrets.fish ### secrets.fish
@@ -148,37 +268,43 @@ abbr -a dcw 'docker context use work-server'
### How it works ### How it works
`config.fish` sources both files with an existence check so the public config works cleanly on any machine that doesn't have the private repo: `config.fish` sources only `local.fish` with an existence check so the public config works cleanly on any machine without the private repo. `local.fish` is responsible for sourcing its own `secrets.fish`:
```fish ```fish
if test -f $HOME/.config/.user-dots/fish/secrets.fish # config.fish resolves the path, then sources local.fish
source $HOME/.config/.user-dots/fish/secrets.fish set -q __fish_user_dots_path
end or set -l __fish_user_dots_path "$XDG_CONFIG_HOME/.user-dots/fish"
test -f "$__fish_user_dots_path/local.fish"
if test -f $HOME/.config/.user-dots/fish/local.fish and source "$__fish_user_dots_path/local.fish"
source $HOME/.config/.user-dots/fish/local.fish
end
``` ```
For convenience, a git-ignored `user-dots` symlink in the fish config directory is pointed at `$__fish_user_dots_path` on startup, so the overlay can be browsed from `~/.config/fish/`. It is recreated if missing and repointed if the path variable changes. Creation is a C2 startup side-effect (`__fish_config_op_autoexec`); it only ever manages a symlink and never clobbers a real file or directory at that path.
To opt out, set `__fish_user_dots_symlink` to a falsy value (or toggle **Dots link** off on the **Paths** page of `config-settings`). Disabling it stops the symlink being generated and removes any existing one immediately — honoured regardless of the C2 master switch.
`fish_variables` (which fish auto-manages and may contain universal variable state) is excluded from this repo via `.gitignore`. `fish_variables` (which fish auto-manages and may contain universal variable state) is excluded from this repo via `.gitignore`.
--- ---
## Minimal Mode ## Minimal Mode
Everything opinionated in this config — command shadows, startup side-effects, key and environment overrides, terminal integrations, logging, and the first-run greeting — is active by default but can be switched off with universal variables. Six category toggles and one master switch are available: Everything opinionated in this config — command shadows, startup side-effects, key and environment overrides, terminal integrations, and the first-run greeting — is active by default but can be switched off. Logging (C5) is the exception: it is **opt-in**, off until you explicitly enable it.
> **The easy way — `config-settings`:** Run `config-settings` for an interactive TUI that manages settings across four pages — **Universal** and **Session** (the opinionated category toggles below, persistent or per-shell), **Sponge** (history-scrubbing: delay, exit codes, purge-on-exit, and extra sensitive variable names), and **Paths** (scrollback log dir, max files, and the user-dots path) — without typing a single variable name. Navigate with the arrow keys (or `h`/`j`/`k`/`l`); toggle rows step OFF ← DEFAULT → ON, value rows edit inline with `Enter` and reset with `←`. `Enter` on a category opens its sub-categories, `/` filters the page — reaching into sub-categories too, listed as `Category Sub` — `?` opens a help overlay, `Tab`/`Shift-Tab` cycle pages, and `q` applies your edits and quits. Edits are collected as you make them and written in one batch on exit; the status bar shows the pending count. The panel is drawn with Python's stdlib `curses`, so it resizes with the terminal and never flickers — see [Installation](#installation) for the `python3` requirement.
If you'd rather set them by hand, each category is controlled by a universal variable. Six category toggles and one master switch are available:
| Variable | Disables | | Variable | Disables |
|---|---| |---|---|
| `__fish_config_op_aliases` | Command shadows: `ls`→eza, `cat`→bat, `cd`→zoxide, `rm`→trash, `top`→btop, and friends; `grep`/`cp`/`mv`/`wget` flag injection | | `__fish_config_op_aliases` | Command shadows: `ls`→eza, `cat`→bat, `cd`→zoxide, `rm`→trash, `top`→btop, `edit`→multi-editor launcher, and friends; `grep`/`cp`/`mv`/`wget` flag injection |
| `__fish_config_op_autoexec` | Startup side-effects: Fisher bootstrap, theme apply, `paru`/`yay` wrapper generation, auto venv activation, WakaTime hook | | `__fish_config_op_autoexec` | Startup side-effects: Fisher bootstrap, theme apply, `paru`/`yay` wrapper generation, auto venv activation, WakaTime hook, auto-pull background fast-forward |
| `__fish_config_op_overrides` | Vi mode, `exit``smart_exit`, `$PAGER`/`$MANPAGER`/`$CDPATH`, bang-bang history expansion, autopair, puffer, Starship prompt, theme colors | | `__fish_config_op_overrides` | Vi mode, `exit``smart_exit`, `$PAGER`/`$MANPAGER`/`$CDPATH`/`XDG`/`PATH`, `$DO_NOT_TRACK`/`$DISABLE_TELEMETRY`, bang-bang history expansion, autopair, puffer, Starship prompt, theme colors |
| `__fish_config_op_integrations` | Kitty/WezTerm window abbreviations, `done` notifications, `spwin`/`tab`/`split`, `hist`, `logs`, `upgrade`, WakaTime | | `__fish_config_op_integrations` | Kitty/WezTerm window abbreviations, `done` notifications, `spwin`/`tab`/`split`, `hist`, `logs`, `upgrade`, WakaTime |
| `__fish_config_op_logging` | Scrollback capture on exit, `paru`/`yay` AUR log wrappers, Kitty watcher capture (sentinel-file coordinated) | | `__fish_config_op_logging` | **Opt-in — off unless explicitly enabled.** Scrollback capture on exit, tmux `pipe-pane` pane logging, zellij `dump-screen` capture on exit, `paru`/`yay` AUR log wrappers, Kitty watcher capture (sentinel-file coordinated) |
| `__fish_config_op_greeting` | Per-session `fish_greeting` (suppresses distro greetings such as CachyOS fastfetch by overriding with an empty function); first-run welcome banner | | `__fish_config_op_greeting` | Per-session `fish_greeting` (suppresses distro greetings such as CachyOS fastfetch by overriding with an empty function); first-run welcome banner |
| `__fish_config_opinionated` | Master switch — all six categories at once | | `__fish_config_opinionated` | Master switch — disables all six categories at once (it is a master *off* switch; it cannot enable opt-in C5 logging) |
Set any of them to a falsy value (`0`, `false`, `no`, `off`, `n`) to disable; erase the variable to re-enable: Set any of them to a falsy value (`0`, `false`, `no`, `off`, `n`) to disable; erase the variable to re-enable. An explicit per-category truthy value overrides a falsy master switch, so you can disable everything with `__fish_config_opinionated=0` and selectively re-enable individual categories:
```fish ```fish
# Plain shell: disable everything opinionated # Plain shell: disable everything opinionated
@@ -187,17 +313,61 @@ set -U __fish_config_opinionated 0
# Or pick a single category, e.g. keep integrations but drop command shadows # Or pick a single category, e.g. keep integrations but drop command shadows
set -U __fish_config_op_aliases off set -U __fish_config_op_aliases off
# Minimal mode but keep the greeting (per-category overrides master)
set -U __fish_config_opinionated 0
set -U __fish_config_op_greeting 1
# Opt in to session logging (C5 is off by default)
set -U __fish_config_op_logging on
# Back to full flavor # Back to full flavor
set -Ue __fish_config_opinionated set -Ue __fish_config_opinionated
set -Ue __fish_config_op_greeting
``` ```
Command shadows react immediately; bindings, prompt, and abbreviations take effect in new shells. With aliases disabled, `rm` deletes permanently again instead of trashing. See `help config opinionated` for the full component list. Command shadows react immediately; bindings, prompt, and abbreviations take effect in new shells. With aliases disabled, `rm` deletes permanently again instead of trashing. See `help config opinionated` for the full component list.
Each category further sub-divides into two to six sub-categories with
their own `__fish_config_op_<category>_<subcategory>` toggles (e.g.
`__fish_config_op_aliases_filesystem`), following the exact same
truthy/falsy/unset cascade one level deeper. Run `config-settings` and
press Enter on a category row to browse and toggle its sub-categories —
or press `/` and type, which searches sub-categories across every
category at once and lists the hits as `Category Sub`. Or see the
[Components Reference](https://fish.rootiest.fyi/08-components-reference/)
for the full sub-category list per category.
---
## Testing
```fish
fish tests/run-tests.fish
```
Runs before every push (and gates the [documentation build](.github/workflows/ci.yml) in CI, so a broken config can't get published): syntax-lints every `.fish` file, then loads the config in an isolated `HOME`/XDG sandbox — never this checkout itself, since it doubles as a real `~/.config/fish` — and runs functional checks against foundational behavior (XDG/PATH/CDPATH setup, key bindings, abbreviations, core functions, the opinionated-component registry, and more).
---
## Contributing
Interested in contributing? See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the
branching/PR workflow, commit conventions, fish coding standards, and the
docs/testing pipeline this repo follows.
**Preferred forge:** [git.rootiest.dev/rootiest/fish-config](https://git.rootiest.dev/rootiest/fish-config)
is the base repository. [github.com/rootiest/fish-config](https://github.com/rootiest/fish-config)
is a push-mirror of it — identical content, but one-way and read-only from a
contributor's perspective. Branches, forks, and merges made on the GitHub
side aren't fed back upstream, so they risk being silently overwritten by
the next mirror push. Until two-way sync exists, please fork, branch, and
open issues/PRs from the Gitea repository rather than the GitHub mirror.
--- ---
## Attribution ## Attribution
The core of the [Zoxide integration](docs/wiki/2-path-setup.md) in this repository was originally adapted from the [icezyclon/zoxide.fish](https://github.com/icezyclon/zoxide.fish) plugin (MIT Licensed) and has since been heavily customized for performance and Fish 4.x compatibility. The core of the [Zoxide integration](https://fish.rootiest.fyi/02-path-setup/) in this repository was originally adapted from the [icezyclon/zoxide.fish](https://github.com/icezyclon/zoxide.fish) plugin (MIT Licensed) and has since been heavily customized for performance and Fish 4.x compatibility.
--- ---
+21
View File
@@ -0,0 +1,21 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Completions for agents-vault.
complete -c agents-vault -f
complete -c agents-vault -s h -l help -d 'Show help message'
complete -c agents-vault -l link -d "Ensure this project's memory link only"
complete -c agents-vault -l push -d 'Commit and push to the vault remote'
complete -c agents-vault -l restore -d 'Relink everything possible, report the rest'
complete -c agents-vault -l status -d 'Show entries, link health, remote, orphans'
# --adopt takes an existing vault slug, so offer the entries that are
# actually there; the vault may not exist yet, in which case this is empty.
# -A because a dot-led slug is legitimate (a relative-path remote keys as
# ..-mirror), and an entry that cannot be completed reads as one that is
# not there.
complete -c agents-vault -l adopt -r -a '(command ls -1A (_agents_vault_dir)/projects 2>/dev/null)' -d 'Bind this project to an existing vault entry'
complete -c agents-vault -l remote -r -d 'Set the vault remote URL'
complete -c agents-vault -s v -l verbose -d 'Print all per-step output (default)'
complete -c agents-vault -s q -l quiet -d 'Print one summary line only if changed'
complete -c agents-vault -s s -l silent -d 'Suppress all output; errors only'
+33
View File
@@ -0,0 +1,33 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# Completions for the `auto-pull` registry command.
function __auto_pull_registered
set -l list "$XDG_CONFIG_HOME/.user-dots/fish/auto-pull.list"
test -r "$list"; or return
for l in (command cat "$list" 2>/dev/null)
test -n "$l"; or continue
printf '%s\t%s\n' (path basename "$l") "$l"
end
end
set -l subcmds list add remove status
# Subcommands (only as the first argument).
complete -c auto-pull -f -n "not __fish_seen_subcommand_from $subcmds" \
-a list -d 'Show registered repos'
complete -c auto-pull -f -n "not __fish_seen_subcommand_from $subcmds" \
-a add -d "Register a repo (default: current)"
complete -c auto-pull -f -n "not __fish_seen_subcommand_from $subcmds" \
-a remove -d 'Unregister a repo'
complete -c auto-pull -f -n "not __fish_seen_subcommand_from $subcmds" \
-a status -d 'Show enabled state and registry path'
complete -c auto-pull -f -n "not __fish_seen_subcommand_from $subcmds" \
-s h -l help -d 'Show help'
# `add` takes a directory path.
complete -c auto-pull -n "__fish_seen_subcommand_from add" -a '(__fish_complete_directories)'
# `remove` completes registered repo basenames.
complete -c auto-pull -f -n "__fish_seen_subcommand_from remove" -a '(__auto_pull_registered)'
+4 -5
View File
@@ -3,7 +3,7 @@
function __bd_debug function __bd_debug
set -l file "$BASH_COMP_DEBUG_FILE" set -l file "$BASH_COMP_DEBUG_FILE"
if test -n "$file" if test -n "$file"
echo "$argv" >> $file echo "$argv" >>$file
end end
end end
@@ -108,7 +108,6 @@ function __bd_requires_order_preservation
return 1 return 1
end end
# This function does two things: # This function does two things:
# - Obtain the completions and store them in the global __bd_comp_results # - Obtain the completions and store them in the global __bd_comp_results
# - Return false if file completion should be performed # - Return false if file completion should be performed
@@ -215,18 +214,18 @@ end
# so we can properly delete any completions provided by another script. # so we can properly delete any completions provided by another script.
# Only do this if the program can be found, or else fish may print some errors; besides, # Only do this if the program can be found, or else fish may print some errors; besides,
# the existing completions will only be loaded if the program can be found. # the existing completions will only be loaded if the program can be found.
if type -q "bd" if type -q bd
# The space after the program name is essential to trigger completion for the program # The space after the program name is essential to trigger completion for the program
# and not completion of the program name itself. # and not completion of the program name itself.
# Also, we use '> /dev/null 2>&1' since '&>' is not supported in older versions of fish. # Also, we use '> /dev/null 2>&1' since '&>' is not supported in older versions of fish.
complete --do-complete "bd " > /dev/null 2>&1 complete --do-complete "bd " >/dev/null 2>&1
end end
# Remove any pre-existing completions for the program since we will be handling all of them. # Remove any pre-existing completions for the program since we will be handling all of them.
complete -c bd -e complete -c bd -e
# this will get called after the two calls below and clear the $__bd_perform_completion_once_result global # this will get called after the two calls below and clear the $__bd_perform_completion_once_result global
complete -c bd -n '__bd_clear_perform_completion_once_result' complete -c bd -n __bd_clear_perform_completion_once_result
# The call to __bd_prepare_completions will setup __bd_comp_results # The call to __bd_prepare_completions will setup __bd_comp_results
# which provides the program's completion choices. # which provides the program's completion choices.
# If this doesn't require order preservation, we don't use the -k flag # If this doesn't require order preservation, we don't use the -k flag
+103
View File
@@ -0,0 +1,103 @@
# fish completion for copilot
# Generated by `copilot completion fish`. Do not edit by hand.
complete -c copilot -n __fish_use_subcommand -f -a login -d 'Authenticate with Copilot'
complete -c copilot -n __fish_use_subcommand -f -a help -d 'Display help information'
complete -c copilot -n __fish_use_subcommand -f -a init -d 'Initialize Copilot instructions'
complete -c copilot -n __fish_use_subcommand -f -a update -d 'Download the latest version'
complete -c copilot -n __fish_use_subcommand -f -a version -d 'Display version information'
complete -c copilot -n __fish_use_subcommand -f -a plugin -d 'Manage plugins'
complete -c copilot -n __fish_use_subcommand -f -a mcp -d 'Manage MCP servers'
complete -c copilot -n __fish_use_subcommand -f -a completion -d 'Generate a shell completion script'
complete -c copilot -l version -s v -f -d 'show version information'
complete -c copilot -l interactive -s i -r -d 'Start interactive mode and automatically execute this prompt'
complete -c copilot -l prompt -s p -r -d 'Execute a prompt in non-interactive mode (exits after completion)'
complete -c copilot -l silent -s s -f -d 'Output only the agent response (no stats), useful for scripting with -p'
complete -c copilot -l enable-memory -f -d 'Enable memory in prompt mode (disabled by default)'
complete -c copilot -l model -r -d 'Set the AI model to use (use \'auto\' to let Copilot pick automatically)'
complete -c copilot -l effort -l reasoning-effort -r -d 'Set the reasoning effort level' -a 'none low medium high xhigh max'
complete -c copilot -l context -r -d 'Set the context window tier (overrides persisted setting)' -a 'default long_context'
complete -c copilot -l enable-reasoning-summaries -f -d 'Request reasoning summaries for OpenAI models'
complete -c copilot -l agent -r -d 'Specify a custom agent to use'
complete -c copilot -l resume -s r -r -d 'Resume from a previous session (optionally specify existing session ID, task ID, ID prefix, or name; name matching is exact, case-insensitive)'
complete -c copilot -l continue -f -d 'Resume the most recent session'
complete -c copilot -l name -s n -r -d 'Set a name for the new session'
complete -c copilot -l session-id -r -d 'Resume an existing session or task by ID, or set the UUID for a new session'
complete -c copilot -l connect -r -d 'Connect directly to a remote session (optionally specify session ID or task ID)'
complete -c copilot -l allow-all-tools -f -d 'Allow all tools to run automatically without confirmation; required for non-interactive mode'
complete -c copilot -l allow-all-paths -f -d 'Disable file path verification and allow access to any path'
complete -c copilot -l disallow-temp-dir -f -d 'Prevent automatic access to the system temporary directory'
complete -c copilot -l no-custom-instructions -f -d 'Disable loading of custom instructions from AGENTS.md and related files'
complete -c copilot -l no-auto-update -f -d 'Disable downloading CLI update automatically (disabled by default in CI environments)'
complete -c copilot -l no-ask-user -f -d 'Disable the ask_user tool (agent works autonomously without asking questions)'
complete -c copilot -l banner -f -d 'Show the startup banner'
complete -c copilot -l no-color -f -d 'Disable all color output'
complete -c copilot -l screen-reader -f -d 'Enable screen reader optimizations'
complete -c copilot -l plain-diff -f -d 'Disable rich diff rendering (syntax highlighting via diff tool specified by git config)'
complete -c copilot -s C -r -d 'Change working directory before doing anything else'
complete -c copilot -l log-dir -r -d 'Set log file directory (default: ~/.copilot/logs/)'
complete -c copilot -l extension-sdk-path -r -d 'Override the bundled @github/copilot-sdk injected into extension subprocesses with a local `copilot-sdk/` folder. Invalid paths fall back to the bundled SDK.'
complete -c copilot -l log-level -r -d 'Set the log level' -a 'none error warning info debug all default'
complete -c copilot -l stream -r -d 'Enable or disable streaming mode' -a 'on off'
complete -c copilot -l output-format -r -d 'Output format: \'text\' (default) or \'json\' (JSONL, one JSON object per line)' -a 'text json'
complete -c copilot -l share -r -d 'Share session to markdown file after completion in non-interactive mode (default: ./copilot-session-<id>.md)'
complete -c copilot -l share-gist -f -d 'Share session to a secret GitHub gist after completion in non-interactive mode'
complete -c copilot -l add-dir -r -d 'Add a directory to the allowed list for file access (can be used multiple times)'
complete -c copilot -l attachment -r -d 'Attach a file (image or native document) to the initial prompt; only valid in non-interactive mode (can be used multiple times)'
complete -c copilot -l disable-mcp-server -r -d 'Disable a specific MCP server (can be used multiple times)'
complete -c copilot -l disable-builtin-mcps -f -d 'Disable all built-in MCP servers (currently: github-mcp-server)'
complete -c copilot -l enable-all-github-mcp-tools -f -d 'Enable all GitHub MCP server tools instead of the default CLI subset. Overrides --add-github-mcp-toolset and --add-github-mcp-tool options.'
complete -c copilot -l add-github-mcp-toolset -r -d 'Add a toolset to enable for the GitHub MCP server instead of the default CLI subset (can be used multiple times). Use "all" for all toolsets.'
complete -c copilot -l add-github-mcp-tool -r -d 'Add a tool to enable for the GitHub MCP server instead of the default CLI subset (can be used multiple times). Use "*" for all tools.'
complete -c copilot -l plugin-dir -r -d 'Load a plugin from a local directory (can be used multiple times)'
complete -c copilot -l additional-mcp-config -r -d 'Additional MCP servers configuration as JSON string or file path (prefix with @) (can be used multiple times; augments config from ~/.copilot/mcp-config.json for this session)'
complete -c copilot -l allow-tool -r -d 'Tools the CLI has permission to use; will not prompt for permission'
complete -c copilot -l deny-tool -r -d 'Tools the CLI does not have permission to use; will not prompt for permission'
complete -c copilot -l available-tools -r -d 'Only these tools will be available to the model'
complete -c copilot -l excluded-tools -r -d 'These tools will not be available to the model'
complete -c copilot -l secret-env-vars -r -d 'Environment variable names whose values are stripped from shell and MCP server environments and redacted from output (e.g., --secret-env-vars=MY_KEY,OTHER_KEY)'
complete -c copilot -l allow-url -r -d 'Allow access to specific URLs or domains'
complete -c copilot -l deny-url -r -d 'Deny access to specific URLs or domains, takes precedence over --allow-url'
complete -c copilot -l allow-all-urls -f -d 'Allow access to all URLs without confirmation'
complete -c copilot -l allow-all -f -d 'Enable all permissions (equivalent to --allow-all-tools --allow-all-paths --allow-all-urls)'
complete -c copilot -l yolo -f -d 'Enable all permissions (equivalent to --allow-all-tools --allow-all-paths --allow-all-urls)'
complete -c copilot -l max-autopilot-continues -r -d 'Maximum number of continuation messages in autopilot mode'
complete -c copilot -l mode -r -d 'Set the initial agent mode' -a 'interactive plan autopilot'
complete -c copilot -l autopilot -f -d 'Start in autopilot mode'
complete -c copilot -l plan -f -d 'Start in plan mode'
complete -c copilot -l experimental -f -d 'Enable experimental features'
complete -c copilot -l no-experimental -f -d 'Disable experimental features'
complete -c copilot -l bash-env -r -d 'Enable BASH_ENV support for bash shells (on|off)'
complete -c copilot -l no-bash-env -f -d 'Disable BASH_ENV support for bash shells'
complete -c copilot -l mouse -r -d 'Enable mouse support in alt screen mode (on|off)'
complete -c copilot -l no-mouse -f -d 'Disable mouse support in alt screen mode'
complete -c copilot -l acp -f -d 'Start as Agent Client Protocol server'
complete -c copilot -l remote -f -d 'Enable remote control of your session from GitHub web and mobile'
complete -c copilot -l no-remote -f -d 'Disable remote control of your session from GitHub web and mobile'
complete -c copilot -n '__fish_seen_subcommand_from login' -l host -r -d 'GitHub host URL (default: https://github.com)'
complete -c copilot -n '__fish_seen_subcommand_from plugin' -f -a install -d 'Install a plugin'
complete -c copilot -n '__fish_seen_subcommand_from plugin' -f -a uninstall -d 'Uninstall a plugin'
complete -c copilot -n '__fish_seen_subcommand_from plugin' -f -a update -d 'Update a plugin'
complete -c copilot -n '__fish_seen_subcommand_from plugin' -f -a list -d 'List installed plugins'
complete -c copilot -n '__fish_seen_subcommand_from plugin' -f -a marketplace -d 'Manage plugin marketplaces'
complete -c copilot -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from update' -l all -f -d 'Update all installed plugins'
complete -c copilot -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from marketplace' -f -a add -d 'Add a marketplace'
complete -c copilot -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from marketplace' -f -a remove -d 'Remove a marketplace'
complete -c copilot -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from marketplace' -f -a list -d 'List registered marketplaces'
complete -c copilot -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from marketplace' -f -a browse -d 'Browse plugins in a marketplace'
complete -c copilot -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from marketplace' -f -a update -d 'Update marketplace plugin catalogs'
complete -c copilot -n '__fish_seen_subcommand_from plugin; and __fish_seen_subcommand_from marketplace; and __fish_seen_subcommand_from remove' -l force -s f -f -d 'Force removal even if plugins are installed'
complete -c copilot -n '__fish_seen_subcommand_from mcp' -f -a list -d 'List configured MCP servers'
complete -c copilot -n '__fish_seen_subcommand_from mcp' -f -a get -d 'Show server details'
complete -c copilot -n '__fish_seen_subcommand_from mcp' -f -a add -d 'Add an MCP server'
complete -c copilot -n '__fish_seen_subcommand_from mcp' -f -a remove -d 'Remove an MCP server'
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from list' -l json -f -d 'Output as JSON'
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from get' -l json -f -d 'Output as JSON'
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from get' -l show-secrets -f -d 'Show full environment variable and header values (masked by default)'
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add' -l transport -r -d 'Server transport' -a 'stdio http sse'
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add' -l env -r -d 'Environment variable (KEY=VALUE, can be repeated)'
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add' -l header -r -d 'HTTP header for remote servers, can be repeated'
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add' -l tools -r -d 'Tool filter: "*" for all, comma-separated list, or "" for none'
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add' -l timeout -r -d 'Timeout in milliseconds'
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add' -l json -f -d 'Output added config as JSON'
complete -c copilot -n '__fish_seen_subcommand_from mcp; and __fish_seen_subcommand_from add' -l show-secrets -f -d 'Show full environment variable and header values in output, masked by default'
+60 -60
View File
@@ -1,38 +1,38 @@
# Print an optspec for argparse to handle cmd's options that are independent of any subcommand. # Print an optspec for argparse to handle cmd's options that are independent of any subcommand.
function __fish_deadbranch_global_optspecs function __fish_deadbranch_global_optspecs
string join \n h/help V/version string join \n h/help V/version
end end
function __fish_deadbranch_needs_command function __fish_deadbranch_needs_command
# Figure out if the current invocation already has a command. # Figure out if the current invocation already has a command.
set -l cmd (commandline -opc) set -l cmd (commandline -opc)
set -e cmd[1] set -e cmd[1]
argparse -s (__fish_deadbranch_global_optspecs) -- $cmd 2>/dev/null argparse -s (__fish_deadbranch_global_optspecs) -- $cmd 2>/dev/null
or return or return
if set -q argv[1] if set -q argv[1]
# Also print the command, so this can be used to figure out what it is. # Also print the command, so this can be used to figure out what it is.
echo $argv[1] echo $argv[1]
return 1 return 1
end end
return 0 return 0
end end
function __fish_deadbranch_using_subcommand function __fish_deadbranch_using_subcommand
set -l cmd (__fish_deadbranch_needs_command) set -l cmd (__fish_deadbranch_needs_command)
test -z "$cmd" test -z "$cmd"
and return 1 and return 1
contains -- $cmd[1] $argv contains -- $cmd[1] $argv
end end
complete -c deadbranch -n "__fish_deadbranch_needs_command" -s h -l help -d 'Print help' complete -c deadbranch -n __fish_deadbranch_needs_command -s h -l help -d 'Print help'
complete -c deadbranch -n "__fish_deadbranch_needs_command" -s V -l version -d 'Print version' complete -c deadbranch -n __fish_deadbranch_needs_command -s V -l version -d 'Print version'
complete -c deadbranch -n "__fish_deadbranch_needs_command" -f -a "list" -d 'List stale branches' complete -c deadbranch -n __fish_deadbranch_needs_command -f -a list -d 'List stale branches'
complete -c deadbranch -n "__fish_deadbranch_needs_command" -f -a "clean" -d 'Delete stale branches (merged only by default, use --force for unmerged)' complete -c deadbranch -n __fish_deadbranch_needs_command -f -a clean -d 'Delete stale branches (merged only by default, use --force for unmerged)'
complete -c deadbranch -n "__fish_deadbranch_needs_command" -f -a "config" -d 'Manage configuration' complete -c deadbranch -n __fish_deadbranch_needs_command -f -a config -d 'Manage configuration'
complete -c deadbranch -n "__fish_deadbranch_needs_command" -f -a "backup" -d 'Manage backups' complete -c deadbranch -n __fish_deadbranch_needs_command -f -a backup -d 'Manage backups'
complete -c deadbranch -n "__fish_deadbranch_needs_command" -f -a "stats" -d 'Show repository branch statistics' complete -c deadbranch -n __fish_deadbranch_needs_command -f -a stats -d 'Show repository branch statistics'
complete -c deadbranch -n "__fish_deadbranch_needs_command" -f -a "completions" -d 'Generate shell completion scripts' complete -c deadbranch -n __fish_deadbranch_needs_command -f -a completions -d 'Generate shell completion scripts'
complete -c deadbranch -n "__fish_deadbranch_needs_command" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c deadbranch -n __fish_deadbranch_needs_command -f -a help -d 'Print this message or the help of the given subcommand(s)'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand list" -s d -l days -d 'Only show branches older than N days (default: from config or 30)' -r complete -c deadbranch -n "__fish_deadbranch_using_subcommand list" -s d -l days -d 'Only show branches older than N days (default: from config or 30)' -r
complete -c deadbranch -n "__fish_deadbranch_using_subcommand list" -l local -d 'Only show local branches' complete -c deadbranch -n "__fish_deadbranch_using_subcommand list" -l local -d 'Only show local branches'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand list" -l remote -d 'Only show remote branches' complete -c deadbranch -n "__fish_deadbranch_using_subcommand list" -l remote -d 'Only show remote branches'
@@ -51,11 +51,11 @@ complete -c deadbranch -n "__fish_deadbranch_using_subcommand clean" -s h -l hel
complete -c deadbranch -n "__fish_deadbranch_using_subcommand clean" -s V -l version -d 'Print version' complete -c deadbranch -n "__fish_deadbranch_using_subcommand clean" -s V -l version -d 'Print version'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and not __fish_seen_subcommand_from set show edit reset help" -s h -l help -d 'Print help' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and not __fish_seen_subcommand_from set show edit reset help" -s h -l help -d 'Print help'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and not __fish_seen_subcommand_from set show edit reset help" -s V -l version -d 'Print version' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and not __fish_seen_subcommand_from set show edit reset help" -s V -l version -d 'Print version'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and not __fish_seen_subcommand_from set show edit reset help" -f -a "set" -d 'Set a configuration value' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and not __fish_seen_subcommand_from set show edit reset help" -f -a set -d 'Set a configuration value'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and not __fish_seen_subcommand_from set show edit reset help" -f -a "show" -d 'Show current configuration' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and not __fish_seen_subcommand_from set show edit reset help" -f -a show -d 'Show current configuration'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and not __fish_seen_subcommand_from set show edit reset help" -f -a "edit" -d 'Open config file in $EDITOR' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and not __fish_seen_subcommand_from set show edit reset help" -f -a edit -d 'Open config file in $EDITOR'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and not __fish_seen_subcommand_from set show edit reset help" -f -a "reset" -d 'Reset configuration to defaults' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and not __fish_seen_subcommand_from set show edit reset help" -f -a reset -d 'Reset configuration to defaults'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and not __fish_seen_subcommand_from set show edit reset help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and not __fish_seen_subcommand_from set show edit reset help" -f -a help -d 'Print this message or the help of the given subcommand(s)'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from set" -s h -l help -d 'Print help'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from set" -s V -l version -d 'Print version' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from set" -s V -l version -d 'Print version'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from show" -s h -l help -d 'Print help' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from show" -s h -l help -d 'Print help'
@@ -64,18 +64,18 @@ complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from edit" -s V -l version -d 'Print version' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from edit" -s V -l version -d 'Print version'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from reset" -s h -l help -d 'Print help' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from reset" -s h -l help -d 'Print help'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from reset" -s V -l version -d 'Print version' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from reset" -s V -l version -d 'Print version'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from help" -f -a "set" -d 'Set a configuration value' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from help" -f -a set -d 'Set a configuration value'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from help" -f -a "show" -d 'Show current configuration' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from help" -f -a show -d 'Show current configuration'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from help" -f -a "edit" -d 'Open config file in $EDITOR' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from help" -f -a edit -d 'Open config file in $EDITOR'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from help" -f -a "reset" -d 'Reset configuration to defaults' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from help" -f -a reset -d 'Reset configuration to defaults'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c deadbranch -n "__fish_deadbranch_using_subcommand config; and __fish_seen_subcommand_from help" -f -a help -d 'Print this message or the help of the given subcommand(s)'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and not __fish_seen_subcommand_from list restore stats clean help" -s h -l help -d 'Print help' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and not __fish_seen_subcommand_from list restore stats clean help" -s h -l help -d 'Print help'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and not __fish_seen_subcommand_from list restore stats clean help" -s V -l version -d 'Print version' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and not __fish_seen_subcommand_from list restore stats clean help" -s V -l version -d 'Print version'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and not __fish_seen_subcommand_from list restore stats clean help" -f -a "list" -d 'List available backups' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and not __fish_seen_subcommand_from list restore stats clean help" -f -a list -d 'List available backups'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and not __fish_seen_subcommand_from list restore stats clean help" -f -a "restore" -d 'Restore a branch from backup' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and not __fish_seen_subcommand_from list restore stats clean help" -f -a restore -d 'Restore a branch from backup'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and not __fish_seen_subcommand_from list restore stats clean help" -f -a "stats" -d 'Show backup storage statistics' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and not __fish_seen_subcommand_from list restore stats clean help" -f -a stats -d 'Show backup storage statistics'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and not __fish_seen_subcommand_from list restore stats clean help" -f -a "clean" -d 'Remove old backups, keeping the most recent ones' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and not __fish_seen_subcommand_from list restore stats clean help" -f -a clean -d 'Remove old backups, keeping the most recent ones'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and not __fish_seen_subcommand_from list restore stats clean help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and not __fish_seen_subcommand_from list restore stats clean help" -f -a help -d 'Print this message or the help of the given subcommand(s)'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from list" -l repo -d 'Show backups for a specific repository by name' -r complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from list" -l repo -d 'Show backups for a specific repository by name' -r
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from list" -l current -d 'Only show backups for current repository' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from list" -l current -d 'Only show backups for current repository'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from list" -s h -l help -d 'Print help' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from list" -s h -l help -d 'Print help'
@@ -94,28 +94,28 @@ complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from clean" -s y -l yes -d 'Skip confirmation prompt' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from clean" -s y -l yes -d 'Skip confirmation prompt'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from clean" -s h -l help -d 'Print help' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from clean" -s h -l help -d 'Print help'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from clean" -s V -l version -d 'Print version' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from clean" -s V -l version -d 'Print version'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from help" -f -a "list" -d 'List available backups' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from help" -f -a list -d 'List available backups'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from help" -f -a "restore" -d 'Restore a branch from backup' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from help" -f -a restore -d 'Restore a branch from backup'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from help" -f -a "stats" -d 'Show backup storage statistics' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from help" -f -a stats -d 'Show backup storage statistics'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from help" -f -a "clean" -d 'Remove old backups, keeping the most recent ones' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from help" -f -a clean -d 'Remove old backups, keeping the most recent ones'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c deadbranch -n "__fish_deadbranch_using_subcommand backup; and __fish_seen_subcommand_from help" -f -a help -d 'Print this message or the help of the given subcommand(s)'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand stats" -s d -l days -d 'Treat branches older than N days as stale (default: from config or 30)' -r complete -c deadbranch -n "__fish_deadbranch_using_subcommand stats" -s d -l days -d 'Treat branches older than N days as stale (default: from config or 30)' -r
complete -c deadbranch -n "__fish_deadbranch_using_subcommand stats" -s h -l help -d 'Print help' complete -c deadbranch -n "__fish_deadbranch_using_subcommand stats" -s h -l help -d 'Print help'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand stats" -s V -l version -d 'Print version' complete -c deadbranch -n "__fish_deadbranch_using_subcommand stats" -s V -l version -d 'Print version'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand completions" -s h -l help -d 'Print help' complete -c deadbranch -n "__fish_deadbranch_using_subcommand completions" -s h -l help -d 'Print help'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand completions" -s V -l version -d 'Print version' complete -c deadbranch -n "__fish_deadbranch_using_subcommand completions" -s V -l version -d 'Print version'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and not __fish_seen_subcommand_from list clean config backup stats completions help" -f -a "list" -d 'List stale branches' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and not __fish_seen_subcommand_from list clean config backup stats completions help" -f -a list -d 'List stale branches'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and not __fish_seen_subcommand_from list clean config backup stats completions help" -f -a "clean" -d 'Delete stale branches (merged only by default, use --force for unmerged)' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and not __fish_seen_subcommand_from list clean config backup stats completions help" -f -a clean -d 'Delete stale branches (merged only by default, use --force for unmerged)'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and not __fish_seen_subcommand_from list clean config backup stats completions help" -f -a "config" -d 'Manage configuration' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and not __fish_seen_subcommand_from list clean config backup stats completions help" -f -a config -d 'Manage configuration'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and not __fish_seen_subcommand_from list clean config backup stats completions help" -f -a "backup" -d 'Manage backups' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and not __fish_seen_subcommand_from list clean config backup stats completions help" -f -a backup -d 'Manage backups'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and not __fish_seen_subcommand_from list clean config backup stats completions help" -f -a "stats" -d 'Show repository branch statistics' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and not __fish_seen_subcommand_from list clean config backup stats completions help" -f -a stats -d 'Show repository branch statistics'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and not __fish_seen_subcommand_from list clean config backup stats completions help" -f -a "completions" -d 'Generate shell completion scripts' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and not __fish_seen_subcommand_from list clean config backup stats completions help" -f -a completions -d 'Generate shell completion scripts'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and not __fish_seen_subcommand_from list clean config backup stats completions help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and not __fish_seen_subcommand_from list clean config backup stats completions help" -f -a help -d 'Print this message or the help of the given subcommand(s)'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from config" -f -a "set" -d 'Set a configuration value' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from config" -f -a set -d 'Set a configuration value'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from config" -f -a "show" -d 'Show current configuration' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from config" -f -a show -d 'Show current configuration'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from config" -f -a "edit" -d 'Open config file in $EDITOR' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from config" -f -a edit -d 'Open config file in $EDITOR'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from config" -f -a "reset" -d 'Reset configuration to defaults' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from config" -f -a reset -d 'Reset configuration to defaults'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from backup" -f -a "list" -d 'List available backups' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from backup" -f -a list -d 'List available backups'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from backup" -f -a "restore" -d 'Restore a branch from backup' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from backup" -f -a restore -d 'Restore a branch from backup'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from backup" -f -a "stats" -d 'Show backup storage statistics' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from backup" -f -a stats -d 'Show backup storage statistics'
complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from backup" -f -a "clean" -d 'Remove old backups, keeping the most recent ones' complete -c deadbranch -n "__fish_deadbranch_using_subcommand help; and __fish_seen_subcommand_from backup" -f -a clean -d 'Remove old backups, keeping the most recent ones'
+79
View File
@@ -0,0 +1,79 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# Completions for the `jobrunner` background job manager.
# `jr` inherits these via `function jr --wraps jobrunner`.
# Offer running jobs as name<TAB>description pairs.
function __jobrunner_complete_jobs
set -l tool ""
set -l tokens (commandline -opc)
set -l idx 1
while test $idx -le (count $tokens)
switch $tokens[$idx]
case -t --tool
set idx (math $idx + 1)
if test $idx -le (count $tokens)
set tool $tokens[$idx]
end
case '--tool=*'
set tool (string replace -- "--tool=" "" $tokens[$idx])
case '-t*'
set tool (string replace -r "^-t" "" $tokens[$idx])
end
set idx (math $idx + 1)
end
for row in (__jobrunner_sessions $tool)
set -l f (string split \t -- $row)
printf '%s\t%s job (PID %s)\n' $f[1] $f[3] $f[2]
end
end
set -l subcmds run list attach kill logs help
set -l needs_job "__fish_seen_subcommand_from attach kill logs -a --attach -k --kill -o --output"
# No file completions; jobs are named, not paths.
complete -c jobrunner -f
# Backend tool selection flag.
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
-s t -l tool -x -a "tmux screen" -d 'Force specific backend'
# Subcommands (only as the first argument).
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
-a run -d 'Start a named job in the background'
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
-a list -d 'List all managed background jobs'
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
-a attach -d 'Re-attach interactively to a job'
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
-a kill -d 'Terminate a running background job'
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
-a logs -d "Print a job's output without attaching"
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
-a help -d 'Show usage help'
# Flag forms.
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
-s r -l run -d 'Start a named job in the background'
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
-s l -l list -d 'List all managed background jobs'
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
-s a -l attach -d 'Re-attach interactively to a job'
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
-s k -l kill -d 'Terminate a running background job'
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
-s o -l output -d "Print a job's output without attaching"
complete -c jobrunner -s h -l help -d 'Show usage help'
# Running jobs, for the subcommands that take one.
complete -c jobrunner -n "$needs_job" -a '(__jobrunner_complete_jobs)'
# A bare job name attaches to it, so offer jobs in first position too.
complete -c jobrunner -n "not __fish_seen_subcommand_from $subcmds" \
-a '(__jobrunner_complete_jobs)'
# After `run <name>`, complete the command to execute.
complete -c jobrunner -n "__fish_seen_subcommand_from run -r --run; and test (count (commandline -opc)) -ge 3" \
-a '(__fish_complete_subcommand)'
+4 -5
View File
@@ -3,7 +3,7 @@
function __ov_debug function __ov_debug
set -l file "$BASH_COMP_DEBUG_FILE" set -l file "$BASH_COMP_DEBUG_FILE"
if test -n "$file" if test -n "$file"
echo "$argv" >> $file echo "$argv" >>$file
end end
end end
@@ -108,7 +108,6 @@ function __ov_requires_order_preservation
return 1 return 1
end end
# This function does two things: # This function does two things:
# - Obtain the completions and store them in the global __ov_comp_results # - Obtain the completions and store them in the global __ov_comp_results
# - Return false if file completion should be performed # - Return false if file completion should be performed
@@ -215,18 +214,18 @@ end
# so we can properly delete any completions provided by another script. # so we can properly delete any completions provided by another script.
# Only do this if the program can be found, or else fish may print some errors; besides, # Only do this if the program can be found, or else fish may print some errors; besides,
# the existing completions will only be loaded if the program can be found. # the existing completions will only be loaded if the program can be found.
if type -q "ov" if type -q ov
# The space after the program name is essential to trigger completion for the program # The space after the program name is essential to trigger completion for the program
# and not completion of the program name itself. # and not completion of the program name itself.
# Also, we use '> /dev/null 2>&1' since '&>' is not supported in older versions of fish. # Also, we use '> /dev/null 2>&1' since '&>' is not supported in older versions of fish.
complete --do-complete "ov " > /dev/null 2>&1 complete --do-complete "ov " >/dev/null 2>&1
end end
# Remove any pre-existing completions for the program since we will be handling all of them. # Remove any pre-existing completions for the program since we will be handling all of them.
complete -c ov -e complete -c ov -e
# this will get called after the two calls below and clear the $__ov_perform_completion_once_result global # this will get called after the two calls below and clear the $__ov_perform_completion_once_result global
complete -c ov -n '__ov_clear_perform_completion_once_result' complete -c ov -n __ov_clear_perform_completion_once_result
# The call to __ov_prepare_completions will setup __ov_comp_results # The call to __ov_prepare_completions will setup __ov_comp_results
# which provides the program's completion choices. # which provides the program's completion choices.
# If this doesn't require order preservation, we don't use the -k flag # If this doesn't require order preservation, we don't use the -k flag
+2
View File
@@ -0,0 +1,2 @@
complete --command play-media --short p --long player --description "Force a specific media player" --require-parameter
complete --command play-media --short h --long help --description "Print this help message"
+21
View File
@@ -0,0 +1,21 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
complete -c rand_string -f
complete -c rand_string -s s -l separator -x -a 'dash underscore dot none' -d 'Set separator for following words'
complete -c rand_string -s c -l case -x -a 'lower upper title' -d 'Set casing for following words'
complete -c rand_string -s h -l help -d 'Show usage help'
# List of all available lists in data/words
set -l categories
if set -q __fish_config_dir
set categories (string replace -r '\.txt$' '' (command ls $__fish_config_dir/data/words/*.txt 2>/dev/null | command xargs -n 1 basename 2>/dev/null))
end
for cat in $categories
complete -c rand_string -a "$cat" -d "Pick a random word from the $cat list"
end
complete -c rand_string -a 'digits=' -d 'Generate N random digits (e.g. digits=3)'
complete -c rand_string -a 'literal=' -d 'Insert a literal string exactly as provided'
@@ -21,7 +21,7 @@ end
function __tailscale_debug function __tailscale_debug
set -l file "$BASH_COMP_DEBUG_FILE" set -l file "$BASH_COMP_DEBUG_FILE"
if test -n "$file" if test -n "$file"
echo "$argv" >> $file echo "$argv" >>$file
end end
end end
@@ -125,7 +125,6 @@ function __tailscale_requires_order_preservation
return 1 return 1
end end
# This function does two things: # This function does two things:
# - Obtain the completions and store them in the global __tailscale_comp_results # - Obtain the completions and store them in the global __tailscale_comp_results
# - Return false if file completion should be performed # - Return false if file completion should be performed
@@ -228,22 +227,21 @@ function __tailscale_prepare_completions
return 0 return 0
end end
# Since Fish completions are only loaded once the user triggers them, we trigger them ourselves # REMOVED (2026-09-07): Cobra's self-priming block —
# so we can properly delete any completions provided by another script. # if type -q "tailscale"; complete --do-complete "tailscale " >/dev/null 2>&1; end
# Only do this if the program can be found, or else fish may print some errors; besides, # It existed to force any pre-existing tailscale completions to load so the
# the existing completions will only be loaded if the program can be found. # `complete -c tailscale -e` below could erase them. From completions/ it has
if type -q "tailscale" # no job: fish autoloads only the FIRST match on $fish_complete_path, and
# The space after the program name is essential to trigger completion for the program # $__fish_config_dir/completions precedes /usr/share/fish/vendor_completions.d,
# and not completion of the program name itself. # so the vendor file is never sourced and there is nothing to erase. It also
# Also, we use '> /dev/null 2>&1' since '&>' is not supported in older versions of fish. # executed the tailscale binary at startup. Verified: completion output is
complete --do-complete "tailscale " > /dev/null 2>&1 # byte-identical with and without it.
end
# Remove any pre-existing completions for the program since we will be handling all of them. # Remove any pre-existing completions for the program since we will be handling all of them.
complete -c tailscale -e complete -c tailscale -e
# this will get called after the two calls below and clear the $__tailscale_perform_completion_once_result global # this will get called after the two calls below and clear the $__tailscale_perform_completion_once_result global
complete -c tailscale -n '__tailscale_clear_perform_completion_once_result' complete -c tailscale -n __tailscale_clear_perform_completion_once_result
# The call to __tailscale_prepare_completions will setup __tailscale_comp_results # The call to __tailscale_prepare_completions will setup __tailscale_comp_results
# which provides the program's completion choices. # which provides the program's completion choices.
# If this doesn't require order preservation, we don't use the -k flag # If this doesn't require order preservation, we don't use the -k flag
+147
View File
@@ -0,0 +1,147 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# GENERATED FILE --- do not edit by hand.
# Regenerate with __fish_config_op_registry_rebuild after editing a
# # COMPONENT header, or automatically via docs/build-manual.py.
# Source: docs/generate_component_registry.py
#
# This file must be sourced before any other conf.d/*.fish file that
# calls the opinionated guard. That currently holds only because fish's
# glob-based conf.d loading happens to sort this filename first
# alphabetically among the guard-calling files -- do not rename it
# without preserving that ordering.
set -g __fish_config_op_registry_keys \
"__auto_source_fallback_venv:" \
"__fish_config_sync_logging:" \
"__fish_user_dots_link:" \
"_zellij_dump_log:" \
"abbr:abbr-integrations" \
"abbr:abbr-overrides" \
"agy:" \
"auto-pull:" \
"autopair:" \
"bash:" \
"bash_expands:" \
"cat:" \
"claude:" \
"config:cachyos-strip-aliases" \
"config:cachyos-strip-overrides" \
"config:cachyos-tricks" \
"config:cdpath" \
"config:exit-wiring" \
"config:greeting-stamp" \
"config:pager-editor-gpg" \
"config:path-setup" \
"config:privacy" \
"config:vi-mode" \
"done:" \
"du:" \
"edit:" \
"first_run:first-run-bootstrap" \
"first_run:first-run-greeting" \
"fish_right_prompt:" \
"help:" \
"hist:" \
"key_bindings:" \
"kitty-logging:" \
"kitty-watcher-reminder:" \
"less:" \
"logs:" \
"ls:" \
"mkdir:" \
"mv:" \
"paru-wrapper:paru-autoexec" \
"paru-wrapper:paru-logging" \
"ping:" \
"puffer:" \
"rg:" \
"rm:" \
"smart_exit:exit-plain" \
"smart_exit:logging-guard" \
"split:" \
"spwin:" \
"ssh:" \
"starship:" \
"tab:" \
"theme:" \
"tmux-logging:" \
"top:" \
"tricks:aliases-tricks" \
"tricks:tricks-bang" \
"tricks:tricks-manpager" \
"upgrade:" \
"wakatime:wakatime-autoexec" \
"wakatime:wakatime-hook" \
"yay-wrapper:yay-autoexec" \
"yay-wrapper:yay-logging" \
"yt-dlp:" \
"zoxide:"
set -g __fish_config_op_registry_values \
autoexec/venv \
logging/terminal-capture \
autoexec/sync \
logging/multiplexer-capture \
integrations/terminal-abbrs \
overrides/key-bindings \
aliases/dev-tools \
autoexec/sync \
overrides/key-bindings \
aliases/shell-tools \
overrides/key-bindings \
aliases/filesystem \
aliases/dev-tools \
aliases/filesystem \
overrides/key-bindings \
overrides/environment \
overrides/environment \
overrides/key-bindings \
greeting/greeting-message \
overrides/environment \
overrides/environment \
overrides/privacy \
overrides/key-bindings \
integrations/notifications \
aliases/filesystem \
aliases/dev-tools \
autoexec/plugin-management \
greeting/first-run \
overrides/prompt \
aliases/shell-tools \
integrations/history-logs \
overrides/key-bindings \
logging/terminal-capture \
logging/terminal-capture \
aliases/shell-tools \
integrations/history-logs \
aliases/filesystem \
aliases/filesystem \
aliases/filesystem \
autoexec/pkg-wrappers \
logging/pkg-logs \
aliases/network \
overrides/key-bindings \
aliases/search \
aliases/filesystem \
overrides/key-bindings \
logging/terminal-capture \
integrations/window-mgmt \
integrations/window-mgmt \
aliases/network \
overrides/prompt \
integrations/window-mgmt \
overrides/prompt \
logging/multiplexer-capture \
aliases/monitor \
aliases/filesystem \
overrides/key-bindings \
overrides/environment \
integrations/pkg-upgrade \
autoexec/telemetry \
integrations/notifications \
autoexec/pkg-wrappers \
logging/pkg-logs \
aliases/network \
aliases/filesystem
+380 -5
View File
@@ -8,82 +8,175 @@
# This file contains all the abbreviations for the terminal. # This file contains all the abbreviations for the terminal.
# It is sourced by Fish on startup. # It is sourced by Fish on startup.
# COMPONENT
# site abbr-integrations: integrations/terminal-abbrs
# site abbr-overrides: overrides/key-bindings
# Abbreviations only expand in the line editor; a script can never use one.
status is-interactive; or return
# Neovim # Neovim
# @category Editors
# @desc nvim
abbr -a n nvim abbr -a n nvim
# @category Editors
# @desc nvim
abbr -a nv nvim abbr -a nv nvim
# @category Editors
# @desc nvim
abbr -a neovim nvim abbr -a neovim nvim
# @category Editors
# @desc cd ~/.config/nvim
abbr -a cdnv 'cd ~/.config/nvim # Neovim Config' abbr -a cdnv 'cd ~/.config/nvim # Neovim Config'
# @category Editors
# @desc cd ~/.config/nvim; nvim
abbr -a cdnvn 'cd ~/.config/nvim;nvim' abbr -a cdnvn 'cd ~/.config/nvim;nvim'
# VSCode # VSCode
# @category AI Assistants
# @desc antigravity-ide
abbr -a v antigravity-ide abbr -a v antigravity-ide
# Kate # Kate
# @category Editors
# @desc kate
abbr -a k kate abbr -a k kate
# WezTerm SSH # WezTerm SSH
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category AI Assistants
# @desc wezterm ssh (WezTerm only)
abbr -a s wezterm ssh abbr -a s wezterm ssh
end end
# Neovim in a new tab # Neovim in a new tab
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Open new tab with nvim (terminal-aware)
abbr -a editt kitty @ launch --type=tab --cwd=current nvim # Kitty abbr -a editt kitty @ launch --type=tab --cwd=current nvim # Kitty
end end
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Open new tab with nvim (terminal-aware)
abbr -a editt wezterm cli spawn nvim # WezTerm abbr -a editt wezterm cli spawn nvim # WezTerm
end end
# LazyGit # LazyGit
# @category Git
# @desc lazygit
abbr -a lg lazygit abbr -a lg lazygit
# Sudo shell # Sudo shell
# @category Miscellaneous
# @desc sudo -s
abbr -a sudu sudo -s abbr -a sudu sudo -s
# Kitty # Kitty
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Miscellaneous
# @desc kitty (Kitty only)
abbr -a kt kitty abbr -a kt kitty
end end
# cat # cat
# @category Miscellaneous
# @desc cat
abbr -a c cat abbr -a c cat
# chezmoi # chezmoi
# @category Chezmoi
# @desc chezmoi
abbr -a cm chezmoi abbr -a cm chezmoi
# chezmoi cd # chezmoi cd
# @category Chezmoi
# @desc chezmoi cd
abbr -a cmcd chezmoi cd abbr -a cmcd chezmoi cd
# @category Chezmoi
# @desc chezmoi cd
abbr -a czcd chezmoi cd abbr -a czcd chezmoi cd
# @category Chezmoi
# @desc chezmoi cd
abbr -a cdcm chezmoi cd abbr -a cdcm chezmoi cd
# @category Chezmoi
# @desc chezmoi cd
abbr -a cdcz chezmoi cd abbr -a cdcz chezmoi cd
# chezmoi edit # chezmoi edit
# @category Chezmoi
# @desc chezmoi edit
abbr -a cme chezmoi edit abbr -a cme chezmoi edit
# @category Chezmoi
# @desc chezmoi edit
abbr -a cze chezmoi edit abbr -a cze chezmoi edit
# chezmoi add # chezmoi add
# @category Chezmoi
# @desc chezmoi add
abbr -a cmad chezmoi add abbr -a cmad chezmoi add
# @category Chezmoi
# @desc chezmoi add
abbr -a czad chezmoi add abbr -a czad chezmoi add
# chezmoi apply # chezmoi apply
# @category Chezmoi
# @desc chezmoi apply
abbr -a cmap chezmoi apply abbr -a cmap chezmoi apply
# @category Chezmoi
# @desc chezmoi apply
abbr -a czap chezmoi apply abbr -a czap chezmoi apply
# chezmoi rm # chezmoi rm
# @category Chezmoi
# @desc chezmoi forget
abbr -a cmrm chezmoi forget abbr -a cmrm chezmoi forget
# @category Chezmoi
# @desc chezmoi forget
abbr -a cmf chezmoi forget abbr -a cmf chezmoi forget
# @category Chezmoi
# @desc chezmoi forget
abbr -a czrm chezmoi forget abbr -a czrm chezmoi forget
# @category Chezmoi
# @desc chezmoi forget
abbr -a czf chezmoi forget abbr -a czf chezmoi forget
# chezmoi init # chezmoi init
# @category Chezmoi
# @desc chezmoi init
abbr -a cmi chezmoi init abbr -a cmi chezmoi init
# @category Chezmoi
# @desc chezmoi init
abbr -a czi chezmoi init abbr -a czi chezmoi init
# Edit # Edit
# @category Editors
# @desc edit
abbr -a e edit abbr -a e edit
# Sudoedit # Sudoedit
# @category Editors
# @desc sudoedit
abbr -a se sudoedit abbr -a se sudoedit
# Git # Git
# @category Git
# @desc git
abbr -a g git abbr -a g git
# @category Git
# @desc generate .gitignore
abbr -a gitig gi abbr -a gitig gi
# @category Git
# @desc generate .gitignore
abbr -a git-ignore gi abbr -a git-ignore gi
# Antigravity # Antigravity
abbr -a ag antigravity # @category AI Assistants
abbr -a ag. antigravity . # @desc agy
abbr -a ag agy
# @category AI Assistants
# @desc agy .
abbr -a ag. agy .
# Quit # Quit
# @category Miscellaneous
# @desc exit
abbr -a /exit exit abbr -a /exit exit
# Window-management abbreviations are opinionated (C4 integrations) # Window-management abbreviations are opinionated (C4 integrations)
if __fish_config_op_enabled __fish_config_op_integrations if __fish_config_op_enabled (status basename) abbr-integrations
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Close current pane/window
abbr -a :q kitty @ close-window # Kitty (Closes the active split/pane) abbr -a :q kitty @ close-window # Kitty (Closes the active split/pane)
# @category Terminal Windows, Tabs, and Panes
# @desc Close current tab
abbr -a :Q kitty @ close-tab # Kitty (Closes the whole tab) abbr -a :Q kitty @ close-tab # Kitty (Closes the whole tab)
end end
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Close current pane/window
abbr -a :q wezterm cli kill-pane # WezTerm abbr -a :q wezterm cli kill-pane # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Close current tab
abbr -a :Q wezterm cli kill-pane # WezTerm abbr -a :Q wezterm cli kill-pane # WezTerm
end end
end end
@@ -91,236 +184,518 @@ end
######### Alternates ########## ######### Alternates ##########
### ls alternates ### ls alternates
# List all files # List all files
# @category Navigation and Listing
# @desc ls
abbr -a l ls abbr -a l ls
# List all files by size # List all files by size
# @category Navigation and Listing
# @desc lss (sort by size)
abbr -a lS lss abbr -a lS lss
# List all files by reverse modified time # List all files by reverse modified time
# @category Navigation and Listing
# @desc lsr (sort by time, oldest first)
abbr -a lsR lsr abbr -a lsR lsr
# List by extension # List by extension
# @category Navigation and Listing
# @desc lx (sort by extension)
abbr -a lX lx abbr -a lX lx
# Tree listing (depth 2) # Tree listing (depth 2)
# @category Navigation and Listing
# @desc lt (tree, depth 2)
abbr -a lT lt abbr -a lT lt
# Full tree listing # Full tree listing
# @category Navigation and Listing
# @desc lstree (full recursive tree)
abbr -a lsT lstree abbr -a lsT lstree
### speed-test alternates ### speed-test alternates
# Speedtest using fast.com # Speedtest using fast.com
# @category Miscellaneous
# @desc fast-cli
abbr -a speedtest-fast fast-cli abbr -a speedtest-fast fast-cli
# Kitty/WezTerm window-management abbreviations are opinionated (C4 # Kitty/WezTerm window-management abbreviations are opinionated (C4
# integrations): they assume an active Kitty or WezTerm session. # integrations): they assume an active Kitty or WezTerm session.
if __fish_config_op_enabled __fish_config_op_integrations if __fish_config_op_enabled (status basename) abbr-integrations
# Window Creation (OS Windows) # Window Creation (OS Windows)
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window
abbr -a :w kitty @ launch --type=os-window # Kitty abbr -a :w kitty @ launch --type=os-window # Kitty
end end
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window
abbr -a :w wezterm cli spawn --new-window # WezTerm abbr -a :w wezterm cli spawn --new-window # WezTerm
end end
# Window Splits (Panes) # Window Splits (Panes)
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split pane horizontally (new pane below)
abbr -a :wv kitty @ launch --location=hsplit # Kitty (Horizontal split) abbr -a :wv kitty @ launch --location=hsplit # Kitty (Horizontal split)
# @category Terminal Windows, Tabs, and Panes
# @desc Split pane vertically (new pane to the right)
abbr -a :wh kitty @ launch --location=vsplit # Kitty (Vertical split) abbr -a :wh kitty @ launch --location=vsplit # Kitty (Vertical split)
end end
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split pane horizontally (new pane below)
abbr -a :wv wezterm cli split-pane --bottom # WezTerm abbr -a :wv wezterm cli split-pane --bottom # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split pane vertically (new pane to the right)
abbr -a :wh wezterm cli split-pane --right # WezTerm abbr -a :wh wezterm cli split-pane --right # WezTerm
end end
# Window Detach (Move Pane) # Window Detach (Move Pane)
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Detach current window to its own OS window
abbr -a :wo kitty @ detach-window --target-tab=new # Kitty (Moves pane to new tab) abbr -a :wo kitty @ detach-window --target-tab=new # Kitty (Moves pane to new tab)
# @category Terminal Windows, Tabs, and Panes
# @desc Move current pane to a new tab
abbr -a :wot kitty @ detach-window # Kitty (Same as above, default behavior) abbr -a :wot kitty @ detach-window # Kitty (Same as above, default behavior)
end end
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Detach current window to its own OS window
abbr -a :wo wezterm cli move-pane-to-new-tab --new-window # WezTerm abbr -a :wo wezterm cli move-pane-to-new-tab --new-window # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Move current pane to a new tab
abbr -a :wot wezterm cli move-pane-to-new-tab # WezTerm abbr -a :wot wezterm cli move-pane-to-new-tab # WezTerm
end end
# Tab Creation # Tab Creation
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New tab
abbr -a :t kitty @ launch --type=tab # Kitty abbr -a :t kitty @ launch --type=tab # Kitty
end end
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New tab
abbr -a :t wezterm cli spawn # WezTerm abbr -a :t wezterm cli spawn # WezTerm
end end
# Rename Tab # Rename Tab
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Set tab title
abbr -a :tl "kitty @ set-tab-title" # Kitty -> Usage: :tl "New Title" abbr -a :tl "kitty @ set-tab-title" # Kitty -> Usage: :tl "New Title"
end end
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Set tab title
abbr -a :tl wezterm cli set-tab-title # WezTerm abbr -a :tl wezterm cli set-tab-title # WezTerm
end end
# Rename Window # Rename Window
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Set window title
abbr -a :tw "kitty @ set-window-title" # Kitty abbr -a :tw "kitty @ set-window-title" # Kitty
end end
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Set window title
abbr -a :tw wezterm cli set-window-title # WezTerm abbr -a :tw wezterm cli set-window-title # WezTerm
end end
# Rename Workspace # Rename Workspace
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Rename workspace (WezTerm only)
abbr -a :twk wezterm cli rename-workspace # WezTerm abbr -a :twk wezterm cli rename-workspace # WezTerm
end end
# Kitty does not have a direct CLI equivalent for renaming a dynamic "workspace" session. # Kitty does not have a direct CLI equivalent for renaming a dynamic "workspace" session.
# Tab Navigation # Tab Navigation
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Focus previous tab
abbr -a :tp "kitty @ focus-tab --match neighbor:left" # Kitty abbr -a :tp "kitty @ focus-tab --match neighbor:left" # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Focus next tab
abbr -a :tn "kitty @ focus-tab --match neighbor:right" # Kitty abbr -a :tn "kitty @ focus-tab --match neighbor:right" # Kitty
end end
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Focus previous tab
abbr -a :tp wezterm cli activate-tab --tab-relative -1 # WezTerm abbr -a :tp wezterm cli activate-tab --tab-relative -1 # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Focus next tab
abbr -a :tn wezterm cli activate-tab --tab-relative 1 # WezTerm abbr -a :tn wezterm cli activate-tab --tab-relative 1 # WezTerm
end end
# Specialty Tab Shortcuts (New Tab in specific dir) # Specialty Tab Shortcuts (New Tab in specific dir)
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/.config/kitty
abbr -a :tgk kitty @ launch --type=tab --cwd ~/.config/kitty # Kitty abbr -a :tgk kitty @ launch --type=tab --cwd ~/.config/kitty # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/.config/nvim
abbr -a :tgn kitty @ launch --type=tab --cwd ~/.config/nvim # Kitty abbr -a :tgn kitty @ launch --type=tab --cwd ~/.config/nvim # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/.config/fish
abbr -a :tgf kitty @ launch --type=tab --cwd ~/.config/fish # Kitty abbr -a :tgf kitty @ launch --type=tab --cwd ~/.config/fish # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~
abbr -a :tgh kitty @ launch --type=tab --cwd ~ abbr -a :tgh kitty @ launch --type=tab --cwd ~
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/.local/share/chezmoi
abbr -a :tgcz kitty @ launch --type=tab --cwd ~/.local/share/chezmoi # Kitty abbr -a :tgcz kitty @ launch --type=tab --cwd ~/.local/share/chezmoi # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/.config/chezmoi
abbr -a :tgcm kitty @ launch --type=tab --cwd ~/.config/chezmoi # Kitty abbr -a :tgcm kitty @ launch --type=tab --cwd ~/.config/chezmoi # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/projects
abbr -a :tgp kitty @ launch --type=tab --cwd ~/projects # Kitty abbr -a :tgp kitty @ launch --type=tab --cwd ~/projects # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at / (root)
abbr -a :tgr kitty @ launch --type=tab -- sudo -i abbr -a :tgr kitty @ launch --type=tab -- sudo -i
end end
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/.config/kitty
abbr -a :tgk wezterm cli spawn --cwd ~/.config/kitty # WezTerm abbr -a :tgk wezterm cli spawn --cwd ~/.config/kitty # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/.config/nvim
abbr -a :tgn wezterm cli spawn --cwd ~/.config/nvim # WezTerm abbr -a :tgn wezterm cli spawn --cwd ~/.config/nvim # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/.config/fish
abbr -a :tgf wezterm cli spawn --cwd ~/.config/fish # WezTerm abbr -a :tgf wezterm cli spawn --cwd ~/.config/fish # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~
abbr -a :tgh wezterm cli spawn --cwd ~ # WezTerm abbr -a :tgh wezterm cli spawn --cwd ~ # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/.local/share/chezmoi
abbr -a :tgcz wezterm cli spawn --cwd ~/.local/share/chezmoi # WezTerm abbr -a :tgcz wezterm cli spawn --cwd ~/.local/share/chezmoi # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/.config/chezmoi
abbr -a :tgcm wezterm cli spawn --cwd ~/.config/chezmoi # WezTerm abbr -a :tgcm wezterm cli spawn --cwd ~/.config/chezmoi # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/projects
abbr -a :tgp wezterm cli spawn --cwd ~/projects # WezTerm abbr -a :tgp wezterm cli spawn --cwd ~/projects # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at / (root)
abbr -a :tgr wezterm cli spawn -- sudo -i # WezTerm abbr -a :tgr wezterm cli spawn -- sudo -i # WezTerm
end end
# Specialty Window Shortcuts (New OS Window in specific dir) # Specialty Window Shortcuts (New OS Window in specific dir)
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~/.config/kitty
abbr -a :wgk kitty @ launch --type=os-window --cwd ~/.config/kitty # Kitty abbr -a :wgk kitty @ launch --type=os-window --cwd ~/.config/kitty # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~/.config/nvim
abbr -a :wgn kitty @ launch --type=os-window --cwd ~/.config/nvim # Kitty abbr -a :wgn kitty @ launch --type=os-window --cwd ~/.config/nvim # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~/.config/fish
abbr -a :wgf kitty @ launch --type=os-window --cwd ~/.config/fish # Kitty abbr -a :wgf kitty @ launch --type=os-window --cwd ~/.config/fish # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~
abbr -a :wgh kitty @ launch --type=os-window --cwd ~ abbr -a :wgh kitty @ launch --type=os-window --cwd ~
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~/.local/share/chezmoi
abbr -a :wgzd kitty @ launch --type=os-window --cwd ~/.local/share/chezmoi # Kitty abbr -a :wgzd kitty @ launch --type=os-window --cwd ~/.local/share/chezmoi # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~/.config/chezmoi
abbr -a :wgcz kitty @ launch --type=os-window --cwd ~/.config/chezmoi # Kitty abbr -a :wgcz kitty @ launch --type=os-window --cwd ~/.config/chezmoi # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~/projects
abbr -a :wgp kitty @ launch --type=os-window --cwd ~/projects # Kitty abbr -a :wgp kitty @ launch --type=os-window --cwd ~/projects # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at / (root)
abbr -a :wgr kitty @ launch --type=os-window -- sudo -i # Kitty abbr -a :wgr kitty @ launch --type=os-window -- sudo -i # Kitty
end end
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~/.config/kitty
abbr -a :wgk wezterm cli spawn --new-window --cwd ~/.config/kitty # WezTerm abbr -a :wgk wezterm cli spawn --new-window --cwd ~/.config/kitty # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~/.config/nvim
abbr -a :wgn wezterm cli spawn --new-window --cwd ~/.config/nvim # WezTerm abbr -a :wgn wezterm cli spawn --new-window --cwd ~/.config/nvim # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~/.config/fish
abbr -a :wgf wezterm cli spawn --new-window --cwd ~/.config/fish # WezTerm abbr -a :wgf wezterm cli spawn --new-window --cwd ~/.config/fish # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~
abbr -a :wgh wezterm cli spawn --new-window --cwd ~ # WezTerm abbr -a :wgh wezterm cli spawn --new-window --cwd ~ # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~/.local/share/chezmoi
abbr -a :wgzd wezterm cli spawn --new-window --cwd ~/.local/share/chezmoi # WezTerm abbr -a :wgzd wezterm cli spawn --new-window --cwd ~/.local/share/chezmoi # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~/.config/chezmoi
abbr -a :wgcz wezterm cli spawn --new-window --cwd ~/.config/chezmoi # WezTerm abbr -a :wgcz wezterm cli spawn --new-window --cwd ~/.config/chezmoi # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~/projects
abbr -a :wgp wezterm cli spawn --new-window --cwd ~/projects # WezTerm abbr -a :wgp wezterm cli spawn --new-window --cwd ~/projects # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at / (root)
abbr -a :wgr wezterm cli spawn --new-window -- sudo -i # WezTerm abbr -a :wgr wezterm cli spawn --new-window -- sudo -i # WezTerm
end end
# Specialty Window Vertical Shortcuts (Split Bottom) # Specialty Window Vertical Shortcuts (Split Bottom)
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/.config/kitty
abbr -a :wvgk kitty @ launch --location=hsplit --cwd ~/.config/kitty # Kitty abbr -a :wvgk kitty @ launch --location=hsplit --cwd ~/.config/kitty # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/.config/nvim
abbr -a :wvgn kitty @ launch --location=hsplit --cwd ~/.config/nvim # Kitty abbr -a :wvgn kitty @ launch --location=hsplit --cwd ~/.config/nvim # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/.config/fish
abbr -a :wvgf kitty @ launch --location=hsplit --cwd ~/.config/fish # Kitty abbr -a :wvgf kitty @ launch --location=hsplit --cwd ~/.config/fish # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~
abbr -a :wvgh kitty @ launch --location=hsplit --cwd ~ # Kitty abbr -a :wvgh kitty @ launch --location=hsplit --cwd ~ # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/.local/share/chezmoi
abbr -a :wvgcz kitty @ launch --location=hsplit --cwd ~/.local/share/chezmoi # Kitty abbr -a :wvgcz kitty @ launch --location=hsplit --cwd ~/.local/share/chezmoi # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/.config/chezmoi
abbr -a :wvgcm kitty @ launch --location=hsplit --cwd ~/.config/chezmoi # Kitty abbr -a :wvgcm kitty @ launch --location=hsplit --cwd ~/.config/chezmoi # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/projects
abbr -a :wvgp kitty @ launch --location=hsplit --cwd ~/projects # Kitty abbr -a :wvgp kitty @ launch --location=hsplit --cwd ~/projects # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at / (root)
abbr -a :wvgr kitty @ launch --location=hsplit -- sudo -i # Kitty abbr -a :wvgr kitty @ launch --location=hsplit -- sudo -i # Kitty
end end
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/.config/kitty
abbr -a :wvgk wezterm cli split-pane --bottom --cwd ~/.config/kitty # WezTerm abbr -a :wvgk wezterm cli split-pane --bottom --cwd ~/.config/kitty # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/.config/nvim
abbr -a :wvgn wezterm cli split-pane --bottom --cwd ~/.config/nvim # WezTerm abbr -a :wvgn wezterm cli split-pane --bottom --cwd ~/.config/nvim # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/.config/fish
abbr -a :wvgf wezterm cli split-pane --bottom --cwd ~/.config/fish # WezTerm abbr -a :wvgf wezterm cli split-pane --bottom --cwd ~/.config/fish # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~
abbr -a :wvgh wezterm cli split-pane --bottom --cwd ~ # WezTerm abbr -a :wvgh wezterm cli split-pane --bottom --cwd ~ # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/.local/share/chezmoi
abbr -a :wvgcz wezterm cli split-pane --bottom --cwd ~/.local/share/chezmoi # WezTerm abbr -a :wvgcz wezterm cli split-pane --bottom --cwd ~/.local/share/chezmoi # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/.config/chezmoi
abbr -a :wvgcm wezterm cli split-pane --bottom --cwd ~/.config/chezmoi # WezTerm abbr -a :wvgcm wezterm cli split-pane --bottom --cwd ~/.config/chezmoi # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/projects
abbr -a :wvgp wezterm cli split-pane --bottom --cwd ~/projects # WezTerm abbr -a :wvgp wezterm cli split-pane --bottom --cwd ~/projects # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at / (root)
abbr -a :wvgr wezterm cli split-pane --bottom -- sudo -i # WezTerm abbr -a :wvgr wezterm cli split-pane --bottom -- sudo -i # WezTerm
end end
# Specialty Window Horizontal Shortcuts (Split Right) # Specialty Window Horizontal Shortcuts (Split Right)
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/.config/kitty
abbr -a :whgk kitty @ launch --location=vsplit --cwd ~/.config/kitty # Kitty abbr -a :whgk kitty @ launch --location=vsplit --cwd ~/.config/kitty # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/.config/nvim
abbr -a :whgn kitty @ launch --location=vsplit --cwd ~/.config/nvim # Kitty abbr -a :whgn kitty @ launch --location=vsplit --cwd ~/.config/nvim # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/.config/fish
abbr -a :whgf kitty @ launch --location=vsplit --cwd ~/.config/fish # Kitty abbr -a :whgf kitty @ launch --location=vsplit --cwd ~/.config/fish # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~
abbr -a :whgh kitty @ launch --location=vsplit --cwd ~ # Kitty abbr -a :whgh kitty @ launch --location=vsplit --cwd ~ # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/.local/share/chezmoi
abbr -a :whgcz kitty @ launch --location=vsplit --cwd ~/.local/share/chezmoi # Kitty abbr -a :whgcz kitty @ launch --location=vsplit --cwd ~/.local/share/chezmoi # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/.config/chezmoi
abbr -a :whgcm kitty @ launch --location=vsplit --cwd ~/.config/chezmoi # Kitty abbr -a :whgcm kitty @ launch --location=vsplit --cwd ~/.config/chezmoi # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/projects
abbr -a :whgp kitty @ launch --location=vsplit --cwd ~/projects # Kitty abbr -a :whgp kitty @ launch --location=vsplit --cwd ~/projects # Kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at / (root)
abbr -a :whgr kitty @ launch --location=vsplit --cwd current sudo -i # Kitty -> Specialty cd Shortcuts abbr -a :whgr kitty @ launch --location=vsplit --cwd current sudo -i # Kitty -> Specialty cd Shortcuts
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.config/kitty
abbr -a :cdk 'cd ~/.config/kitty/ # Kitty Config' abbr -a :cdk 'cd ~/.config/kitty/ # Kitty Config'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.config/kitty; nvim
abbr -a :cdkn 'cd ~/.config/kitty;nvim' abbr -a :cdkn 'cd ~/.config/kitty;nvim'
end end
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/.config/kitty
abbr -a :whgk wezterm cli split-pane --bottom --cwd ~/.config/kitty # WezTerm abbr -a :whgk wezterm cli split-pane --bottom --cwd ~/.config/kitty # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/.config/nvim
abbr -a :whgn wezterm cli split-pane --bottom --cwd ~/.config/nvim # WezTerm abbr -a :whgn wezterm cli split-pane --bottom --cwd ~/.config/nvim # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/.config/fish
abbr -a :whgf wezterm cli split-pane --bottom --cwd ~/.config/fish # WezTerm abbr -a :whgf wezterm cli split-pane --bottom --cwd ~/.config/fish # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~
abbr -a :whgh wezterm cli split-pane --bottom --cwd ~ # WezTerm abbr -a :whgh wezterm cli split-pane --bottom --cwd ~ # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/.local/share/chezmoi
abbr -a :whgcz wezterm cli split-pane --bottom --cwd ~/.local/share/chezmoi # WezTerm abbr -a :whgcz wezterm cli split-pane --bottom --cwd ~/.local/share/chezmoi # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/.config/chezmoi
abbr -a :whgcm wezterm cli split-pane --bottom --cwd ~/.config/chezmoi # WezTerm abbr -a :whgcm wezterm cli split-pane --bottom --cwd ~/.config/chezmoi # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/projects
abbr -a :whgp wezterm cli split-pane --bottom --cwd ~/projects # WezTerm abbr -a :whgp wezterm cli split-pane --bottom --cwd ~/projects # WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at / (root)
abbr -a :whgr wezterm cli split-pane --bottom -- sudo -i # WezTerm abbr -a :whgr wezterm cli split-pane --bottom -- sudo -i # WezTerm
end end
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.config/nvim
abbr -a :cdn cd '~/.config/nvim/ # Neovim Config' abbr -a :cdn cd '~/.config/nvim/ # Neovim Config'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.config/nvim; nvim
abbr -a :cdnn 'cd ~/.config/nvim;nvim' abbr -a :cdnn 'cd ~/.config/nvim;nvim'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.config/fish
abbr -a :cdf 'cd ~/.config/fish/ # Fish Config' abbr -a :cdf 'cd ~/.config/fish/ # Fish Config'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.config/fish; nvim
abbr -a :cdfn 'cd ~/.config/fish;nvim' abbr -a :cdfn 'cd ~/.config/fish;nvim'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~
abbr -a :cdh 'cd ~ # Home Directory' abbr -a :cdh 'cd ~ # Home Directory'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~; nvim
abbr -a :cdhn 'cd ~;nvim' abbr -a :cdhn 'cd ~;nvim'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.local/share/chezmoi
abbr -a :cdcz cd '~/.local/share/chezmoi/ # Chezmoi Source' abbr -a :cdcz cd '~/.local/share/chezmoi/ # Chezmoi Source'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.local/share/chezmoi; nvim
abbr -a :cdczn 'cd ~/.local/share/chezmoi;nvim' abbr -a :cdczn 'cd ~/.local/share/chezmoi;nvim'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.config/chezmoi
abbr -a :cdcm 'cd ~/.config/chezmoi/ # Chezmoi Config' abbr -a :cdcm 'cd ~/.config/chezmoi/ # Chezmoi Config'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.config/chezmoi; nvim
abbr -a :cdcmn 'cd ~/.config/chezmoi;nvim' abbr -a :cdcmn 'cd ~/.config/chezmoi;nvim'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/projects/...
abbr -a :cdp --regex ':cdp' --set-cursor 'cd ~/projects/%' abbr -a :cdp --regex ':cdp' --set-cursor 'cd ~/projects/%'
# abbr -a cdp_slash --position anywhere --regex ':cdp/' --set-cursor 'cd ~/projects/%' # abbr -a cdp_slash --position anywhere --regex ':cdp/' --set-cursor 'cd ~/projects/%'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/projects; nvim
abbr -a :cdpn 'cd ~/projects;nvim' abbr -a :cdpn 'cd ~/projects;nvim'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.config/wezterm
abbr -a :cdw 'cd ~/.config/wezterm/ # WezTerm Config' abbr -a :cdw 'cd ~/.config/wezterm/ # WezTerm Config'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.config/wezterm; nvim
abbr -a :cdwn 'cd ~/.config/wezterm;nvim' abbr -a :cdwn 'cd ~/.config/wezterm;nvim'
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Open new tab with nvim (terminal-aware)
abbr -a editt kitty @ launch --type tab nvim abbr -a editt kitty @ launch --type tab nvim
end end
# Spawn window # Spawn window
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc spwin (spawn new OS window)
abbr -a :sw spwin abbr -a :sw spwin
end end
end end
### Docker ### ### Docker ###
# @category Docker
# @desc docker context use default
abbr -a dcl 'docker context use default # Local Host' abbr -a dcl 'docker context use default # Local Host'
# @category Docker
# @desc ld (lazydocker)
abbr -a lzd ld abbr -a lzd ld
# @category Docker
# @desc docker context ls
abbr -a dcls 'docker context ls' abbr -a dcls 'docker context ls'
### Beads ### ### Beads ###
# @category Miscellaneous
# @desc bd list
abbr -a bl 'bd list' abbr -a bl 'bd list'
# @category Miscellaneous
# @desc bd sync
abbr -a bs 'bd sync' abbr -a bs 'bd sync'
# @category Miscellaneous
# @desc bd create --title
abbr -a bC 'bd create --title' abbr -a bC 'bd create --title'
# @category Miscellaneous
# @desc bd show
abbr -a bsh 'bd show' abbr -a bsh 'bd show'
# @category Miscellaneous
# @desc lazybeads
abbr -a lb lazybeads abbr -a lb lazybeads
### Systemctl ### ### Systemctl ###
# @category Systemctl
# @desc systemctl
abbr -a sc systemctl abbr -a sc systemctl
# @category Systemctl
# @desc sudo systemctl
abbr -a ssc 'sudo systemctl' abbr -a ssc 'sudo systemctl'
# @category Systemctl
# @desc systemctl --user
abbr -a scu 'systemctl --user' abbr -a scu 'systemctl --user'
# @category Systemctl
# @desc systemctl status
abbr -a st 'systemctl status' abbr -a st 'systemctl status'
# @category Systemctl
# @desc systemctl start
abbr -a scs 'systemctl start' abbr -a scs 'systemctl start'
# @category Systemctl
# @desc systemctl restart
abbr -a scr 'systemctl restart' abbr -a scr 'systemctl restart'
# @category Systemctl
# @desc sudo systemctl status
abbr -a ssct 'sudo systemctl status' abbr -a ssct 'sudo systemctl status'
# @category Systemctl
# @desc sudo systemctl start
abbr -a sscs 'sudo systemctl start' abbr -a sscs 'sudo systemctl start'
# @category Systemctl
# @desc sudo systemctl restart
abbr -a sscr 'sudo systemctl restart' abbr -a sscr 'sudo systemctl restart'
### Alternate command names ###
# Expand to the canonical function name so muscle-memory typos still work,
# while surfacing the real command instead of silently forwarding to it.
# @category Miscellaneous
# @desc repo-open
abbr -a open-repo repo-open
# @category Miscellaneous
# @desc open-url
abbr -a url-open open-url
### History Expansions and Substitutions ### ### History Expansions and Substitutions ###
# Bash-style history expansion is opinionated (C3 overrides), gated atomically # Bash-style history expansion is opinionated (C3 overrides), gated atomically
# with conf.d/tricks.fish, conf.d/puffer.fish, and functions/expand_*.fish. # with conf.d/tricks.fish, conf.d/puffer.fish, and functions/expand_*.fish.
if __fish_config_op_enabled __fish_config_op_overrides if __fish_config_op_enabled (status basename) abbr-overrides
# @category History Expansion
# @name !^
# @desc Expand to the first argument of the previous command
abbr -a !^ --position anywhere --function expand_bang_caret abbr -a !^ --position anywhere --function expand_bang_caret
# @category History Expansion
# @name !*
# @desc Expand to all arguments of the previous command
abbr -a '!*' --position anywhere --function expand_bang_all abbr -a '!*' --position anywhere --function expand_bang_all
# @category History Expansion
# @name ^old^new^
# @desc Interactive typo substitution (replace 'old' with 'new' in previous command)
abbr -a typo_sub --position anywhere --regex '\^([^^]+)\^([^^]*)' --function expand_typo_sub abbr -a typo_sub --position anywhere --regex '\^([^^]+)\^([^^]*)' --function expand_typo_sub
# @category History Expansion
# @name !string
# @desc Expand to the most recent command starting with 'string'
abbr -a bang_string --position anywhere --regex '![\w.-]+' --function expand_bang_string abbr -a bang_string --position anywhere --regex '![\w.-]+' --function expand_bang_string
# @category History Expansion
# @name !?string?
# @desc Expand to the most recent command containing 'string'
abbr -a bang_search --position anywhere --regex '!\?[\w.-]+\??' --function expand_bang_search abbr -a bang_search --position anywhere --regex '!\?[\w.-]+\??' --function expand_bang_search
# @category History Expansion
# @name !-n
# @desc Expand to the nth-previous command
abbr -a bang_minus_n --position anywhere --regex '!-(\d+)' --function expand_bang_minus_n abbr -a bang_minus_n --position anywhere --regex '!-(\d+)' --function expand_bang_minus_n
end end
+70
View File
@@ -0,0 +1,70 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# ╭──────────────────────────────────────────────────────────╮
# │ Auto-Pull (C2 — Autoexec)
# ╰──────────────────────────────────────────────────────────╯
#
# Background, fast-forward-only `git pull` for opted-in repositories. Fires
# when the working directory enters the fish-config repo (always covered as a
# baseline) or any repository registered via the `auto-pull` command. The
# actual sync is delegated to `_auto_pull_sync`, which only ever fast-forwards
# a clean repo — see that function for the full safety contract.
#
# Manage the registry with: auto-pull add / remove / list / status
# Registers an --on-variable PWD handler that backgrounds a git fetch. In a
# script that cd's, that is both wasted work and AGENTS.md Task #4's
# credential-prompt hazard fired from a background job.
status is-interactive; or return
# C2 guard: when auto-execution is disabled, do not register the handler.
__fish_config_op_enabled (status basename); or exit
# COMPONENT
# autoexec/sync
#
# SYNOPSIS
# __auto_pull_on_pwd (event handler, --on-variable PWD)
#
# DESCRIPTION
# On every directory change, checks whether the new $PWD is inside a
# registered repository (or the fish-config baseline) and, if so, kicks a
# background fast-forward. A throttle global ensures it fires once per
# repository entry rather than on every sub-directory change.
function __auto_pull_on_pwd --on-variable PWD
set -q __fish_config_dir; or set -g __fish_config_dir $XDG_CONFIG_HOME/fish
set -q __fish_user_dots_path; or set -l __fish_user_dots_path "$XDG_CONFIG_HOME/.user-dots/fish"
set -l list "$__fish_user_dots_path/auto-pull.list"
# Candidate roots: the fish-config repo plus the user's registry.
set -l roots $__fish_config_dir
test -r "$list"; and set -a roots (command cat "$list" 2>/dev/null)
# Find the registered root containing $PWD (exact match or a sub-directory).
set -l hit
for r in $roots
test -n "$r"; or continue
if test "$PWD" = "$r"; or string match -q -- "$r/*" "$PWD"
set hit "$r"
break
end
end
# Outside every registered repo: clear the throttle so re-entry re-syncs.
if test -z "$hit"
set -e __auto_pull_last
return
end
# Already synced for this repo entry — skip until we leave and return.
test "$hit" = "$__auto_pull_last"; and return
set -g __auto_pull_last "$hit"
# Background fast-forward. A --no-config child sources just the worker so
# it stays fast and free of shell side-effects; real `git`, no shadows.
set -l worker "$__fish_config_dir/functions/_auto_pull_sync.fish"
test -r "$worker"; or return
fish --no-config -c 'source $argv[1]; _auto_pull_sync $argv[2]' -- "$worker" "$hit" &
disown 2>/dev/null
end
+4 -1
View File
@@ -1,8 +1,11 @@
status is-interactive || exit status is-interactive || exit
# COMPONENT
# overrides/key-bindings
# Local modification: opinionated guard (AGENTS.md Task #3). Bracket # Local modification: opinionated guard (AGENTS.md Task #3). Bracket
# auto-pairing intercepts single-character input, classified as C3 overrides. # auto-pairing intercepts single-character input, classified as C3 overrides.
__fish_config_op_enabled __fish_config_op_overrides || exit __fish_config_op_enabled (status basename) || exit
set --global autopair_left "(" "[" "{" '"' "'" set --global autopair_left "(" "[" "{" '"' "'"
set --global autopair_right ")" "]" "}" '"' "'" set --global autopair_right ")" "]" "}" '"' "'"
+149
View File
@@ -0,0 +1,149 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# COMPONENT
# overrides/key-bindings
# Provides bash-style history expansion functions for abbreviations.
# These functions are gated by the C3 overrides switch.
# The six expand_* functions are reachable only through abbr --function
# (conf.d/abbr.fish:677-697), i.e. only during interactive expansion.
status is-interactive; or return
# Execute expand_bang_all
function expand_bang_all --description 'Execute expand_bang_all'
# Opinionated guard (C3): no expansion when overrides are disabled.
__fish_config_op_enabled (status basename); or return 1
set -l token $argv[1]
if test -z "$token"
set token (commandline -t)
end
set -l tokens (string split -n " " -- $history[1])
if test (count $tokens) -gt 1
echo -- (string join " " -- $tokens[2..-1])
else
echo -- $token
end
end
# Execute expand_bang_caret
function expand_bang_caret --description 'Execute expand_bang_caret'
# Opinionated guard (C3): no expansion when overrides are disabled.
__fish_config_op_enabled (status basename); or return 1
# Split the last history item into a list
set -l tokens (string split -n ' ' -- $history[1])
# tokens[1] is the command, tokens[2] is the first argument
if set -q tokens[2]
echo -- $tokens[2]
end
end
# Execute expand_bang_minus_n
function expand_bang_minus_n --description 'Execute expand_bang_minus_n'
# Opinionated guard (C3): no expansion when overrides are disabled.
__fish_config_op_enabled (status basename); or return 1
set -l token $argv[1]
if test -z "$token"
set token (commandline -t)
end
# Extract the number from the regex match
if string match -qr '!-(\d+)' -- "$token"
set -l n (string match -r '!-(\d+)' -- "$token")[2]
if test (count $history) -ge $n
echo -- $history[$n]
else
echo -- $token
end
else
echo -- $token
end
end
# Execute expand_bang_search
function expand_bang_search --description 'Execute expand_bang_search'
# Opinionated guard (C3): no expansion when overrides are disabled.
__fish_config_op_enabled (status basename); or return 1
set -l token $argv[1]
if test -z "$token"
set token (commandline -t)
end
# Extract query: looks for text after !? and before an optional ?
set -l query (string match -r '!\?([^?]+)' -- $token)[2]
if test -n "$query"
# Search history for a match anywhere in the command
set -l match (builtin history search --contains --max=1 -- $query)
if test -n "$match"
echo -- $match
return
end
end
echo -- $token
end
# Execute expand_bang_string
function expand_bang_string --description 'Execute expand_bang_string'
# Opinionated guard (C3): no expansion when overrides are disabled.
__fish_config_op_enabled (status basename); or return 1
# Fish 4.x passes the matched token as argv[1]
set -l token $argv[1]
if test -z "$token"
set token (commandline -t)
end
# Remove the '!' to get the search query
set -l query (string sub -s 2 -- $token)
if test -n "$query"
# Search history for a prefix match
set -l match (builtin history search --prefix --max=1 -- $query)
if test -n "$match"
echo -- $match
return
end
end
# If no match or empty query, return the token so it doesn't vanish
echo -- $token
end
# Execute expand_typo_sub
function expand_typo_sub --description 'Execute expand_typo_sub'
# Opinionated guard (C3): no expansion when overrides are disabled.
__fish_config_op_enabled (status basename); or return 1
# In newer Fish, the matched token is often passed as $argv[1]
# if the abbr is set up correctly. We'll fallback to commandline just in case.
set -l last_cmd $history[1]
set -l current_token $argv[1]
if test -z "$current_token"
set current_token (commandline -t)
end
if string match -qr '\^([^^]+)\^([^^]*)' -- "$current_token"
set -l captured (string match -r '\^([^^]+)\^([^^]*)' -- "$current_token")
set -l old $captured[2]
set -l new $captured[3]
if test -n "$old"
# Using -- to ensure strings starting with '-' aren't treated as flags
echo -- (string replace -a -- "$old" "$new" "$last_cmd")
end
else
# Return the token itself so it doesn't vanish
echo -- "$current_token"
end
end
+4 -1
View File
@@ -19,6 +19,9 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE. # SOFTWARE.
#
# COMPONENT
# integrations/notifications
if not status is-interactive if not status is-interactive
exit exit
@@ -26,7 +29,7 @@ end
# Local modification: opinionated guard (AGENTS.md Task #3). Desktop # Local modification: opinionated guard (AGENTS.md Task #3). Desktop
# notifications assume a graphical session, classified as C4 integrations. # notifications assume a graphical session, classified as C4 integrations.
__fish_config_op_enabled __fish_config_op_integrations; or exit __fish_config_op_enabled (status basename); or exit
set -g __done_version 1.19.1 set -g __done_version 1.19.1
+16 -2
View File
@@ -7,6 +7,10 @@
# #
# Runs exactly once on the first interactive fish session after install. # Runs exactly once on the first interactive fish session after install.
# To reset for testing, run: set -Ue __fish_config_first_run_complete # To reset for testing, run: set -Ue __fish_config_first_run_complete
#
# COMPONENT
# site first-run-greeting: greeting/first-run
# site first-run-bootstrap: autoexec/plugin-management
# Exit early in non-interactive shells (scripts, completions, subshells) # Exit early in non-interactive shells (scripts, completions, subshells)
if not status is-interactive if not status is-interactive
@@ -22,11 +26,21 @@ end
# leave the shell in a state that re-triggers everything next session. # leave the shell in a state that re-triggers everything next session.
set -U __fish_config_first_run_complete 1 set -U __fish_config_first_run_complete 1
# ──────────────────────────── Man page symlink ──────────────────────────
# Install fish-config.1 into the user man database once, like an install step.
# Unconditional: standard enough that no category gate is warranted.
set -l _man1 ~/.local/share/man/man1
set -l _src ~/.config/fish/docs/fish-config.1
if test -f $_src; and not test -L $_man1/fish-config.1
mkdir -p $_man1
ln -sf $_src $_man1/fish-config.1
end
# ──────────────────────────── Welcome message ─────────────────────────── # ──────────────────────────── Welcome message ───────────────────────────
# Printing a first-run welcome banner is opinionated (C6 greeting). The # Printing a first-run welcome banner is opinionated (C6 greeting). The
# first-run state variable is already set unconditionally above, so # first-run state variable is already set unconditionally above, so
# disabling the greeting never re-triggers this file. # disabling the greeting never re-triggers this file.
if __fish_config_op_enabled __fish_config_op_greeting if __fish_config_op_enabled (status basename) first-run-greeting
echo "" echo ""
echo " Welcome to your fish shell configuration!" echo " Welcome to your fish shell configuration!"
echo " Run 'help config' for offline documentation." echo " Run 'help config' for offline documentation."
@@ -38,7 +52,7 @@ end
# Startup side-effects below (Fisher curl, fisher update, theme apply) are # Startup side-effects below (Fisher curl, fisher update, theme apply) are
# opinionated (C2 auto-execution). The first-run state variable is already # opinionated (C2 auto-execution). The first-run state variable is already
# set above either way, so disabling auto-exec never re-triggers this file. # set above either way, so disabling auto-exec never re-triggers this file.
if not __fish_config_op_enabled __fish_config_op_autoexec if not __fish_config_op_enabled (status basename) first-run-bootstrap
return return
end end
+70
View File
@@ -0,0 +1,70 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# ╭──────────────────────────────────────────────────────────╮
# │ help config wrapper │
# ╰──────────────────────────────────────────────────────────╯
#
# COMPONENT
# aliases/shell-tools
#
# SYNOPSIS
# help [topic] [sub-topic...]
# help config [section] [-w|--html] [-m|--man] [-h|--help]
#
# DESCRIPTION
# Wraps the built-in Fish help command. Intercepts the specific topic
# "config" and forwards any subsequent sub-topics/arguments straight to the
# custom 'config-help' utility. For all other topics, it forwards the
# arguments intact to the original, built-in system help utility.
#
# When the first argument is "config", the following flags are recognized
# and delegated to 'config-help':
# -w, --html Open the offline HTML docs in the default browser
# -m, --man Open the compiled man page via man -l
# -h, --help Print config-help usage reference
#
# Flags that appear WITHOUT a leading "config" argument — including
# -h/--help — are forwarded unchanged to the native Fish help command, so
# built-in behavior is never overridden for non-config topics.
#
# NOTES
# To prevent infinite recursion, the wrapper backs up the native help
# function as '__original_help' before shadowing it. This MUST happen from
# conf.d, not functions/help.fish: as of Fish 4.x the native help is
# embedded in the binary (embedded:functions/help.fish) with no on-disk
# file to source, and a functions/help.fish autoload shadow makes the name
# 'help' resolve to our own wrapper (or nothing, mid-autoload) — so the
# backup could never capture the real help. Sourced here at startup, before
# any shadow exists, `functions -c help` copies the embedded original.
#
# EXAMPLE
# help config keys # → config-help keys
# help config --html # opens the offline HTML docs in the browser
# help config keys --man # opens the compiled man page via man -l
# help string # forwards to native fish docs for 'string'
# --- Initialization & Backup ---
# Copy the native (embedded) help to __original_help before we shadow it.
if not functions -q __original_help
functions -c help __original_help
end
# --- Wrapper Definition ---
function help --wraps help --description "Custom wrapper to intercept 'help config'"
# Opinionated guard (C1): fall back to the native fish help when disabled.
if not __fish_config_op_enabled (status current-function)
__original_help $argv
return $status
end
if test "$argv[1]" = config
# All arguments after 'config' — including flags (-w/--html, -m/--man,
# -h/--help) and section keywords — are forwarded to config-help.
# Flags are only intercepted here when 'config' is the first argument,
# so native fish help flags are never shadowed for other topics.
config-help $argv[2..]
else
__original_help $argv
end
end
+26 -3
View File
@@ -8,6 +8,9 @@
# This file defines custom key bindings for the Fish shell. # This file defines custom key bindings for the Fish shell.
# It is sourced by Fish on startup. # It is sourced by Fish on startup.
# COMPONENT
# overrides/key-bindings
# ────────────────── Bind Prewious Path Head to Ctrl+G ───────────────── # ────────────────── Bind Prewious Path Head to Ctrl+G ─────────────────
# Bindings to insert the previous path head into the command line # Bindings to insert the previous path head into the command line
# Behaves like `!$:h` does in bash # Behaves like `!$:h` does in bash
@@ -44,11 +47,19 @@
# This allows for rapid-fire math without leaving the current shell. # This allows for rapid-fire math without leaving the current shell.
# ────────────────────────────────────────────────────────────────────── # ──────────────────────────────────────────────────────────────────────
# Defines only fish_user_key_bindings, which fish calls from the interactive
# reader and nowhere else.
status is-interactive; or return
function fish_user_key_bindings function fish_user_key_bindings
# Custom key chords are opinionated (C3 overrides); skip them entirely # Custom key chords are opinionated (C3 overrides); skip them entirely
# when overrides are disabled so stock bindings remain untouched. # when overrides are disabled so stock bindings remain untouched.
__fish_config_op_enabled __fish_config_op_overrides; or return # NOTE: (status basename), not (status current-function) -- this guard
# lives inside fish's own reserved fish_user_key_bindings function, whose
# name is not this file's identity; the registry key is this file's
# bare basename, key_bindings.
__fish_config_op_enabled (status basename); or return
# ───────────────────────────── Set Bindings ───────────────────────────── # ───────────────────────────── Set Bindings ─────────────────────────────
# #
@@ -58,7 +69,8 @@ function fish_user_key_bindings
bind ctrl-alt-u _replace_command_token bind ctrl-alt-u _replace_command_token
type -q qalc && bind ctrl-alt-= _qalc_eval type -q qalc && bind ctrl-alt-= _qalc_eval
bind ctrl-enter _smart_execute bind ctrl-enter _smart_execute
bind @@ __fzf_inline_picker bind ctrl-right nextd-or-forward-word
bind \e\[1\;5C nextd-or-forward-word
# Set bindings for all Vi modes: # Set bindings for all Vi modes:
# 'default' is Vi-Command, 'insert' is Vi-Insert, 'visual' is Vi-Visual # 'default' is Vi-Command, 'insert' is Vi-Insert, 'visual' is Vi-Visual
@@ -68,6 +80,17 @@ function fish_user_key_bindings
bind --mode $mode ctrl-alt-u _replace_command_token bind --mode $mode ctrl-alt-u _replace_command_token
type -q qalc && bind --mode $mode ctrl-alt-= _qalc_eval type -q qalc && bind --mode $mode ctrl-alt-= _qalc_eval
bind --mode $mode ctrl-enter _smart_execute bind --mode $mode ctrl-enter _smart_execute
bind --mode $mode @@ __fzf_inline_picker bind --mode $mode ctrl-right nextd-or-forward-word
bind --mode $mode \e\[1\;5C nextd-or-forward-word
end end
# @ is Emacs/Vi-insert only. Emacs bindings and Vi's "default" (normal)
# mode share the same bind_mode name, so a mode-less `bind @` would also
# land in Vi normal mode, turning its current no-op @ into a self-insert.
# Register the mode-less form only when Vi bindings aren't the active
# base, and rely on the explicit insert-mode bind otherwise.
if test "$fish_key_bindings" != fish_vi_key_bindings
bind @ __fzf_inline_picker
end
bind --mode insert @ __fzf_inline_picker
end end
+25
View File
@@ -0,0 +1,25 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# COMPONENT
# logging/terminal-capture
#
# C5 — Logging & Capture: a non-blocking, per-session reminder shown inside Kitty
# when the fish-config scrollback watcher is not yet set up. It never blocks the
# shell; it simply prints how to enable or silence it. The notice stops once the
# user runs `kitty-logging install` (a watcher line then exists in kitty.conf) or
# `kitty-logging dismiss` (sets the universal variable below).
status is-interactive; or exit
type -q kitty; or exit
set -q KITTY_WINDOW_ID; or exit
__fish_config_op_enabled (status basename); or exit
__fish_variable_check __fish_config_kitty_watcher_dismissed; and exit
__kitty_logging_has_watcher; and exit
set_color --bold yellow
echo "Kitty session logging is available but not set up."
set_color normal
echo " Enable: kitty-logging install"
echo " Silence: kitty-logging dismiss"
+6
View File
@@ -13,6 +13,12 @@
# solely in functions/ are never registered and their --on-variable triggers # solely in functions/ are never registered and their --on-variable triggers
# never fire. # never fire.
# Calls __fish_config_sync_logging at every shell start, which mkdir+touches
# the C5 sentinel on disk. Its only consumers — the Kitty watcher and the
# paru/yay wrappers — are interactive-context; every interactive shell still
# refreshes it.
status is-interactive; or return
function __fish_config_logging_changed --on-variable __fish_config_op_logging \ function __fish_config_logging_changed --on-variable __fish_config_op_logging \
--description 'C5 event handler: sync logging state when __fish_config_op_logging changes' --description 'C5 event handler: sync logging state when __fish_config_op_logging changes'
__fish_config_sync_logging __fish_config_sync_logging
+40 -12
View File
@@ -2,15 +2,24 @@
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
# #
# Generates ~/.local/bin/paru on first run (and on version bump) when # Generates ~/.local/bin/paru on first run (and on version bump) when
# /usr/bin/paru is installed. The wrapper tees paru output to a # paru is installed. The wrapper runs paru in a PTY so progress
# timestamped log file and prunes old logs, mirroring smart_exit behavior. # bars are preserved, renders the captured animation to a clean static log
# (via scripts/clean_progress_log.py), and prunes old logs.
# COMPONENT
# site paru-autoexec: autoexec/pkg-wrappers
# site paru-logging: logging/pkg-logs
# Defines nothing; its only effect is generating ~/.local/bin/paru, an
# idempotent write every interactive session already performs.
status is-interactive; or return
# Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec). # Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec).
# Wrapper generation is also gated by C5 (Logging & Capture). # Wrapper generation is also gated by C5 (Logging & Capture).
__fish_config_op_enabled __fish_config_op_autoexec; or return __fish_config_op_enabled (status basename) paru-autoexec; or return
# C5 — Logging & Capture: remove generated wrapper and skip when logging is off # C5 — Logging & Capture: remove generated wrapper and skip when logging is off
if not __fish_config_op_enabled __fish_config_op_logging if not __fish_config_op_enabled (status basename) paru-logging
if test -f "$HOME/.local/bin/paru" if test -f "$HOME/.local/bin/paru"
and grep -q "# paru-wrapper-version:" "$HOME/.local/bin/paru" 2>/dev/null and grep -q "# paru-wrapper-version:" "$HOME/.local/bin/paru" 2>/dev/null
rm -f "$HOME/.local/bin/paru" rm -f "$HOME/.local/bin/paru"
@@ -18,12 +27,13 @@ if not __fish_config_op_enabled __fish_config_op_logging
return return
end end
set -l _paru_real /usr/bin/paru # Resolve the real paru binary, skipping our own shim (never /usr/bin-assumed).
set -l _paru_real (__fish_real_command paru)
set -l _paru_wrapper "$HOME/.local/bin/paru" set -l _paru_wrapper "$HOME/.local/bin/paru"
set -l _paru_wrapper_version 1 set -l _paru_wrapper_version 6
# Skip entirely if the real paru binary isn't present # Skip entirely if the real paru binary isn't present
test -x $_paru_real; or return test -x "$_paru_real"; or return
# Check if wrapper already exists at the expected version # Check if wrapper already exists at the expected version
if test -f $_paru_wrapper if test -f $_paru_wrapper
@@ -38,22 +48,40 @@ printf '%s\n' \
'#!/usr/bin/env bash' \ '#!/usr/bin/env bash' \
"# paru-wrapper-version: $_paru_wrapper_version" \ "# paru-wrapper-version: $_paru_wrapper_version" \
'# Auto-generated by conf.d/paru-wrapper.fish — do not edit by hand.' \ '# Auto-generated by conf.d/paru-wrapper.fish — do not edit by hand.' \
'# Tees paru output to a timestamped log file and prunes old ones.' \ '# Runs paru in a PTY via script(1) so progress bars are preserved on screen,' \
'set -o pipefail' \ '# then renders the captured terminal animation to a clean static log.' \
'' \ '' \
'log_dir="${SCROLLBACK_HISTORY_DIR:-$HOME/.terminal_history}"' \ 'log_dir="${SCROLLBACK_HISTORY_DIR:-$HOME/.terminal_history}"' \
'mkdir -p "$log_dir"' \ 'mkdir -p "$log_dir"' \
'log_file="$log_dir/paru_$(date +%Y-%m-%d_%H-%M-%S).log"' \ 'log_file="$log_dir/paru_$(date +%Y-%m-%d_%H-%M-%S).log"' \
'' \ '' \
'/usr/bin/paru "$@" 2>&1 | tee "$log_file"' \ '# Build a safely-quoted command string for script(1).' \
'# script(1) allocates a PTY so paru detects a real terminal and shows progress.' \
"cmd_str=\"$_paru_real\"" \
'for arg in "$@"; do' \
' cmd_str+=" $(printf '"'"'%q'"'"' "$arg")"' \
done \
'script -q -e -c "$cmd_str" "$log_file"' \
'exit_code=$?' \
'' \
'# Render the captured terminal animation (progress bars repaint in place via' \
'# cursor moves) down to its final static frame, preserving ANSI color. Falls' \
'# back to dropping only the script(1) header/footer when python3 is missing.' \
'cleaner="${XDG_CONFIG_HOME:-$HOME/.config}/fish/scripts/clean_progress_log.py"' \
'if command -v python3 >/dev/null 2>&1 && [[ -f "$cleaner" ]]; then' \
' python3 "$cleaner" < "$log_file" > "${log_file}.tmp" 2>/dev/null && mv "${log_file}.tmp" "$log_file" || rm -f "${log_file}.tmp"' \
else \
' sed -i "/^Script \(started\|done\) on /d" "$log_file" 2>/dev/null || true' \
fi \
'' \ '' \
'max_files="${SCROLLBACK_HISTORY_MAX_FILES:-100}"' \ 'max_files="${SCROLLBACK_HISTORY_MAX_FILES:-100}"' \
'mapfile -t logs < <(ls -1t "$log_dir"/paru_*.log 2>/dev/null)' \ 'mapfile -t logs < <(ls -1t "$log_dir"/paru_*.log 2>/dev/null)' \
'excess=$(( ${#logs[@]} - max_files ))' \ 'excess=$(( ${#logs[@]} - max_files ))' \
'for (( i = ${#logs[@]} - 1; i >= ${#logs[@]} - excess && i >= 0; i-- )); do' \ 'for (( i = ${#logs[@]} - 1; i >= ${#logs[@]} - excess && i >= 0; i-- )); do' \
' rm -f "${logs[$i]}"' \ ' rm -f "${logs[$i]}"' \
'done' \ done \
> $_paru_wrapper '' \
'exit $exit_code' >$_paru_wrapper
chmod +x $_paru_wrapper chmod +x $_paru_wrapper
+16 -1
View File
@@ -1,9 +1,12 @@
status is-interactive || exit status is-interactive || exit
# COMPONENT
# overrides/key-bindings
# Local modification: opinionated guard (AGENTS.md Task #3). Puffer's key # Local modification: opinionated guard (AGENTS.md Task #3). Puffer's key
# intercepts are part of the bang-bang system, gated atomically under C3 # intercepts are part of the bang-bang system, gated atomically under C3
# overrides with conf.d/tricks.fish, conf.d/abbr.fish, and expand_*.fish. # overrides with conf.d/tricks.fish, conf.d/abbr.fish, and expand_*.fish.
__fish_config_op_enabled __fish_config_op_overrides || exit __fish_config_op_enabled (status basename) || exit
function _puffer_fish_key_bindings --on-variable fish_key_bindings function _puffer_fish_key_bindings --on-variable fish_key_bindings
set -l modes set -l modes
@@ -13,9 +16,21 @@ function _puffer_fish_key_bindings --on-variable fish_key_bindings
set modes insert default set modes insert default
end end
# @category History Expansion
# @name !.
# @desc Expand .. to ../.. and so on
bind --mode $modes[1] '.' _puffer_fish_expand_dot bind --mode $modes[1] '.' _puffer_fish_expand_dot
# @category History Expansion
# @name !!
# @desc Expand to the previous command
bind --mode $modes[1] '!' _puffer_fish_expand_bang bind --mode $modes[1] '!' _puffer_fish_expand_bang
# @category History Expansion
# @name !$
# @desc Expand to the last argument of the previous command
bind --mode $modes[1] '$' _puffer_fish_expand_buck bind --mode $modes[1] '$' _puffer_fish_expand_buck
# @category History Expansion
# @name !*
# @desc Expand to all arguments of the previous command
bind --mode $modes[1] '*' _puffer_fish_expand_star bind --mode $modes[1] '*' _puffer_fish_expand_star
bind --mode $modes[2] --erase '.' '!' '$' '*' bind --mode $modes[2] --erase '.' '!' '$' '*'
end end
+13 -2
View File
@@ -95,8 +95,19 @@ function __sponge_register_secret_values --on-event fish_prompt
set -l secret_values set -l secret_values
set -l sensitive_vars (set --names --export | string match --regex -- \ # Base credential-name tokens, plus any user-supplied extras from
'(?i)(?:TOKEN|PASSWORD|PASSWD|SECRET|API[_-]KEY|PRIVATE[_-]KEY|ACCESS[_-]KEY|AUTH[_-]KEY|CREDENTIAL|KOPIA_PASSWORD)') # __fish_sponge_extra_sensitive (set via config-settings → Sponge page).
set -l _sensitive_names \
TOKEN PASSWORD PASSWD SECRET 'API[_-]KEY' 'PRIVATE[_-]KEY' \
'ACCESS[_-]KEY' 'AUTH[_-]KEY' CREDENTIAL KOPIA_PASSWORD \
$__fish_sponge_extra_sensitive
set -l _sensitive_alt (string join '|' $_sensitive_names)
# --entire returns the full matching variable NAME (e.g. GITHUB_TOKEN), not
# just the matched token substring (TOKEN) — required so $$var below
# dereferences the real variable instead of an unset partial name.
set -l sensitive_vars (set --names --export | string match --regex --entire -- \
"(?i)(?:$_sensitive_alt)")
for var in $sensitive_vars for var in $sensitive_vars
# Take only the first element — array vars yield multiple values. # Take only the first element — array vars yield multiple values.
+9 -1
View File
@@ -1,12 +1,20 @@
# Copyright (C) 2026 Rootiest # Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
# COMPONENT
# overrides/prompt
# #
# Defines fish_prompt only when starship is installed. # Defines fish_prompt only when starship is installed.
# Without starship, fish's built-in prompt already emits OSC 133;A # Without starship, fish's built-in prompt already emits OSC 133;A
# on the prompt line itself, so no wrapper is needed. # on the prompt line itself, so no wrapper is needed.
# Defines fish_prompt; no script renders a prompt. Checked before the
# op-guard so the builtin short-circuits ahead of three function autoloads.
status is-interactive; or return
# Replacing the prompt is opinionated (C3 overrides) # Replacing the prompt is opinionated (C3 overrides)
__fish_config_op_enabled __fish_config_op_overrides; or return __fish_config_op_enabled (status basename); or return
type -q starship; or return type -q starship; or return
+10 -1
View File
@@ -1,5 +1,9 @@
# Copyright (C) 2026 Rootiest # Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
# COMPONENT
# overrides/prompt
# #
# ╭──────────────────────────────────────────────────────────╮ # ╭──────────────────────────────────────────────────────────╮
# │ Fish Theme │ # │ Fish Theme │
@@ -9,13 +13,18 @@
# Forcing theme colors and $FZF_DEFAULT_OPTS is opinionated (C3 overrides). # Forcing theme colors and $FZF_DEFAULT_OPTS is opinionated (C3 overrides).
# The FZF variable is universal, so clean up our Catppuccin value if it # The FZF variable is universal, so clean up our Catppuccin value if it
# lingers from a session where overrides were still enabled. # lingers from a session where overrides were still enabled.
if not __fish_config_op_enabled __fish_config_op_overrides if not __fish_config_op_enabled (status basename)
if set -q FZF_DEFAULT_OPTS; and string match -q '*#1E1E2E*' -- "$FZF_DEFAULT_OPTS" if set -q FZF_DEFAULT_OPTS; and string match -q '*#1E1E2E*' -- "$FZF_DEFAULT_OPTS"
set --erase FZF_DEFAULT_OPTS set --erase FZF_DEFAULT_OPTS
end end
return return
end end
# Below the cleanup block on purpose: that branch erases a stale universal
# FZF_DEFAULT_OPTS and must keep running wherever it runs today. Everything
# past here is fish_color_* for the syntax highlighter, interactive-only.
status is-interactive; or return
# ────────────────────── Syntax highlighting colors ────────────────────── # ────────────────────── Syntax highlighting colors ──────────────────────
set --global fish_color_autosuggestion 6c7086 set --global fish_color_autosuggestion 6c7086
set --global fish_color_cancel f38ba8 set --global fish_color_cancel f38ba8
+18
View File
@@ -0,0 +1,18 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# COMPONENT
# logging/multiplexer-capture
#
# C5 — Logging & Capture: starts a pipe-pane log for the current tmux pane
# when fish launches inside a tmux session. Each fish shell gets its own
# timestamped log file in SCROLLBACK_HISTORY_DIR (default: ~/.terminal_history).
# Naming: tmux_<session>-w<window>-p<pane>_YYYY-MM-DD_HH-MM-SS.log
__fish_config_op_enabled (status basename); or exit
status is-interactive; or exit
type -q tmux; or exit
set -q TMUX; or exit
_tmux_pipe_log
+76 -21
View File
@@ -7,32 +7,43 @@
# │ system aliases, and history/backup utilities │ # │ system aliases, and history/backup utilities │
# ╰──────────────────────────────────────────────────────────╯ # ╰──────────────────────────────────────────────────────────╯
# COMPONENT
# site aliases-tricks: aliases/filesystem
# site tricks-manpager: overrides/environment
# site tricks-bang: overrides/key-bindings
## Environment setup ## Environment setup
# Apply .profile: use this to put fish compatible .profile stuff in # Apply .profile: use this to put fish compatible .profile stuff in
if test -f ~/.fish_profile if test -f ~/.fish_profile
source ~/.fish_profile source ~/.fish_profile
end end
# Append unique directories to $PATH (fish_add_path handles duplicates automatically) # This file is sourced twice per shell on CachyOS (once by the conf.d
fish_add_path ~/.local/bin # autoload, once forced by config.fish to re-win over the distro's own
fish_add_path ~/Applications/depot_tools # tricks.fish). The PATH/MANPAGER setup below doesn't need to repeat on
# the second pass -- only the functions/aliases further down do, since
# those are what re-assert over the distro config. Gate the expensive
# calls (fish_add_path, type -q bat) behind a once-per-session guard.
# ponytail: per-session guard, not per-value; if this file grows more
# expensive one-time setup, extend the same guard rather than adding more.
if not set -q __fish_config_tricks_env_applied
set -g __fish_config_tricks_env_applied 1
# Expose user-local man pages and keep fish-config.1 symlink current # Append unique directories to $PATH (fish_add_path handles duplicates automatically)
if not contains ~/.local/share/man $MANPATH fish_add_path ~/.local/bin
set -gx MANPATH ~/.local/share/man $MANPATH fish_add_path ~/Applications/depot_tools
end
set -l _man1 ~/.local/share/man/man1
set -l _src ~/.config/fish/docs/fish-config.1
if test -f $_src; and not test -L $_man1/fish-config.1
mkdir -p $_man1
ln -sf $_src $_man1/fish-config.1
end
# Format man pages using bat (only if bat is installed) # Expose user-local man pages
# Overriding $MANPAGER is opinionated (C3 overrides) if not contains ~/.local/share/man $MANPATH
if type -q bat; and __fish_config_op_enabled __fish_config_op_overrides set -gx MANPATH ~/.local/share/man $MANPATH
set -gx MANROFFOPT -c end
set -gx MANPAGER "sh -c 'col -bx | bat -l man -p'"
# Format man pages using bat (only if bat is installed)
# Overriding $MANPAGER is opinionated (C3 overrides)
if type -q bat; and __fish_config_op_enabled (status basename) tricks-manpager
set -gx MANROFFOPT -c
set -gx MANPAGER "sh -c 'col -bx | bat -l man -p'"
end
end end
# Set settings for https://github.com/franciscolourenco/done # Set settings for https://github.com/franciscolourenco/done
@@ -43,7 +54,7 @@ set -gx __done_notification_urgency_level low
# Functions needed for !! and !$ https://github.com/oh-my-fish/plugin-bang-bang # Functions needed for !! and !$ https://github.com/oh-my-fish/plugin-bang-bang
# The bang-bang system is opinionated (C3 overrides) and is gated atomically # The bang-bang system is opinionated (C3 overrides) and is gated atomically
# here, in conf.d/abbr.fish, conf.d/puffer.fish, and functions/expand_*.fish. # here, in conf.d/abbr.fish, conf.d/puffer.fish, and functions/expand_*.fish.
if __fish_config_op_enabled __fish_config_op_overrides if __fish_config_op_enabled (status basename) tricks-bang
function __history_previous_command function __history_previous_command
switch (commandline -t) switch (commandline -t)
case "!" case "!"
@@ -66,10 +77,22 @@ if __fish_config_op_enabled __fish_config_op_overrides
# Apply bang-bang key bindings based on current key binding mode # Apply bang-bang key bindings based on current key binding mode
if [ "$fish_key_bindings" = fish_vi_key_bindings ] if [ "$fish_key_bindings" = fish_vi_key_bindings ]
# @category History Expansion
# @name !!
# @desc Expand to the previous command
bind -Minsert ! __history_previous_command bind -Minsert ! __history_previous_command
# @category History Expansion
# @name !$
# @desc Expand to the last argument of the previous command
bind -Minsert '$' __history_previous_command_arguments bind -Minsert '$' __history_previous_command_arguments
else else
# @category History Expansion
# @name !!
# @desc Expand to the previous command
bind ! __history_previous_command bind ! __history_previous_command
# @category History Expansion
# @name !$
# @desc Expand to the last argument of the previous command
bind '$' __history_previous_command_arguments bind '$' __history_previous_command_arguments
end end
end end
@@ -77,7 +100,7 @@ end
# Fish command history override to show timestamps # Fish command history override to show timestamps
# Shadowing the history command is opinionated (C1 aliasing); when disabled, # Shadowing the history command is opinionated (C1 aliasing); when disabled,
# the function is never defined and fish's stock history behavior applies. # the function is never defined and fish's stock history behavior applies.
if __fish_config_op_enabled __fish_config_op_aliases if __fish_config_op_enabled (status basename) aliases-tricks
function history function history
builtin history --show-time='%F %T ' builtin history --show-time='%F %T '
end end
@@ -100,23 +123,47 @@ end
## Useful aliases ## Useful aliases
# Navigation short-cuts # Navigation short-cuts
# @category Shell Aliases
# @desc cd ..
alias ..='cd ..' alias ..='cd ..'
# @category Shell Aliases
# @desc cd ../..
alias ...='cd ../..' alias ...='cd ../..'
# @category Shell Aliases
# @desc cd ../../..
alias ....='cd ../../..' alias ....='cd ../../..'
# @category Shell Aliases
# @desc cd ../../../..
alias .....='cd ../../../..' alias .....='cd ../../../..'
# @category Shell Aliases
# @desc cd ../../../../..
alias ......='cd ../../../../..' alias ......='cd ../../../../..'
# Silent flag injection into POSIX tools is opinionated (C1 aliasing) # Silent flag injection into POSIX tools is opinionated (C1 aliasing)
if __fish_config_op_enabled __fish_config_op_aliases if __fish_config_op_enabled (status basename) aliases-tricks
# Tools & Core command color overrides # Tools & Core command color overrides
# @category Shell Aliases
# @desc dir --color=auto
alias dir='dir --color=auto' alias dir='dir --color=auto'
# @category Shell Aliases
# @desc vdir --color=auto
alias vdir='vdir --color=auto' alias vdir='vdir --color=auto'
# @category Shell Aliases
# @desc grep --color=auto
alias grep='grep --color=auto' alias grep='grep --color=auto'
# @category Shell Aliases
# @desc fgrep --color=auto
alias fgrep='fgrep --color=auto' alias fgrep='fgrep --color=auto'
# @category Shell Aliases
# @desc egrep --color=auto
alias egrep='egrep --color=auto' alias egrep='egrep --color=auto'
# Safety aliases (Confirmation before overwriting/deleting) # Safety aliases (Confirmation before overwriting/deleting)
# @category Shell Aliases
# @desc cp -i
alias cp="cp -i" alias cp="cp -i"
# @category Shell Aliases
# @desc mv -i
alias mv="mv -i" alias mv="mv -i"
# Force wget to resume partial downloads # Force wget to resume partial downloads
@@ -124,9 +171,17 @@ if __fish_config_op_enabled __fish_config_op_aliases
end end
# Archives and networking short-hands # Archives and networking short-hands
# @category Shell Aliases
# @desc tar -acf
alias tarnow='tar -acf ' alias tarnow='tar -acf '
# @category Shell Aliases
# @desc tar -zxvf
alias untar='tar -zxvf ' alias untar='tar -zxvf '
# @category Shell Aliases
# @desc nc termbin.com 9999
alias tb='nc termbin.com 9999' alias tb='nc termbin.com 9999'
# System Logs # System Logs
# @category Shell Aliases
# @desc journalctl -p 3 -xb
alias jctl="journalctl -p 3 -xb" alias jctl="journalctl -p 3 -xb"
+37 -28
View File
@@ -5,44 +5,53 @@
# see: https://github.com/ik11235/wakatime.fish # see: https://github.com/ik11235/wakatime.fish
### ###
# COMPONENT
# site wakatime-autoexec: autoexec/telemetry
# site wakatime-hook: integrations/notifications
# Registers a fish_postexec handler; that event is emitted only by the
# interactive reader, so the handler is dead weight in a script.
status is-interactive; or return
# Local modification: opinionated guard (AGENTS.md Task #3). WakaTime # Local modification: opinionated guard (AGENTS.md Task #3). WakaTime
# reporting is classified under both C2 auto-execution and C4 integrations; # reporting is classified under both C2 auto-execution and C4 integrations;
# disabling either category skips registering the hook. # disabling either category skips registering the hook.
__fish_config_op_enabled __fish_config_op_autoexec; or exit __fish_config_op_enabled (status basename) wakatime-autoexec; or exit
__fish_config_op_enabled __fish_config_op_integrations; or exit __fish_config_op_enabled (status basename) wakatime-hook; or exit
function __register_wakatime_fish_before_exec -e fish_postexec function __register_wakatime_fish_before_exec -e fish_postexec
if set -q FISH_WAKATIME_DISABLED if set -q FISH_WAKATIME_DISABLED
return 0 return 0
end end
set -l exec_command_str
set exec_command_str (string split -f1 ' ' "$argv") set -l exec_command_str
if test "$exec_command_str" = 'exit' set exec_command_str (string split -f1 ' ' "$argv")
return 0
end
set -l PLUGIN_NAME "ik11235/wakatime.fish" if test "$exec_command_str" = exit
set -l PLUGIN_VERSION "0.0.6" return 0
end
set -l project set -l PLUGIN_NAME "ik11235/wakatime.fish"
set -l wakatime_path set -l PLUGIN_VERSION "0.0.6"
if type -p wakatime 2>&1 > /dev/null set -l project
set wakatime_path (type -p wakatime) set -l wakatime_path
else if type -p ~/.wakatime/wakatime-cli 2>&1 > /dev/null
set wakatime_path (type -p ~/.wakatime/wakatime-cli)
else
return 1
end
if git rev-parse --is-inside-work-tree &> /dev/null if type -p wakatime 2>&1 >/dev/null
set project (basename (git rev-parse --show-toplevel)) set wakatime_path (type -p wakatime)
else else if type -p ~/.wakatime/wakatime-cli 2>&1 >/dev/null
set project "Terminal" set wakatime_path (type -p ~/.wakatime/wakatime-cli)
end else
return 1
end
$wakatime_path --write --plugin "$PLUGIN_NAME/$PLUGIN_VERSION" --entity-type app --project "$project" --entity "$exec_command_str" &> /dev/null&; disown if git rev-parse --is-inside-work-tree &>/dev/null
set project (basename (git rev-parse --show-toplevel))
else
set project Terminal
end
$wakatime_path --write --plugin "$PLUGIN_NAME/$PLUGIN_VERSION" --entity-type app --project "$project" --entity "$exec_command_str" &>/dev/null &
disown
end end
+40 -12
View File
@@ -2,15 +2,24 @@
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
# #
# Generates ~/.local/bin/yay on first run (and on version bump) when # Generates ~/.local/bin/yay on first run (and on version bump) when
# /usr/bin/yay is installed. The wrapper tees yay output to a # yay is installed. The wrapper runs yay in a PTY so progress
# timestamped log file and prunes old logs, mirroring smart_exit behavior. # bars are preserved, renders the captured animation to a clean static log
# (via scripts/clean_progress_log.py), and prunes old logs.
# COMPONENT
# site yay-autoexec: autoexec/pkg-wrappers
# site yay-logging: logging/pkg-logs
# Defines nothing; its only effect is generating ~/.local/bin/yay, an
# idempotent write every interactive session already performs.
status is-interactive; or return
# Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec). # Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec).
# Wrapper generation is also gated by C5 (Logging & Capture). # Wrapper generation is also gated by C5 (Logging & Capture).
__fish_config_op_enabled __fish_config_op_autoexec; or return __fish_config_op_enabled (status basename) yay-autoexec; or return
# C5 — Logging & Capture: remove generated wrapper and skip when logging is off # C5 — Logging & Capture: remove generated wrapper and skip when logging is off
if not __fish_config_op_enabled __fish_config_op_logging if not __fish_config_op_enabled (status basename) yay-logging
if test -f "$HOME/.local/bin/yay" if test -f "$HOME/.local/bin/yay"
and grep -q "# yay-wrapper-version:" "$HOME/.local/bin/yay" 2>/dev/null and grep -q "# yay-wrapper-version:" "$HOME/.local/bin/yay" 2>/dev/null
rm -f "$HOME/.local/bin/yay" rm -f "$HOME/.local/bin/yay"
@@ -18,12 +27,13 @@ if not __fish_config_op_enabled __fish_config_op_logging
return return
end end
set -l _yay_real /usr/bin/yay # Resolve the real yay binary, skipping our own shim (never /usr/bin-assumed).
set -l _yay_real (__fish_real_command yay)
set -l _yay_wrapper "$HOME/.local/bin/yay" set -l _yay_wrapper "$HOME/.local/bin/yay"
set -l _yay_wrapper_version 1 set -l _yay_wrapper_version 6
# Skip entirely if the real yay binary isn't present # Skip entirely if the real yay binary isn't present
test -x $_yay_real; or return test -x "$_yay_real"; or return
# Check if wrapper already exists at the expected version # Check if wrapper already exists at the expected version
if test -f $_yay_wrapper if test -f $_yay_wrapper
@@ -38,22 +48,40 @@ printf '%s\n' \
'#!/usr/bin/env bash' \ '#!/usr/bin/env bash' \
"# yay-wrapper-version: $_yay_wrapper_version" \ "# yay-wrapper-version: $_yay_wrapper_version" \
'# Auto-generated by conf.d/yay-wrapper.fish — do not edit by hand.' \ '# Auto-generated by conf.d/yay-wrapper.fish — do not edit by hand.' \
'# Tees yay output to a timestamped log file and prunes old ones.' \ '# Runs yay in a PTY via script(1) so progress bars are preserved on screen,' \
'set -o pipefail' \ '# then renders the captured terminal animation to a clean static log.' \
'' \ '' \
'log_dir="${SCROLLBACK_HISTORY_DIR:-$HOME/.terminal_history}"' \ 'log_dir="${SCROLLBACK_HISTORY_DIR:-$HOME/.terminal_history}"' \
'mkdir -p "$log_dir"' \ 'mkdir -p "$log_dir"' \
'log_file="$log_dir/yay_$(date +%Y-%m-%d_%H-%M-%S).log"' \ 'log_file="$log_dir/yay_$(date +%Y-%m-%d_%H-%M-%S).log"' \
'' \ '' \
'/usr/bin/yay "$@" 2>&1 | tee "$log_file"' \ '# Build a safely-quoted command string for script(1).' \
'# script(1) allocates a PTY so yay detects a real terminal and shows progress.' \
"cmd_str=\"$_yay_real\"" \
'for arg in "$@"; do' \
' cmd_str+=" $(printf '"'"'%q'"'"' "$arg")"' \
done \
'script -q -e -c "$cmd_str" "$log_file"' \
'exit_code=$?' \
'' \
'# Render the captured terminal animation (progress bars repaint in place via' \
'# cursor moves) down to its final static frame, preserving ANSI color. Falls' \
'# back to dropping only the script(1) header/footer when python3 is missing.' \
'cleaner="${XDG_CONFIG_HOME:-$HOME/.config}/fish/scripts/clean_progress_log.py"' \
'if command -v python3 >/dev/null 2>&1 && [[ -f "$cleaner" ]]; then' \
' python3 "$cleaner" < "$log_file" > "${log_file}.tmp" 2>/dev/null && mv "${log_file}.tmp" "$log_file" || rm -f "${log_file}.tmp"' \
else \
' sed -i "/^Script \(started\|done\) on /d" "$log_file" 2>/dev/null || true' \
fi \
'' \ '' \
'max_files="${SCROLLBACK_HISTORY_MAX_FILES:-100}"' \ 'max_files="${SCROLLBACK_HISTORY_MAX_FILES:-100}"' \
'mapfile -t logs < <(ls -1t "$log_dir"/yay_*.log 2>/dev/null)' \ 'mapfile -t logs < <(ls -1t "$log_dir"/yay_*.log 2>/dev/null)' \
'excess=$(( ${#logs[@]} - max_files ))' \ 'excess=$(( ${#logs[@]} - max_files ))' \
'for (( i = ${#logs[@]} - 1; i >= ${#logs[@]} - excess && i >= 0; i-- )); do' \ 'for (( i = ${#logs[@]} - 1; i >= ${#logs[@]} - excess && i >= 0; i-- )); do' \
' rm -f "${logs[$i]}"' \ ' rm -f "${logs[$i]}"' \
'done' \ done \
> $_yay_wrapper '' \
'exit $exit_code' >$_yay_wrapper
chmod +x $_yay_wrapper chmod +x $_yay_wrapper
+24
View File
@@ -0,0 +1,24 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# C5 — Logging & Capture: registers a fish_exit handler that dumps the current
# Zellij pane's scrollback to a log file when the shell exits. Unlike tmux
# (streamed live via pipe-pane), Zellij has no continuous-capture facility, so
# we snapshot once on exit via `zellij action dump-screen --full`.
#
# The handler is registered whenever fish runs inside Zellij; the C5 logging
# guard is evaluated inside _zellij_dump_log at exit time, so toggling
# __fish_config_op_logging takes effect on the next exit without a restart
# (no sync_logging coordination needed, since there is no live stream to stop).
#
# Event-handler functions must be defined at startup (conf.d) so the --on-event
# binding is registered; autoloaded functions in functions/ never register.
status is-interactive; or exit
type -q zellij; or exit
set -q ZELLIJ; or exit
function __zellij_dump_on_exit --on-event fish_exit \
--description 'C5 event handler: dump Zellij pane scrollback on shell exit'
_zellij_dump_log
end
+4 -1
View File
@@ -3,6 +3,9 @@
# Adapted from icezyclon/zoxide.fish (MIT) # Adapted from icezyclon/zoxide.fish (MIT)
# Heavily customized for Fish 4.x compatibility and performance # Heavily customized for Fish 4.x compatibility and performance
# COMPONENT
# aliases/filesystem
if status is-interactive if status is-interactive
if type -q zoxide if type -q zoxide
@@ -65,7 +68,7 @@ if status is-interactive
# Shadowing cd with zoxide is opinionated (C1 aliasing); z and zi # Shadowing cd with zoxide is opinionated (C1 aliasing); z and zi
# remain available either way. # remain available either way.
if __fish_config_op_enabled __fish_config_op_aliases if __fish_config_op_enabled (status basename)
alias cd=z alias cd=z
end end
+107 -74
View File
@@ -7,7 +7,7 @@
# ───────────────────── Opinionated component guards ───────────────────── # ───────────────────── Opinionated component guards ─────────────────────
# Opinionated components (AGENTS.md Task #3) are wrapped in # Opinionated components (AGENTS.md Task #3) are wrapped in
# __fish_config_op_enabled <category> guards throughout this file and conf.d/. # __fish_config_op_enabled <identity> [<site>] guards throughout this file and conf.d/.
# The helper always evaluates the master switch __fish_config_opinionated # The helper always evaluates the master switch __fish_config_opinionated
# first (falsy disables everything), then the per-category opt-out variable: # first (falsy disables everything), then the per-category opt-out variable:
# __fish_config_op_aliases C1 — command shadows / flag injection # __fish_config_op_aliases C1 — command shadows / flag injection
@@ -15,15 +15,30 @@
# __fish_config_op_overrides C3 — key bindings, env, prompt overrides # __fish_config_op_overrides C3 — key bindings, env, prompt overrides
# __fish_config_op_integrations C4 — terminal/tool coupling # __fish_config_op_integrations C4 — terminal/tool coupling
# __fish_config_op_logging C5 — scrollback capture / AUR log wrappers # __fish_config_op_logging C5 — scrollback capture / AUR log wrappers
# (opt-in: unset means OFF)
# __fish_config_op_greeting C6 — per-session greeting / first-run welcome # __fish_config_op_greeting C6 — per-session greeting / first-run welcome
# Example: set -U __fish_config_op_aliases off (erase to re-enable) # Example: set -U __fish_config_op_aliases off (erase to re-enable)
# C5 is the one exception: it defaults to disabled and needs an explicit
# truthy value — set -U __fish_config_op_logging on
# COMPONENT
# site cachyos-tricks: overrides/environment
# site cachyos-strip-aliases: aliases/filesystem
# site cachyos-strip-overrides: overrides/key-bindings
# site privacy: overrides/privacy
# site pager-editor-gpg: overrides/environment
# site exit-wiring: overrides/key-bindings
# site path-setup: overrides/environment
# site cdpath: overrides/environment
# site vi-mode: overrides/key-bindings
# site greeting-stamp: greeting/greeting-message
# ──────────────────────── Source CachyOS configs ──────────────────────── # ──────────────────────── Source CachyOS configs ────────────────────────
if test -f /usr/share/cachyos-fish-config/cachyos-config.fish if test -f /usr/share/cachyos-fish-config/cachyos-config.fish
source /usr/share/cachyos-fish-config/cachyos-config.fish source /usr/share/cachyos-fish-config/cachyos-config.fish
# Surgically overriding the distro config is opinionated (C3 overrides): # Surgically overriding the distro config is opinionated (C3 overrides):
# skip it entirely when overrides are disabled, keeping CachyOS defaults. # skip it entirely when overrides are disabled, keeping CachyOS defaults.
if __fish_config_op_enabled __fish_config_op_overrides if __fish_config_op_enabled (status basename) cachyos-tricks
# Source our tricks over the cachyOS config # Source our tricks over the cachyOS config
test -f "$__fish_config_dir/conf.d/tricks.fish" test -f "$__fish_config_dir/conf.d/tricks.fish"
and source "$__fish_config_dir/conf.d/tricks.fish" and source "$__fish_config_dir/conf.d/tricks.fish"
@@ -38,7 +53,7 @@ if test -f /usr/share/cachyos-fish-config/cachyos-config.fish
# The distro config ships opinionated pieces of its own (it is the origin # The distro config ships opinionated pieces of its own (it is the origin
# of tricks.fish); strip them when the matching category is disabled so # of tricks.fish); strip them when the matching category is disabled so
# the guards hold on CachyOS systems too. # the guards hold on CachyOS systems too.
if not __fish_config_op_enabled __fish_config_op_aliases if not __fish_config_op_enabled (status basename) cachyos-strip-aliases
for _fname in grep fgrep egrep dir vdir wget for _fname in grep fgrep egrep dir vdir wget
functions -q $_fname; and functions --erase $_fname functions -q $_fname; and functions --erase $_fname
end end
@@ -50,7 +65,7 @@ if test -f /usr/share/cachyos-fish-config/cachyos-config.fish
and source $__fish_data_dir/functions/$_fname.fish and source $__fish_data_dir/functions/$_fname.fish
end end
end end
if not __fish_config_op_enabled __fish_config_op_overrides if not __fish_config_op_enabled (status basename) cachyos-strip-overrides
for _fname in __history_previous_command __history_previous_command_arguments for _fname in __history_previous_command __history_previous_command_arguments
functions -q $_fname; and functions --erase $_fname functions -q $_fname; and functions --erase $_fname
end end
@@ -64,66 +79,84 @@ set --erase _fname
# ───────────────────────────── XDG variables ──────────────────────────── # ───────────────────────────── XDG variables ────────────────────────────
# XDG Base Directory variables (standard practice) # XDG Base Directory variables (standard practice)
set -gx XDG_CONFIG_HOME $HOME/.config # Sets default config dir to ~/.config # We set these unconditionally to ensure a consistent baseline, but only if
set -gx XDG_CACHE_HOME $HOME/.cache # Sets default cache dir to ~/.cache # they are not already defined by the system/user.
set -gx XDG_DATA_HOME $HOME/.local/share # Sets default data dir to ~/.local/share set -q XDG_CONFIG_HOME; or set -gx XDG_CONFIG_HOME $HOME/.config # Sets default config dir to ~/.config
set -gx XDG_STATE_HOME $HOME/.local/state # Sets default state dir to ~/.local/state set -q XDG_CACHE_HOME; or set -gx XDG_CACHE_HOME $HOME/.cache # Sets default cache dir to ~/.cache
set -q XDG_DATA_HOME; or set -gx XDG_DATA_HOME $HOME/.local/share # Sets default data dir to ~/.local/share
set -q XDG_STATE_HOME; or set -gx XDG_STATE_HOME $HOME/.local/state # Sets default state dir to ~/.local/state
# Attempt to keep various config/cache files out of the home directory root # Attempt to keep various config/cache files out of the home directory root
set -gx RANDFILE "$XDG_STATE_HOME/rnd" set -q RANDFILE; or set -gx RANDFILE "$XDG_STATE_HOME/rnd"
set -gx WGETRC "$XDG_CONFIG_HOME/wget/wgetrc" set -q WGETRC; or set -gx WGETRC "$XDG_CONFIG_HOME/wget/wgetrc"
set -gx WGET_HSTS_FILE "$XDG_CACHE_HOME/wget-hsts" set -q WGET_HSTS_FILE; or set -gx WGET_HSTS_FILE "$XDG_CACHE_HOME/wget-hsts"
set -gx NPM_CONFIG_PREFIX "$XDG_DATA_HOME/npm-global" set -q NPM_CONFIG_PREFIX; or set -gx NPM_CONFIG_PREFIX "$XDG_DATA_HOME/npm-global"
set -gx NPM_CONFIG_USERCONFIG "$XDG_CONFIG_HOME/npm/npmrc" set -q NPM_CONFIG_USERCONFIG; or set -gx NPM_CONFIG_USERCONFIG "$XDG_CONFIG_HOME/npm/npmrc"
set -gx ANDROID_USER_HOME "$XDG_DATA_HOME/android" set -q ANDROID_USER_HOME; or set -gx ANDROID_USER_HOME "$XDG_DATA_HOME/android"
set -gx CARGO_HOME "$XDG_DATA_HOME/cargo" set -q CARGO_HOME; or set -gx CARGO_HOME "$XDG_DATA_HOME/cargo"
set -gx RUSTUP_HOME "$XDG_DATA_HOME/rustup" set -q RUSTUP_HOME; or set -gx RUSTUP_HOME "$XDG_DATA_HOME/rustup"
set -gx GOPATH "$XDG_DATA_HOME/go" set -q GOPATH; or set -gx GOPATH "$XDG_DATA_HOME/go"
set -gx BUN_INSTALL "$XDG_DATA_HOME/bun" set -q BUN_INSTALL; or set -gx BUN_INSTALL "$XDG_DATA_HOME/bun"
set -gx GNUPGHOME "$XDG_CONFIG_HOME/gnupg" set -q GNUPGHOME; or set -gx GNUPGHOME "$XDG_CONFIG_HOME/gnupg"
set -gx WAKATIME_HOME "$XDG_CONFIG_HOME/wakatime" set -q WAKATIME_HOME; or set -gx WAKATIME_HOME "$XDG_CONFIG_HOME/wakatime"
set -gx HISTFILE "$XDG_STATE_HOME/bash_history" set -q HISTFILE; or set -gx HISTFILE "$XDG_STATE_HOME/bash_history"
set -gx EXINIT "set viminfofile=$XDG_STATE_HOME/vim/viminfo | source $MYVIMRC" set -q EXINIT; or set -gx EXINIT "set viminfofile=$XDG_STATE_HOME/vim/viminfo | source $MYVIMRC"
set -gx NVIDIA_SETTINGS_RW_CONFIG_FILE "$XDG_CONFIG_HOME/nvidia/settings" set -q NVIDIA_SETTINGS_RW_CONFIG_FILE; or set -gx NVIDIA_SETTINGS_RW_CONFIG_FILE "$XDG_CONFIG_HOME/nvidia/settings"
set -gx CODEIUM_HOME "$XDG_CONFIG_HOME/codeium" set -q CODEIUM_HOME; or set -gx CODEIUM_HOME "$XDG_CONFIG_HOME/codeium"
set -gx WORDLIST "$XDG_CONFIG_HOME/hunspell_en_US" set -q WORDLIST; or set -gx WORDLIST "$XDG_CONFIG_HOME/hunspell_en_US"
# ───────────────────────── Privacy variables ────────────────────────────
# Global telemetry opt-out variables (C3 overrides: privacy)
# Various CLI tools, runtimes, and AI-agent tools respect these variables.
if __fish_config_op_enabled (status basename) privacy
set -gx DO_NOT_TRACK 1
set -gx DISABLE_TELEMETRY 1
end
# ─────────────────────────── Pager variables ──────────────────────────── # ─────────────────────────── Pager variables ────────────────────────────
# Overriding $PAGER is opinionated (C3 overrides) # Overriding $PAGER, $EDITOR, and $GPG_TTY is opinionated (C3 overrides)
if __fish_config_op_enabled __fish_config_op_overrides if __fish_config_op_enabled (status basename) pager-editor-gpg
if type -q ov if type -q ov
set -gx PAGER ov set -gx PAGER ov
else if type -q less else if type -q less
set -gx PAGER less set -gx PAGER less
end end
end
# ─────────────────────────── Editor variables ─────────────────────────── # ─────────────────────────── Editor variables ───────────────────────────
# Set Editor variables with fallback to vi if nvim isn't available. This ensures that # Set Editor variables with fallback to vi if nvim isn't available. This ensures that
# tools that rely on these variables (like git commit messages) will work out of the box, # tools that rely on these variables (like git commit messages) will work out of the box,
# while still preferring nvim if it's installed. # while still preferring nvim if it's installed.
if type -q nvim if type -q nvim
set -gx NVIM_APPNAME nvim set -gx NVIM_APPNAME nvim
set -gx EDITOR (command -s nvim) set -gx EDITOR (command -s nvim)
else else
set -gx EDITOR (command -s vi) set -gx EDITOR (command -s vi)
end end
set -gx VISUAL $EDITOR # set -gx VISUAL $EDITOR # <- Use local.fish to set your preferred GUI editor.
set -gx SUDO_EDITOR $EDITOR set -gx SUDO_EDITOR $EDITOR
# ──────────────────────────── GPG variables ───────────────────────────── # ──────────────────────────── GPG variables ─────────────────────────────
# Helps ensure that GPG can prompt for passphrases correctly when invoked from the terminal. # Helps ensure that GPG can prompt for passphrases correctly when invoked from the terminal.
set -gx GPG_TTY (tty) set -gx GPG_TTY (tty)
end
# ────────────────────────── Scrollback History ────────────────────────── # ────────────────────────── Scrollback History ──────────────────────────
# Directory where scrollback history is saved into log files. # Optional fish-style source of truth (set -U via config-settings); exported
# for the POSIX wrappers (paru/yay/tmux/zellij/_prune_terminal_logs) that read
# them. We export the default unconditionally, then override from the universal
# var only if set — deliberately NOT creating a global, which would shadow the
# universal and stop live edits (config-settings → Paths) from taking effect.
set -gx SCROLLBACK_HISTORY_DIR "$HOME/.terminal_history" set -gx SCROLLBACK_HISTORY_DIR "$HOME/.terminal_history"
# Maximum number of scrollback history files to keep set -q __fish_scrollback_history_dir
and set -gx SCROLLBACK_HISTORY_DIR $__fish_scrollback_history_dir
set -gx SCROLLBACK_HISTORY_MAX_FILES 100 set -gx SCROLLBACK_HISTORY_MAX_FILES 100
set -q __fish_scrollback_history_max_files
and set -gx SCROLLBACK_HISTORY_MAX_FILES $__fish_scrollback_history_max_files
# Wire up a clean exit function that won't fire on background subshells # Wire up a clean exit function that won't fire on background subshells
# Replacing the exit builtin is opinionated (C3 overrides); smart_exit also # Replacing the exit builtin is opinionated (C3 overrides); smart_exit also
# guards itself so a live toggle takes effect without restarting the shell. # guards itself so a live toggle takes effect without restarting the shell.
if status is-interactive; and __fish_config_op_enabled __fish_config_op_overrides if status is-interactive; and __fish_config_op_enabled (status basename) exit-wiring
function exit --description 'Safe interactive exit' function exit --description 'Safe interactive exit'
# If the smart_exit file exists in our function path, invoke it explicitly # If the smart_exit file exists in our function path, invoke it explicitly
if functions -q smart_exit if functions -q smart_exit
@@ -139,16 +172,19 @@ end
# Adds common user bin directories to the PATH. The -mg --move option for cargo ensures that # Adds common user bin directories to the PATH. The -mg --move option for cargo ensures that
# the cargo bin directory is moved to the end of the PATH, which can help avoid conflicts # the cargo bin directory is moved to the end of the PATH, which can help avoid conflicts
# with system-installed Rust tools while still allowing user-installed cargo binaries to be found. # with system-installed Rust tools while still allowing user-installed cargo binaries to be found.
fish_add_path $HOME/.local/bin # Standard user-local executables (XDG spec) # PATH setup is opinionated (C3 overrides)
fish_add_path $HOME/.local/share/../bin # Alternative/legacy path for local user binaries if __fish_config_op_enabled (status basename) path-setup
fish_add_path $HOME/Applications # User-installed applications and standalone apps fish_add_path $HOME/.local/bin # Standard user-local executables (XDG spec)
fish_add_path $HOME/scripts # Custom personal shell scripts and automation fish_add_path $HOME/.local/share/../bin # Alternative/legacy path for local user binaries
fish_add_path -mga $CARGO_HOME/bin # Rust binaries and tools installed via Cargo fish_add_path $HOME/Applications # User-installed applications and standalone apps
fish_add_path $BUN_INSTALL/bin # Bun runtime executables and globally installed packages fish_add_path $HOME/scripts # Custom personal shell scripts and automation
fish_add_path $XDG_DATA_HOME/npm-global/bin # Global Node.js/npm packages (XDG compliant location) fish_add_path -mga $CARGO_HOME/bin # Rust binaries and tools installed via Cargo
fish_add_path $HOME/.lmstudio/bin # LM Studio CLI tools for local LLM management fish_add_path $BUN_INSTALL/bin # Bun runtime executables and globally installed packages
fish_add_path $HOME/.resend/bin # Resend email service CLI tools fish_add_path $XDG_DATA_HOME/npm-global/bin # Global Node.js/npm packages (XDG compliant location)
fish_add_path $HOME/.fzf/bin # Fuzzy Finder (fzf) core binary and helper scripts fish_add_path $HOME/.lmstudio/bin # LM Studio CLI tools for local LLM management
fish_add_path $HOME/.resend/bin # Resend email service CLI tools
fish_add_path $HOME/.fzf/bin # Fuzzy Finder (fzf) core binary and helper scripts
end
# ───────────────────────── CDPATH projects dir ────────────────────────── # ───────────────────────── CDPATH projects dir ──────────────────────────
# Allows cd-ing to directories within $HOME/projects or $HOME without needing to specify the full path. # Allows cd-ing to directories within $HOME/projects or $HOME without needing to specify the full path.
@@ -160,7 +196,7 @@ fish_add_path $HOME/.fzf/bin # Fuzzy Finder (fzf) core binary an
# so if you have a directory named 'myproject' in the current directory, # so if you have a directory named 'myproject' in the current directory,
# running 'cd myproject' will take you there instead of $HOME/projects/myproject. # running 'cd myproject' will take you there instead of $HOME/projects/myproject.
# CDPATH injection is opinionated (C3 overrides) # CDPATH injection is opinionated (C3 overrides)
if __fish_config_op_enabled __fish_config_op_overrides if __fish_config_op_enabled (status basename) cdpath
set -gx CDPATH . $HOME/projects $HOME set -gx CDPATH . $HOME/projects $HOME
end end
@@ -175,7 +211,7 @@ if status is-interactive
# This is optional but can improve the user experience for those who prefer Vi-style key bindings. # This is optional but can improve the user experience for those who prefer Vi-style key bindings.
# Global Vi mode is opinionated (C3 overrides); without it fish keeps its # Global Vi mode is opinionated (C3 overrides); without it fish keeps its
# default Emacs-style bindings. # default Emacs-style bindings.
if __fish_config_op_enabled __fish_config_op_overrides if __fish_config_op_enabled (status basename) vi-mode
set -g fish_key_bindings fish_vi_key_bindings set -g fish_key_bindings fish_vi_key_bindings
end end
@@ -215,30 +251,27 @@ if status is-interactive
# │ This is useful for machine-specific behavior or configurations. │ # │ This is useful for machine-specific behavior or configurations. │
# ╰────────────────────────────── OVERRIDES ─────────────────────────────╯ # ╰────────────────────────────── OVERRIDES ─────────────────────────────╯
# #
# Define user-dots path variable for a more legible secrets/local config. # Resolve user-dots path. Customize via: set -U __fish_user_dots_path /your/path
set -l dot_fish "$XDG_CONFIG_HOME/.user-dots/fish" set -q __fish_user_dots_path
# ───────────────────────── Source user secrets ────────────────────────── or set -l __fish_user_dots_path "$XDG_CONFIG_HOME/.user-dots/fish"
# Sources a secrets.fish file if it exists, which can be used to store # ────────────────────── user-dots convenience symlink ───────────────────
# sensitive environment variables and configurations that shouldn't be # Keep $__fish_config_dir/user-dots tracking the resolved path so it can be
# committed to version control. # browsed from the fish config dir. Git-ignored. Controlled by the
# This allows you to keep things like API keys, database credentials, # __fish_user_dots_symlink toggle (config-settings → Paths); creation is a
# and other secrets out of your main config files and safely ignored by git. # C2 side-effect, removal-on-opt-out is honoured regardless. See the helper.
test -f "$dot_fish/secrets.fish"; and source "$dot_fish/secrets.fish" __fish_user_dots_link
# ─────────────────────── Source machine-local config ──────────────────── # ─────────────────────── Source machine-local config ────────────────────
# Sources a local.fish file if it exists, which can be used for machine-specific # Sources local.fish if it exists. That file handles sourcing its own
# variables and configurations that shouldn't be shared across machines. # secrets.fish companion when needed.
# This allows you to have different settings on different machines without affecting test -f "$__fish_user_dots_path/local.fish"; and source "$__fish_user_dots_path/local.fish"
# your main config or secrets files. For example, you might want different PATH additions,
# aliases, or environment variables on your work laptop vs. your home desktop.
test -f "$dot_fish/local.fish"; and source "$dot_fish/local.fish"
# ─────────────────── C6: Greeting & First-Run UI override ─────────────── # ─────────────────── C6: Greeting & First-Run UI override ───────────────
# When the greeting category is disabled, stamp out any fish_greeting # When the greeting category is disabled, stamp out any fish_greeting
# function that distro configs set (e.g., CachyOS defines it as fastfetch). # function that distro configs set (e.g., CachyOS defines it as fastfetch).
# This runs last inside the interactive block so our empty definition wins # This runs last inside the interactive block so our empty definition wins
# over whatever cachyos-config.fish or vendor conf.d installed. # over whatever cachyos-config.fish or vendor conf.d installed.
if not __fish_config_op_enabled __fish_config_op_greeting if not __fish_config_op_enabled (status basename) greeting-stamp
function fish_greeting function fish_greeting
end end
end end
+108
View File
@@ -0,0 +1,108 @@
admiring
adoring
affectionate
agitated
amazing
angry
awesome
beautiful
blissful
bold
boring
brave
busy
charming
clever
compassionate
competent
condescending
confident
cool
cranky
crazy
dazzling
determined
distracted
dreamy
eager
ecstatic
elastic
elated
elegant
eloquent
epic
exciting
fervent
festive
flamboyant
focused
friendly
frosty
funny
gallant
gifted
goofy
gracious
great
happy
hardcore
heuristic
hopeful
hungry
infallible
inspiring
intelligent
interesting
jolly
jovial
keen
kind
laughing
loving
lucid
magical
modest
musing
mystifying
naughty
nervous
nice
nifty
nostalgic
objective
optimistic
peaceful
pedantic
pensive
practical
priceless
quirky
quizzical
recursing
relaxed
reverent
romantic
sad
serene
sharp
silly
sleepy
stoic
strange
stupefied
suspicious
sweet
tender
thirsty
trusting
unruffled
upbeat
vibrant
vigilant
vigorous
wizardly
wonderful
xenodochial
youthful
zealous
zen
+223
View File
@@ -0,0 +1,223 @@
aardvark
albatross
alligator
alpaca
ant
anteater
antelope
ape
armadillo
baboon
badger
barracuda
bat
bear
beaver
bee
bison
boar
buffalo
butterfly
camel
capybara
caribou
cat
caterpillar
cattle
chamois
cheetah
chicken
chimpanzee
chinchilla
chough
clam
cobra
cockroach
cod
cormorant
coyote
crab
crane
crocodile
crow
curlew
deer
dinosaur
dog
dogfish
dolphin
donkey
dotterel
dove
dragonfly
duck
dugong
dunlin
eagle
echidna
eel
eland
elephant
elk
emu
falcon
ferret
finch
fish
flamingo
fly
fox
frog
gaur
gazelle
gerbil
giraffe
gnat
gnu
goat
goldfinch
goldfish
goose
gorilla
goshawk
grasshopper
grouse
guanaco
gull
hamster
hare
hawk
hedgehog
heron
herring
hippopotamus
hornet
horse
human
hummingbird
hyena
ibex
ibis
jackal
jaguar
jay
jellyfish
kangaroo
kingfisher
koala
kookabura
kouprey
kudu
lapwing
lark
lemur
leopard
lion
llama
lobster
locust
loris
louse
lyrebird
magpie
mallard
manatee
mandrill
mantis
marten
meerkat
mink
mole
mongoose
monkey
moose
mosquito
mouse
mule
narwhal
newt
nightingale
octopus
okapi
opossum
oryx
ostrich
otter
owl
oyster
panther
parrot
partridge
peafowl
pelican
penguin
pheasant
pig
pigeon
pony
porcupine
porpoise
quail
quelea
quetzal
rabbit
raccoon
rail
ram
rat
raven
red-deer
red-panda
reindeer
rhinoceros
rook
salamander
salmon
sand-dollar
sandpiper
sardine
scorpion
seahorse
seal
shark
sheep
shrew
skunk
snail
snake
sparrow
spider
spoonbill
squid
squirrel
starling
stingray
stinkbug
stork
swallow
swan
tapir
tarsier
termite
tiger
toad
trout
turkey
turtle
viper
vulture
wallaby
walrus
wasp
weasel
whale
wildcat
wolf
wolverine
wombat
woodcock
woodpecker
worm
wren
yak
zebra
+81
View File
@@ -0,0 +1,81 @@
amber
amethyst
apricot
aqua
aquamarine
auburn
azure
beige
black
blue
bronze
brown
buff
carmine
celadon
cerise
cerulean
charcoal
chartreuse
chocolate
cinnamon
copper
coral
cream
crimson
cyan
denim
emerald
fuchsia
gold
goldenrod
gray
green
grey
indigo
ivory
jade
khaki
lavender
lemon
lilac
lime
magenta
mahogany
maroon
mauve
mustard
navy
ochre
olive
orange
orchid
peach
pear
periwinkle
pink
plum
puce
purple
quartz
red
rose
ruby
rust
salmon
sapphire
scarlet
silver
slate
tan
taupe
teal
tomato
topaz
turquoise
ultramarine
umber
vanilla
violet
white
yellow
+236
View File
@@ -0,0 +1,236 @@
agnesi
albattani
allen
almeida
antonelli
archimedes
ardinghelli
aryabhata
austin
babbage
banach
banzai
bardeen
bartik
bassi
beaver
bell
benz
bhabha
bhaskara
black
blackburn
blackwell
bohr
booth
borg
bose
bouman
boyd
brahmagupta
brattain
brown
buck
burnell
cannon
carson
cartwright
carver
cerf
chandrasekhar
chaplygin
chatelet
chatterjee
chaum
chebyshev
clarke
cohen
colden
cori
cray
curie
curran
darwin
davinci
dewdney
dhawan
diffie
dijkstra
dirac
driscoll
dubinsky
easley
edison
einstein
elbakyan
elgamal
elion
ellis
engelbart
euclid
euler
faraday
feistel
fermat
fermi
feynman
franklin
gagarin
galileo
galois
ganguly
gates
gauss
germain
goldberg
goldstine
goldwasser
golick
goodall
gould
greider
grothendieck
haibt
hamilton
haslett
hawking
heisenberg
hellman
hermann
herschel
hertz
heyrovsky
hodgkin
hofstadter
hoover
hopper
hugle
hypatia
ishizaka
jackson
jang
jemison
jennings
jepsen
johnson
joliot
jones
kalam
kapitsa
kare
keldysh
keller
kepler
khayyam
khorana
kilby
kirch
knuth
kowalevski
lalande
lamarr
lamport
leakey
leavitt
lederberg
lehmann
lewin
lichterman
liskov
lovelace
lumiere
mahavira
margulis
matsumoto
maxwell
mayer
mccarthy
mcclintock
mclaren
mclean
mcnulty
meitner
mendel
mendeleev
meninsky
merkle
mestorf
mirzakhani
montalcini
moore
morse
moser
murdock
napier
nash
neumann
newton
nightingale
nobel
noether
northcutt
noyce
panini
pare
pascal
pasteur
payne
perlman
pike
poincare
poitras
proskuriakova
ptolemy
raman
ramanujan
rhodes
ride
ritchie
robinson
roentgen
rosalind
rubin
saha
sammet
sanderson
satoshi
shamir
shannon
shaw
shirley
shockley
shtern
sinoussi
snyder
solomon
spence
stonebraker
sutherland
swanson
swartz
swirles
taussig
tesla
tharp
thompson
torvalds
tu
turing
varahamihira
vaughan
villani
visvesvaraya
volhard
wescoff
wilbur
wiles
williams
williamson
wilson
wing
wozniak
wright
wu
yalow
yonath
zhukovsky
+1296
View File
File diff suppressed because it is too large Load Diff
+1000
View File
File diff suppressed because it is too large Load Diff
+1047
View File
File diff suppressed because it is too large Load Diff
+546
View File
@@ -0,0 +1,546 @@
#!/usr/bin/env python3
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Wrap code-shaped tokens in inline code spans for the Starlight site.
Section 5 is generated from the `functions/*.fish` comment headers, which
are read as plain text by `config-help`, by `funcsave`, and by anyone
opening the source file. Backticks there would be noise, so the headers
are authored without them -- and the site inherited that, rendering
`-a/--all` and `__fish_config_op_aliases` as ordinary prose.
This module closes that gap at render time: it walks the markdown a page
is about to be written as, finds the tokens whose shape only ever means
"code" (flags, `$vars`, snake_case identifiers, paths, key chords, known
command names) and wraps each one in a code span. The SSOT is never
touched, so the man page and `config-help` keep the plain-text form.
Everything here is conservative by construction: leaving a token alone is
always safe and wrapping the wrong one is not, so every rule bails out the
moment it is unsure. The regions that must never be rewritten -- fenced
blocks, indented code blocks, existing code spans, link targets, URLs, JSX
attributes, `<FileTree>` bodies, headings -- are recognised first and
passed through.
"""
import functools
import re
from pathlib import Path
FENCE_RE = re.compile(r"^\s*(```|~~~)")
# ---------------------------------------------------------------------------
# Vocabulary
# ---------------------------------------------------------------------------
# Commands a reader expects to see typeset as code. This is the *wide* list:
# it decides that a table column holds command lines (see _command_columns),
# where position already proves the name is a command. Wrapping a bare
# mention in running prose is gated on the strict tier below.
STANDARD_COMMANDS = frozenset(
"""
apk apt awk basename bash bat bg bind brew builtin cargo cat cd chmod
chown chsh cmp column cp curl cut date dd delta df diff dig dirname dnf
docker dpkg du echo emacs emerge env eza exec exit export fastfetch fd
fdisk fg fgrep file find fisher flatpak fzf gh git grep gzip head help
hexdump host hostname id ifconfig install ip jq jobs journalctl kill
killall kitten kitty last less ln locale ls lsblk lsd lsof make man
micro mkdir more mount mpv mv nano nc neofetch neovim netstat nix nl
nohup npm nproc nvim od open openssl pacman paru paste pgrep ping pip
pip3 pkill pr printf ps pwd python python3 readlink realpath rg rm rmdir
rpm rsync scp sed seq sh shutdown sleep snap sort source ssh stat
strings su sudo sync systemctl tac tail tar tee test time tldr tmux
touch tr trash tree type udisksctl umount uname uniq unzip uv vdir vi
vim vlc wait wc wezterm wget which who whoami wl-copy wl-paste xargs
xbps-install xclip xdg-open xsel yay yum yt-dlp zellij zip zoxide zsh
zypper
abbr alias and argparse begin block break case command complete contains
continue count else emit end eval false for function funcsave functions
history if math not or random read return set set_color status string
switch true while
""".split()
)
# Names that also read as ordinary English (or as this manual's own prose)
# often enough that a bare mention is not evidence of a command. They still
# take part in command-line and list detection, where position disambiguates
# -- they just never get wrapped on their own.
AMBIGUOUS_COMMANDS = frozenset(
"""
abbr alias all and at basename bat begin bg bind block branch break case
cat cd cheat cleanup clone column command complete contains continue copy
count cut date dd df dir dirname do docker du duf dust echo edit else emit
end env eval exec exit export false fc fg file find fish for free function
functions git go head help hist history host hostname id if in install ip
jobs join key kill last less link list ln lock locale log logs look ls make
man math micro more mount mv next no not note od open or ov p page paste
pkg poke ports pr ps pwd random read real replay return rm run screen sed
search seq set sh show sleep sort source spark split stat status string
strings su switch sync tab tac tail tar tee test time top touch tr trash
tree true type uniq upgrade view vi wait watch wc which while who write
yes zip
builtin fast function vdir
""".split()
)
# Extensions that make a bare `name.ext` token unambiguously a filename.
PATH_EXTENSIONS = (
"fish md mdx json jsonc toml yml yaml py sh bash zsh lua conf cfg ini "
"txt log list service socket desktop css scss ts js astro nix rasi 1"
).split()
# English function words. A candidate command line containing one is prose.
STOPWORDS = frozenset(
"""
a an the this that these those it its is are was were be been being am
to of in into on at by for from with without within about across after
before during over under again then than so such as and or but nor if
when while where which who whom whose why how all any both each few more
most other some only own same too very can will just should now via per
also either neither every no not
""".split()
)
_CATALOG_ARRAY_RE = re.compile(
r"set\s+-g\s+_fdc_(?:bins|cargo|pm)\s+((?:[^\n]*\\\n)*[^\n]*)"
)
def dependency_names(repo: Path) -> set[str]:
"""Every tool name in the `fish-deps` catalog (`_fdc_*` arrays).
`functions/_fish_deps_catalog.fish` is this repo's dependency database;
reading it here means a tool added there starts rendering as code with
no second list to keep in sync.
"""
path = repo / "functions" / "_fish_deps_catalog.fish"
if not path.exists():
return set()
names: set[str] = set()
for m in _CATALOG_ARRAY_RE.finditer(path.read_text(encoding="utf-8")):
for token in m.group(1).replace("\\\n", " ").split():
token = token.strip("\"'")
if token and re.fullmatch(r"[\w.@+-]+", token):
names.add(token)
return names
def function_names(repo: Path) -> set[str]:
"""Public function names, from the `functions/` directory listing.
Underscore-prefixed internals are skipped only because the snake_case
rule already covers them, and covers them everywhere -- including the
ones that have no file of their own.
"""
directory = repo / "functions"
if not directory.is_dir():
return set()
return {p.stem for p in directory.glob("*.fish") if not p.stem.startswith("_")}
class Vocabulary:
"""The command names the rules recognise, in two tiers.
`full` is every name we know of, used where position already proves a
token is a command (a command-line table cell, an arrow chain, a
comma-separated run). `strict` is the subset safe to wrap on sight in
running prose: `zoxide` yes, `find` no.
"""
__slots__ = ("full", "strict")
def __init__(self, names: set[str]):
# `and`, `or`, `not`, `if` … are fish builtins, but as vocabulary
# entries they turn every conjunction into a command name and break
# list and command-line detection. They are never worth wrapping.
self.full = frozenset(names) - STOPWORDS
self.strict = frozenset(
n
for n in names
if n not in AMBIGUOUS_COMMANDS
and (len(n) >= 3 or any(c.isdigit() for c in n))
)
def __eq__(self, other):
return (
isinstance(other, Vocabulary)
and self.full == other.full
and self.strict == other.strict
)
def __hash__(self):
return hash((self.full, self.strict))
def vocabulary(repo: Path) -> Vocabulary:
"""Build the command vocabulary from the repo plus the standard list."""
return Vocabulary(
set(STANDARD_COMMANDS) | dependency_names(repo) | function_names(repo)
)
EMPTY_VOCABULARY = Vocabulary(set())
# ---------------------------------------------------------------------------
# Token grammar
# ---------------------------------------------------------------------------
# A token may not start inside a word, a path, a code span, a history
# expansion, or a hyphenated compound: `` `zoxide` ``-backed must not see
# `-backed` as a flag, `and/or` must not see `/or` as a path, and `!-N` must
# not see `-N` as one either.
BEFORE = r"(?<![\w`$/\\~.=+!-])"
# Ruling out a trailing `/` keeps a partially-recognised slash run
# (`grep/cp/mv/wget`, where only `grep` is in the vocabulary) from being
# wrapped one limb at a time.
AFTER = r"(?![\w`/])"
_SEG = r"[\w.@+-]+"
# The last segment of a path may not end in `.`, so a sentence-final full
# stop stays outside the span. A segment that is nothing but dots (`..`,
# `...`) is the exception: there the dots are the segment.
_LAST = r"(?:[\w.@+-]*[\w@+-]|\.+)"
_EXT = "|".join(PATH_EXTENSIONS)
# Key chords: `Ctrl-R`, `Ctrl+Alt+F`. Both separators appear in the manual.
_MODIFIER = r"(?:Ctrl|Alt|Shift|Super|Meta|Cmd|Opt)"
_KEY = (
r"(?:F\d{1,2}|Tab|Enter|Return|Space|Esc|Escape|Backspace|Delete|Insert"
r"|Home|End|Up|Down|Left|Right|PgUp|PgDn|[A-Za-z0-9])"
)
KEYBIND = rf"{_MODIFIER}(?:[+-]{_MODIFIER})*[+-]{_KEY}"
# `$EDITOR`, `${var}`, `$XDG_CONFIG_HOME/aichat/roles/cli.md`.
VAR = rf"\$\{{?[A-Za-z_]\w*\}}?(?:(?:/{_SEG})*/{_LAST})?"
PATH = (
rf"(?:~|\.{{1,2}})/(?:{_SEG}/)*(?:{_LAST})?" # ~/… ./… ../…
rf"|/(?:{_SEG}/)+(?:{_LAST})?" # /etc/sudoers.d/nofail-toggle
rf"|(?:{_SEG}/)+[\w@+-][\w.@+-]*\.(?:{_EXT})" # conf.d/abbr.fish
rf"|[\w@+-][\w.@+-]*\.(?:{_EXT})" # config.fish
rf"|(?:{_SEG}\.)+{_SEG}/" # conf.d/
)
# `-a`, `--dry-run`, `--color=auto`. A bare `--` (this manual's ASCII em
# dash) never matches: a letter has to follow. A single-hyphen flag is
# capped at five characters and may not contain a hyphen, so a hyphenated
# compound continued across a conjunction ("filesystem-inspection and
# -modification") is not mistaken for one.
FLAG = r"--[A-Za-z][\w-]*(?:=[\w.,:/@+-]+)?|-[A-Za-z][A-Za-z0-9]{0,4}(?:=[\w.,:/@+-]+)?"
# `XDG_CONFIG_HOME`, `NO_TMUX=1`. An underscore is required, so ordinary
# acronyms (`URL`, `AGPL`, `TCP`) are never touched.
ENVVAR = r"[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+(?:=[\w.,:/@+-]+)?"
# snake_case: `__fish_config_op_aliases`, `_fdc_bins`, `fish_greeting`,
# `prompt_pwd`, `expand_bang_*`. An internal underscore is required, which
# is also what keeps `_emphasised_` markdown out of the match.
IDENT = r"_{0,2}[a-z][a-z0-9]*(?:_(?:[a-z0-9]+|\*))+"
# Regions that are already code, or are markup rather than prose. `url`
# also covers `git@host:owner/repo.git` and `ssh://…`, whose scheme would
# otherwise be read as a bare command name.
PROTECTED = (
r"(?P<code>``+.+?``+|`[^`\n]*`)"
r"|(?P<link>\[[^\]\n]*\]\([^)\n]*\))"
r"|(?P<url>[A-Za-z][\w+.-]*://\S+|[\w.-]+@[\w.-]+(?::\S+)?)"
r"|(?P<tag></?[A-Za-z][^>\n]*?/?>)"
)
ARROW = r"(?:->|→|=>)"
# Shortest comma run that reads as a list of tools rather than as prose.
MIN_RUN_NAMES = 3
# `, and` must be tried before a bare `,` so the conjunction is a separator
# and not an item.
RUN_SPLIT = r",?\s+(?:and|or)\s+|,\s*"
RUN_SPLIT_RE = re.compile(RUN_SPLIT)
# A command name inside a chain is followed by `->`, so the usual "no
# trailing hyphen" guard has to make room for exactly that.
_CMD_END = r"(?!\w)(?!-(?!>))"
def _alternation(names) -> str:
"""Regex alternation over names, longest first so `rg` can't beat `rga`."""
if not names:
return r"(?!)"
return "|".join(re.escape(n) for n in sorted(names, key=lambda s: (-len(s), s)))
def _atom(vocab: Vocabulary) -> str:
cmd = rf"(?:{_alternation(vocab.strict)})(?![\w-])"
return rf"(?:{KEYBIND}|{VAR}|{PATH}|{FLAG}|{ENVVAR}|{IDENT}|{cmd})"
@functools.lru_cache(maxsize=4)
def _scanner(vocab: Vocabulary) -> re.Pattern:
"""The single pass over a line: protected regions plus wrappable tokens."""
full = rf"(?:{_alternation(vocab.full)})"
chain_link = rf"(?:{full}{_CMD_END}|{VAR})"
name = rf"{full}(?![\w-])"
return re.compile(
PROTECTED
# `ls->eza, cat->bat`: a shadow chain. Position makes even an
# ambiguous name unmistakably a command here.
+ rf"|(?P<chain>{BEFORE}{chain_link}(?:\s*{ARROW}\s*{chain_link})+{AFTER})"
# `cargo, starship, uv, zoxide`: a run of nothing but tool names.
+ rf"|(?P<run>{BEFORE}{name}(?:,\s*{name})+"
+ rf"(?:,?\s+(?:and|or)\s+{name})?{AFTER})"
# `-a/--all`: slash-joined atoms, each wrapped on its own.
+ rf"|(?P<group>{BEFORE}{_atom(vocab)}(?:/{_atom(vocab)})*{AFTER})"
)
@functools.lru_cache(maxsize=4)
def _atom_re(vocab: Vocabulary) -> re.Pattern:
return re.compile(_atom(vocab))
# ---------------------------------------------------------------------------
# Table cells that are whole command lines
# ---------------------------------------------------------------------------
# The abbreviation tables' second column is an expansion, not a sentence:
# `sudo -s`, `cd ../..`, `journalctl -p 3 -xb`. Wrapping only the flag would
# leave a bare `sudo` in front of a code span; the cell wants to be one span.
#
# Whether a column holds command lines is decided for the column as a whole
# -- one cell is far too little evidence, as `zoxide frecency-based
# navigation` (prose, in a column of prose) and `docker context ls` (a
# command, in a column of commands) open identically.
CELL_TOKEN_RE = re.compile(r"^[\w$~./=:;@+*?%'\"-]+$")
CELL_NAME_RE = re.compile(r"^[a-z][\w.+-]*$")
CELL_OPERATORS = frozenset((r"\|", "|", "&&", "||", ">", ">>", "<", ";"))
MAX_CELL_TOKENS = 8
COMMAND_COLUMN_RATIO = 0.7
MIN_COMMAND_COLUMN_ROWS = 3
def _cell_tokens(cell: str) -> list[str] | None:
"""Tokenise a cell that could be a command line, or None if it can't be."""
text = cell.strip()
if not text or any(c in text for c in "`<([)]"):
return None
tokens = text.split()
if not (1 <= len(tokens) <= MAX_CELL_TOKENS):
return None
for token in tokens:
if token in CELL_OPERATORS:
continue
if not CELL_TOKEN_RE.match(token):
return None
if token[:1].isupper() or token.lower() in STOPWORDS:
return None
return tokens
def _is_command_cell(cell: str, vocab: Vocabulary) -> bool:
"""True when a cell in a command column really is one command line."""
tokens = _cell_tokens(cell)
if tokens is None:
return False
return tokens[0] in vocab.full or bool(CELL_NAME_RE.match(tokens[0]))
def _opens_with_command(cell: str, vocab: Vocabulary) -> bool:
"""The per-cell evidence the column vote is counted from."""
tokens = _cell_tokens(cell)
return tokens is not None and tokens[0] in vocab.full
# ---------------------------------------------------------------------------
# Line classification
# ---------------------------------------------------------------------------
HEADING_RE = re.compile(r"^\s{0,3}#{1,6}\s")
TABLE_ROW_RE = re.compile(r"^\s*\|.*\|\s*$")
TABLE_RULE_RE = re.compile(r"^\s*\|[\s:|-]+\|\s*$")
IMPORT_RE = re.compile(r"^\s*import\s")
FILE_TREE_OPEN = "<FileTree"
FILE_TREE_CLOSE = "</FileTree>"
CELL_SPLIT_RE = re.compile(r"(?<!\\)\|")
# A four-space indent is this manual's code block. The site never sees one
# -- prettify() has already turned it into a fence by the time this module
# runs -- but build_concat() keeps the indented form, because that is what
# pandoc and `config-help` want, and its contents are code that must not be
# rewritten: the table of contents alone would otherwise have `ov`, `bat`,
# `less` and `cat` wrapped inside a code block.
INDENTED_CODE = " "
def _skip_line(line: str) -> bool:
"""True for a line that must be passed through untouched.
Headings are excluded because Starlight derives anchors -- and this
pipeline derives `LinkCard` hrefs -- from their text. A line opening
with `<` is component markup, whose attributes are JSX, not markdown.
"""
stripped = line.strip()
return bool(
not stripped
or HEADING_RE.match(line)
or IMPORT_RE.match(line)
or stripped.startswith("<")
or TABLE_RULE_RE.match(line)
)
def _row_cells(line: str) -> list[str]:
return CELL_SPLIT_RE.split(line)
def _command_columns(rows: list[str], vocab: Vocabulary) -> set[int]:
"""Which column indices of one table hold command lines rather than prose."""
votes: dict[int, list[int]] = {}
for line in rows:
if TABLE_RULE_RE.match(line):
continue
for index, cell in enumerate(_row_cells(line)):
if not cell.strip() or "`" in cell:
continue
votes.setdefault(index, []).append(_opens_with_command(cell, vocab))
return {
index
for index, seen in votes.items()
if len(seen) >= MIN_COMMAND_COLUMN_ROWS
and sum(seen) / len(seen) >= COMMAND_COLUMN_RATIO
}
# ---------------------------------------------------------------------------
# The pass
# ---------------------------------------------------------------------------
# Spans this pass creates are marked, not back-ticked, until the very end:
# adjacent ones are merged (`eza` `-l` `-a` -> `eza -l -a`), and only spans
# this pass created may take part in that.
MARK = "\x01"
MERGE_RE = re.compile(rf"{MARK} {MARK}")
def _mark(text: str) -> str:
return f"{MARK}{text}{MARK}"
def _wrap_atoms(text: str, atom_re: re.Pattern) -> str:
"""Mark each atom of a slash-joined group, keeping the separators.
Rescanning the group rather than capturing during the first match keeps
the grammar readable; the round-trip check makes that shortcut safe --
if the rescan disagrees with the original match, nothing is changed.
"""
wrapped = atom_re.sub(lambda m: _mark(m.group(0)), text)
if wrapped.replace(MARK, "") != text:
return text
return wrapped
def _wrap_split(text: str, separator: str) -> str:
"""Mark each item of a separated run, keeping the separators."""
parts = re.split(rf"({separator})", text)
return "".join(p if i % 2 else _mark(p) for i, p in enumerate(parts))
def _transform(text: str, scanner: re.Pattern, atom_re: re.Pattern, vocab: Vocabulary) -> str:
def repl(m: re.Match) -> str:
group = m.lastgroup
if group == "chain":
return _wrap_split(m.group(0), rf"\s*{ARROW}\s*")
if group == "run":
# A long run anchored by at least one unambiguous tool name is
# a list of commands; two names, one of them a word like
# `function`, is a sentence.
names = RUN_SPLIT_RE.split(m.group(0))
if len(names) < MIN_RUN_NAMES or not any(
n in vocab.strict for n in names
):
# Not a list after all -- hand the text back to the
# ordinary token rules rather than swallowing it.
return _wrap_atoms(m.group(0), atom_re)
return _wrap_split(m.group(0), RUN_SPLIT)
if group == "group":
return _wrap_atoms(m.group(0), atom_re)
return m.group(0)
return scanner.sub(repl, text)
def _transform_line(
line: str,
scanner: re.Pattern,
atom_re: re.Pattern,
vocab: Vocabulary,
command_columns: set[int],
) -> str:
if not command_columns:
return _transform(line, scanner, atom_re, vocab)
out = []
for index, cell in enumerate(_row_cells(line)):
if index in command_columns and _is_command_cell(cell, vocab):
body = cell.strip()
lead = cell[: len(cell) - len(cell.lstrip())]
trail = cell[len(cell.rstrip()) :]
out.append(f"{lead}{_mark(body)}{trail}")
else:
out.append(_transform(cell, scanner, atom_re, vocab))
return "|".join(out)
def _finish(line: str) -> str:
"""Merge abutting new spans, then turn the marks into backticks."""
return MERGE_RE.sub(" ", line).replace(MARK, "`")
def add_code_spans(text: str, vocab: Vocabulary = EMPTY_VOCABULARY) -> str:
"""Wrap code-shaped tokens in `text` in inline code spans.
`text` is a rendered page body (no frontmatter). Fenced blocks,
indented code blocks, `<FileTree>` bodies, headings, component markup,
existing code spans, link targets and URLs are left exactly as they
are.
"""
scanner = _scanner(vocab)
atom_re = _atom_re(vocab)
lines = text.split("\n")
eligible = [False] * len(lines)
in_fence = False
in_tree = False
for i, line in enumerate(lines):
if FENCE_RE.match(line):
in_fence = not in_fence
continue
if in_fence:
continue
if FILE_TREE_OPEN in line:
in_tree = True
if in_tree:
if FILE_TREE_CLOSE in line:
in_tree = False
continue
if line.startswith(INDENTED_CODE):
continue
eligible[i] = not _skip_line(line)
# Command columns are a property of a whole table, so the contiguous
# runs of table rows are resolved before any line is rewritten.
columns: list[set[int]] = [set() for _ in lines]
start = None
for i, line in enumerate(lines + [""]):
is_row = i < len(lines) and eligible[i] and TABLE_ROW_RE.match(line)
if is_row and start is None:
start = i
elif not is_row and start is not None:
found = _command_columns(lines[start:i], vocab)
for j in range(start, i):
columns[j] = found
start = None
return "\n".join(
_finish(_transform_line(line, scanner, atom_re, vocab, columns[i]))
if eligible[i]
else line
for i, line in enumerate(lines)
)
+4581 -1010
View File
File diff suppressed because it is too large Load Diff
+247 -22
View File
@@ -11,6 +11,10 @@ synopsis=# SYNOPSIS
description=# DESCRIPTION description=# DESCRIPTION
toc=# TABLE OF CONTENTS toc=# TABLE OF CONTENTS
contents=# TABLE OF CONTENTS contents=# TABLE OF CONTENTS
autopair=# DESCRIPTION
puffer=# DESCRIPTION
puffer-fish=# DESCRIPTION
logging-events=# DESCRIPTION
# ── Section 1: Configuration Variables ─────────────────────── # ── Section 1: Configuration Variables ───────────────────────
variables=# 1. CONFIGURATION VARIABLES variables=# 1. CONFIGURATION VARIABLES
@@ -20,6 +24,10 @@ toolhomes=## Tool Homes (XDG-compliant)
editor=## Editor and Pager editor=## Editor and Pager
pager=## Editor and Pager pager=## Editor and Pager
scrollback=## Scrollback History scrollback=## Scrollback History
__fish_scrollback_history_dir=## Scrollback History
__fish_scrollback_history_max_files=## Scrollback History
scrollback-dir=## Scrollback History
misc-vars=## Other
# ── Section 2: PATH ─────────────────────────────────────────── # ── Section 2: PATH ───────────────────────────────────────────
path=# 2. PATH SETUP path=# 2. PATH SETUP
@@ -27,7 +35,6 @@ path=# 2. PATH SETUP
# ── Section 3: Key Bindings ─────────────────────────────────── # ── Section 3: Key Bindings ───────────────────────────────────
keybindings=# 3. KEY BINDINGS keybindings=# 3. KEY BINDINGS
bindings=# 3. KEY BINDINGS bindings=# 3. KEY BINDINGS
key-bindings=# 3. KEY BINDINGS
keys=# 3. KEY BINDINGS keys=# 3. KEY BINDINGS
fzf-bindings=## FZF Bindings (bundled from PatrickF1/fzf.fish) fzf-bindings=## FZF Bindings (bundled from PatrickF1/fzf.fish)
fzf=## FZF Bindings (bundled from PatrickF1/fzf.fish) fzf=## FZF Bindings (bundled from PatrickF1/fzf.fish)
@@ -60,6 +67,8 @@ cat=### cat
copy=### copy copy=### copy
du=### du du=### du
dusize=### dusize dusize=### dusize
dirs=### lD
lsdirs=### lD
ls=### ls ls=### ls
lsr=### lsr lsr=### lsr
lss=### lss lss=### lss
@@ -69,8 +78,10 @@ ltr=### ltr
lx=### lx lx=### lx
mkdir=### mkdir mkdir=### mkdir
mkcd=### mkcd mkcd=### mkcd
mv=### mv
poke=### poke poke=### poke
rm=### rm rm=### rm
rg=### rg
scrub=### scrub scrub=### scrub
nav-fns=## 5.2 Navigation nav-fns=## 5.2 Navigation
cdi=### cdi cdi=### cdi
@@ -83,6 +94,7 @@ less=### less
rawfish=### rawfish rawfish=### rawfish
view=### view view=### view
git=## 5.4 Git and Version Control git=## 5.4 Git and Version Control
auto-pull=### auto-pull
branch=### branch branch=### branch
gi=### gi gi=### gi
gitignore=### gi gitignore=### gi
@@ -101,6 +113,7 @@ parur=### parur
deps=## 5.6 Dependency Management deps=## 5.6 Dependency Management
fish-deps=### fish-deps fish-deps=### fish-deps
check-deps=### check_fish_deps check-deps=### check_fish_deps
fzf-update=### fzf-update
system=## 5.7 System and Monitoring system=## 5.7 System and Monitoring
top=### top top=### top
swapstat=### swapstat swapstat=### swapstat
@@ -116,36 +129,128 @@ split=### split
spwin=### spwin spwin=### spwin
detach=### detach detach=### detach
bkg=### bkg bkg=### bkg
fish-mode-prompt=### fish_mode_prompt
fish-prompt=### fish_prompt
fish-right-prompt=### fish_right_prompt
right-prompt=### fish_right_prompt
jobrunner=### jobrunner
jr=### jr
ssh=### ssh ssh=### ssh
clipboard=## 5.9 Clipboard clipboard=## 5.9 Clipboard
copy-fn=### y copy-fn=### y
p=### p
paste=### paste paste=### paste
network=## 5.10 Network network=## 5.10 Network
fast=### fast
fast-cli=### fast-cli
speedtest=### fast-cli
gip=### gip gip=### gip
gip4=### gip4
ipv4=### gip4
gip6=### gip6
ipv6=### gip6
ping=### ping ping=### ping
qr=### qr qr=### qr
logging=## 5.11 Pager and Logging logging=## 5.11 Pager and Logging
logs=### logs logs=### logs
smart-exit=### smart_exit smart-exit=### smart_exit
sponge-filter-secrets=### sponge_filter_secrets
secret-filter=### sponge_filter_secrets
ai=## 5.12 AI and Developer Tools ai=## 5.12 AI and Developer Tools
antigravity=### antigravity antigravity-ide=### antigravity-ide
claude=### claude-resume agy=### agy
agents-init=### agents-init
agents=### agents-init
agents-tools=### agents-init
version-bump=### agents-init
.version=### agents-init
structure-version=### agents-init
core.hooksPath=### agents-init
devlogs=### agents-init
claude-cli=### claude
claude-docs=### claude-docs claude-docs=### claude-docs
claude-pr=### claude-pr claude-pr=### claude-pr
code-resume=### code-resume dops=### dops
docker-ps=### dops
qc=### qc
quick-chat=### qc
aichat=### qc
superpowers=### superpowers superpowers=### superpowers
media=## 5.13 Media and Utilities media=## 5.13 Media and Utilities
dng2avif=### dng2avif dng2avif=### dng2avif
play-media=### play-media
video=### play-media
audio=### play-media
mpv=### play-media
vlc=### play-media
spark=### spark spark=### spark
steam-dl=### steam-dl
steam=### steam-dl
yt-dlp=### yt-dlp
miscfns=## 5.14 Miscellaneous miscfns=## 5.14 Miscellaneous
bash=### bash bash=### bash
bd-pull=### bd-pull
beads=### bd-pull
cffetch=### cffetch
fastfetch=### ffetch
neofetch=### cffetch
sysinfo=### cffetch
cheat=### cheat cheat=### cheat
config-help=### config-help
config-update=### config-update
config-settings=### config-settings
config-toggle=### config-toggle
toggle=### config-settings
dockup=### dockup dockup=### dockup
fetch=### cffetch
ffetch=### ffetch
fzf_configure_bindings=### fzf_configure_bindings
joplin=### joplin joplin=### joplin
ld=### ld
lazydocker=### ld
open-url=### open-url
url-open=### open-url
repo-open=### repo-open
open-repo=### repo-open
rand_string=### rand_string
random=### rand_string
password=### rand_string
randomword=### rand_string
replay=### replay replay=### replay
tmux=### tmux-clean tmux=### tmux-clean
wake-lock=### wake-lock wake-lock=### wake-lock
zellij=### zellij
# ── Tool-name synonyms (replacement → shadowed command) ──────
# These tools don't appear in any heading, so the fallback scan can't
# find them; map each to the function that wraps it.
eza=### ls
exa=### ls
lsd=### ls
trash=### rm
btop=### top
prettyping=### ping
duf=### du
dust=### du
kitten=### ssh
bat=### cat
# ── Tool integrations (Section: Integrations) ────────────────
zoxide=### Zoxide
z=### Zoxide
direnv=### DirEnv
venv=### Auto Python Venv
virtualenv=### Auto Python Venv
python=### Auto Python Venv
wakatime=### WakaTime
tailscale=### Tailscale
done=### Done Notifications
notifications=### Done Notifications
notify=### Done Notifications
pager-hierarchy=## Pager Hierarchy
shell-aliases=## 4.11 Shell Aliases
kitty-logging=### kitty-logging
watcher=### kitty-logging
kitty-scrollback=### Scrollback History
# ── Section 6: Dependency Catalog ──────────────────────────── # ── Section 6: Dependency Catalog ────────────────────────────
catalog=# 6. DEPENDENCY CATALOG catalog=# 6. DEPENDENCY CATALOG
@@ -153,12 +258,16 @@ deps-catalog=# 6. DEPENDENCY CATALOG
required=## Required required=## Required
integrations=## Integrations integrations=## Integrations
recommended=## Recommended recommended=## Recommended
optional-deps=## Optional
terminal-emulators=## Terminal Emulators
install-methods=## Install Methods install-methods=## Install Methods
# ── Section 7: Customization ────────────────────────────────── # ── Section 7: Customization ──────────────────────────────────
customization=# 7. CUSTOMIZATION customization=# 7. CUSTOMIZATION
customize=# 7. CUSTOMIZATION customize=# 7. CUSTOMIZATION
local=## Machine-local Configuration local=## Machine-local Configuration
user-dots=## Machine-local Configuration
dots-link=## Machine-local Configuration
secrets=## Secrets and API Keys secrets=## Secrets and API Keys
overrides=## Overriding Configuration Variables overrides=## Overriding Configuration Variables
universal=## Fish Universal Variables universal=## Fish Universal Variables
@@ -167,34 +276,150 @@ minimal=## Opinionated Components (Minimal Mode)
minimal-mode=## Opinionated Components (Minimal Mode) minimal-mode=## Opinionated Components (Minimal Mode)
opt-out=## Opinionated Components (Minimal Mode) opt-out=## Opinionated Components (Minimal Mode)
toggles=## Opinionated Components (Minimal Mode) toggles=## Opinionated Components (Minimal Mode)
agent-vault=## Agent Memory Vault
__fish_agent_vault_dir=## Agent Memory Vault
__fish_agent_vault_autopush=## Agent Memory Vault
component-reference=# 8. COMPONENTS REFERENCE
components=# 8. COMPONENTS REFERENCE
c0=## Per-function overrides: `C0`/`always`
always-tag=## Per-function overrides: `C0`/`always`
c1=## C1 — Command Shadows
command-shadows=## C1 — Command Shadows
aliases-detail=## C1 — Command Shadows
filesystem=### filesystem
network-shadow=### network
monitor=### monitor
shell-tools=### shell-tools
dev-tools=### dev-tools
c2=## C2 — Startup Side-Effects
autoexec=## C2 — Startup Side-Effects
startup=## C2 — Startup Side-Effects
plugin-management=### plugin-management
pkg-wrappers=### pkg-wrappers
venv-toggle=### venv
telemetry=### telemetry
sync=### sync
c3=## C3 — Key and Environment Overrides
overrides-detail=## C3 — Key and Environment Overrides
bang-bang=## C3 — Key and Environment Overrides
bindings-toggle=### key-bindings
environment=### environment
prompt-toggle=### prompt
privacy=### privacy
privacy-toggle=### privacy
do-not-track=### privacy
disable-telemetry=### privacy
c4=## C4 — Terminal and Tool Integration
integrations-detail=## C4 — Terminal and Tool Integration
terminal-abbrs=### terminal-abbrs
window-mgmt=### window-mgmt
window-management=### window-mgmt
notifications-toggle=### notifications
history-logs=### history-logs
pkg-upgrade=### pkg-upgrade
c5=## C5 — Logging and Capture
logging-detail=## C5 — Logging and Capture
logging-sentinel=## C5 — Logging and Capture
zellij=## C5 — Logging and Capture
zellij-logging=## C5 — Logging and Capture
tmux-logging=## C5 — Logging and Capture
pipe-pane=## C5 — Logging and Capture
dump-screen=## C5 — Logging and Capture
terminal-capture=### terminal-capture
multiplexer-capture=### multiplexer-capture
pkg-logs=### pkg-logs
c6=## C6 — Greeting and First-Run UI
greeting=## C6 — Greeting and First-Run UI
first-run=### first-run
greeting-message=### greeting-message
# ── Section 8: Fisher Plugins ───────────────────────────────── # ── Prompt and Theme ──────────────────────────────────────────
plugins=# 8. FISHER PLUGINS prompt-theme=## Prompt and Theme
fisher=# 8. FISHER PLUGINS prompt=## Prompt and Theme
starship=### Starship
fallback-prompt=### Catppuccin Fallback Prompt
catppuccin-prompt=### Catppuccin Fallback Prompt
nim-prompt=### Catppuccin Fallback Prompt
fzf-theme=### FZF
catppuccin-theme=### Catppuccin Mocha Syntax Highlighting
# ── Section 9: Fisher Plugins ─────────────────────────────────
plugins=# 9. FISHER PLUGINS
fisher=# 9. FISHER PLUGINS
fisher-managed=## Fisher-Managed Plugins fisher-managed=## Fisher-Managed Plugins
sponge=## Fisher-Managed Plugins sponge=## Fisher-Managed Plugins
sponge-filtering=## Sponge History Filtering sponge-filtering=## Sponge History Filtering
history-filtering=## Sponge History Filtering history-filtering=## Sponge History Filtering
privacy=## Sponge History Filtering privacy=## Sponge History Filtering
__fish_sponge_extra_sensitive=## Sponge History Filtering
extra-sensitive=## Sponge History Filtering
sponge-settings=### config-settings
bundled-plugins=## Bundled Plugin Functionality bundled-plugins=## Bundled Plugin Functionality
fish-plugins-manifest=## fish_plugins Manifest fish-plugins-manifest=## fish_plugins Manifest
# ── Section 9: Installation ──────────────────────────────────── # ── Section 10: Installation ────────────────────────────────────
installation=# 9. INSTALLATION installation=# 10. INSTALLATION
install=# 9. INSTALLATION install=# 10. INSTALLATION
sentinel=## Return Sentinel sentinel=## Return Sentinel
updating=## Updating updating=## Updating
# ── Section 10: Personalization ─────────────────────────────── # ── Section 11: Personalization ───────────────────────────────
personalization=# 10. PERSONALIZATION personalization=# 11. PERSONALIZATION
personalize=# 10. PERSONALIZATION personalize=# 11. PERSONALIZATION
secrets=## secrets.fish secrets-file=## secrets.fish
local-config=## local.fish local-config=## local.fish
# ── Section 11: Viewing This Manual ────────────────────────── # ── Section 12: Troubleshooting ──────────────────────────────
viewing=# 11. VIEWING THIS MANUAL troubleshooting=# 12. TROUBLESHOOTING
manual=# 11. VIEWING THIS MANUAL troubleshoot=# 12. TROUBLESHOOTING
ov=## With ov (recommended) faq=# 12. TROUBLESHOOTING
man-page=## As a man page (if compiled) uninstall=## Uninstalling and Reverting to Backup
manpage=## As a man page (if compiled) revert=## Uninstalling and Reverting to Backup
jump=## Jumping to a section fish-version=## Fish Version Requirement
version-req=## Fish Version Requirement
disable-logging=## Enable or Disable Session Logging
enable-logging=## Enable or Disable Session Logging
disable-greeting=## Change or Disable the Greeting
change-greeting=## Change or Disable the Greeting
secrets-trouble=## Secrets and Machine-Local Configuration
local-trouble=## Secrets and Machine-Local Configuration
return-sentinel=## Tool Init Does Nothing (Return Sentinel)
tool-init=## Tool Init Does Nothing (Return Sentinel)
missing-deps=## Missing Dependencies
vi-mode=## Vi Mode Keybindings
vi-trouble=## Vi Mode Keybindings
emacs-mode=## Vi Mode Keybindings
minimal-trouble=## What's with the C1-C6 stuff?
# ── Section 13: Viewing This Manual ──────────────────────────
viewing=# 13. VIEWING THIS MANUAL
manual=# 13. VIEWING THIS MANUAL
ov=## In the terminal
manpage=## As a man page
jump=## In the terminal
html=## The documentation website
browser=## The documentation website
site=## The documentation website
source=## Reading the source directly
raw-source=## Reading the source directly
# ── Section 14: Testing ───────────────────────────────────────
testing=# 14. TESTING
tests=# 14. TESTING
# ── Section 15: Contributing ──────────────────────────────────
contributing=# 15. CONTRIBUTING
contribute=# 15. CONTRIBUTING
forge=# 15. CONTRIBUTING
# ── Section 16: Attribution ───────────────────────────────────
attribution=# 16. ATTRIBUTION
credits=# 16. ATTRIBUTION
# ── Section 17: License ───────────────────────────────────────
license=# 17. LICENSE
licensing=# 17. LICENSE
agpl=# 17. LICENSE
copyright=# 17. LICENSE
+3627 -813
View File
File diff suppressed because it is too large Load Diff
+127
View File
@@ -0,0 +1,127 @@
#!/usr/bin/env python3
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Generate the committed opinionated-component registry.
Walks every `# COMPONENT` header in functions/*.fish, conf.d/*.fish, and
config.fish and writes conf.d/__fish_config_op_registry.fish, the fish
data file __fish_config_op_registry_lookup reads at shell startup.
Run manually (via __fish_config_op_registry_rebuild) after editing a
# COMPONENT header, and automatically as a pre-step in build-manual.py
before the manual is built.
"""
import sys
from pathlib import Path
import manualtools as mt
DOCS = Path(__file__).parent
REPO = DOCS.parent
OUTPUT = REPO / "conf.d" / "__fish_config_op_registry.fish"
def collect_components() -> dict[str, list[str]]:
"""Gather every `# COMPONENT` header across the whole repo.
Concatenates raw component lines when the same identity appears in
more than one source (e.g. functions/auto-pull.fish and
conf.d/auto-pull.fish both self-identify as "auto-pull" at runtime,
since the guard can only ever look up the bare status
current-function/basename string) rather than letting one silently
overwrite the other.
"""
out: dict[str, list[str]] = {}
for source in (
mt.parse_components(REPO / "functions"),
mt.parse_components(REPO / "conf.d"),
mt.parse_component_file(REPO / "config.fish"),
):
for identity, lines in source.items():
out.setdefault(identity, []).extend(lines)
return out
def build_registry(components: dict[str, list[str]]) -> tuple[dict[str, list[str]], list[str]]:
"""Turn {identity: [raw COMPONENT lines]} into ({"identity:site": [tags]}, warnings).
A site with both always/on and always/off tagged is a contradiction:
both are stripped and a warning is emitted, but generation continues
-- any other real tag on that same site survives. A site whose
effective tag set is empty after stripping produces no registry entry
at all, which __fish_config_op_enabled already treats as always/on
(fail-open) at guard time -- see spec §4.5.
"""
registry: dict[str, list[str]] = {}
warnings: list[str] = []
for identity, raw_lines in components.items():
by_site: dict[str, list[str]] = {}
for site, tag in mt.parse_component_lines(raw_lines):
by_site.setdefault(site, []).append(tag)
for site, tags in by_site.items():
if "always/on" in tags and "always/off" in tags:
label = identity if not site else f"{identity}:{site}"
warnings.append(
f"{label}: both always/on and always/off tagged; ignoring both"
)
tags = [t for t in tags if t not in ("always/on", "always/off")]
if tags:
registry[f"{identity}:{site}"] = list(dict.fromkeys(tags))
return registry, warnings
def render(registry: dict[str, list[str]]) -> str:
keys = sorted(registry)
lines = [
"# Copyright (C) 2026 Rootiest",
"# SPDX-License-Identifier: AGPL-3.0-or-later",
"#",
"# GENERATED FILE --- do not edit by hand.",
"# Regenerate with __fish_config_op_registry_rebuild after editing a",
"# # COMPONENT header, or automatically via docs/build-manual.py.",
"# Source: docs/generate_component_registry.py",
"#",
"# This file must be sourced before any other conf.d/*.fish file that",
"# calls the opinionated guard. That currently holds only because fish's",
"# glob-based conf.d loading happens to sort this filename first",
"# alphabetically among the guard-calling files -- do not rename it",
"# without preserving that ordering.",
"",
]
if not keys:
lines.append("set -g __fish_config_op_registry_keys")
lines.append("set -g __fish_config_op_registry_values")
return "\n".join(lines) + "\n"
quoted_keys = [f'"{k}"' for k in keys]
lines.append("set -g __fish_config_op_registry_keys \\")
lines += [f" {k} \\" for k in quoted_keys[:-1]] + [f" {quoted_keys[-1]}"]
lines.append("")
values = [
(
'"' + " ".join(registry[k]) + '"'
if any(c in " ".join(registry[k]) for c in ' \t*?[]"\'\\$')
else " ".join(registry[k])
)
for k in keys
]
lines.append("set -g __fish_config_op_registry_values \\")
lines += [f" {v} \\" for v in values[:-1]] + [f" {values[-1]}"]
return "\n".join(lines) + "\n"
def main() -> int:
components = collect_components()
registry, warnings = build_registry(components)
for w in warnings:
print(f" WARN {w}", file=sys.stderr)
OUTPUT.write_text(render(registry))
print(f"wrote {OUTPUT} ({len(registry)} entries)", file=sys.stderr)
return 0
if __name__ == "__main__":
sys.path.insert(0, str(Path(__file__).parent))
raise SystemExit(main())
-301
View File
@@ -1,301 +0,0 @@
<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>
-495
View File
@@ -1,495 +0,0 @@
<!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>NAME</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="2-synopsis.html" accesskey="n" rel="next">SYNOPSIS</a>
</span>
<span class="navlink">
<span class="navlink-label">Previous:</span> <a href="index.html" accesskey="p" rel="previous">FISH-CONFIG</a>
</span>
</div>
</nav>
<h1 data-number="1" id="name">NAME</h1>
<p>fish-config - personal fish shell configuration for Fish 4.x with
modern CLI tool integration</p>
</body>
</html>
-534
View File
@@ -1,534 +0,0 @@
<!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>6. DEPENDENCY CATALOG</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="11-7-customization.html" accesskey="n" rel="next">7. CUSTOMIZATION</a>
</span>
<span class="navlink">
<span class="navlink-label">Previous:</span> <a href="9-5-functions-reference.html" accesskey="p" rel="previous">5. FUNCTIONS REFERENCE</a>
</span>
</div>
</nav>
<h1 data-number="10" id="6-dependency-catalog">6. DEPENDENCY
CATALOG</h1>
<p>fish-deps manages these tools. Run <code>fish-deps</code> to check
status, or <code>fish-deps install</code> to install missing ones.</p>
<h2 data-number="10.1" id="required">Required</h2>
<pre><code>uv Python package manager (Astral)
cargo Rust toolchain (via rustup)
fish Fish shell &gt;= 4.0
fisher Fish plugin manager
starship Cross-shell prompt
fzf Fuzzy finder
zoxide Smart cd with frecency
direnv Per-directory environment loading
paru AUR helper (Arch only; preferred)
yay AUR helper (Arch only; fallback)</code></pre>
<h2 data-number="10.2" id="integrations-1">Integrations</h2>
<pre><code>wakatime Developer time tracking
tailscale Mesh VPN client</code></pre>
<h2 data-number="10.3" id="recommended">Recommended</h2>
<pre><code>eza Modern ls replacement
lsd ls replacement (fallback to eza)
bat Syntax-highlighted cat
btop Modern resource monitor
dust Disk usage tree (Rust)
duf Disk usage/free overview
prettyping Colorized ping wrapper
ov Modern pager (replaces less)
ripgrep Fast line search
lazygit Terminal git UI
lazydocker Terminal docker UI
trash Safe delete (trash-cli)
kitty GPU-accelerated terminal (primary)
wezterm GPU-accelerated terminal (alternative)</code></pre>
<h2 data-number="10.4" id="install-methods">Install Methods</h2>
<p>The install priority for each tool:</p>
<pre><code>cargo Rust tools (eza, lsd, bat, dust, ov, ripgrep, trashy, zoxide,
starship) — always gets the latest crate version
system PM paru / apt / brew / dnf / etc. — for tools without a crate
git clone fzf — installed from GitHub to ~/.fzf/
curl starship installer, fisher bootstrap, uv installer
pipx Python-based tools</code></pre>
<hr />
</body>
</html>
-609
View File
@@ -1,609 +0,0 @@
<!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>~/.config/.user-dots/fish/local.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>~/.config/.user-dots/fish/secrets.fish</code></pre>
<p>Store API tokens, GPG keys, private credentials here. This file is
never committed.</p>
<p>Both files are sourced at the end of config.fish on every interactive
session, so they 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>
<pre><code>Variable Disables
------------------------------ ------------------------------------
__fish_config_op_aliases Command shadows and flag injection:
ls-&gt;eza, cat-&gt;bat, cd-&gt;zoxide,
rm-&gt;trash, less-&gt;ov, top-&gt;btop,
ping-&gt;prettyping, ssh-&gt;kitten,
du-&gt;duf/dust, mkdir/bash wrappers,
history timestamps, grep/cp/mv/wget
flag injection, help intercept
__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-&gt;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 &amp; capture: scrollback
capture on exit, paru/yay AUR log
wrappers, Kitty watcher capture;
sentinel file coordinates
cross-process state
__fish_config_op_greeting Greeting &amp; 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</code></pre>
<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>
<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="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.3"
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 &quot;Catppuccin Latte&quot;</code></pre>
<hr />
</body>
</html>
-561
View File
@@ -1,561 +0,0 @@
<!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>8. FISHER PLUGINS</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="13-9-installation.html" accesskey="n" rel="next">9. INSTALLATION</a>
</span>
<span class="navlink">
<span class="navlink-label">Previous:</span> <a href="11-7-customization.html" accesskey="p" rel="previous">7. CUSTOMIZATION</a>
</span>
</div>
</nav>
<h1 data-number="12" id="8-fisher-plugins">8. FISHER PLUGINS</h1>
<p>Fisher is bootstrapped automatically on the <strong>first interactive
session</strong> via <code>conf.d/first_run.fish</code>. This also
applies the Catppuccin Mocha theme and prints a one-time welcome message
(gated by __fish_config_op_greeting; set it to 0 to suppress).
Subsequent sessions skip all first-run logic with zero overhead.</p>
<p>To re-trigger first-run initialization (e.g., after a fresh install
or for testing), run:</p>
<pre><code>set -Ue __fish_config_first_run_complete</code></pre>
<p>Then open a new shell.</p>
<h2 data-number="12.1" id="fisher-managed-plugins">Fisher-Managed
Plugins</h2>
<p>The following plugins are fully managed by Fisher. Their files are
installed into the repo directory by Fisher and are listed in
<code>.gitignore</code> — do not commit them. Fisher installs and
updates them automatically.</p>
<pre><code>jorgebucaran/fisher Plugin manager itself
meaningful-ooo/sponge Remove failed commands from history</code></pre>
<h2 data-number="12.2" id="sponge-history-filtering">Sponge History
Filtering</h2>
<p>Sponge removes failed commands from history and, via
conf.d/sponge_privacy.fish, also filters privacy-sensitive commands
through three layers:</p>
<p>Layer 1 — Static patterns (universal, persistent across sessions):
Commands matching any of these structural signatures are never
recorded:</p>
<pre><code>--password / --token / --passphrase / --api-key flags with values
Inline env assignments: GITHUB_TOKEN=xxx, MY_API_KEY=abc
Fish set with sensitive names: set -gx GITHUB_TOKEN xxx
URLs with embedded credentials: https://user:pass@host
HTTP Authorization headers: curl -H &quot;Authorization: ...&quot;
Basic auth flags: curl -u user:pass
sshpass, docker login -p, openssl -passin/-passout</code></pre>
<p>Layer 2 — Dynamic secret values (session globals, refreshed each
login): On the first prompt, after secrets.fish has loaded, the literal
values of all exported variables whose names suggest credentials (TOKEN,
PASSWORD, SECRET, API_KEY, etc.) are collected, regex-escaped, and added
as a session-scoped overlay. Because globals shadow universals in Fish,
the combined list is what sponge sees. Rotating a token takes effect on
the next login automatically.</p>
<p>Layer 3 — Per-command filter (sponge_filter_secrets): Catches
credentials in variables exported after login, such as tokens sourced
from a project .env file mid-session.</p>
<p>To add your own persistent patterns:</p>
<pre><code>set -U -a sponge_regex_patterns &#39;your-regex-here&#39;</code></pre>
<h2 data-number="12.3" id="bundled-plugin-functionality">Bundled Plugin
Functionality</h2>
<p>The remaining plugin functionality is bundled directly with this
config rather than managed through Fisher. The bundled versions include
customizations for Fish 4.x compatibility and improved behavior that
differ from their upstream releases. Installing them through Fisher
would overwrite these customizations.</p>
<p>Bundled components and their upstream origins:</p>
<pre><code>catppuccin/fish → themes/ + conf.d/theme.fish
PatrickF1/fzf.fish → functions/_fzf_*.fish + conf.d/fzf.fish
franciscolourenco/done → conf.d/done.fish
jorgebucaran/autopair.fish → functions/_autopair_*.fish + conf.d/autopair.fish
nickeb96/puffer-fish → functions/_puffer_fish_*.fish + conf.d/puffer.fish</code></pre>
<p>Do not run <code>fisher install</code> for these — it will overwrite
the customized versions. To update their behavior, edit the relevant
bundled files directly.</p>
<h2 data-number="12.4" id="fish_plugins-manifest">fish_plugins
Manifest</h2>
<p>The <code>fish_plugins</code> file at the config root:</p>
<pre><code>jorgebucaran/fisher Plugin manager itself
meaningful-ooo/sponge Remove failed commands from history</code></pre>
<p>To update all Fisher-managed plugins, run <code>fisher update</code>
or <code>fish-deps update</code> which calls it as its first step.</p>
<hr />
</body>
</html>
-521
View File
@@ -1,521 +0,0 @@
<!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>9. INSTALLATION</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="14-10-personalization.html" accesskey="n" rel="next">10. PERSONALIZATION</a>
</span>
<span class="navlink">
<span class="navlink-label">Previous:</span> <a href="12-8-fisher-plugins.html" accesskey="p" rel="previous">8. FISHER PLUGINS</a>
</span>
</div>
</nav>
<h1 data-number="13" id="9-installation">9. INSTALLATION</h1>
<p>This configuration is managed as a git repository. To deploy on a new
machine:</p>
<pre><code>mv ~/.config/fish ~/.config/fish.bak # back up any existing config
git clone https://git.rootiest.dev/rootiest/fish-config.git ~/.config/fish</code></pre>
<p>Then open a new Fish shell. Fisher installs automatically on first
launch and the Catppuccin Mocha theme is applied. All other plugin
functionality is bundled directly with this config and requires no
additional installation.</p>
<h2 data-number="13.1" id="return-sentinel">Return Sentinel</h2>
<p>config.fish ends with a return sentinel guard. Any lines appended
after it by a tool's setup command (starship init fish | source, zoxide
init fish | source, etc.) will have no effect. All integrations are
managed via conf.d/ files.</p>
<p>If a new tool's shell integration appears to do nothing, check
whether its setup command appended an init line below the sentinel and
create a dedicated conf.d/<tool>.fish instead.</p>
<h2 data-number="13.2" id="updating">Updating</h2>
<p>Pull the latest changes from the upstream repository without needing
a configured git remote:</p>
<pre><code>config-update Fetch and apply the latest commits from upstream
config-update --dry-run Preview available changes without applying them
config-update --force Stash local changes, pull, then restore the stash</code></pre>
<p>The remote URL (<a
href="https://git.rootiest.dev/rootiest/fish-config.git">https://git.rootiest.dev/rootiest/fish-config.git</a>)
is hard-coded, so this works on a fresh clone with no origin configured.
All git output is suppressed. Run exec fish after a successful update to
reload.</p>
<hr />
</body>
</html>
-532
View File
@@ -1,532 +0,0 @@
<!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>10. PERSONALIZATION</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="15-11-viewing-this-manual.html" accesskey="n" rel="next">11. VIEWING THIS MANUAL</a>
</span>
<span class="navlink">
<span class="navlink-label">Previous:</span> <a href="13-9-installation.html" accesskey="p" rel="previous">9. INSTALLATION</a>
</span>
</div>
</nav>
<h1 data-number="14" id="10-personalization">10. PERSONALIZATION</h1>
<p>Sensitive credentials and machine-specific settings are kept out of
version control in a private directory at ~/.config/.user-dots/fish/.
Two files are sourced automatically by config.fish if they exist:</p>
<pre><code>~/.config/.user-dots/fish/
├── secrets.fish API keys, tokens, passwords, personal identifiers
└── local.fish Machine-specific paths and environment variables</code></pre>
<p>fish_variables (auto-managed by fish) is excluded from this repo via
.gitignore. Do not commit it.</p>
<h2 data-number="14.1" id="secretsfish">secrets.fish</h2>
<p>Store anything you would not commit to a public repo: API keys, auth
tokens, passwords, and personal identifiers.</p>
<pre><code>set -gx MY_NAME &quot;Your Name&quot;
set -gx MY_EMAIL &quot;you@example.com&quot;
set -gx GPG_RECIPIENT &quot;you@example.com&quot;
set -gx GITHUB_TOKEN ghp_yourTokenHere
set -gx OPENAI_API_KEY sk-proj-yourKeyHere
set -gx GITEA_TOKEN yourGiteaTokenHere
set -gx GITEA_CHOSEN_LOGIN your.gitea.instance
set -gx KOPIA_PASSWORD yourKopiaPassword</code></pre>
<h2 data-number="14.2" id="localfish">local.fish</h2>
<p>Store paths and variables specific to one machine — things that would
be wrong on any other system.</p>
<pre><code># CDPATH — directories searched by cd
set -gx CDPATH . /home/youruser/projects /home/youruser
# Path to your shared .gitignore boilerplate
set -gx GITIGNORE_BOILERPLATE ~/.config/git/gitignore_boilerplate
# SSH shortcuts
abbr -a sshr &#39;ssh you@your-server.local&#39;
abbr -a sshw &#39;ssh you@work-server.example.com&#39;
# Docker context shortcuts
abbr -a dcr &#39;docker context use my-remote-server&#39;
abbr -a dcw &#39;docker context use work-server&#39;</code></pre>
<p>Both files are sourced at the end of config.fish with an existence
check so the public config works cleanly on any machine without the
private repo.</p>
<hr />
</body>
</html>
-545
View File
@@ -1,545 +0,0 @@
<!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>11. VIEWING THIS MANUAL</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>
<span class="navlink">
<span class="navlink-label">Previous:</span> <a href="14-10-personalization.html" accesskey="p" rel="previous">10. PERSONALIZATION</a>
</span>
</div>
</nav>
<h1 data-number="15" id="11-viewing-this-manual">11. VIEWING THIS
MANUAL</h1>
<h2 data-number="15.1" id="with-ov-recommended">With ov
(recommended)</h2>
<pre><code>help config</code></pre>
<p>ov renders the Markdown with syntax highlighting and section-based
navigation.</p>
<pre><code>Space next section
^ previous section
Alt+u toggle section list sidebar
/ search forward
n / N next / previous search match
g go to line number
j interactive jump target (line, %, or &#39;section&#39;)
q quit</code></pre>
<h2 data-number="15.2" id="with-bat">With bat</h2>
<pre><code>bat --language=markdown --paging=always ~/.config/fish/docs/fish-config.md</code></pre>
<h2 data-number="15.3" id="as-a-man-page">As a man page</h2>
<pre><code>help config --man
help config pkg --man</code></pre>
<p>Opens the compiled docs/fish-config.1 directly via man -l, bypassing
the pager fallback chain. If a section keyword is given, the pager opens
at the nearest matching heading. The symlink and MANPATH are also
configured automatically on shell start for the standard invocation:</p>
<pre><code>man fish-config</code></pre>
<p>NOTE: fish-config (hyphen) is this config's man page. fish_config
(underscore) is fish's built-in browser-based configuration tool — a
completely separate command. Do not mix them up.</p>
<h2 data-number="15.4" id="in-the-browser-html">In the browser
(HTML)</h2>
<pre><code>help config --html
help config pkg --html</code></pre>
<p>Opens docs/html/index.html in the default web browser. If a section
keyword is given, the browser opens directly at the matching anchor
(resolved via docs/html/sitemap.json). Browser detection queries the
system's x-scheme-handler/https MIME entry (via xdg-mime) to find the
real browser binary, then falls back through known browser binaries
(firefox, chromium, vivaldi, etc.), and finally xdg-open as a last
resort. Set $fish_help_browser or $BROWSER to override.</p>
<h2 data-number="15.5" id="as-a-wiki">As a wiki</h2>
<p>The generated Markdown wiki lives in docs/wiki/. index.md provides
the project overview and a full table of contents. Each section page has
a navigation bar at the top linking to every other section.</p>
<p>The wiki is auto-generated from this file by the CI pipeline on every
push to main that changes docs/fish-config.md.</p>
<h2 data-number="15.6" id="jumping-to-a-section">Jumping to a
section</h2>
<pre><code>help config keybindings
help config abbreviations
help config pkg
help config logs
help config fish-deps</code></pre>
<p>The keyword is matched case-insensitively against section
headings.</p>
</body>
</html>
-503
View File
@@ -1,503 +0,0 @@
<!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>SYNOPSIS</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="3-description.html" accesskey="n" rel="next">DESCRIPTION</a>
</span>
<span class="navlink">
<span class="navlink-label">Previous:</span> <a href="1-name.html" accesskey="p" rel="previous">NAME</a>
</span>
</div>
</nav>
<h1 data-number="2" id="synopsis">SYNOPSIS</h1>
<pre><code>help config [SECTION]</code></pre>
<p>Open this manual in the best available pager. Optionally jump to a
section by keyword:</p>
<pre><code>help config keybindings
help config pkg
help config abbreviations
help config logs</code></pre>
<p>The <code>help config</code> syntax integrates with fish's built-in
help command. The underlying <code>config-help</code> function is also
available directly.</p>
</body>
</html>
-535
View File
@@ -1,535 +0,0 @@
<!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>DESCRIPTION</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="4-table-of-contents.html" accesskey="n" rel="next">TABLE OF CONTENTS</a>
</span>
<span class="navlink">
<span class="navlink-label">Previous:</span> <a href="2-synopsis.html" accesskey="p" rel="previous">SYNOPSIS</a>
</span>
</div>
</nav>
<h1 data-number="3" id="description">DESCRIPTION</h1>
<p>A production-grade Fish shell configuration targeting Fish 4.x. It
provides:</p>
<ul>
<li>Drop-in replacements for common Unix tools (ls, cat, rm, du, ping,
less)</li>
<li>Deep Kitty and WezTerm terminal integration: tab/window/pane
management from the command line</li>
<li>Scrollback history snapshots saved to ~/.terminal_history on session
exit</li>
<li>Automatic Python virtualenv activation on directory change</li>
<li>Cross-platform package management via pkg and fish-deps</li>
<li>AI session helpers for Claude Code and Antigravity</li>
<li>Catppuccin Mocha color theme throughout</li>
</ul>
<p>The configuration is split across:</p>
<pre><code>config.fish Main entry point; sets env vars and PATH
conf.d/
abbr.fish All abbreviations
cheat.fish cheat.sh completions
done.fish Desktop notifications for long commands
first_run.fish One-time init: Fisher bootstrap, theme, welcome
key_bindings.fish Custom key bindings and Vi mode
paru-wrapper.fish Auto-generates ~/.local/bin/paru logging wrapper
starship.fish fish_prompt with OSC 133 shell-integration markers
tailscale.fish Tailscale CLI tab completions
theme.fish Catppuccin syntax highlight colors
sponge_privacy.fish Sponge privacy patterns; filters credentials from history
tricks.fish PATH, bang-bang helpers, bat man pages, aliases
wakatime.fish WakaTime shell hook
yay-wrapper.fish Auto-generates ~/.local/bin/yay logging wrapper
zoxide.fish Zoxide z/zi integration; overrides cd
functions/ Custom functions, one per file, autoloaded
completions/ Tab completion scripts
integrations/
fzf.fish FZF Catppuccin theme and key binding config
docs/ Offline documentation and compiled man page
fish-config.md Primary source manual (terminal-readable)
fish-config.1 Compiled man page (auto-generated by CI)
fish-config.index Section index for help config navigation
html/ Chunked HTML docs (auto-generated by CI)
wiki/ Markdown wiki (auto-generated by CI)</code></pre>
<hr />
</body>
</html>
-530
View File
@@ -1,530 +0,0 @@
<!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>TABLE OF CONTENTS</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="5-1-configuration-variables.html" accesskey="n" rel="next">1. CONFIGURATION VARIABLES</a>
</span>
<span class="navlink">
<span class="navlink-label">Previous:</span> <a href="3-description.html" accesskey="p" rel="previous">DESCRIPTION</a>
</span>
</div>
</nav>
<h1 data-number="4" id="table-of-contents">TABLE OF CONTENTS</h1>
<pre><code>1. Configuration Variables
2. PATH Setup
3. Key Bindings
4. Abbreviations
4.1 Editors
4.2 Navigation and Listing
4.3 Git
4.4 Terminal Windows, Tabs, and Panes
4.5 Chezmoi
4.6 Docker
4.7 Systemctl
4.8 AI Assistants
4.9 History Expansion
4.10 Miscellaneous
4.11 Shell Aliases
5. Functions Reference
5.1 File and Directory
5.2 Navigation
5.3 Editors and Viewers
5.4 Git and Version Control
5.5 Package Management
5.6 Dependency Management
5.7 System and Monitoring
5.8 Terminal Management
5.9 Clipboard
5.10 Network
5.11 Pager and Logging
5.12 AI and Developer Tools
5.13 Media and Utilities
5.14 Miscellaneous
6. Dependency Catalog
7. Customization
8. Fisher Plugins
9. Installation
10. Personalization
11. Viewing This Manual</code></pre>
<hr />
</body>
</html>
-583
View File
@@ -1,583 +0,0 @@
<!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>1. CONFIGURATION VARIABLES</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="6-2-path-setup.html" accesskey="n" rel="next">2. PATH SETUP</a>
</span>
<span class="navlink">
<span class="navlink-label">Previous:</span> <a href="4-table-of-contents.html" accesskey="p" rel="previous">TABLE OF CONTENTS</a>
</span>
</div>
</nav>
<h1 data-number="5" id="1-configuration-variables">1. CONFIGURATION
VARIABLES</h1>
<p>These variables are exported from config.fish on every interactive
session. Override them in ~/.config/.user-dots/fish/local.fish.</p>
<h2 data-number="5.1" id="environment-directories-xdg">Environment
Directories (XDG)</h2>
<pre><code>XDG_CONFIG_HOME ~/.config
XDG_CACHE_HOME ~/.cache
XDG_DATA_HOME ~/.local/share
XDG_STATE_HOME ~/.local/state</code></pre>
<p>Tools that respect XDG are directed to these paths rather than
polluting $HOME.</p>
<h2 data-number="5.2" id="tool-homes-xdg-compliant">Tool Homes
(XDG-compliant)</h2>
<pre><code>CARGO_HOME $XDG_DATA_HOME/cargo
RUSTUP_HOME $XDG_DATA_HOME/rustup
GOPATH $XDG_DATA_HOME/go
BUN_INSTALL $XDG_DATA_HOME/bun
NPM_CONFIG_PREFIX $XDG_DATA_HOME/npm-global
GNUPGHOME $XDG_CONFIG_HOME/gnupg
WAKATIME_HOME $XDG_CONFIG_HOME/wakatime</code></pre>
<h2 data-number="5.3" id="editor-and-pager">Editor and Pager</h2>
<pre><code>EDITOR nvim (falls back to vi if nvim is absent)
VISUAL same as EDITOR
SUDO_EDITOR same as EDITOR
PAGER ov (falls back to less)</code></pre>
<h2 data-number="5.4" id="scrollback-history">Scrollback History</h2>
<pre><code>SCROLLBACK_HISTORY_DIR ~/.terminal_history
SCROLLBACK_HISTORY_MAX_FILES 100</code></pre>
<p>Scrollback logs accumulate in SCROLLBACK_HISTORY_DIR as timestamped
files. When the count exceeds SCROLLBACK_HISTORY_MAX_FILES the oldest
are pruned automatically on exit. Use <code>logs</code> to browse them
interactively.</p>
<h2 data-number="5.5" id="other">Other</h2>
<pre><code>GPG_TTY $(tty) — ensures GPG passphrase prompts work
CLAUDE_CODE_NO_FLICKER 1 — suppress terminal flicker in Claude Code
CDPATH . ~/projects ~</code></pre>
<p>Opinionated defaults (CDPATH, PAGER/MANPAGER, Vi mode, command
shadows, terminal integrations) can be switched off per category with
universal variables — see Section 7, "Opinionated Components (Minimal
Mode)".</p>
<h2 data-number="5.6" id="pager-hierarchy">Pager Hierarchy</h2>
<p>$PAGER is set to ov when available, falling back to less. The less
wrapper function extends this into a full chain so anything that calls
less directly also benefits:</p>
<pre><code>$PAGER → ov → less → more → cat</code></pre>
<p>When bat is installed, man pages are rendered with syntax
highlighting:</p>
<pre><code>MANROFFOPT -c
MANPAGER sh -c &#39;col -bx | bat -l man -p&#39;</code></pre>
<h2 data-number="5.7" id="integrations">Integrations</h2>
<h3 data-number="5.7.1" id="zoxide">Zoxide</h3>
<p>cd, z, and cdi/zi are all mapped to zoxide-backed navigation. Tab
completions for cd and z blend standard directory entries (CWD and
CDPATH) with frecency results so both familiar and frequently-visited
paths appear in one list.</p>
<h3 data-number="5.7.2" id="direnv">DirEnv</h3>
<p>Automatically loads .envrc files on directory change. Takes priority
over the auto-venv logic — if a directory is managed by direnv, the
auto-venv activation is skipped entirely.</p>
<h3 data-number="5.7.3" id="auto-python-venv">Auto Python Venv</h3>
<p>When entering a directory that contains a .venv/, the virtualenv is
activated automatically and deactivated when you leave the project
tree.</p>
<h3 data-number="5.7.4" id="wakatime">WakaTime</h3>
<p>Every shell command is reported to WakaTime for time-tracking. Set
FISH_WAKATIME_DISABLED=1 to disable without removing the plugin.</p>
<h3 data-number="5.7.5" id="tailscale">Tailscale</h3>
<p>Full tab completion for the tailscale CLI is provided via
conf.d/tailscale.fish.</p>
<h3 data-number="5.7.6" id="done-notifications">Done Notifications</h3>
<p>Desktop notifications fire when a command takes longer than 10
seconds and the terminal window is not focused. Configured via fish
universal variables:</p>
<pre><code>__done_min_cmd_duration 10000 ms
__done_notification_urgency_level low</code></pre>
<h3 data-number="5.7.7" id="scrollback-history-1">Scrollback
History</h3>
<p>When running inside Kitty, closing a shell session via exit saves a
timestamped scrollback snapshot to SCROLLBACK_HISTORY_DIR. Files are
named:</p>
<pre><code>scrollback_YYYY-MM-DD_HH-MM-SS.log</code></pre>
<p>The paru and yay wrappers (auto-generated in ~/.local/bin/) tee all
output to:</p>
<pre><code>paru_YYYY-MM-DD_HH-MM-SS.log
yay_YYYY-MM-DD_HH-MM-SS.log</code></pre>
<p>Before pruning, _scrollback_prune_junk silently removes empty files,
files with only a single meaningful line (e.g. bare [exited] captures),
and Kitty tab-rename prompt captures. Use exit --no-log (or exit -n) to
skip capture.</p>
<hr />
</body>
</html>
-506
View File
@@ -1,506 +0,0 @@
<!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>2. PATH SETUP</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="7-3-key-bindings.html" accesskey="n" rel="next">3. KEY BINDINGS</a>
</span>
<span class="navlink">
<span class="navlink-label">Previous:</span> <a href="5-1-configuration-variables.html" accesskey="p" rel="previous">1. CONFIGURATION VARIABLES</a>
</span>
</div>
</nav>
<h1 data-number="6" id="2-path-setup">2. PATH SETUP</h1>
<p>Directories prepended to PATH in this order (first wins):</p>
<pre><code>~/.local/bin Standard user-local executables
~/Applications User-installed standalone apps
~/scripts Personal shell scripts
~/bin Cargo binaries (appended — lowest priority)
$BUN_INSTALL/bin Bun runtime and global packages
$NPM_CONFIG_PREFIX/bin Global npm packages
~/.lmstudio/bin LM Studio CLI
~/.resend/bin Resend CLI
~/.fzf/bin fzf binary (git-installed)</code></pre>
<p>Cargo binaries are intentionally appended (lowest priority) to avoid
shadowing system-installed Rust tools.</p>
<hr />
</body>
</html>
-538
View File
@@ -1,538 +0,0 @@
<!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>3. KEY BINDINGS</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="8-4-abbreviations.html" accesskey="n" rel="next">4. ABBREVIATIONS</a>
</span>
<span class="navlink">
<span class="navlink-label">Previous:</span> <a href="6-2-path-setup.html" accesskey="p" rel="previous">2. PATH SETUP</a>
</span>
</div>
</nav>
<h1 data-number="7" id="3-key-bindings">3. KEY BINDINGS</h1>
<p>The shell uses Vi key bindings (fish_vi_key_bindings). All custom
bindings are active in Insert, Normal, and Visual modes unless
noted.</p>
<pre><code>Binding Action
─────────────────────────────────────────────────────────────────────
Ctrl+G Insert the head of the previous command&#39;s last path
argument. Equivalent to !$:h in Bash.
Example: previous = &quot;cd /usr/local/bin&quot;
Ctrl+G inserts &quot;/usr/local&quot;
Ctrl+F Interactive history substitution. Type old/new then
press Ctrl+F to apply s/old/new/ to the previous
command. Equivalent to !!:s/old/new/ in Bash.
Example: previous = &quot;echo this is a test&quot;
type &quot;this is/that was&quot;, press Ctrl+F
result = &quot;echo that was a test&quot;
Ctrl+Alt+U Strip the first token of the current command line,
leaving arguments in place with the cursor at the
start. Useful for quickly retyping the command.
Example: &quot;mkdir new_folder&quot; -&gt; &quot; new_folder&quot;
Ctrl+Alt+= Evaluate the current command line buffer with
Qalculate! (qalc) and print the result inline.
Requires qalc to be installed.
Example: type &quot;150 * 1.08&quot;, press Ctrl+Alt+=
prints 162
Ctrl+Enter Smart execute: runs commands instantly without
pressing Enter a second time for certain fast-path
commands (speedtest-fast, etc.).
@@ FZF inline picker. Type @@ anywhere on the command
line to open an fzf picker and insert a selection
at the cursor position.</code></pre>
<h2 data-number="7.1"
id="fzf-bindings-bundled-from-patrickf1fzffish">FZF Bindings (bundled
from PatrickF1/fzf.fish)</h2>
<pre><code>Ctrl+R Search command history
Ctrl+Alt+F Search git-tracked files
Ctrl+Alt+L Search git log
Ctrl+Alt+S Search git status
Ctrl+V Search shell variables
Ctrl+Alt+P Search running processes</code></pre>
<hr />
</body>
</html>
-641
View File
@@ -1,641 +0,0 @@
<!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>4. ABBREVIATIONS</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="9-5-functions-reference.html" accesskey="n" rel="next">5. FUNCTIONS REFERENCE</a>
</span>
<span class="navlink">
<span class="navlink-label">Previous:</span> <a href="7-3-key-bindings.html" accesskey="p" rel="previous">3. KEY BINDINGS</a>
</span>
</div>
</nav>
<h1 data-number="8" id="4-abbreviations">4. ABBREVIATIONS</h1>
<p>Abbreviations expand when you press Space or Enter. They are
terminal-aware: some expand differently in Kitty vs WezTerm vs other
terminals.</p>
<h2 data-number="8.1" id="41-editors">4.1 Editors</h2>
<pre><code>n / nv / neovim nvim
e edit
se sudoedit
k kate
editt Open new tab with nvim (terminal-aware)
cdnv cd ~/.config/nvim
cdnvn cd ~/.config/nvim; nvim</code></pre>
<h2 data-number="8.2" id="42-navigation-and-listing">4.2 Navigation and
Listing</h2>
<pre><code>l ls
lS lss (sort by size)
lsR lsr (sort by time, oldest first)
lX lx (sort by extension)
lT lt (tree, depth 2)
lsT lstree (full recursive tree)
lzd ld (lazydocker)
cdi zi (interactive zoxide picker)</code></pre>
<h2 data-number="8.3" id="43-git">4.3 Git</h2>
<pre><code>g git
lg lazygit
gitig / git-ignore gi (generate .gitignore)</code></pre>
<h2 data-number="8.4" id="44-terminal-windows-tabs-and-panes">4.4
Terminal Windows, Tabs, and Panes</h2>
<p>These abbreviations control the terminal emulator. Each has a Kitty
variant and a WezTerm variant; the correct one is inserted based on
$TERM or $TERM_PROGRAM.</p>
<pre><code>:w New OS window
:wv Split pane horizontally (new pane below)
:wh Split pane vertically (new pane to the right)
:wo Detach current window to its own OS window
:wot Move current pane to a new tab
:t New tab
:tl Set tab title
:tw Set window title
:twk Rename workspace (WezTerm only)
:tp Focus previous tab
:tn Focus next tab
:q Close current pane/window
:Q Close current tab
:sw spwin (spawn new OS window)</code></pre>
<p>Quick-navigate shortcuts open windows/tabs/panes with preset working
dirs:</p>
<pre><code>:tgk New tab at ~/.config/kitty
:tgn New tab at ~/.config/nvim
:tgf New tab at ~/.config/fish
:tgh New tab at ~
:tgcz New tab at chezmoi source dir
:tgcm New tab at chezmoi source dir
:tgp New tab at ~/projects
:tgr New tab at / (root)</code></pre>
<p>Prefixes :wg* and :wvg* / :whg* open OS windows or splits to the same
set of dirs, respectively.</p>
<p>Prefixes :cd* open tabs with a quick cd shortcut:</p>
<pre><code>:cdn cd ~/.config/nvim
:cdf cd ~/.config/fish
:cdh cd ~
:cdcz cd to chezmoi source
:cdp cd ~/projects</code></pre>
<p>Appending n to any :cd* abbreviation also runs nvim after changing
dir.</p>
<h2 data-number="8.5" id="45-chezmoi">4.5 Chezmoi</h2>
<pre><code>cm / cme / cmi / cmap / cmad / cmrm / cmcd /
cz / cze / czi / czap / czad / czrm / czcd
cm / cz chezmoi
cmcd / czcd chezmoi cd
cme / cze chezmoi edit
cmad / czad chezmoi add
cmap / czap chezmoi apply
cmrm / cmf / czrm / czf chezmoi forget
cmi / czi chezmoi init</code></pre>
<h2 data-number="8.6" id="46-docker">4.6 Docker</h2>
<pre><code>dcl docker context use default
dcls docker context ls
lzd ld (lazydocker)</code></pre>
<h2 data-number="8.7" id="47-systemctl">4.7 Systemctl</h2>
<pre><code>sc systemctl
ssc sudo systemctl
scu systemctl --user
st systemctl status
scs sudo systemctl start
scr sudo systemctl restart
ssct sudo systemctl start
sscs sudo systemctl stop
sscr sudo systemctl restart</code></pre>
<h2 data-number="8.8" id="48-ai-assistants">4.8 AI Assistants</h2>
<pre><code>ag antigravity
ag. antigravity .
v antigravity-ide
s wezterm ssh (WezTerm only)</code></pre>
<h2 data-number="8.9" id="49-history-expansion">4.9 History
Expansion</h2>
<p>These are implemented as keybinding helpers, but can also be
typed:</p>
<pre><code>!^ Expand to first argument of previous command
!* Expand to all arguments of previous command
typo_sub Interactive typo substitution (Ctrl+F)
bang_string !string expansion
bang_search !?string search
bang_minus_n !-n (nth-previous command)</code></pre>
<h2 data-number="8.10" id="410-miscellaneous">4.10 Miscellaneous</h2>
<pre><code>/exit exit
:q Close pane (alias for terminal close)
:Q Close tab
sudu sudo -s
kt kitty (Kitty only)
c cat
speedtest-fast fast-cli
bl bd list
bs bd sync
bC bd create --title
bsh bd show
lb lazybeads</code></pre>
<h2 data-number="8.11" id="411-shell-aliases">4.11 Shell Aliases</h2>
<p>These aliases are defined in conf.d/tricks.fish via alias (which
creates Fish functions). They are active in all interactive
sessions.</p>
<h3 data-number="8.11.1" id="navigation">Navigation</h3>
<pre><code>.. cd ..
... cd ../..
.... cd ../../..
..... cd ../../../..
...... cd ../../../../..</code></pre>
<h3 data-number="8.11.2" id="color-overrides">Color Overrides</h3>
<p>Force color output for common tools:</p>
<pre><code>grep grep --color=auto
fgrep fgrep --color=auto
egrep egrep --color=auto
dir dir --color=auto
vdir vdir --color=auto</code></pre>
<h3 data-number="8.11.3" id="safety-wrappers">Safety Wrappers</h3>
<p>Add -i (interactive confirmation) to destructive commands:</p>
<pre><code>cp cp -i
mv mv -i</code></pre>
<h3 data-number="8.11.4" id="archives-and-networking">Archives and
Networking</h3>
<pre><code>tarnow tar -acf Create compressed archive (auto-detects format)
untar tar -zxvf Extract a gzip-compressed archive
wget wget -c Resume interrupted downloads by default
tb nc termbin.com 9999 Pipe content to termbin.com for quick sharing</code></pre>
<h3 data-number="8.11.5" id="system-logs">System Logs</h3>
<pre><code>jctl journalctl -p 3 -xb Show priority-3 (error) journal entries
from the current boot</code></pre>
<hr />
</body>
</html>
File diff suppressed because it is too large Load Diff
-886
View File
@@ -1,886 +0,0 @@
<!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>FISH-CONFIG</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>
<span class="navlink">
</span>
</div>
<div class="sitenav">
<span class="navlink">
<span class="navlink-label">Next:</span> <a href="1-name.html" accesskey="n" rel="next">NAME</a>
</span>
<span class="navlink">
</span>
</div>
</nav>
<header id="title-block-header">
<h1 class="title">FISH-CONFIG</h1>
<p class="author">Rootiest</p>
<p class="date">June 2026</p>
</header>
<nav id="TOC" role="doc-toc">
<ul>
<li><a href="1-name.html" id="toc-name">NAME</a></li>
<li><a href="2-synopsis.html" id="toc-synopsis">SYNOPSIS</a></li>
<li><a href="3-description.html"
id="toc-description">DESCRIPTION</a></li>
<li><a href="4-table-of-contents.html" id="toc-table-of-contents">TABLE
OF CONTENTS</a></li>
<li><a href="5-1-configuration-variables.html"
id="toc-1-configuration-variables">1. CONFIGURATION VARIABLES</a>
<ul>
<li><a
href="5-1-configuration-variables.html#environment-directories-xdg"
id="toc-environment-directories-xdg">Environment Directories
(XDG)</a></li>
<li><a href="5-1-configuration-variables.html#tool-homes-xdg-compliant"
id="toc-tool-homes-xdg-compliant">Tool Homes (XDG-compliant)</a></li>
<li><a href="5-1-configuration-variables.html#editor-and-pager"
id="toc-editor-and-pager">Editor and Pager</a></li>
<li><a href="5-1-configuration-variables.html#scrollback-history"
id="toc-scrollback-history">Scrollback History</a></li>
<li><a href="5-1-configuration-variables.html#other"
id="toc-other">Other</a></li>
<li><a href="5-1-configuration-variables.html#pager-hierarchy"
id="toc-pager-hierarchy">Pager Hierarchy</a></li>
<li><a href="5-1-configuration-variables.html#integrations"
id="toc-integrations">Integrations</a>
<ul>
<li><a href="5-1-configuration-variables.html#zoxide"
id="toc-zoxide">Zoxide</a></li>
<li><a href="5-1-configuration-variables.html#direnv"
id="toc-direnv">DirEnv</a></li>
<li><a href="5-1-configuration-variables.html#auto-python-venv"
id="toc-auto-python-venv">Auto Python Venv</a></li>
<li><a href="5-1-configuration-variables.html#wakatime"
id="toc-wakatime">WakaTime</a></li>
<li><a href="5-1-configuration-variables.html#tailscale"
id="toc-tailscale">Tailscale</a></li>
<li><a href="5-1-configuration-variables.html#done-notifications"
id="toc-done-notifications">Done Notifications</a></li>
<li><a href="5-1-configuration-variables.html#scrollback-history-1"
id="toc-scrollback-history-1">Scrollback History</a></li>
</ul></li>
</ul></li>
<li><a href="6-2-path-setup.html" id="toc-2-path-setup">2. PATH
SETUP</a></li>
<li><a href="7-3-key-bindings.html" id="toc-3-key-bindings">3. KEY
BINDINGS</a>
<ul>
<li><a
href="7-3-key-bindings.html#fzf-bindings-bundled-from-patrickf1fzffish"
id="toc-fzf-bindings-bundled-from-patrickf1fzffish">FZF Bindings
(bundled from PatrickF1/fzf.fish)</a></li>
</ul></li>
<li><a href="8-4-abbreviations.html" id="toc-4-abbreviations">4.
ABBREVIATIONS</a>
<ul>
<li><a href="8-4-abbreviations.html#41-editors" id="toc-41-editors">4.1
Editors</a></li>
<li><a href="8-4-abbreviations.html#42-navigation-and-listing"
id="toc-42-navigation-and-listing">4.2 Navigation and Listing</a></li>
<li><a href="8-4-abbreviations.html#43-git" id="toc-43-git">4.3
Git</a></li>
<li><a href="8-4-abbreviations.html#44-terminal-windows-tabs-and-panes"
id="toc-44-terminal-windows-tabs-and-panes">4.4 Terminal Windows, Tabs,
and Panes</a></li>
<li><a href="8-4-abbreviations.html#45-chezmoi" id="toc-45-chezmoi">4.5
Chezmoi</a></li>
<li><a href="8-4-abbreviations.html#46-docker" id="toc-46-docker">4.6
Docker</a></li>
<li><a href="8-4-abbreviations.html#47-systemctl"
id="toc-47-systemctl">4.7 Systemctl</a></li>
<li><a href="8-4-abbreviations.html#48-ai-assistants"
id="toc-48-ai-assistants">4.8 AI Assistants</a></li>
<li><a href="8-4-abbreviations.html#49-history-expansion"
id="toc-49-history-expansion">4.9 History Expansion</a></li>
<li><a href="8-4-abbreviations.html#410-miscellaneous"
id="toc-410-miscellaneous">4.10 Miscellaneous</a></li>
<li><a href="8-4-abbreviations.html#411-shell-aliases"
id="toc-411-shell-aliases">4.11 Shell Aliases</a>
<ul>
<li><a href="8-4-abbreviations.html#navigation"
id="toc-navigation">Navigation</a></li>
<li><a href="8-4-abbreviations.html#color-overrides"
id="toc-color-overrides">Color Overrides</a></li>
<li><a href="8-4-abbreviations.html#safety-wrappers"
id="toc-safety-wrappers">Safety Wrappers</a></li>
<li><a href="8-4-abbreviations.html#archives-and-networking"
id="toc-archives-and-networking">Archives and Networking</a></li>
<li><a href="8-4-abbreviations.html#system-logs"
id="toc-system-logs">System Logs</a></li>
</ul></li>
</ul></li>
<li><a href="9-5-functions-reference.html"
id="toc-5-functions-reference">5. FUNCTIONS REFERENCE</a>
<ul>
<li><a href="9-5-functions-reference.html#51-file-and-directory"
id="toc-51-file-and-directory">5.1 File and Directory</a>
<ul>
<li><a href="9-5-functions-reference.html#cat" id="toc-cat">cat</a></li>
<li><a href="9-5-functions-reference.html#copy"
id="toc-copy">copy</a></li>
<li><a href="9-5-functions-reference.html#du" id="toc-du">du</a></li>
<li><a href="9-5-functions-reference.html#dusize"
id="toc-dusize">dusize</a></li>
<li><a href="9-5-functions-reference.html#ld" id="toc-ld">lD</a></li>
<li><a href="9-5-functions-reference.html#ls" id="toc-ls">ls</a></li>
<li><a href="9-5-functions-reference.html#lsr" id="toc-lsr">lsr</a></li>
<li><a href="9-5-functions-reference.html#lss" id="toc-lss">lss</a></li>
<li><a href="9-5-functions-reference.html#lstree"
id="toc-lstree">lstree</a></li>
<li><a href="9-5-functions-reference.html#lt" id="toc-lt">lt</a></li>
<li><a href="9-5-functions-reference.html#ltr" id="toc-ltr">ltr</a></li>
<li><a href="9-5-functions-reference.html#lx" id="toc-lx">lx</a></li>
<li><a href="9-5-functions-reference.html#mkdir"
id="toc-mkdir">mkdir</a></li>
<li><a href="9-5-functions-reference.html#mkcd"
id="toc-mkcd">mkcd</a></li>
<li><a href="9-5-functions-reference.html#poke"
id="toc-poke">poke</a></li>
<li><a href="9-5-functions-reference.html#rm" id="toc-rm">rm</a></li>
<li><a href="9-5-functions-reference.html#scrub"
id="toc-scrub">scrub</a></li>
</ul></li>
<li><a href="9-5-functions-reference.html#52-navigation"
id="toc-52-navigation">5.2 Navigation</a>
<ul>
<li><a href="9-5-functions-reference.html#cdi" id="toc-cdi">cdi</a></li>
<li><a href="9-5-functions-reference.html#clone"
id="toc-clone">clone</a></li>
<li><a href="9-5-functions-reference.html#clonet"
id="toc-clonet">clonet</a></li>
</ul></li>
<li><a href="9-5-functions-reference.html#53-editors-and-viewers"
id="toc-53-editors-and-viewers">5.3 Editors and Viewers</a>
<ul>
<li><a href="9-5-functions-reference.html#edit"
id="toc-edit">edit</a></li>
<li><a href="9-5-functions-reference.html#fc" id="toc-fc">fc</a></li>
<li><a href="9-5-functions-reference.html#less"
id="toc-less">less</a></li>
<li><a href="9-5-functions-reference.html#rawfish"
id="toc-rawfish">rawfish</a></li>
<li><a href="9-5-functions-reference.html#view"
id="toc-view">view</a></li>
</ul></li>
<li><a href="9-5-functions-reference.html#54-git-and-version-control"
id="toc-54-git-and-version-control">5.4 Git and Version Control</a>
<ul>
<li><a href="9-5-functions-reference.html#branch"
id="toc-branch">branch</a></li>
<li><a href="9-5-functions-reference.html#gi" id="toc-gi">gi</a></li>
<li><a href="9-5-functions-reference.html#git-clean"
id="toc-git-clean">git-clean</a></li>
<li><a href="9-5-functions-reference.html#gitup"
id="toc-gitup">gitup</a></li>
<li><a href="9-5-functions-reference.html#gitui"
id="toc-gitui">gitui</a></li>
<li><a href="9-5-functions-reference.html#hist"
id="toc-hist">hist</a></li>
</ul></li>
<li><a href="9-5-functions-reference.html#55-package-management"
id="toc-55-package-management">5.5 Package Management</a>
<ul>
<li><a href="9-5-functions-reference.html#pkg" id="toc-pkg">pkg</a></li>
<li><a href="9-5-functions-reference.html#search"
id="toc-search">search</a></li>
<li><a href="9-5-functions-reference.html#upgrade"
id="toc-upgrade">upgrade</a></li>
<li><a href="9-5-functions-reference.html#cleanup"
id="toc-cleanup">cleanup</a></li>
<li><a href="9-5-functions-reference.html#parur"
id="toc-parur">parur</a></li>
</ul></li>
<li><a href="9-5-functions-reference.html#56-dependency-management"
id="toc-56-dependency-management">5.6 Dependency Management</a>
<ul>
<li><a href="9-5-functions-reference.html#fish-deps"
id="toc-fish-deps">fish-deps</a></li>
<li><a href="9-5-functions-reference.html#check_fish_deps"
id="toc-check_fish_deps">check_fish_deps</a></li>
</ul></li>
<li><a href="9-5-functions-reference.html#57-system-and-monitoring"
id="toc-57-system-and-monitoring">5.7 System and Monitoring</a>
<ul>
<li><a href="9-5-functions-reference.html#top" id="toc-top">top</a></li>
<li><a href="9-5-functions-reference.html#swapstat"
id="toc-swapstat">swapstat</a></li>
<li><a href="9-5-functions-reference.html#sbver"
id="toc-sbver">sbver</a></li>
<li><a href="9-5-functions-reference.html#ports"
id="toc-ports">ports</a></li>
<li><a href="9-5-functions-reference.html#screensleep"
id="toc-screensleep">screensleep</a></li>
<li><a href="9-5-functions-reference.html#lock"
id="toc-lock">lock</a></li>
<li><a href="9-5-functions-reference.html#sudo-toggle"
id="toc-sudo-toggle">sudo-toggle</a></li>
<li><a href="9-5-functions-reference.html#limine-edit"
id="toc-limine-edit">limine-edit</a></li>
</ul></li>
<li><a href="9-5-functions-reference.html#58-terminal-management"
id="toc-58-terminal-management">5.8 Terminal Management</a>
<ul>
<li><a href="9-5-functions-reference.html#tab" id="toc-tab">tab</a></li>
<li><a href="9-5-functions-reference.html#split"
id="toc-split">split</a></li>
<li><a href="9-5-functions-reference.html#spwin"
id="toc-spwin">spwin</a></li>
<li><a href="9-5-functions-reference.html#detach"
id="toc-detach">detach</a></li>
<li><a href="9-5-functions-reference.html#bkg" id="toc-bkg">bkg</a></li>
<li><a href="9-5-functions-reference.html#ssh" id="toc-ssh">ssh</a></li>
</ul></li>
<li><a href="9-5-functions-reference.html#59-clipboard"
id="toc-59-clipboard">5.9 Clipboard</a>
<ul>
<li><a href="9-5-functions-reference.html#y" id="toc-y">y</a></li>
<li><a href="9-5-functions-reference.html#p" id="toc-p">p</a></li>
<li><a href="9-5-functions-reference.html#paste"
id="toc-paste">paste</a></li>
</ul></li>
<li><a href="9-5-functions-reference.html#510-network"
id="toc-510-network">5.10 Network</a>
<ul>
<li><a href="9-5-functions-reference.html#gip" id="toc-gip">gip</a></li>
<li><a href="9-5-functions-reference.html#gip4"
id="toc-gip4">gip4</a></li>
<li><a href="9-5-functions-reference.html#gip6"
id="toc-gip6">gip6</a></li>
<li><a href="9-5-functions-reference.html#ping"
id="toc-ping">ping</a></li>
<li><a href="9-5-functions-reference.html#qr" id="toc-qr">qr</a></li>
</ul></li>
<li><a href="9-5-functions-reference.html#511-pager-and-logging"
id="toc-511-pager-and-logging">5.11 Pager and Logging</a>
<ul>
<li><a href="9-5-functions-reference.html#logs"
id="toc-logs">logs</a></li>
<li><a href="9-5-functions-reference.html#smart_exit"
id="toc-smart_exit">smart_exit</a></li>
</ul></li>
<li><a href="9-5-functions-reference.html#512-ai-and-developer-tools"
id="toc-512-ai-and-developer-tools">5.12 AI and Developer Tools</a>
<ul>
<li><a href="9-5-functions-reference.html#antigravity"
id="toc-antigravity">antigravity</a></li>
<li><a href="9-5-functions-reference.html#antigravity-ide"
id="toc-antigravity-ide">antigravity-ide</a></li>
<li><a href="9-5-functions-reference.html#antigravity-resume"
id="toc-antigravity-resume">antigravity-resume</a></li>
<li><a href="9-5-functions-reference.html#claude-resume"
id="toc-claude-resume">claude-resume</a></li>
<li><a href="9-5-functions-reference.html#claude-docs"
id="toc-claude-docs">claude-docs</a></li>
<li><a href="9-5-functions-reference.html#claude-pr"
id="toc-claude-pr">claude-pr</a></li>
<li><a href="9-5-functions-reference.html#code-resume"
id="toc-code-resume">code-resume</a></li>
<li><a href="9-5-functions-reference.html#superpowers"
id="toc-superpowers">superpowers</a></li>
</ul></li>
<li><a href="9-5-functions-reference.html#513-media-and-utilities"
id="toc-513-media-and-utilities">5.13 Media and Utilities</a>
<ul>
<li><a href="9-5-functions-reference.html#dng2avif"
id="toc-dng2avif">dng2avif</a></li>
<li><a href="9-5-functions-reference.html#steam-dl"
id="toc-steam-dl">steam-dl</a></li>
<li><a href="9-5-functions-reference.html#spark"
id="toc-spark">spark</a></li>
</ul></li>
<li><a href="9-5-functions-reference.html#514-miscellaneous"
id="toc-514-miscellaneous">5.14 Miscellaneous</a>
<ul>
<li><a href="9-5-functions-reference.html#config-help"
id="toc-config-help">config-help</a></li>
<li><a href="9-5-functions-reference.html#config-update"
id="toc-config-update">config-update</a></li>
<li><a href="9-5-functions-reference.html#bash"
id="toc-bash">bash</a></li>
<li><a href="9-5-functions-reference.html#bd-pull"
id="toc-bd-pull">bd-pull</a></li>
<li><a href="9-5-functions-reference.html#cheat"
id="toc-cheat">cheat</a></li>
<li><a href="9-5-functions-reference.html#cffetch--ffetch"
id="toc-cffetch--ffetch">cffetch / ffetch</a></li>
<li><a href="9-5-functions-reference.html#dockup"
id="toc-dockup">dockup</a></li>
<li><a href="9-5-functions-reference.html#joplin"
id="toc-joplin">joplin</a></li>
<li><a href="9-5-functions-reference.html#ld-1"
id="toc-ld-1">ld</a></li>
<li><a href="9-5-functions-reference.html#replay"
id="toc-replay">replay</a></li>
<li><a href="9-5-functions-reference.html#tmux-clean"
id="toc-tmux-clean">tmux-clean</a></li>
<li><a href="9-5-functions-reference.html#wake-lock"
id="toc-wake-lock">wake-lock</a></li>
<li><a href="9-5-functions-reference.html#zellij"
id="toc-zellij">zellij</a></li>
</ul></li>
</ul></li>
<li><a href="10-6-dependency-catalog.html"
id="toc-6-dependency-catalog">6. DEPENDENCY CATALOG</a>
<ul>
<li><a href="10-6-dependency-catalog.html#required"
id="toc-required">Required</a></li>
<li><a href="10-6-dependency-catalog.html#integrations-1"
id="toc-integrations-1">Integrations</a></li>
<li><a href="10-6-dependency-catalog.html#recommended"
id="toc-recommended">Recommended</a></li>
<li><a href="10-6-dependency-catalog.html#install-methods"
id="toc-install-methods">Install Methods</a></li>
</ul></li>
<li><a href="11-7-customization.html" id="toc-7-customization">7.
CUSTOMIZATION</a>
<ul>
<li><a href="11-7-customization.html#machine-local-configuration"
id="toc-machine-local-configuration">Machine-local
Configuration</a></li>
<li><a href="11-7-customization.html#secrets-and-api-keys"
id="toc-secrets-and-api-keys">Secrets and API Keys</a></li>
<li><a href="11-7-customization.html#overriding-configuration-variables"
id="toc-overriding-configuration-variables">Overriding Configuration
Variables</a></li>
<li><a href="11-7-customization.html#fish-universal-variables"
id="toc-fish-universal-variables">Fish Universal Variables</a></li>
<li><a
href="11-7-customization.html#opinionated-components-minimal-mode"
id="toc-opinionated-components-minimal-mode">Opinionated Components
(Minimal Mode)</a></li>
<li><a href="11-7-customization.html#prompt-and-theme"
id="toc-prompt-and-theme">Prompt and Theme</a>
<ul>
<li><a href="11-7-customization.html#starship"
id="toc-starship">Starship</a></li>
<li><a href="11-7-customization.html#fzf" id="toc-fzf">FZF</a></li>
<li><a
href="11-7-customization.html#catppuccin-mocha-syntax-highlighting"
id="toc-catppuccin-mocha-syntax-highlighting">Catppuccin Mocha Syntax
Highlighting</a></li>
</ul></li>
</ul></li>
<li><a href="12-8-fisher-plugins.html" id="toc-8-fisher-plugins">8.
FISHER PLUGINS</a>
<ul>
<li><a href="12-8-fisher-plugins.html#fisher-managed-plugins"
id="toc-fisher-managed-plugins">Fisher-Managed Plugins</a></li>
<li><a href="12-8-fisher-plugins.html#sponge-history-filtering"
id="toc-sponge-history-filtering">Sponge History Filtering</a></li>
<li><a href="12-8-fisher-plugins.html#bundled-plugin-functionality"
id="toc-bundled-plugin-functionality">Bundled Plugin
Functionality</a></li>
<li><a href="12-8-fisher-plugins.html#fish_plugins-manifest"
id="toc-fish_plugins-manifest">fish_plugins Manifest</a></li>
</ul></li>
<li><a href="13-9-installation.html" id="toc-9-installation">9.
INSTALLATION</a>
<ul>
<li><a href="13-9-installation.html#return-sentinel"
id="toc-return-sentinel">Return Sentinel</a></li>
<li><a href="13-9-installation.html#updating"
id="toc-updating">Updating</a></li>
</ul></li>
<li><a href="14-10-personalization.html" id="toc-10-personalization">10.
PERSONALIZATION</a>
<ul>
<li><a href="14-10-personalization.html#secretsfish"
id="toc-secretsfish">secrets.fish</a></li>
<li><a href="14-10-personalization.html#localfish"
id="toc-localfish">local.fish</a></li>
</ul></li>
<li><a href="15-11-viewing-this-manual.html"
id="toc-11-viewing-this-manual">11. VIEWING THIS MANUAL</a>
<ul>
<li><a href="15-11-viewing-this-manual.html#with-ov-recommended"
id="toc-with-ov-recommended">With ov (recommended)</a></li>
<li><a href="15-11-viewing-this-manual.html#with-bat"
id="toc-with-bat">With bat</a></li>
<li><a href="15-11-viewing-this-manual.html#as-a-man-page"
id="toc-as-a-man-page">As a man page</a></li>
<li><a href="15-11-viewing-this-manual.html#in-the-browser-html"
id="toc-in-the-browser-html">In the browser (HTML)</a></li>
<li><a href="15-11-viewing-this-manual.html#as-a-wiki"
id="toc-as-a-wiki">As a wiki</a></li>
<li><a href="15-11-viewing-this-manual.html#jumping-to-a-section"
id="toc-jumping-to-a-section">Jumping to a section</a></li>
</ul></li>
</ul>
</nav>
</body>
</html>
File diff suppressed because one or more lines are too long
+10
View File
@@ -0,0 +1,10 @@
---
title: Name
manTitle: NAME
man: true
site: false
sidebar:
order: 1
---
fish-config - personal fish shell configuration for Fish 4.x with modern CLI tool integration
+21
View File
@@ -0,0 +1,21 @@
---
title: Synopsis
manTitle: SYNOPSIS
man: true
site: false
sidebar:
order: 2
---
help config [SECTION]
Open this manual in the best available pager. Optionally jump to a section
by keyword:
help config keybindings
help config pkg
help config abbreviations
help config logs
The `help config` syntax integrates with fish's built-in help command.
The underlying `config-help` function is also available directly.
+12
View File
@@ -0,0 +1,12 @@
---
title: Table Of Contents
manTitle: TABLE OF CONTENTS
man: true
site: false
sidebar:
order: 4
---
<!-- GENERATED: toc -->
---
+156
View File
@@ -0,0 +1,156 @@
---
title: Configuration Variables
manTitle: 1. CONFIGURATION VARIABLES
sidebar:
order: 5
helpKeywords:
- variables
- config
---
These variables are exported from config.fish on every interactive session.
Override them in local.fish (see Section 10, Personalization).
## Environment Directories (XDG)
| Variable | Value |
|---|---|
| `XDG_CONFIG_HOME` | `~/.config` |
| `XDG_CACHE_HOME` | `~/.cache` |
| `XDG_DATA_HOME` | `~/.local/share` |
| `XDG_STATE_HOME` | `~/.local/state` |
Tools that respect XDG are directed to these paths rather than polluting `$HOME`.
## Tool Homes (XDG-compliant)
| Variable | Value |
|---|---|
| `CARGO_HOME` | `$XDG_DATA_HOME/cargo` |
| `RUSTUP_HOME` | `$XDG_DATA_HOME/rustup` |
| `GOPATH` | `$XDG_DATA_HOME/go` |
| `BUN_INSTALL` | `$XDG_DATA_HOME/bun` |
| `NPM_CONFIG_PREFIX` | `$XDG_DATA_HOME/npm-global` |
| `GNUPGHOME` | `$XDG_CONFIG_HOME/gnupg` |
| `WAKATIME_HOME` | `$XDG_CONFIG_HOME/wakatime` |
## Editor and Pager
| Variable | Value / Notes |
|---|---|
| `EDITOR` | `nvim` (falls back to `vi` if `nvim` is absent) |
| `VISUAL` | unset by default; set a GUI editor via `local.fish` (the `edit` function falls back to a GUI chain when `VISUAL` is empty) |
| `SUDO_EDITOR` | same as `EDITOR` |
| `PAGER` | `ov` (falls back to `less`) |
## Scrollback History
| Variable | Value / Notes |
|---|---|
| `__fish_scrollback_history_dir` | (unset → `~/.terminal_history`) |
| `__fish_scrollback_history_max_files` | (unset → `100`) |
| `SCROLLBACK_HISTORY_DIR` | `~/.terminal_history` (exported mirror) |
| `SCROLLBACK_HISTORY_MAX_FILES` | `100` (exported mirror) |
The `__fish_scrollback_history_*` universal variables are the fish-style source
of truth — set them via `config-settings` → Paths, or `set -U` directly.
`config.fish` exports the `SCROLLBACK_HISTORY_*` mirrors from them, because the
POSIX wrapper scripts (`paru`/`yay`/`tmux`/`zellij` logging and `_prune_terminal_logs`)
read the exported names from the environment. When the `__fish_` vars are unset,
the documented defaults are exported. `config.fish` deliberately does not create
a global source var, which would shadow the universal and stop live edits from
taking effect.
Scrollback logs accumulate in `SCROLLBACK_HISTORY_DIR` as timestamped files.
When the count exceeds `SCROLLBACK_HISTORY_MAX_FILES` the oldest are pruned
automatically on exit. Use `logs` to browse them interactively.
## Other
| Variable | Value | Notes |
|---|---|---|
| `GPG_TTY` | `$(tty)` | ensures GPG passphrase prompts work |
| `CLAUDE_CODE_NO_FLICKER` | `1` | suppress terminal flicker in Claude Code |
| `CDPATH` | `. ~/projects ~` | |
Opinionated defaults (`CDPATH`, `PAGER`/`MANPAGER`, Vi mode, command shadows,
terminal integrations) can be switched off per category with universal
variables — see Section 7, "Opinionated Components (Minimal Mode)".
## Pager Hierarchy
`$PAGER` is set to `ov` when available, falling back to `less`. The `less` wrapper
function extends this into a full chain so anything that calls `less` directly
also benefits:
`$PAGER``ov``less``more``cat`
When `bat` is installed, man pages are rendered with syntax highlighting:
| Variable | Value |
|---|---|
| `MANROFFOPT` | `-c` |
| `MANPAGER` | `sh -c 'col -bx \| bat -l man -p'` |
## Integrations
### Zoxide
`cd`, `z`, and `cdi`/`zi` are all mapped to `zoxide`-backed navigation. Tab completions
for `cd` and `z` blend standard directory entries (CWD and `CDPATH`) with frecency
results so both familiar and frequently-visited paths appear in one list.
### DirEnv
Automatically loads `.envrc` files on directory change. Takes priority over
the auto-venv logic — if a directory is managed by `direnv`, the auto-venv
activation is skipped entirely.
### Auto Python Venv
When entering a directory that contains a `.venv/`, the virtualenv is activated
automatically and deactivated when you leave the project tree.
### WakaTime
Every shell command is reported to WakaTime for time-tracking. Set
`FISH_WAKATIME_DISABLED=1` to disable without removing the plugin.
### Tailscale
Full tab completion for the `tailscale` CLI is provided via
`completions/tailscale.fish`, autoloaded on the first `tailscale<TAB>`.
### Done Notifications
Desktop notifications fire when a command takes longer than 10 seconds and
the terminal window is not focused. Configured via fish universal variables:
| Variable | Value |
|---|---|
| `__done_min_cmd_duration` | `10000` ms |
| `__done_notification_urgency_level` | `low` |
### Scrollback History
When running inside Kitty, closing a shell session via `exit` saves a timestamped
scrollback snapshot to `SCROLLBACK_HISTORY_DIR`. Files are named:
`scrollback_YYYY-MM-DD_HH-MM-SS.log`
The `paru` and `yay` wrappers (auto-generated in `~/.local/bin/`) run the command
inside a PTY via `script(1)` so download progress bars are preserved on screen,
then render the captured terminal animation down to a clean static log via
`scripts/clean_progress_log.py` (a small terminal-screen emulator that replays
cursor movements, collapses repainted progress frames to their final state,
and preserves ANSI color). If `python3` is unavailable the wrapper falls back to
dropping only the `script(1)` header/footer. Output is saved to:
- `paru_YYYY-MM-DD_HH-MM-SS.log`
- `yay_YYYY-MM-DD_HH-MM-SS.log`
Before pruning, `_scrollback_prune_junk` silently removes empty files, files
with only a single meaningful line (e.g. bare `[exited]` captures), and Kitty
tab-rename prompt captures. Use `exit --no-log` (or `exit -n`) to skip capture.
---
+31
View File
@@ -0,0 +1,31 @@
---
title: PATH Setup
manTitle: 2. PATH SETUP
sidebar:
order: 6
helpKeywords:
- path
---
Directories prepended to PATH in this order (first wins):
| Directory | Purpose |
|---|---|
| `~/.local/bin` | Standard user-local executables |
| `~/Applications` | User-installed standalone apps |
| `~/scripts` | Personal shell scripts |
| `~/bin` | Cargo binaries (appended — lowest priority) |
| `$BUN_INSTALL/bin` | Bun runtime and global packages |
| `$NPM_CONFIG_PREFIX/bin` | Global npm packages |
| `~/.lmstudio/bin` | LM Studio CLI |
| `~/.resend/bin` | Resend CLI |
| `~/.fzf/bin` | `fzf` binary (git-installed) |
Cargo binaries are intentionally appended (lowest priority) to avoid
shadowing system-installed Rust tools.
NOTE: While these directories are merged with your system's existing `$PATH` values, any executables in the prepended directories above will override (shadow) system binaries of the same name.
TIP: This standard PATH setup is gated behind the opinionated component overrides toggle. If you prefer to manage your PATH completely manually, you can disable it by setting `__fish_config_op_overrides` to `0` (or toggle it off in the `config-settings` menu).
---
@@ -1,7 +1,13 @@
# 3. KEY BINDINGS ---
title: Key Bindings
**Sections:** [Index](index.md) | [1. Configuration Variables](1-configuration-variables.md) | [2. Path Setup](2-path-setup.md) | **3. Key Bindings** | [4. Abbreviations](4-abbreviations.md) | [5. Functions Reference](5-functions-reference.md) | [6. Dependency Catalog](6-dependency-catalog.md) | [7. Customization](7-customization.md) | [8. Fisher Plugins](8-fisher-plugins.md) | [9. Installation](9-installation.md) | [10. Personalization](10-personalization.md) | [11. Viewing This Manual](11-viewing-this-manual.md) manTitle: 3. KEY BINDINGS
sidebar:
order: 7
helpKeywords:
- keybindings
- bindings
- key-bindings
- keys
--- ---
The shell uses Vi key bindings (fish_vi_key_bindings). All custom bindings The shell uses Vi key bindings (fish_vi_key_bindings). All custom bindings
@@ -36,9 +42,15 @@ are active in Insert, Normal, and Visual modes unless noted.
pressing Enter a second time for certain fast-path pressing Enter a second time for certain fast-path
commands (speedtest-fast, etc.). commands (speedtest-fast, etc.).
@@ FZF inline picker. Type @@ anywhere on the command @@ FZF inline picker. Type @ twice anywhere on the
line to open an fzf picker and insert a selection command line to open an fzf picker and replace the
at the cursor position. @@ with the selection. The @@ must be typed as its
own token: "cat @@" triggers it, but "cat@@" does
not.
Ctrl+Right Accept autosuggestion one word/directory segment
at a time. (Restores Fish 3.x behavior by binding
to nextd-or-forward-word).
## FZF Bindings (bundled from PatrickF1/fzf.fish) ## FZF Bindings (bundled from PatrickF1/fzf.fish)
@@ -0,0 +1,6 @@
---
title: Editors
manTitle: 4.1 Editors
---
<!-- GENERATED: Editors -->
@@ -0,0 +1,6 @@
---
title: Navigation and Listing
manTitle: 4.2 Navigation and Listing
---
<!-- GENERATED: Navigation and Listing -->
+6
View File
@@ -0,0 +1,6 @@
---
title: Git
manTitle: 4.3 Git
---
<!-- GENERATED: Git -->
@@ -0,0 +1,10 @@
---
title: Terminal Windows, Tabs, and Panes
manTitle: 4.4 Terminal Windows, Tabs, and Panes
---
These abbreviations control the terminal emulator. Each has a Kitty
variant and a WezTerm variant; the correct one is inserted based on
`$TERM` or `$TERM_PROGRAM`.
<!-- GENERATED: Terminal Windows, Tabs, and Panes -->
@@ -0,0 +1,6 @@
---
title: Chezmoi
manTitle: 4.5 Chezmoi
---
<!-- GENERATED: Chezmoi -->
@@ -0,0 +1,6 @@
---
title: Docker
manTitle: 4.6 Docker
---
<!-- GENERATED: Docker -->
@@ -0,0 +1,6 @@
---
title: Systemctl
manTitle: 4.7 Systemctl
---
<!-- GENERATED: Systemctl -->
@@ -0,0 +1,6 @@
---
title: AI Assistants
manTitle: 4.8 AI Assistants
---
<!-- GENERATED: AI Assistants -->
@@ -0,0 +1,10 @@
---
title: History Expansion
manTitle: 4.9 History Expansion
---
Bash-style history expansions trigger on Space or Enter. Some are implemented
as abbreviations (e.g. `!*`), while others (`!!`, `!$`, `!.`) are implemented
as keybindings, but they all serve the same purpose.
<!-- GENERATED: History Expansion -->
@@ -0,0 +1,6 @@
---
title: Miscellaneous
manTitle: 4.10 Miscellaneous
---
<!-- GENERATED: Miscellaneous -->
@@ -0,0 +1,9 @@
---
title: Shell Aliases
manTitle: 4.11 Shell Aliases
---
These aliases are defined in conf.d/tricks.fish via alias (which creates Fish
functions). They are active in all interactive sessions.
<!-- GENERATED: Shell Aliases -->
+27
View File
@@ -0,0 +1,27 @@
---
title: Abbreviations
manTitle: 4. ABBREVIATIONS
sidebar:
order: 8
helpKeywords:
- abbreviations
- abbr
- abbrs
---
Abbreviations expand when you press Space or Enter. They are terminal-aware:
some expand differently in Kitty vs WezTerm vs other terminals.
<CardGrid>
<LinkCard title="Editors" href="/04-abbreviations/01-editors/" />
<LinkCard title="Navigation and Listing" href="/04-abbreviations/02-navigation-and-listing/" />
<LinkCard title="Git" href="/04-abbreviations/03-git/" />
<LinkCard title="Terminal Windows, Tabs, and Panes" href="/04-abbreviations/04-terminal-windows-tabs-and-panes/" />
<LinkCard title="Chezmoi" href="/04-abbreviations/05-chezmoi/" />
<LinkCard title="Docker" href="/04-abbreviations/06-docker/" />
<LinkCard title="Systemctl" href="/04-abbreviations/07-systemctl/" />
<LinkCard title="AI Assistants" href="/04-abbreviations/08-ai-assistants/" />
<LinkCard title="History Expansion" href="/04-abbreviations/09-history-expansion/" />
<LinkCard title="Miscellaneous" href="/04-abbreviations/10-miscellaneous/" />
<LinkCard title="Shell Aliases" href="/04-abbreviations/11-shell-aliases/" />
</CardGrid>
@@ -0,0 +1,10 @@
---
title: File and Directory
manTitle: 5.1 File and Directory
sidebar:
order: 1
helpKeywords:
- files
---
+10
View File
@@ -0,0 +1,10 @@
---
title: Navigation
manTitle: 5.2 Navigation
sidebar:
order: 2
helpKeywords:
- nav-fns
---
@@ -0,0 +1,10 @@
---
title: Editors and Viewers
manTitle: 5.3 Editors and Viewers
sidebar:
order: 3
helpKeywords:
- editors
---
@@ -0,0 +1,10 @@
---
title: Git and Version Control
manTitle: 5.4 Git and Version Control
sidebar:
order: 4
helpKeywords:
- git
---
@@ -0,0 +1,11 @@
---
title: Package Management
manTitle: 5.5 Package Management
sidebar:
order: 5
helpKeywords:
- package-manager
- packages
---
@@ -0,0 +1,10 @@
---
title: Dependency Management
manTitle: 5.6 Dependency Management
sidebar:
order: 6
helpKeywords:
- deps
---

Some files were not shown because too many files have changed in this diff Show More