Compare commits

..
314 Commits
Author SHA1 Message Date
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
301 changed files with 29345 additions and 15825 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\"]
}"
+87
View File
@@ -0,0 +1,87 @@
name: Generate documentation
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"
workflow_dispatch:
jobs:
build-docs:
runs-on: racknerd-mini
steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.GITEA_TOKEN }}
- name: Install dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y software-properties-common
sudo add-apt-repository -y ppa:fish-shell/release-4
sudo apt-get update -qq
sudo apt-get install -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: Build documentation site
run: |
python3 docs/build-manual.py --site
cd docs/site
npm ci
npx astro build
- name: Deploy to Cloudflare Pages
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
run: |
cd docs/site
npx --yes wrangler pages deploy dist/ \
--project-name=fish-config-docs \
--branch=main \
--commit-dirty=true
- name: Commit generated docs
run: |
git config user.name "Gitea Actions"
git config user.email "actions@gitea"
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
+15
View File
@@ -293,3 +293,18 @@ pyrightconfig.json
# 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
+111 -47
View File
@@ -5,6 +5,8 @@ built around a Catppuccin Mocha aesthetic with a curated set of modern
CLI tool integrations, smart shell functions, and a heavily customized
abbreviation system for keyboard-driven workflows.
📖 **[Documentation site](https://fish.rootiest.fyi/)**
## Table of Contents
- [Overview](#overview)
@@ -28,26 +30,28 @@ This config layers on top of the CachyOS base Fish configuration and adds:
- **Smart CLI wrappers** that prefer modern tools (`eza`, `bat`, `btop`, `dust`, `prettyping`) with graceful fallbacks
- **Auto Python venv** activation on directory change (direnv-aware)
- **Kitty terminal** deep integration for splits, tabs, and SSH
- **Automatic session logging** — terminal scrollback, multiplexer panes (tmux/zellij), and AUR-helper output are captured to `~/.terminal_history` (see the caution below and [Session Logging](#session-logging))
- **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
- **WakaTime** shell activity tracking
- **Opt-out toggles** for every opinionated component — see [Minimal Mode](#minimal-mode)
> [!CAUTION]
> **This configuration logs your terminal sessions to disk by default.**
> Out of the box 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.
> **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 all logging off, set the C5 category variable:
> To turn logging on, set the C5 category variable:
>
> ```fish
> set -U __fish_config_op_logging off
> set -U __fish_config_op_logging on
> ```
>
> Or run **`config-toggle`** for an interactive menu to flip logging (and any
> 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)
@@ -58,50 +62,91 @@ This config layers on top of the CachyOS base Fish configuration and adds:
## Session Logging
This config captures terminal output to `~/.terminal_history` (override with
This config can capture terminal output to `~/.terminal_history` (override with
`$SCROLLBACK_HISTORY_DIR`) so you can search back through past sessions. It is
**on by default**. Five sources feed it:
**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 shell exit (`dump-screen`) | `zellij_<session>-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.
Disable all of it with a single universal variable:
All of it is controlled by a single universal variable:
```fish
set -U __fish_config_op_logging off # disable; takes effect in every open shell
set -Ue __fish_config_op_logging # re-enable (erase the override)
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)
```
Prefer an interactive interface? Run **`config-toggle`** for a full-screen
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 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` turns it off along with everything else.
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
### [📖 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`
on every push to `main`. It covers configuration variables, key bindings, abbreviations,
all functions, the dependency catalog, customization, and more.
A Starlight-powered site rebuilt on every push to `main`. It covers
configuration variables, key bindings, abbreviations, all functions, the
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/**`.
Never edit the generated `docs/fish-config.md` — it's rebuilt from both
sources and any hand-edits are discarded.
To browse the docs from the terminal:
@@ -109,10 +154,10 @@ To browse the docs from the terminal:
|---|---|
| `help config` | Open the terminal manual in the best available pager |
| `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 <keyword> --html` | Open HTML docs at the matching section anchor |
| `help config --html` | Open the documentation site in the default browser |
| `help config --man` | Open the compiled man page via `man -l` |
| `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**.
@@ -134,7 +179,7 @@ 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.
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.
> [!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.
@@ -153,12 +198,18 @@ Pull the latest changes from upstream without needing a configured git remote:
## 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
└── local.fish # Machine-specific paths and environment variables
└── local.fish # Machine-specific paths, env vars, and sourcing secrets
```
### secrets.fish
@@ -210,39 +261,41 @@ abbr -a dcw 'docker context use work-server'
### 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
if test -f $HOME/.config/.user-dots/fish/secrets.fish
source $HOME/.config/.user-dots/fish/secrets.fish
end
if test -f $HOME/.config/.user-dots/fish/local.fish
source $HOME/.config/.user-dots/fish/local.fish
end
# config.fish resolves the path, then sources local.fish
set -q __fish_user_dots_path
or set -l __fish_user_dots_path "$XDG_CONFIG_HOME/.user-dots/fish"
test -f "$__fish_user_dots_path/local.fish"
and source "$__fish_user_dots_path/local.fish"
```
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`.
---
## 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.
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-toggle`:** Run `config-toggle` for an interactive TUI that flips every setting below on, off, or back to default — per-session or universally — without typing a single variable name. Use the arrow keys (or `h`/`j`/`k`/`l`) to navigate and adjust, `Tab` to switch scope, and `q` to quit. Changes apply instantly. The panel auto-sizes to your terminal width (four tiers from 52- to 78-wide with a 6-column margin), centers itself horizontally, and redraws within ~0.3 s of a resize.
> **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 clear with `←`. `Tab`/`Shift-Tab` cycle pages and `q` quits. Changes apply instantly. The panel auto-sizes to your terminal width (four tiers from 52- to 78-wide with a 6-column margin), centers itself horizontally, and redraws within ~0.3 s of a resize.
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 |
|---|---|
| `__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_autoexec` | Startup side-effects: Fisher bootstrap, theme apply, `paru`/`yay` wrapper generation, auto venv activation, WakaTime hook |
| `__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_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, auto-pull background fast-forward |
| `__fish_config_op_overrides` | Vi mode, `exit``smart_exit`, `$PAGER`/`$MANPAGER`/`$CDPATH`/`XDG`/`PATH`, 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_logging` | 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_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_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. 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:
@@ -257,6 +310,9 @@ set -U __fish_config_op_aliases off
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
set -Ue __fish_config_opinionated
set -Ue __fish_config_op_greeting
@@ -264,11 +320,19 @@ 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.
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
see the [Components Reference](https://fish.rootiest.fyi/08-components-reference/)
for the full sub-category list per category.
---
## 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.
---
+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)'
+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'
+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)'
+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'
+146
View File
@@ -0,0 +1,146 @@
# 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: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/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"
+375 -3
View File
@@ -8,82 +8,172 @@
# This file contains all the abbreviations for the terminal.
# It is sourced by Fish on startup.
# COMPONENT
# site abbr-integrations: integrations/terminal-abbrs
# site abbr-overrides: overrides/key-bindings
# Neovim
# @category Editors
# @desc nvim
abbr -a n nvim
# @category Editors
# @desc nvim
abbr -a nv nvim
# @category Editors
# @desc nvim
abbr -a neovim nvim
# @category Editors
# @desc cd ~/.config/nvim
abbr -a cdnv 'cd ~/.config/nvim # Neovim Config'
# @category Editors
# @desc cd ~/.config/nvim; nvim
abbr -a cdnvn 'cd ~/.config/nvim;nvim'
# VSCode
# @category AI Assistants
# @desc antigravity-ide
abbr -a v antigravity-ide
# Kate
# @category Editors
# @desc kate
abbr -a k kate
# WezTerm SSH
if test "$TERM_PROGRAM" = WezTerm
# @category AI Assistants
# @desc wezterm ssh (WezTerm only)
abbr -a s wezterm ssh
end
# Neovim in a new tab
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
end
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
end
# LazyGit
# @category Git
# @desc lazygit
abbr -a lg lazygit
# Sudo shell
# @category Miscellaneous
# @desc sudo -s
abbr -a sudu sudo -s
# Kitty
if test "$TERM" = xterm-kitty
# @category Miscellaneous
# @desc kitty (Kitty only)
abbr -a kt kitty
end
# cat
# @category Miscellaneous
# @desc cat
abbr -a c cat
# chezmoi
# @category Chezmoi
# @desc chezmoi
abbr -a cm chezmoi
# chezmoi cd
# @category Chezmoi
# @desc chezmoi cd
abbr -a cmcd chezmoi cd
# @category Chezmoi
# @desc chezmoi cd
abbr -a czcd chezmoi cd
# @category Chezmoi
# @desc chezmoi cd
abbr -a cdcm chezmoi cd
# @category Chezmoi
# @desc chezmoi cd
abbr -a cdcz chezmoi cd
# chezmoi edit
# @category Chezmoi
# @desc chezmoi edit
abbr -a cme chezmoi edit
# @category Chezmoi
# @desc chezmoi edit
abbr -a cze chezmoi edit
# chezmoi add
# @category Chezmoi
# @desc chezmoi add
abbr -a cmad chezmoi add
# @category Chezmoi
# @desc chezmoi add
abbr -a czad chezmoi add
# chezmoi apply
# @category Chezmoi
# @desc chezmoi apply
abbr -a cmap chezmoi apply
# @category Chezmoi
# @desc chezmoi apply
abbr -a czap chezmoi apply
# chezmoi rm
# @category Chezmoi
# @desc chezmoi forget
abbr -a cmrm chezmoi forget
# @category Chezmoi
# @desc chezmoi forget
abbr -a cmf chezmoi forget
# @category Chezmoi
# @desc chezmoi forget
abbr -a czrm chezmoi forget
# @category Chezmoi
# @desc chezmoi forget
abbr -a czf chezmoi forget
# chezmoi init
# @category Chezmoi
# @desc chezmoi init
abbr -a cmi chezmoi init
# @category Chezmoi
# @desc chezmoi init
abbr -a czi chezmoi init
# Edit
# @category Editors
# @desc edit
abbr -a e edit
# Sudoedit
# @category Editors
# @desc sudoedit
abbr -a se sudoedit
# Git
# @category Git
# @desc git
abbr -a g git
# @category Git
# @desc generate .gitignore
abbr -a gitig gi
# @category Git
# @desc generate .gitignore
abbr -a git-ignore gi
# Antigravity
# @category AI Assistants
# @desc agy
abbr -a ag agy
# @category AI Assistants
# @desc agy .
abbr -a ag. agy .
# Quit
# @category Miscellaneous
# @desc exit
abbr -a /exit exit
# 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
# @category Terminal Windows, Tabs, and Panes
# @desc Close current pane/window
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)
end
if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Close current pane/window
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
end
end
@@ -91,236 +181,518 @@ end
######### Alternates ##########
### ls alternates
# List all files
# @category Navigation and Listing
# @desc ls
abbr -a l ls
# List all files by size
# @category Navigation and Listing
# @desc lss (sort by size)
abbr -a lS lss
# List all files by reverse modified time
# @category Navigation and Listing
# @desc lsr (sort by time, oldest first)
abbr -a lsR lsr
# List by extension
# @category Navigation and Listing
# @desc lx (sort by extension)
abbr -a lX lx
# Tree listing (depth 2)
# @category Navigation and Listing
# @desc lt (tree, depth 2)
abbr -a lT lt
# Full tree listing
# @category Navigation and Listing
# @desc lstree (full recursive tree)
abbr -a lsT lstree
### speed-test alternates
# Speedtest using fast.com
# @category Miscellaneous
# @desc fast-cli
abbr -a speedtest-fast fast-cli
# Kitty/WezTerm window-management abbreviations are opinionated (C4
# 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)
if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window
abbr -a :w kitty @ launch --type=os-window # Kitty
end
if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window
abbr -a :w wezterm cli spawn --new-window # WezTerm
end
# Window Splits (Panes)
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)
# @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)
end
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split pane vertically (new pane to the right)
abbr -a :wh wezterm cli split-pane --right # WezTerm
end
# Window Detach (Move Pane)
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)
# @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)
end
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
# @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
end
# Tab Creation
if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc New tab
abbr -a :t kitty @ launch --type=tab # Kitty
end
if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc New tab
abbr -a :t wezterm cli spawn # WezTerm
end
# Rename Tab
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"
end
if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Set tab title
abbr -a :tl wezterm cli set-tab-title # WezTerm
end
# Rename Window
if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Set window title
abbr -a :tw "kitty @ set-window-title" # Kitty
end
if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Set window title
abbr -a :tw wezterm cli set-window-title # WezTerm
end
# Rename Workspace
if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Rename workspace (WezTerm only)
abbr -a :twk wezterm cli rename-workspace # WezTerm
end
# Kitty does not have a direct CLI equivalent for renaming a dynamic "workspace" session.
# Tab Navigation
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
# @category Terminal Windows, Tabs, and Panes
# @desc Focus next tab
abbr -a :tn "kitty @ focus-tab --match neighbor:right" # Kitty
end
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
# @category Terminal Windows, Tabs, and Panes
# @desc Focus next tab
abbr -a :tn wezterm cli activate-tab --tab-relative 1 # WezTerm
end
# Specialty Tab Shortcuts (New Tab in specific dir)
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
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/.config/nvim
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
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~
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
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/.config/chezmoi
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
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at / (root)
abbr -a :tgr kitty @ launch --type=tab -- sudo -i
end
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
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/.config/nvim
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
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~
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
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at ~/.config/chezmoi
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
# @category Terminal Windows, Tabs, and Panes
# @desc New tab at / (root)
abbr -a :tgr wezterm cli spawn -- sudo -i # WezTerm
end
# Specialty Window Shortcuts (New OS Window in specific dir)
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
# @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
# @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
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~
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
# @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
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~/projects
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
end
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
# @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
# @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
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~
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
# @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
# @category Terminal Windows, Tabs, and Panes
# @desc New OS window at ~/projects
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
end
# Specialty Window Vertical Shortcuts (Split Bottom)
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/.config/nvim
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/.config/chezmoi
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at / (root)
abbr -a :wvgr kitty @ launch --location=hsplit -- sudo -i # Kitty
end
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/.config/nvim
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at ~/.config/chezmoi
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split bottom at / (root)
abbr -a :wvgr wezterm cli split-pane --bottom -- sudo -i # WezTerm
end
# Specialty Window Horizontal Shortcuts (Split Right)
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/.config/nvim
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/.config/chezmoi
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
# @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
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.config/kitty
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'
end
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/.config/nvim
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at ~/.config/chezmoi
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
# @category Terminal Windows, Tabs, and Panes
# @desc Split right at / (root)
abbr -a :whgr wezterm cli split-pane --bottom -- sudo -i # WezTerm
end
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.config/nvim
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'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.config/fish
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'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~
abbr -a :cdh 'cd ~ # Home Directory'
# @category Terminal Windows, Tabs, and Panes
# @desc 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'
# @category Terminal Windows, Tabs, and Panes
# @desc 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'
# @category Terminal Windows, Tabs, and Panes
# @desc 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_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'
# @category Terminal Windows, Tabs, and Panes
# @desc cd ~/.config/wezterm
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'
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
end
# Spawn window
if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc spwin (spawn new OS window)
abbr -a :sw spwin
end
end
### Docker ###
# @category Docker
# @desc docker context use default
abbr -a dcl 'docker context use default # Local Host'
# @category Docker
# @desc ld (lazydocker)
abbr -a lzd ld
# @category Docker
# @desc docker context ls
abbr -a dcls 'docker context ls'
### Beads ###
# @category Miscellaneous
# @desc bd list
abbr -a bl 'bd list'
# @category Miscellaneous
# @desc bd sync
abbr -a bs 'bd sync'
# @category Miscellaneous
# @desc bd create --title
abbr -a bC 'bd create --title'
# @category Miscellaneous
# @desc bd show
abbr -a bsh 'bd show'
# @category Miscellaneous
# @desc lazybeads
abbr -a lb lazybeads
### Systemctl ###
# @category Systemctl
# @desc systemctl
abbr -a sc systemctl
# @category Systemctl
# @desc sudo systemctl
abbr -a ssc 'sudo systemctl'
# @category Systemctl
# @desc systemctl --user
abbr -a scu 'systemctl --user'
# @category Systemctl
# @desc systemctl status
abbr -a st 'systemctl status'
# @category Systemctl
# @desc systemctl start
abbr -a scs 'systemctl start'
# @category Systemctl
# @desc systemctl restart
abbr -a scr 'systemctl restart'
# @category Systemctl
# @desc sudo systemctl status
abbr -a ssct 'sudo systemctl status'
# @category Systemctl
# @desc sudo systemctl start
abbr -a sscs 'sudo systemctl start'
# @category Systemctl
# @desc 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 ###
# Bash-style history expansion is opinionated (C3 overrides), gated atomically
# 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
# @category History Expansion
# @name !*
# @desc Expand to all arguments of the previous command
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
# @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
# @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
# @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
end
+65
View File
@@ -0,0 +1,65 @@
# 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
# 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
# COMPONENT
# overrides/key-bindings
# Local modification: opinionated guard (AGENTS.md Task #3). Bracket
# 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_right ")" "]" "}" '"' "'"
+141
View File
@@ -0,0 +1,141 @@
# 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.
# 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,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# COMPONENT
# integrations/notifications
if not status is-interactive
exit
@@ -26,7 +29,7 @@ end
# Local modification: opinionated guard (AGENTS.md Task #3). Desktop
# 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
+6 -2
View File
@@ -7,6 +7,10 @@
#
# Runs exactly once on the first interactive fish session after install.
# 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)
if not status is-interactive
@@ -36,7 +40,7 @@ end
# Printing a first-run welcome banner is opinionated (C6 greeting). The
# first-run state variable is already set unconditionally above, so
# 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 " Welcome to your fish shell configuration!"
echo " Run 'help config' for offline documentation."
@@ -48,7 +52,7 @@ end
# Startup side-effects below (Fisher curl, fisher update, theme apply) are
# opinionated (C2 auto-execution). The first-run state variable is already
# 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
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
+12 -1
View File
@@ -8,6 +8,9 @@
# This file defines custom key bindings for the Fish shell.
# It is sourced by Fish on startup.
# COMPONENT
# overrides/key-bindings
# ────────────────── Bind Prewious Path Head to Ctrl+G ─────────────────
# Bindings to insert the previous path head into the command line
# Behaves like `!$:h` does in bash
@@ -48,7 +51,11 @@ function fish_user_key_bindings
# Custom key chords are opinionated (C3 overrides); skip them entirely
# 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 ─────────────────────────────
#
@@ -59,6 +66,8 @@ function fish_user_key_bindings
type -q qalc && bind ctrl-alt-= _qalc_eval
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:
# 'default' is Vi-Command, 'insert' is Vi-Insert, 'visual' is Vi-Visual
@@ -69,5 +78,7 @@ function fish_user_key_bindings
type -q qalc && bind --mode $mode ctrl-alt-= _qalc_eval
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
+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"
+12 -7
View File
@@ -2,16 +2,20 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Generates ~/.local/bin/paru on first run (and on version bump) when
# /usr/bin/paru is installed. The wrapper runs paru in a PTY so progress
# paru is installed. The wrapper runs paru in a PTY so progress
# 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
# Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec).
# 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
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"
and grep -q "# paru-wrapper-version:" "$HOME/.local/bin/paru" 2>/dev/null
rm -f "$HOME/.local/bin/paru"
@@ -19,12 +23,13 @@ if not __fish_config_op_enabled __fish_config_op_logging
return
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_version 5
set -l _paru_wrapper_version 6
# 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
if test -f $_paru_wrapper
@@ -48,7 +53,7 @@ printf '%s\n' \
'' \
'# 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="/usr/bin/paru"' \
"cmd_str=\"$_paru_real\"" \
'for arg in "$@"; do' \
' cmd_str+=" $(printf '"'"'%q'"'"' "$arg")"' \
'done' \
+16 -1
View File
@@ -1,9 +1,12 @@
status is-interactive || exit
# COMPONENT
# overrides/key-bindings
# Local modification: opinionated guard (AGENTS.md Task #3). Puffer's key
# 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.
__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
set -l modes
@@ -13,9 +16,21 @@ function _puffer_fish_key_bindings --on-variable fish_key_bindings
set modes insert default
end
# @category History Expansion
# @name !.
# @desc Expand .. to ../.. and so on
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
# @category History Expansion
# @name !$
# @desc Expand to the last argument of the previous command
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[2] --erase '.' '!' '$' '*'
end
+13 -2
View File
@@ -95,8 +95,19 @@ function __sponge_register_secret_values --on-event fish_prompt
set -l secret_values
set -l sensitive_vars (set --names --export | string match --regex -- \
'(?i)(?:TOKEN|PASSWORD|PASSWD|SECRET|API[_-]KEY|PRIVATE[_-]KEY|ACCESS[_-]KEY|AUTH[_-]KEY|CREDENTIAL|KOPIA_PASSWORD)')
# Base credential-name tokens, plus any user-supplied extras from
# __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
# Take only the first element — array vars yield multiple values.
+5 -1
View File
@@ -1,12 +1,16 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# COMPONENT
# overrides/prompt
#
# Defines fish_prompt only when starship is installed.
# Without starship, fish's built-in prompt already emits OSC 133;A
# on the prompt line itself, so no wrapper is needed.
# 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
+5 -1
View File
@@ -1,5 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# COMPONENT
# overrides/prompt
#
# ╭──────────────────────────────────────────────────────────╮
# │ Fish Theme │
@@ -9,7 +13,7 @@
# Forcing theme colors and $FZF_DEFAULT_OPTS is opinionated (C3 overrides).
# The FZF variable is universal, so clean up our Catppuccin value if it
# 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"
set --erase FZF_DEFAULT_OPTS
end
+5 -1
View File
@@ -1,12 +1,16 @@
# 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 __fish_config_op_logging; or exit
__fish_config_op_enabled (status basename); or exit
status is-interactive; or exit
type -q tmux; or exit
set -q TMUX; or exit
+53 -4
View File
@@ -7,6 +7,11 @@
# │ 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
# Apply .profile: use this to put fish compatible .profile stuff in
if test -f ~/.fish_profile
@@ -24,7 +29,7 @@ end
# 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 __fish_config_op_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
@@ -37,7 +42,7 @@ set -gx __done_notification_urgency_level low
# 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
# 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
switch (commandline -t)
case "!"
@@ -60,10 +65,22 @@ if __fish_config_op_enabled __fish_config_op_overrides
# Apply bang-bang key bindings based on current key binding mode
if [ "$fish_key_bindings" = fish_vi_key_bindings ]
# @category History Expansion
# @name !!
# @desc Expand to the 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
else
# @category History Expansion
# @name !!
# @desc Expand to the 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
end
end
@@ -71,7 +88,7 @@ end
# Fish command history override to show timestamps
# Shadowing the history command is opinionated (C1 aliasing); when disabled,
# 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
builtin history --show-time='%F %T '
end
@@ -94,23 +111,47 @@ end
## Useful aliases
# Navigation short-cuts
# @category Shell Aliases
# @desc cd ..
alias ..='cd ..'
# @category Shell Aliases
# @desc cd ../..
alias ...='cd ../..'
# @category Shell Aliases
# @desc cd ../../..
alias ....='cd ../../..'
# @category Shell Aliases
# @desc cd ../../../..
alias .....='cd ../../../..'
# @category Shell Aliases
# @desc cd ../../../../..
alias ......='cd ../../../../..'
# 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
# @category Shell Aliases
# @desc dir --color=auto
alias dir='dir --color=auto'
# @category Shell Aliases
# @desc vdir --color=auto
alias vdir='vdir --color=auto'
# @category Shell Aliases
# @desc grep --color=auto
alias grep='grep --color=auto'
# @category Shell Aliases
# @desc fgrep --color=auto
alias fgrep='fgrep --color=auto'
# @category Shell Aliases
# @desc egrep --color=auto
alias egrep='egrep --color=auto'
# Safety aliases (Confirmation before overwriting/deleting)
# @category Shell Aliases
# @desc cp -i
alias cp="cp -i"
# @category Shell Aliases
# @desc mv -i
alias mv="mv -i"
# Force wget to resume partial downloads
@@ -118,9 +159,17 @@ if __fish_config_op_enabled __fish_config_op_aliases
end
# Archives and networking short-hands
# @category Shell Aliases
# @desc tar -acf
alias tarnow='tar -acf '
# @category Shell Aliases
# @desc tar -zxvf
alias untar='tar -zxvf '
# @category Shell Aliases
# @desc nc termbin.com 9999
alias tb='nc termbin.com 9999'
# System Logs
# @category Shell Aliases
# @desc journalctl -p 3 -xb
alias jctl="journalctl -p 3 -xb"
+6 -2
View File
@@ -5,11 +5,15 @@
# see: https://github.com/ik11235/wakatime.fish
###
# COMPONENT
# site wakatime-autoexec: autoexec/telemetry
# site wakatime-hook: integrations/notifications
# Local modification: opinionated guard (AGENTS.md Task #3). WakaTime
# reporting is classified under both C2 auto-execution and C4 integrations;
# disabling either category skips registering the hook.
__fish_config_op_enabled __fish_config_op_autoexec; or exit
__fish_config_op_enabled __fish_config_op_integrations; or exit
__fish_config_op_enabled (status basename) wakatime-autoexec; or exit
__fish_config_op_enabled (status basename) wakatime-hook; or exit
function __register_wakatime_fish_before_exec -e fish_postexec
if set -q FISH_WAKATIME_DISABLED
+12 -7
View File
@@ -2,16 +2,20 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Generates ~/.local/bin/yay on first run (and on version bump) when
# /usr/bin/yay is installed. The wrapper runs yay in a PTY so progress
# yay is installed. The wrapper runs yay in a PTY so progress
# 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
# Auto-generating a wrapper in ~/.local/bin is opinionated (C2 auto-exec).
# 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
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"
and grep -q "# yay-wrapper-version:" "$HOME/.local/bin/yay" 2>/dev/null
rm -f "$HOME/.local/bin/yay"
@@ -19,12 +23,13 @@ if not __fish_config_op_enabled __fish_config_op_logging
return
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_version 5
set -l _yay_wrapper_version 6
# 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
if test -f $_yay_wrapper
@@ -48,7 +53,7 @@ printf '%s\n' \
'' \
'# 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="/usr/bin/yay"' \
"cmd_str=\"$_yay_real\"" \
'for arg in "$@"; do' \
' cmd_str+=" $(printf '"'"'%q'"'"' "$arg")"' \
'done' \
+4 -1
View File
@@ -3,6 +3,9 @@
# Adapted from icezyclon/zoxide.fish (MIT)
# Heavily customized for Fish 4.x compatibility and performance
# COMPONENT
# aliases/filesystem
if status is-interactive
if type -q zoxide
@@ -65,7 +68,7 @@ if status is-interactive
# Shadowing cd with zoxide is opinionated (C1 aliasing); z and zi
# remain available either way.
if __fish_config_op_enabled __fish_config_op_aliases
if __fish_config_op_enabled (status basename)
alias cd=z
end
+98 -74
View File
@@ -7,7 +7,7 @@
# ───────────────────── Opinionated component guards ─────────────────────
# 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
# first (falsy disables everything), then the per-category opt-out variable:
# __fish_config_op_aliases C1 — command shadows / flag injection
@@ -15,15 +15,29 @@
# __fish_config_op_overrides C3 — key bindings, env, prompt overrides
# __fish_config_op_integrations C4 — terminal/tool coupling
# __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
# 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 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 ────────────────────────
if test -f /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):
# 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
test -f "$__fish_config_dir/conf.d/tricks.fish"
and source "$__fish_config_dir/conf.d/tricks.fish"
@@ -38,7 +52,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
# of tricks.fish); strip them when the matching category is disabled so
# 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
functions -q $_fname; and functions --erase $_fname
end
@@ -50,7 +64,7 @@ if test -f /usr/share/cachyos-fish-config/cachyos-config.fish
and source $__fish_data_dir/functions/$_fname.fish
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
functions -q $_fname; and functions --erase $_fname
end
@@ -64,66 +78,76 @@ set --erase _fname
# ───────────────────────────── XDG variables ────────────────────────────
# XDG Base Directory variables (standard practice)
set -gx XDG_CONFIG_HOME $HOME/.config # Sets default config dir to ~/.config
set -gx XDG_CACHE_HOME $HOME/.cache # Sets default cache dir to ~/.cache
set -gx XDG_DATA_HOME $HOME/.local/share # Sets default data dir to ~/.local/share
set -gx XDG_STATE_HOME $HOME/.local/state # Sets default state dir to ~/.local/state
# We set these unconditionally to ensure a consistent baseline, but only if
# they are not already defined by the system/user.
set -q XDG_CONFIG_HOME; or set -gx XDG_CONFIG_HOME $HOME/.config # Sets default config dir to ~/.config
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
set -gx RANDFILE "$XDG_STATE_HOME/rnd"
set -gx WGETRC "$XDG_CONFIG_HOME/wget/wgetrc"
set -gx WGET_HSTS_FILE "$XDG_CACHE_HOME/wget-hsts"
set -gx NPM_CONFIG_PREFIX "$XDG_DATA_HOME/npm-global"
set -gx NPM_CONFIG_USERCONFIG "$XDG_CONFIG_HOME/npm/npmrc"
set -gx ANDROID_USER_HOME "$XDG_DATA_HOME/android"
set -gx CARGO_HOME "$XDG_DATA_HOME/cargo"
set -gx RUSTUP_HOME "$XDG_DATA_HOME/rustup"
set -gx GOPATH "$XDG_DATA_HOME/go"
set -gx BUN_INSTALL "$XDG_DATA_HOME/bun"
set -gx GNUPGHOME "$XDG_CONFIG_HOME/gnupg"
set -gx WAKATIME_HOME "$XDG_CONFIG_HOME/wakatime"
set -gx HISTFILE "$XDG_STATE_HOME/bash_history"
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 -gx CODEIUM_HOME "$XDG_CONFIG_HOME/codeium"
set -gx WORDLIST "$XDG_CONFIG_HOME/hunspell_en_US"
set -q RANDFILE; or set -gx RANDFILE "$XDG_STATE_HOME/rnd"
set -q WGETRC; or set -gx WGETRC "$XDG_CONFIG_HOME/wget/wgetrc"
set -q WGET_HSTS_FILE; or set -gx WGET_HSTS_FILE "$XDG_CACHE_HOME/wget-hsts"
set -q NPM_CONFIG_PREFIX; or set -gx NPM_CONFIG_PREFIX "$XDG_DATA_HOME/npm-global"
set -q NPM_CONFIG_USERCONFIG; or set -gx NPM_CONFIG_USERCONFIG "$XDG_CONFIG_HOME/npm/npmrc"
set -q ANDROID_USER_HOME; or set -gx ANDROID_USER_HOME "$XDG_DATA_HOME/android"
set -q CARGO_HOME; or set -gx CARGO_HOME "$XDG_DATA_HOME/cargo"
set -q RUSTUP_HOME; or set -gx RUSTUP_HOME "$XDG_DATA_HOME/rustup"
set -q GOPATH; or set -gx GOPATH "$XDG_DATA_HOME/go"
set -q BUN_INSTALL; or set -gx BUN_INSTALL "$XDG_DATA_HOME/bun"
set -q GNUPGHOME; or set -gx GNUPGHOME "$XDG_CONFIG_HOME/gnupg"
set -q WAKATIME_HOME; or set -gx WAKATIME_HOME "$XDG_CONFIG_HOME/wakatime"
set -q HISTFILE; or set -gx HISTFILE "$XDG_STATE_HOME/bash_history"
set -q EXINIT; or set -gx EXINIT "set viminfofile=$XDG_STATE_HOME/vim/viminfo | source $MYVIMRC"
set -q NVIDIA_SETTINGS_RW_CONFIG_FILE; or set -gx NVIDIA_SETTINGS_RW_CONFIG_FILE "$XDG_CONFIG_HOME/nvidia/settings"
set -q CODEIUM_HOME; or set -gx CODEIUM_HOME "$XDG_CONFIG_HOME/codeium"
set -q WORDLIST; or set -gx WORDLIST "$XDG_CONFIG_HOME/hunspell_en_US"
# ─────────────────────────── Pager variables ────────────────────────────
# Overriding $PAGER is opinionated (C3 overrides)
if __fish_config_op_enabled __fish_config_op_overrides
# Overriding $PAGER, $EDITOR, and $GPG_TTY is opinionated (C3 overrides)
if __fish_config_op_enabled (status basename) pager-editor-gpg
if type -q ov
set -gx PAGER ov
else if type -q less
set -gx PAGER less
end
end
# ─────────────────────────── Editor variables ───────────────────────────
# 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,
# while still preferring nvim if it's installed.
if type -q nvim
set -gx NVIM_APPNAME nvim
set -gx EDITOR (command -s nvim)
else
set -gx EDITOR (command -s vi)
end
set -gx VISUAL $EDITOR
set -gx SUDO_EDITOR $EDITOR
# ─────────────────────────── Editor variables ───────────────────────────
# 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,
# while still preferring nvim if it's installed.
if type -q nvim
set -gx NVIM_APPNAME nvim
set -gx EDITOR (command -s nvim)
else
set -gx EDITOR (command -s vi)
end
# set -gx VISUAL $EDITOR # <- Use local.fish to set your preferred GUI editor.
set -gx SUDO_EDITOR $EDITOR
# ──────────────────────────── GPG variables ─────────────────────────────
# Helps ensure that GPG can prompt for passphrases correctly when invoked from the terminal.
set -gx GPG_TTY (tty)
# ──────────────────────────── GPG variables ─────────────────────────────
# Helps ensure that GPG can prompt for passphrases correctly when invoked from the terminal.
set -gx GPG_TTY (tty)
end
# ────────────────────────── 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"
# 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 -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
# Replacing the exit builtin is opinionated (C3 overrides); smart_exit also
# 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'
# If the smart_exit file exists in our function path, invoke it explicitly
if functions -q smart_exit
@@ -139,16 +163,19 @@ end
# 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
# 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)
fish_add_path $HOME/.local/share/../bin # Alternative/legacy path for local user binaries
fish_add_path $HOME/Applications # User-installed applications and standalone apps
fish_add_path $HOME/scripts # Custom personal shell scripts and automation
fish_add_path -mga $CARGO_HOME/bin # Rust binaries and tools installed via Cargo
fish_add_path $BUN_INSTALL/bin # Bun runtime executables and globally installed packages
fish_add_path $XDG_DATA_HOME/npm-global/bin # Global Node.js/npm packages (XDG compliant location)
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
# PATH setup is opinionated (C3 overrides)
if __fish_config_op_enabled (status basename) path-setup
fish_add_path $HOME/.local/bin # Standard user-local executables (XDG spec)
fish_add_path $HOME/.local/share/../bin # Alternative/legacy path for local user binaries
fish_add_path $HOME/Applications # User-installed applications and standalone apps
fish_add_path $HOME/scripts # Custom personal shell scripts and automation
fish_add_path -mga $CARGO_HOME/bin # Rust binaries and tools installed via Cargo
fish_add_path $BUN_INSTALL/bin # Bun runtime executables and globally installed packages
fish_add_path $XDG_DATA_HOME/npm-global/bin # Global Node.js/npm packages (XDG compliant location)
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 ──────────────────────────
# Allows cd-ing to directories within $HOME/projects or $HOME without needing to specify the full path.
@@ -160,7 +187,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,
# running 'cd myproject' will take you there instead of $HOME/projects/myproject.
# 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
end
@@ -175,7 +202,7 @@ if status is-interactive
# 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
# 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
end
@@ -215,30 +242,27 @@ if status is-interactive
# │ This is useful for machine-specific behavior or configurations. │
# ╰────────────────────────────── OVERRIDES ─────────────────────────────╯
#
# Define user-dots path variable for a more legible secrets/local config.
set -l dot_fish "$XDG_CONFIG_HOME/.user-dots/fish"
# ───────────────────────── Source user secrets ──────────────────────────
# Sources a secrets.fish file if it exists, which can be used to store
# sensitive environment variables and configurations that shouldn't be
# committed to version control.
# This allows you to keep things like API keys, database credentials,
# and other secrets out of your main config files and safely ignored by git.
test -f "$dot_fish/secrets.fish"; and source "$dot_fish/secrets.fish"
# Resolve user-dots path. Customize via: set -U __fish_user_dots_path /your/path
set -q __fish_user_dots_path
or set -l __fish_user_dots_path "$XDG_CONFIG_HOME/.user-dots/fish"
# ────────────────────── user-dots convenience symlink ───────────────────
# Keep $__fish_config_dir/user-dots tracking the resolved path so it can be
# browsed from the fish config dir. Git-ignored. Controlled by the
# __fish_user_dots_symlink toggle (config-settings → Paths); creation is a
# C2 side-effect, removal-on-opt-out is honoured regardless. See the helper.
__fish_user_dots_link
# ─────────────────────── Source machine-local config ────────────────────
# Sources a local.fish file if it exists, which can be used for machine-specific
# variables and configurations that shouldn't be shared across machines.
# This allows you to have different settings on different machines without affecting
# 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"
# Sources local.fish if it exists. That file handles sourcing its own
# secrets.fish companion when needed.
test -f "$__fish_user_dots_path/local.fish"; and source "$__fish_user_dots_path/local.fish"
# ─────────────────── C6: Greeting & First-Run UI override ───────────────
# When the greeting category is disabled, stamp out any fish_greeting
# function that distro configs set (e.g., CachyOS defines it as fastfetch).
# This runs last inside the interactive block so our empty definition wins
# 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
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
+865
View File
@@ -0,0 +1,865 @@
#!/usr/bin/env python3
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Generate publishable artifacts from the docs/manual SSOT.
--concat one ordered markdown document for pandoc / config-help
--site Starlight content tree + sidebar.json
"""
import argparse
import json
import re
import shutil
import sys
from pathlib import Path
import manualtools as mt
import generate_component_registry
DOCS = Path(__file__).parent
MANUAL = DOCS / "manual"
FUNCTIONS = DOCS.parent / "functions"
SLUG_DIR = "reference"
def _is_function_page(path: Path, root: Path) -> bool:
"""True for a Section 5 category stub (not its index)."""
rel = path.relative_to(root)
return bool(rel.parts) and rel.parts[0].endswith("-functions") and rel.name != "index.md"
def _entry_slug(title: str) -> str:
"""The site's page slug for an entry heading."""
return re.sub(r"[^\w-]+", "-", title.strip().lower()).strip("-")
def _entry_link(name: str, functions: dict) -> str:
"""Link a dependency name to its entry page; plain code span if unknown."""
fn = functions.get(name)
if not fn:
return f"`{name}`"
category = re.sub(r"^\d+-", "", fn["CATEGORY"][0])
return f"[`{name}`](/{SLUG_DIR}/{category}/{_entry_slug(name)}/)"
def _with_entries(body: str, path: Path, entries: dict) -> str:
"""Append this category's generated `## name` entries to its stub body."""
generated = entries.get(path.stem, [])
if not generated:
return body
blocks = [f"## {name}\n\n{entry}" for name, entry in generated]
return "\n\n".join(([body] if body.strip() else []) + blocks)
def _with_abbreviations(body: str, abbrs: dict[str, list[dict]]) -> str:
"""Inject generated abbreviation tables into the document placeholders."""
rendered_abbrs = {}
for cat, items in abbrs.items():
lines_cat = [" Abbreviation Description", " ───────────────────────────────────────────────────────────────────"]
for abbr in items:
name = abbr["name"]
desc = abbr["desc"]
# Left-pad description to ensure at least 2 spaces for cell split
name_part = name.ljust(16)
if len(name_part) < len(name) + 2:
name_part = name + " "
lines_cat.append(f" {name_part}{desc}")
rendered_abbrs[cat] = "\n".join(lines_cat)
for cat, table in rendered_abbrs.items():
placeholder = f"<!-- GENERATED: {cat} -->"
body = body.replace(placeholder, table)
return body
def build_concat(root: Path) -> str:
"""Concatenate the manual into one ordered markdown document.
Each file contributes `# {manTitle or title}` at a level matching its
depth, and its body headings are demoted by the same amount.
`root / "_pandoc.yml"` (if present) holds the original document's
pandoc metadata block (title/section/header/date/author) as raw text,
with no frontmatter fences and no Astro-visible frontmatter key. When
present, its contents are re-emitted byte-for-byte as the leading
`---`-fenced block, ahead of every heading.
"""
entries = build_entries(mt.parse_functions(FUNCTIONS))
chunks: list[str] = []
pandoc_path = root / "_pandoc.yml"
if pandoc_path.exists():
raw = pandoc_path.read_text().rstrip("\n")
chunks.append(f"---\n{raw}\n---")
for path, depth in mt.walk(root):
fm, body = mt.parse(path)
if not fm.get("man", True):
continue
heading = fm.get("manTitle") or fm.get("title", path.stem)
chunks.append("#" * (depth + 1) + " " + heading)
if _is_function_page(path, root):
body = _with_entries(body, path, entries)
elif "04-abbreviations" in path.parts:
abbrs = mt.parse_abbreviations(DOCS.parent / "conf.d")
body = _with_abbreviations(body, abbrs)
if body:
body = re.sub(r"<LinkButton.*?</LinkButton>\n*", "", body, flags=re.DOTALL)
body = re.sub(r"<CardGrid.*?</CardGrid>\n*", "", body, flags=re.DOTALL)
body = re.sub(r"\[([^\]]+)\]\(/[^)]+\)", r"\1", body)
chunks.append(mt.shift_headings(body, depth))
return "\n\n".join(chunks) + "\n"
SENTENCE_RE = re.compile(r"^(.+?[.!?])(\s|$)", re.S)
PIPELINE_KEYS = ("man", "site", "manTitle", "helpKeywords")
JSX_ATTR_ESCAPES = (
("&", "&amp;"),
('"', "&quot;"),
("<", "&lt;"),
("{", "&#123;"),
)
def _jsx_attr_escape(value: str) -> str:
"""Escape a string for safe use inside a quoted JSX attribute value.
`&` must go first so escaping later characters doesn't double-escape
the ampersands it introduces. `"` closes the attribute early; `<` and
`{` are otherwise-live MDX/JSX syntax that must not be interpreted.
"""
for char, escape in JSX_ATTR_ESCAPES:
value = value.replace(char, escape)
return value
def _first_sentence(body: str) -> str:
"""Extract a one-line description from the start of an entry body.
The `Synopsis:` block is skipped whole label line plus its
deeper-indented continuation lines. It restates the calling convention,
which the card already shows as its title, so using one as the card
description wastes the line.
Source prose is hard-wrapped, so the leading paragraph is unwrapped
before the sentence match otherwise a card truncates at the first
line break, mid-clause.
"""
para: list[str] = []
in_fence = False
syn_indent: int | None = None
for raw in body.split("\n"):
line = raw.strip()
indent = len(raw) - len(raw.lstrip())
if syn_indent is not None:
if line and indent <= syn_indent:
syn_indent = None
else:
continue
if line.startswith("```"):
in_fence = not in_fence
if para:
break
continue
if in_fence:
continue
if not line or line.startswith(("#", "|", "-", "*", ">")):
if para:
break
continue
if line.startswith("Synopsis:"):
syn_indent = indent
continue
para.append(line)
if not para:
return ""
text = " ".join(para)
m = SENTENCE_RE.match(text)
return (m.group(1) if m else text)[:160]
# Commands common enough in this manual that a block whose every line starts
# with one is certainly shell, not prose or a two-column reference table.
SHELL_HEADS = frozenset(
"""
abbr alias apt bg bind brew builtin cargo cat cd chmod code command cp curl
dnf docker echo end env exec export fg fish fisher for funcsave function git help
if jobs kitty ls man math mkdir mv nvim npm pacman paru pip pip3 pkg printf
python python3 rm set shutdown source string sudo switch systemctl test time
tmux touch trash type wget wezterm while yay zellij zypper
fish_default_key_bindings fish_vi_key_bindings
""".split()
)
SYNOPSIS_PREFIX = "Synopsis:"
EXAMPLE_PREFIX = "Example:"
INDENT = " "
def _is_prose(para: list[str]) -> bool:
"""True when a paragraph reads as sentences rather than as code or a table.
Column-aligned reference tables are the main thing to keep out of a
syntax-highlighted fence, and internal runs of two-or-more spaces are
what distinguishes them from prose. `<` and `{` are excluded because
the emitted paragraph is live markdown, where both would be parsed.
"""
text = " ".join(para)
if "<" in text or "{" in text:
return False
if not para or para[-1].rstrip()[-1:] not in ".:":
return False
return all(
len(line.split()) >= 3 and " " not in line.strip() for line in para
)
def _is_shell(para: list[str], entry_name: str | None) -> bool:
"""True when every line of a paragraph looks like a shell command."""
name_re = (
re.compile(rf"(?<![\w-]){re.escape(entry_name)}(?![\w-])")
if entry_name
else None
)
for line in para:
stripped = line.strip()
if not stripped or stripped.startswith("#"):
continue
if name_re and name_re.search(stripped):
continue
if stripped.split()[0].lstrip("$").rstrip(";") not in SHELL_HEADS:
return False
return True
# A lone indented line that's just a path ending in a known extension —
# e.g. pointing at where a file lives — reads better as a titled snippet
# than an unhighlighted grey slab.
PATH_LINE_RE = re.compile(r"^[~$][\w./{}-]*\.\w+$")
# A leading "# in local.fish" / "# local.fish" comment names the file an
# example belongs to; promote it to the fence title instead of leaving it
# as a literal comment inside the code.
FILENAME_COMMENT_RE = re.compile(r"^#\s*(?:in\s+)?([$~\w./-]+\.\w+)\s*$")
CELL_SPLIT = re.compile(r"\s{2,}")
# A rule line under a header row — the "Component Reference" tables'
# authoring convention (header, dashes, data rows all at the same indent,
# no ":"-terminated label). Either one solid run of dashes, or (RST-style)
# one dash run per column, gapped the same way CELL_SPLIT splits cells.
RULE_CELL_RE = re.compile(r"^[─\-]{3,}$")
def _cell(text: str, code: bool) -> str:
"""Render one table cell. `|` must be escaped even inside a code span."""
text = text.strip().replace("|", r"\|")
return f"`{text}`" if code and text else text
def _as_table(para: list[str]) -> str | None:
"""Render an aligned two-column block as a markdown table, else None.
Option and subcommand tables are the one thing in this manual that is
genuinely tabular, and the indented-code fallback renders them as a grey
slab. Everything else stays in that fallback: returning None is always
safe, so every check here is free to be conservative.
The rows must form one contiguous indented run, optionally introduced by
a label line (`Options:`) and closed by a sentence. Lines indented deeper
than the run are wrapped descriptions and fold into the row above.
"""
starts = [i for i, ln in enumerate(para) if ln.startswith(" ")]
if len(starts) < 2 or starts != list(range(starts[0], starts[-1] + 1)):
return None
head = para[: starts[0]]
body = para[starts[0] : starts[-1] + 1]
tail = para[starts[-1] + 1 :]
if head and not head[-1].rstrip().endswith(":"):
return None # a head that isn't a label means mixed content
indent = min(len(ln) - len(ln.lstrip()) for ln in body)
rows: list[list[str]] = []
for line in body:
if len(line) - len(line.lstrip()) > indent and rows:
rows[-1][1] += " " + line.strip()
continue
parts = CELL_SPLIT.split(line.strip(), 1)
if len(parts) != 2 or not parts[1].strip():
return None # not column-aligned; a numbered list, or prose
rows.append([parts[0], parts[1].strip()])
if len(rows) < 2:
return None
if any("<" in value or "{" in value for _, value in rows):
return None # live markdown in the prose column
out = [line.strip() for line in head]
out += ["| | |", "|---|---|"]
out += [f"| {_cell(k, True)} | {_cell(v, False)} |" for k, v in rows]
out += [line.strip() for line in tail]
return "\n".join(out)
def _as_ruled_table(para: list[str]) -> str | None:
"""Render a header + solid-rule + rows block as an N-column table, else None.
This is the "Component Reference" tables' convention: header row, a
dashed rule, then data rows at the same indent (no ":"-label, no extra
nesting the two things _as_table looks for). A row that splits into
just one cell is a word-wrapped continuation of the row above; anything
else that doesn't match the header's column count is a source alignment
bug, so bail out to the code-block fallback rather than guess.
"""
if len(para) < 4:
return None
rule_cells = CELL_SPLIT.split(para[1].strip())
if not all(RULE_CELL_RE.match(cell) for cell in rule_cells):
return None
header = CELL_SPLIT.split(para[0].strip())
n = len(header)
if n < 2:
return None
rows: list[list[str]] = []
for line in para[2:]:
parts = CELL_SPLIT.split(line.strip(), n - 1)
if len(parts) == n:
rows.append(parts)
elif len(parts) == 1 and rows:
rows[-1][-1] += " " + parts[0].strip()
else:
return None
if len(rows) < 2:
return None
# Unlike _as_table's prose column, these tables legitimately contain
# placeholders like <session> or brace globs — code-span protects them
# instead of rejecting the whole table.
def cell(text: str, code: bool) -> str:
needs_protection = ("<" in text or "{" in text) and "`" not in text
return _cell(text, code or needs_protection)
out = [f"| {' | '.join(header)} |", "|" + "|".join(["---"] * n) + "|"]
for row in rows:
cells = [cell(row[0], True)] + [cell(c, False) for c in row[1:]]
out.append(f"| {' | '.join(cells)} |")
return "\n".join(out)
TREE_ROOT_RE = re.compile(r"^[~$][\w./{}-]*/$")
TREE_BRANCH_RE = re.compile(r"^([│ \t]*)[├└]──\s*(\S+)\s*(.*)$")
def _as_file_tree(para: list[str]) -> str | None:
"""Render a hand-drawn box-drawing tree as a Starlight <FileTree>, else None."""
if len(para) < 2 or not TREE_ROOT_RE.match(para[0].strip()):
return None
branches = []
for line in para[1:]:
m = TREE_BRANCH_RE.match(line)
if not m:
return None
branches.append(m.groups())
out = ["<FileTree>", f"- {para[0].strip()}"]
for prefix, name, desc in branches:
depth = len(prefix.replace('\t', ' ')) // 4
indent = " " * (depth + 1)
out.append(f"{indent}- {name} {desc}".rstrip())
out.append("</FileTree>")
return "\n".join(out)
def _render_para(para: list[str], entry_name: str | None, deeper: bool) -> str:
"""Render one paragraph of a former indented block.
`deeper` marks paragraphs carrying their own extra indentation nested
option tables, whose alignment only survives inside a code block.
"""
if not deeper:
if _is_prose(para):
return "\n".join(line.strip() for line in para)
if len(para) == 1 and PATH_LINE_RE.match(para[0].strip()):
path = para[0].strip()
name = path.rsplit("/", 1)[-1]
return f'```fish title="{name}"\n{path}\n```'
if _is_shell(para, entry_name):
body = para
title = None
m = FILENAME_COMMENT_RE.match(para[0].strip())
if m:
title, body = m.group(1), para[1:]
info = f'fish title="{title}"' if title else "fish"
return f"```{info}\n" + "\n".join(body) + "\n```"
table = _as_ruled_table(para) or _as_table(para) or _as_file_tree(para)
if table is not None:
return table
return "\n".join(INDENT + line for line in para)
def _prettify_block(block: list[str], entry_name: str | None) -> str:
"""Convert one indented block into fenced code, prose, and tables.
The manual is authored man-page style: every example, table, and
description sits in a single 4-space-indented block, which renders on
the site as one unhighlighted grey slab. Splitting a block into its
paragraphs recovers the structure the indentation flattened.
"""
lines = [line[len(INDENT) :] if line.startswith(INDENT) else line for line in block]
out: list[str] = []
if lines and lines[0].startswith(SYNOPSIS_PREFIX):
synopsis = [lines.pop(0)[len(SYNOPSIS_PREFIX) :].strip()]
# A multi-line synopsis is authored aligned under the first line;
# keep the whole thing in one fence rather than orphaning the rest.
while lines and lines[0].startswith(" "):
synopsis.append(lines.pop(0).strip())
# A "Usage" title (Starlight's filename-title convention, repurposed
# as a label) makes the synopsis read as a snippet of the function
# it documents rather than a bare command example.
info = 'fish title="Usage"' if entry_name else "fish"
out.append(f"```{info}\n" + "\n".join(synopsis) + "\n```")
para: list[str] = []
for line in lines + [""]:
if line.strip():
para.append(line)
continue
if para:
if para[0].strip() == EXAMPLE_PREFIX:
example = para[1:]
if example and _is_shell(example, entry_name):
body = "\n".join(example)
out.append(f'```fish title="Examples"\n{body}\n```')
else:
deeper = any(line.startswith(" ") for line in example)
out.append(_render_para(example, entry_name, deeper))
else:
deeper = any(line.startswith(" ") for line in para)
out.append(_render_para(para, entry_name, deeper))
para = []
return "\n\n".join(chunk for chunk in out if chunk.strip())
ASIDE_LABELS: dict[str, tuple[str, str, str | None]] = {
"NOTE": ("note", "Note", None),
"IMPORTANT": ("note", "Important", "star"),
"TIP": ("tip", "Tip", None),
"HINT": ("tip", "Hint", "question-circle"),
"WARNING": ("caution", "Warning", "warning"),
"CAUTION": ("caution", "Caution", None),
"DANGER": ("danger", "Danger", None),
}
ASIDE_RE = re.compile(rf"^({'|'.join(ASIDE_LABELS)}):\s*(.*)$")
def _as_aside(para: list[str]) -> str | None:
"""Render a `LABEL: ...` flat paragraph as a Starlight <Aside>, else None."""
m = ASIDE_RE.match(para[0])
if not m:
return None
label, rest = m.groups()
aside_type, title, icon = ASIDE_LABELS[label]
body = "\n".join(([rest] if rest else []) + para[1:])
attrs = f'type="{aside_type}" title="{title}"'
if icon:
attrs += f' icon="{icon}"'
return f"<Aside {attrs}>\n{body}\n</Aside>"
def prettify(body: str, entry_name: str | None = None) -> str:
"""Rewrite a body's indented code blocks and labeled asides for the website.
Site-only: the man page and `config-help` keep reading the untouched
SSOT, where the indented form and the `LABEL:` text are exactly what
pandoc/`config-help` want.
"""
out: list[str] = []
block: list[str] = []
flat: list[str] = []
in_fence = False
def flush_flat() -> None:
out.append(_as_aside(flat) or "\n".join(flat))
for line in body.split("\n"):
if mt.FENCE_RE.match(line):
in_fence = not in_fence
if not in_fence and (line.startswith(INDENT) or (not line.strip() and block)):
if flat:
flush_flat()
flat.clear()
block.append(line)
continue
if block:
while block and not block[-1].strip():
block.pop()
out.append(_prettify_block(block, entry_name))
out.append("")
block = []
if in_fence or not line.strip():
if flat:
flush_flat()
flat.clear()
out.append(line)
else:
flat.append(line)
if flat:
flush_flat()
if block:
while block and not block[-1].strip():
block.pop()
out.append(_prettify_block(block, entry_name))
return "\n".join(out)
ENTRY_HEADS = {
"ARGUMENTS": "Arguments:",
"EXIT STATUS": "Exit Status:",
"RETURNS": "Returns:",
"NOTES": "Notes:",
}
def render_entry(fn: dict[str, list[str]], used_by: list[str], link=None) -> str:
"""Render one parsed function header as a manual entry body.
Emits the same man-page shape Section 5 was authored in one 4-space
indented block opening with `Synopsis:` so `prettify` keeps handling it
for the site and pandoc keeps handling it for the man page, with no
special case on either side.
`link` maps a function name to its markdown link, or is None for the man
page, where a URL in the middle of a sentence is noise.
"""
out: list[str] = []
syn = fn.get("SYNOPSIS", [])
if syn:
pad = " " * len(SYNOPSIS_PREFIX + " ")
out.append(f"{SYNOPSIS_PREFIX} {syn[0]}")
out += [pad + line for line in syn[1:]]
out.append("")
for line in fn.get("DESCRIPTION", []):
out.append(line)
for label, head in ENTRY_HEADS.items():
body = fn.get(label)
if not body:
continue
out += ["", head] + [" " + line for line in body]
if fn.get("EXAMPLE"):
out += ["", EXAMPLE_PREFIX] + fn["EXAMPLE"]
block = "\n".join((INDENT + line).rstrip() for line in out)
def names(raw: list[str]) -> list[str]:
return [n for n in re.split(r"[,\s]+", " ".join(raw)) if n]
refs = []
for label, values in (
("Dependencies", names(fn.get("DEPENDENCIES", []))),
("Used by", sorted(used_by)),
):
if values:
rendered = ", ".join(link(v) if link else f"`{v}`" for v in values)
refs.append(f"**{label}:** {rendered}")
if refs:
block += "\n\n" + "\n\n".join(refs)
return block
def build_entries(functions: dict[str, dict], link=None) -> dict[str, list[tuple[str, str]]]:
"""Group rendered entries by category stem, ordered by function name.
The `Used by` reverse index is computed here in one pass rather than
authored: a bidirectional link maintained by hand drifts the moment one
side is edited.
"""
used_by: dict[str, list[str]] = {}
for name, fn in functions.items():
for dep in re.split(r"[,\s]+", " ".join(fn.get("DEPENDENCIES", []))):
if dep in functions:
used_by.setdefault(dep, []).append(name)
out: dict[str, list[tuple[str, str]]] = {}
for name in sorted(functions):
fn = functions[name]
body = render_entry(fn, used_by.get(name, []), link)
out.setdefault(fn["CATEGORY"][0], []).append((name, body))
return out
def _page_fm(fm: dict) -> dict:
"""Strip pipeline-only keys from frontmatter destined for the site."""
return {k: v for k, v in fm.items() if k not in PIPELINE_KEYS}
def _split_entries(body: str) -> tuple[str, list[tuple[str, str]]]:
"""Split a category body into (intro, [(entry title, entry body)]).
Fence-aware: an H2-looking line (`## ...`) inside a fenced code block
(tracked the same way as `manualtools.shift_headings`) is treated as
ordinary body text, not an entry boundary.
"""
lines = body.split("\n")
heading_re = re.compile(r"^## (.+)$")
boundaries: list[tuple[int, str]] = []
in_fence = False
for i, line in enumerate(lines):
if mt.FENCE_RE.match(line):
in_fence = not in_fence
continue
if not in_fence:
m = heading_re.match(line)
if m:
boundaries.append((i, m.group(1)))
if not boundaries:
return body.strip(), []
intro = "\n".join(lines[: boundaries[0][0]]).strip()
entries = []
for idx, (line_no, title) in enumerate(boundaries):
start = line_no + 1
end = boundaries[idx + 1][0] if idx + 1 < len(boundaries) else len(lines)
# Strip newlines only: a bare .strip() would eat the leading
# indentation of the entry's first line, detaching the `Synopsis:`
# line from the indented block it opens.
entry_body = "\n".join(lines[start:end]).strip("\n")
entries.append((title.strip(), entry_body))
return intro, entries
def _inject_subheading_cards(body: str) -> str:
"""Extract `## Heading`s and inject a CardGrid after the intro."""
headings = []
for line in body.splitlines():
m = re.match(r"^##\s+(.+)$", line)
if m:
headings.append(m.group(1).strip())
if len(headings) < 2:
return body
parts = body.split("\n## ", 1)
if len(parts) != 2:
return body
intro = parts[0].strip()
rest = "## " + parts[1]
cards = []
for title in headings:
safe_title = _jsx_attr_escape(title)
slug = re.sub(r"[^\w\s-]", "", title.lower())
slug = re.sub(r"[-\s]+", "-", slug).strip("-")
cards.append(f' <LinkCard title="{safe_title}" href="#{slug}" />')
cardgrid = "<CardGrid>\n" + "\n".join(cards) + "\n</CardGrid>\n\n"
return f"{intro}\n\n{cardgrid}{rest}"
ASTRO_ASIDE_COMPONENTS = {"<Aside": "Aside", "<FileTree": "FileTree", "<LinkButton": "LinkButton", "<CardGrid": "CardGrid", "<LinkCard": "LinkCard"}
def _write_prettified(target: Path, fm: dict, content: str) -> None:
"""Write a prettified page, promoting to .mdx when it needs a component import.
A page stays .md (prettify()'s default, no imports) unless its rendered
content actually contains an <Aside> or <FileTree> the only two
components a prettified (non-hand-built) page can contain.
"""
needed = [name for marker, name in ASTRO_ASIDE_COMPONENTS.items() if marker in content]
if needed:
imports = f"import {{ {', '.join(needed)} }} from '@astrojs/starlight/components';\n\n"
target = target.with_suffix(".mdx")
content = imports + content
target.write_text(mt.serialize(fm, content))
def build_site(root: Path, out: Path) -> list[dict]:
"""Write the Starlight content tree. Returns the sidebar structure."""
if out.exists():
shutil.rmtree(out)
out.mkdir(parents=True)
functions = mt.parse_functions(FUNCTIONS)
entries = build_entries(functions, link=lambda n: _entry_link(n, functions))
sidebar: list[dict] = [{"label": "Home", "link": "/"}]
standard_groups: dict = {}
functions_group: dict = {}
functions_index_target = None
functions_index_fm = None
functions_index_body = None
functions_cards = []
for path, _depth in mt.walk(root):
fm, body = mt.parse(path)
if not fm.get("site", True):
continue
rel = path.relative_to(root)
is_function_dir = rel.parts and rel.parts[0].endswith("-functions")
if not is_function_dir:
target = out / rel
if "04-abbreviations" in path.parts:
abbrs = mt.parse_abbreviations(DOCS.parent / "conf.d")
body = _with_abbreviations(body, abbrs)
target.parent.mkdir(parents=True, exist_ok=True)
body = _inject_subheading_cards(body)
_write_prettified(target, _page_fm(fm), prettify(body))
if len(rel.parts) > 1:
group_dir = rel.parts[0]
if rel.name == "index.md":
group = {
"label": fm["title"],
"collapsed": True,
"items": [{"label": "Categories", "link": f"/{group_dir}/"}]
}
standard_groups[group_dir] = group
sidebar.append(group)
elif rel.name != "404.md":
if group_dir in standard_groups:
standard_groups[group_dir]["items"].append({
"label": fm["title"],
"link": f"/{group_dir}/{rel.stem}/"
})
else:
sidebar.append({"label": fm["title"], "link": f"/{group_dir}/{rel.stem}/"})
else:
if rel.name not in ("index.md", "404.md"):
sidebar.append({"label": fm["title"], "link": "/" + rel.stem + "/"})
continue
# Section 5: category index page keeps its slot; entries explode.
#
# Deliberately NOT "functions": Cloudflare Pages reserves a top-level
# `functions/` directory in the deploy output for Pages Functions
# (server-side handlers) and silently drops it from the static-asset
# upload. The pages build fine and never arrive — every entry 404s in
# production while working locally. test_site_avoids_reserved_dir
# guards this.
slug_dir = SLUG_DIR
if rel.name == "index.md":
functions_index_target = out / slug_dir / "index.md"
functions_index_fm = fm
functions_index_body = body
functions_cards = []
# Built explicitly rather than by `autogenerate`, which labels
# each group with its raw directory slug and republishes this
# index as a child of the group it already titles.
functions_group = {
"label": fm["title"],
"collapsed": True,
"items": [{"label": "Categories", "link": f"/{slug_dir}/"}],
}
sidebar.append(functions_group)
continue
category = re.sub(r"^\d+-", "", rel.stem)
cat_dir = out / slug_dir / category
cat_dir.mkdir(parents=True, exist_ok=True)
intro, page_entries = _split_entries(_with_entries(body, path, entries))
cat_title = fm["title"]
cat_desc = fm.get("description", "")
safe_title = _jsx_attr_escape(cat_title)
safe_desc = _jsx_attr_escape(cat_desc)
href = f"/{slug_dir}/{category}/"
functions_cards.append(
f' <LinkCard title="{safe_title}" href="{href}"'
+ (f' description="{safe_desc}"' if cat_desc else "")
+ " />"
)
cards = []
links = []
for title, entry_body in page_entries:
entry_slug = _entry_slug(title)
desc = _first_sentence(entry_body)
entry_fm = {"title": title}
if desc:
entry_fm["description"] = desc
_write_prettified(
cat_dir / f"{entry_slug}.md",
entry_fm,
prettify(entry_body, title.split()[0]),
)
href = f"/{slug_dir}/{category}/{entry_slug}/"
links.append({"label": title, "link": href})
safe_title = _jsx_attr_escape(title)
safe_desc = _jsx_attr_escape(desc)
cards.append(
f' <LinkCard title="{safe_title}" href="{href}"'
+ (f' description="{safe_desc}"' if desc else "")
+ " />"
)
overview = (
"import { CardGrid, LinkCard } from '@astrojs/starlight/components';\n\n"
+ (f"{intro}\n\n" if intro else "")
+ "<CardGrid>\n"
+ "\n".join(cards)
+ "\n</CardGrid>\n"
)
(cat_dir / "index.mdx").write_text(mt.serialize(_page_fm(fm), overview))
functions_group.setdefault("items", []).append(
{
"label": fm["title"],
"collapsed": True,
"items": [
{"label": f"{fm['title']} Overview", "link": f"/{slug_dir}/{category}/"},
*links,
],
}
)
if functions_index_target:
overview_content = (
(f"{functions_index_body}\n\n" if functions_index_body.strip() else "")
+ "<CardGrid>\n"
+ "\n".join(functions_cards)
+ "\n</CardGrid>\n"
)
_write_prettified(functions_index_target, _page_fm(functions_index_fm), prettify(overview_content))
return sidebar
def main() -> int:
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("--concat", action="store_true", help="emit the pandoc document")
ap.add_argument("--site", action="store_true", help="emit the Starlight content tree")
ap.add_argument("-o", "--output", type=Path, help="write to PATH instead of stdout")
args = ap.parse_args()
if not (args.concat or args.site):
ap.error("nothing to do: pass --concat and/or --site")
generate_component_registry.main()
if args.site:
src = DOCS / "site" / "src"
out = src / "content" / "docs"
sidebar = build_site(MANUAL, out)
(src / "sidebar.json").write_text(json.dumps(sidebar, indent=2) + "\n")
print(f"wrote site content to {out} ({len(sidebar)} sidebar entries)")
if args.concat:
text = build_concat(MANUAL)
if args.output:
args.output.write_text(text)
print(f"wrote {args.output}")
else:
sys.stdout.write(text)
return 0
if __name__ == "__main__":
sys.path.insert(0, str(Path(__file__).parent))
raise SystemExit(main())
+3815 -1225
View File
File diff suppressed because it is too large Load Diff
+130 -41
View File
@@ -24,6 +24,9 @@ toolhomes=## Tool Homes (XDG-compliant)
editor=## Editor and Pager
pager=## Editor and Pager
scrollback=## Scrollback History
__fish_scrollback_history_dir=## Scrollback History
__fish_scrollback_history_max_files=## Scrollback History
scrollback-dir=## Scrollback History
# ── Section 2: PATH ───────────────────────────────────────────
path=# 2. PATH SETUP
@@ -88,6 +91,7 @@ less=### less
rawfish=### rawfish
view=### view
git=## 5.4 Git and Version Control
auto-pull=### auto-pull
branch=### branch
gi=### gi
gitignore=### gi
@@ -121,6 +125,8 @@ split=### split
spwin=### spwin
detach=### detach
bkg=### bkg
jobrunner=### jobrunner
jr=### jr
ssh=### ssh
clipboard=## 5.9 Clipboard
copy-fn=### y
@@ -133,21 +139,37 @@ logging=## 5.11 Pager and Logging
logs=### logs
smart-exit=### smart_exit
ai=## 5.12 AI and Developer Tools
antigravity=### antigravity
antigravity-ide=### antigravity-ide
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=### claude-resume
claude-docs=### claude-docs
claude-pr=### claude-pr
code-resume=### code-resume
qc=### qc
quick-chat=### qc
aichat=### qc
superpowers=### superpowers
media=## 5.13 Media and Utilities
dng2avif=### dng2avif
spark=### spark
yt-dlp=### yt-dlp
miscfns=## 5.14 Miscellaneous
config-help=### config-help
open-url=### open-url
url-open=### open-url
repo-open=### repo-open
open-repo=### repo-open
config-update=### config-update
config-toggle=### config-toggle
toggle=### config-toggle
config-settings=### config-settings
config-toggle=### config-settings
toggle=### config-settings
bash=### bash
cheat=### cheat
dockup=### dockup
@@ -155,7 +177,37 @@ joplin=### joplin
replay=### replay
tmux=### tmux-clean
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
# ── Section 6: Dependency Catalog ────────────────────────────
catalog=# 6. DEPENDENCY CATALOG
@@ -169,6 +221,8 @@ install-methods=## Install Methods
customization=# 7. CUSTOMIZATION
customize=# 7. CUSTOMIZATION
local=## Machine-local Configuration
user-dots=## Machine-local Configuration
dots-link=## Machine-local Configuration
secrets=## Secrets and API Keys
overrides=## Overriding Configuration Variables
universal=## Fish Universal Variables
@@ -177,24 +231,29 @@ minimal=## Opinionated Components (Minimal Mode)
minimal-mode=## Opinionated Components (Minimal Mode)
opt-out=## Opinionated Components (Minimal Mode)
toggles=## Opinionated Components (Minimal Mode)
component-reference=### Component Reference
components=### Component Reference
c1=#### C1 — Command Shadows
command-shadows=#### C1 — Command Shadows
aliases-detail=#### C1 — Command Shadows
c2=#### C2 — Startup Side-Effects
autoexec=#### C2 — Startup Side-Effects
startup=#### C2 — Startup Side-Effects
c3=#### C3 — Key and Environment Overrides
overrides-detail=#### C3 — Key and Environment Overrides
bang-bang=#### C3 — Key and Environment Overrides
c4=#### C4 — Terminal and Tool Integration
integrations-detail=#### C4 — Terminal and Tool Integration
c5=#### C5 — Logging and Capture
logging-detail=#### C5 — Logging and Capture
logging-sentinel=#### C5 — Logging and Capture
c6=#### C6Greeting and First-Run UI
greeting=#### C6Greeting and First-Run UI
component-reference=# 8. COMPONENTS REFERENCE
components=# 8. COMPONENTS REFERENCE
c1=## C1 — Command Shadows
command-shadows=## C1 — Command Shadows
aliases-detail=## C1 — Command Shadows
c2=## C2 — Startup Side-Effects
autoexec=## C2 — Startup Side-Effects
startup=## C2 — Startup Side-Effects
c3=## C3 — Key and Environment Overrides
overrides-detail=## C3 — Key and Environment Overrides
bang-bang=## C3 — Key and Environment Overrides
c4=## C4 — Terminal and Tool Integration
integrations-detail=## C4 — Terminal and Tool Integration
c5=## C5 — Logging and Capture
logging-detail=## C5 — Logging and Capture
logging-sentinel=## C5 — Logging and Capture
zellij=## C5Logging and Capture
zellij-logging=## C5Logging and Capture
tmux-logging=## C5 — Logging and Capture
pipe-pane=## C5 — Logging and Capture
dump-screen=## C5 — Logging and Capture
c6=## C6 — Greeting and First-Run UI
greeting=## C6 — Greeting and First-Run UI
# ── Prompt and Theme ──────────────────────────────────────────
prompt-theme=## Prompt and Theme
@@ -205,33 +264,63 @@ nim-prompt=### Catppuccin Fallback Prompt
fzf-theme=### FZF
catppuccin-theme=### Catppuccin Mocha Syntax Highlighting
# ── Section 8: Fisher Plugins ─────────────────────────────────
plugins=# 8. FISHER PLUGINS
fisher=# 8. FISHER PLUGINS
# ── Section 9: Fisher Plugins ─────────────────────────────────
plugins=# 9. FISHER PLUGINS
fisher=# 9. FISHER PLUGINS
fisher-managed=## Fisher-Managed Plugins
sponge=## Fisher-Managed Plugins
sponge-filtering=## Sponge History Filtering
history-filtering=## 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
fish-plugins-manifest=## fish_plugins Manifest
# ── Section 9: Installation ────────────────────────────────────
installation=# 9. INSTALLATION
install=# 9. INSTALLATION
# ── Section 10: Installation ────────────────────────────────────
installation=# 10. INSTALLATION
install=# 10. INSTALLATION
sentinel=## Return Sentinel
updating=## Updating
# ── Section 10: Personalization ───────────────────────────────
personalization=# 10. PERSONALIZATION
personalize=# 10. PERSONALIZATION
secrets=## secrets.fish
# ── Section 11: Personalization ───────────────────────────────
personalization=# 11. PERSONALIZATION
personalize=# 11. PERSONALIZATION
secrets-file=## secrets.fish
local-config=## local.fish
# ── Section 11: Viewing This Manual ──────────────────────────
viewing=# 11. VIEWING THIS MANUAL
manual=# 11. VIEWING THIS MANUAL
ov=## With ov (recommended)
man-page=## As a man page (if compiled)
manpage=## As a man page (if compiled)
jump=## Jumping to a section
# ── Section 12: Troubleshooting ──────────────────────────────
troubleshooting=# 12. TROUBLESHOOTING
troubleshoot=# 12. TROUBLESHOOTING
faq=# 12. TROUBLESHOOTING
uninstall=## Uninstalling and Reverting to Backup
revert=## Uninstalling and Reverting to Backup
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
man-page=## As a man page
manpage=## As a man page
jump=## In the terminal
html=## The documentation website
browser=## The documentation website
site=## The documentation website
+2943 -1019
View File
File diff suppressed because it is too large Load Diff
+121
View File
@@ -0,0 +1,121 @@
#!/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]) + '"' for k in keys]
lines.append("set -g __fish_config_op_registry_values \\")
lines += [f" {v} \\" for v in values[:-1]] + [f" {values[-1]}"]
lines.append("")
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>
-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>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>fish Fish shell &gt;= 4.0
fzf Fuzzy finder
zoxide Smart cd with frecency</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>cargo Rust toolchain (via rustup); used by fish-deps to install
Rust-based tools and to build fish from source. All paths
are gated on type -q cargo and degrade gracefully.
starship Cross-shell prompt; loaded via type -q starship guard.
Without it the Catppuccin nim-style fallback prompt activates.
uv Python package and project manager (Astral); used by the
fish-from-source build path in fish-deps. All consumers
degrade gracefully without it.
direnv Per-directory environment loading; integration is fully
guarded with type -q direnv. Without it the direnv hook
is simply not loaded and auto-venv activates normally.
paru AUR helper (Arch only; preferred); guarded throughout —
non-Arch systems silently skip AUR-specific paths.
yay AUR helper (Arch only; fallback to paru); same guards apply.
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)
python3 Standalone interpreter — used by the AI session helpers
(save_claude_session / save_antigravity_session) and the
paru/yay log cleaner. Note: uv does not provide python3 on
PATH, and Arch&#39;s base does not include it, so it is listed
separately. All consumers degrade gracefully without it.</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</code></pre>
<hr />
</body>
</html>
-794
View File
@@ -1,794 +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>
<p>An explicit per-category truthy value takes precedence over the
master switch: setting __fish_config_opinionated=0 disables all unset
categories, but a category with an explicit truthy value remains enabled
regardless.</p>
<pre><code>Variable Disables
------------------------------ ------------------------------------
__fish_config_op_aliases Command shadows and flag injection:
ls-&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, claude
AGENTS.md auto-link
__fish_config_op_autoexec Startup side-effects: Fisher
bootstrap, theme apply, paru/yay
wrapper generation, auto venv
activation, WakaTime hook
__fish_config_op_overrides Key and env overrides: Vi mode,
exit-&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
# Minimal mode but keep the greeting:
set -U __fish_config_opinionated 0
set -U __fish_config_op_greeting 1
# (erase both to go back to full-flavor defaults)</code></pre>
<p>Notes:</p>
<ul>
<li>Command shadows (rm, cat, ls, ...) react immediately; conf.d-level
components (bindings, prompt, abbreviations, hooks) take effect in new
shells.</li>
<li>With aliases disabled, rm falls back to bare <code>command rm</code>
— files are deleted permanently, not trashed.</li>
<li>Disabled integration commands (spwin, tab, split, hist, logs,
upgrade) print an error naming the variable that disabled them.</li>
<li>On CachyOS, the distro fish config's own aliases, history override,
and bang-bang bindings are stripped per category as well.</li>
</ul>
<h3 data-number="11.5.1" id="component-reference">Component
Reference</h3>
<p>The following tables detail every component in each category. Use
this reference to understand exactly which behaviors change when you
toggle a category variable.</p>
<h4 data-number="11.5.1.1" id="c1--command-shadows">C1 — Command
Shadows</h4>
<p>Disabling __fish_config_op_aliases restores standard system behavior
for all of these commands.</p>
<pre><code>Command / Alias Active behavior Disabled fallback
───────────────────────────────────────────────────────────────────────────
ls eza -l -a --icons --hyperlink system ls
cat bat syntax-highlighted; dirs → ls /usr/bin/cat
cd zoxide frecency-based navigation fish builtin cd
rm moves files to trash (recoverable) command rm (permanent)
less $PAGER → ov → less → more → cat system less
du duf (disk overview) or dust (dir tree) system du
top btop resource monitor system top
ping prettyping --nolegend animation system ping
ssh kitten ssh in Kitty terminal system ssh
rg rg --hyperlink-format=kitty system rg
mkdir verbose path-tree display on creation mkdir -p silently
bash XDG bashrc + $SHELL reset on exit system bash
history timestamps prepended to every entry fish builtin history
cp / mv forced -i confirmation prompt cp / mv unmodified
wget forced --continue (resume downloads) system wget
grep/fgrep/egrep forced --color=auto system grep variants
dir / vdir forced --color=auto system dir / vdir
help config intercepts &quot;help config&quot; → config-help fish builtin help
claude auto-links AGENTS.md as CLAUDE.md before launch command claude</code></pre>
<p>When C1 is disabled, <code>rm</code> uses bare
<code>command rm</code> with no wrapper — files are permanently deleted,
not trashed. There is no intermediate safety net.</p>
<h4 data-number="11.5.1.2" id="c2--startup-side-effects">C2 — Startup
Side-Effects</h4>
<p>These run automatically without any user action. Disabling
__fish_config_op_autoexec prevents all of them.</p>
<pre><code>Component Trigger What it does
───────────────────────────────────────────────────────────────────────────
Fisher bootstrap First shell only Downloads and installs fisher
Fisher update After bootstrap Installs all fish_plugins entries
Catppuccin Mocha theme First shell only Applies theme via fish_config
paru wrapper Every startup Writes ~/.local/bin/paru wrapper
yay wrapper Every startup Writes ~/.local/bin/yay wrapper
Python venv activation On every cd Sources .venv/bin/activate.fish
WakaTime command hook On every command Reports to WakaTime API</code></pre>
<p>When C2 is disabled: no Fisher install, no theme application, no
paru/yay wrapper generation, no automatic venv activation, and no
WakaTime reporting. The first-run completion marker
(__fish_config_first_run_complete) is still set so the init does not
re-run on subsequent shells.</p>
<p>Python venv activation fires on every directory change. If a
directory uses direnv (.envrc present), direnv takes priority and
auto-venv is skipped for that directory.</p>
<h4 data-number="11.5.1.3" id="c3--key-and-environment-overrides">C3 —
Key and Environment Overrides</h4>
<p>These change fundamental shell behavior: how keys work, which pager
opens, and what the prompt looks like. Disabling
__fish_config_op_overrides removes all of them.</p>
<pre><code>Override What it replaces or sets
───────────────────────────────────────────────────────────────────────────
Vi mode fish_vi_key_bindings replaces default Emacs mode
exit → smart_exit exit wrapper that captures scrollback before closing
PAGER=ov ov used by git, man, and all $PAGER-aware tools
MANPAGER=bat pipeline man pages rendered with syntax highlighting
CDPATH=. ~/projects ~ bare dir names resolve against ~/projects and ~
Bang-bang system ! and $ keys expand history; !^, !*, !-N, !?str?,
^old^new abbreviations; six expand_bang_* helpers
Autopair ( [ { &quot; &#39; auto-close to (), [], {}, &quot;&quot;, &#39;&#39;
Puffer key intercepts . ! $ * keys intercepted for smart expansion
Starship prompt fish_prompt replaced by Starship + OSC 133 markers
Catppuccin colors 30+ fish_color_* variables set to Mocha palette
FZF_DEFAULT_OPTS FZF themed to Catppuccin Mocha colors
Right prompt fish_right_prompt: exit code (on failure) + dim timestamp; always rendered; Docker context added when starship+C3 active</code></pre>
<p>The bang-bang system spans key_bindings.fish, abbr.fish, puffer.fish,
and six expand_bang_*.fish functions. All are gated together — disabling
C3 removes the entire bang-expansion system at once.</p>
<p>When C3 is disabled, <code>exit</code> falls back to
<code>builtin exit</code> with no scrollback capture, no Kitty IPC, and
no file I/O on exit. The scrollback capture block is independently
controlled by C5 (see below).</p>
<h4 data-number="11.5.1.4" id="c4--terminal-and-tool-integration">C4 —
Terminal and Tool Integration</h4>
<p>These features couple the shell to specific external tools. Disabling
__fish_config_op_integrations disables all of them.</p>
<pre><code>Component Requires
───────────────────────────────────────────────────────────────────────────
~60 Kitty/WezTerm abbrs Active Kitty or WezTerm session
(:w, :wv, :wh, :t, etc.)
Done desktop notifications Graphical desktop with a notification daemon
spwin Kitty or WezTerm
tab Kitty, WezTerm, or Konsole
split Kitty or WezTerm
hist fzf + wl-copy (Wayland clipboard)
logs fzf + ov; reads from ~/.terminal_history/
upgrade paru or yay (Arch Linux only)
WakaTime hook wakatime CLI and a configured API key</code></pre>
<p>Disabled integration commands (spwin, tab, split, hist, logs,
upgrade) print a colored error to stderr naming the variable that
disabled them rather than silently failing.</p>
<h4 data-number="11.5.1.5" id="c5--logging-and-capture">C5 — Logging and
Capture</h4>
<p>Three components capture shell output to disk. Disabling
__fish_config_op_logging skips all capture and removes the logging
wrappers.</p>
<pre><code>Component What it captures
───────────────────────────────────────────────────────────────────────────
Scrollback capture Terminal session output saved to:
~/.terminal_history/scrollback_YYYY-MM-DD_HH-MM-SS.log
paru wrapper All paru/AUR output captured to:
~/.terminal_history/paru_YYYY-MM-DD_HH-MM-SS.log
yay wrapper All yay/AUR output captured to:
~/.terminal_history/yay_YYYY-MM-DD_HH-MM-SS.log
Kitty watcher watcher.py captures scrollback when Kitty closes</code></pre>
<p>Logging coordination via sentinel file</p>
<p>C5 uses a sentinel file to synchronize state between the shell and
out-of-process components (the Kitty watcher and all running
shells):</p>
<pre><code>~/.config/fish/.logging_disabled</code></pre>
<p>Disabling __fish_config_op_logging:</p>
<ol type="1">
<li>Creates the sentinel immediately in every open shell.</li>
<li>Removes ~/.local/bin/paru and ~/.local/bin/yay logging wrappers;
bare /usr/bin/paru and /usr/bin/yay are used instead.</li>
<li>Kitty's watcher.py reads the sentinel on each save attempt and skips
capture — no Kitty restart required.</li>
<li>smart_exit stops saving scrollback logs.</li>
</ol>
<p>Re-enabling __fish_config_op_logging:</p>
<ol type="1">
<li>Removes the sentinel in every open shell.</li>
<li>Regenerates paru/yay logging wrappers in ~/.local/bin/.</li>
<li>Kitty watcher resumes capture on the next session exit.</li>
</ol>
<p>Changes propagate to all running shells through an event handler that
fires whenever __fish_config_op_logging changes — no shell restart
needed.</p>
<p>Note: C3 and C5 compose independently. C3 controls whether the
smart_exit wrapper is active at all; C5 controls only the
scrollback-capture block inside it. With C3 disabled, exit is plain
builtin exit regardless of C5.</p>
<h4 data-number="11.5.1.6" id="c6--greeting-and-first-run-ui">C6 —
Greeting and First-Run UI</h4>
<pre><code>Component What it shows
───────────────────────────────────────────────────────────────────────────
First-run welcome banner One-time message on first interactive session
fish_greeting override Empty function defined late in config.fish to
suppress distro greetings (e.g. CachyOS sets
fish_greeting to fastfetch by default)</code></pre>
<p>When C6 is disabled, no greeting is printed by this config. Any
greeting set by the distro or other configs runs normally — this config
simply does not override it.</p>
<h2 data-number="11.6" id="prompt-and-theme">Prompt and Theme</h2>
<h3 data-number="11.6.1" id="starship">Starship</h3>
<p>The primary prompt is Starship, initialized by conf.d/starship.fish.
Configure it via ~/.config/starship.toml.</p>
<p>conf.d/starship.fish defines a fish_prompt wrapper that only
activates when starship is in PATH. It emits OSC 133;A (prompt start)
immediately before Starship renders and OSC 133;B (input start)
immediately after, placing both markers on the prompt line itself. This
allows ov to use them as sticky section headers when browsing scrollback
logs. Without Starship, fish's built-in prompt handles these markers
automatically.</p>
<h3 data-number="11.6.2" id="catppuccin-fallback-prompt">Catppuccin
Fallback Prompt</h3>
<p>When Starship is absent or C3 overrides are disabled, a built-in
nim-style two-line prompt activates from functions/fish_prompt.fish. No
external dependencies — fish builtins only.</p>
<p>Layout:</p>
<pre><code>┬─[user@host:~/path] (main)
╰─&gt;$</code></pre>
<p>Elements:</p>
<pre><code>user Yellow (Catppuccin Yellow); red if root
@host Blue (local) or Teal (SSH)
~/path prompt_pwd abbreviation (Catppuccin Text)
(main) Current git branch in Catppuccin Pink; omitted outside repos
─[V:name] Active Python venv basename; omitted when none
─[N/I/R/V] Vi-mode indicator when vi bindings are active
┬─ / ╰─&gt; Connector lines: Catppuccin Green on success, Red on failure</code></pre>
<p>The right prompt (fish_right_prompt.fish) always renders, regardless
of C3 state. On failure it shows a red ✘ and the exit code; on success
it shows only the dim timestamp. When starship is installed and C3 is
enabled, the active Docker context is also shown (if non-default):</p>
<pre><code>✘ 1 󰡨 myctx Fri Jun 12 00:51:21 2026 ← failed, starship+C3 active
✘ 1 Fri Jun 12 00:51:21 2026 ← failed, fallback prompt
Fri Jun 12 00:51:21 2026 ← success (no ✘)</code></pre>
<h3 data-number="11.6.3" id="fzf">FZF</h3>
<p>FZF is themed to Catppuccin Mocha via FZF_DEFAULT_OPTS set in
integrations/fzf.fish. The colors applied:</p>
<pre><code>Background: #1E1E2E (base) #313244 (surface0)
Foreground: #CDD6F4 (text)
Highlights: #F38BA8 (red) #CBA6F7 (mauve) #B4BEFE (lavender)</code></pre>
<p>To customize, override FZF_DEFAULT_OPTS in local.fish.</p>
<h3 data-number="11.6.4"
id="catppuccin-mocha-syntax-highlighting">Catppuccin Mocha Syntax
Highlighting</h3>
<p>The Catppuccin Mocha theme ships with this config in themes/ and is
applied on first run via <code>conf.d/first_run.fish</code>. Colors are
stored in fish_variables (universal). To switch variants, install a
different theme from themes/:</p>
<pre><code>fish_config theme save &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>
-546
View File
@@ -1,546 +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 is created once on first
run (like an install step) and MANPATH is set each session, enabling 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>
-540
View File
@@ -1,540 +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
autopair.fish Auto-pair brackets and quotes (bundled from jorgebucaran/autopair.fish)
cheat.fish cheat.sh tab 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
logging-events.fish C5 --on-variable event handlers; syncs logging state at startup
paru-wrapper.fish Auto-generates ~/.local/bin/paru logging wrapper
puffer.fish !! / !$ / ./ expansion (bundled from nickeb96/puffer-fish)
sponge_privacy.fish Sponge privacy patterns; filters credentials from history
starship.fish fish_prompt with OSC 133 shell-integration markers
tailscale.fish Tailscale CLI tab completions
theme.fish Catppuccin syntax highlight colors
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
scripts/
clean_progress_log.py Strips paru/yay typescript animations to clean static logs
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>
-589
View File
@@ -1,589 +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/) 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:</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 agy
ag. agy .
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
-898
View File
@@ -1,898 +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#rg" id="toc-rg">rg</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#agy" id="toc-agy">agy</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#agents-init"
id="toc-agents-init">agents-init</a></li>
<li><a href="9-5-functions-reference.html#claude"
id="toc-claude">claude</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#config-toggle"
id="toc-config-toggle">config-toggle</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>
<ul>
<li><a href="11-7-customization.html#component-reference"
id="toc-component-reference">Component Reference</a></li>
</ul></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#catppuccin-fallback-prompt"
id="toc-catppuccin-fallback-prompt">Catppuccin Fallback Prompt</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.
+57
View File
@@ -0,0 +1,57 @@
---
title: Table Of Contents
manTitle: TABLE OF CONTENTS
man: true
site: false
sidebar:
order: 4
---
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. Troubleshooting
11.1 Uninstalling and Reverting to Backup
11.2 Fish Version Requirement
11.3 Enable or Disable Session Logging
11.4 Change or Disable the Greeting
11.5 Secrets and Machine-Local Configuration
11.6 Tool Init Does Nothing (Return Sentinel)
11.7 Missing Dependencies
11.8 Vi Mode Keybindings
11.9 What's with the C1-C6 stuff?
12. Viewing This Manual
---
+155
View File
@@ -0,0 +1,155 @@
---
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 `conf.d/tailscale.fish`.
### 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
**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)
---
title: Key Bindings
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
@@ -40,6 +46,10 @@ are active in Insert, Normal, and Visual modes unless noted.
line to open an fzf picker and insert a selection
at the cursor position.
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)
Ctrl+R Search command history
@@ -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
---
@@ -0,0 +1,10 @@
---
title: System and Monitoring
manTitle: 5.7 System and Monitoring
sidebar:
order: 7
helpKeywords:
- system
---
@@ -0,0 +1,10 @@
---
title: Terminal Management
manTitle: 5.8 Terminal Management
sidebar:
order: 8
helpKeywords:
- terminal-mgmt
---
+10
View File
@@ -0,0 +1,10 @@
---
title: Clipboard
manTitle: 5.9 Clipboard
sidebar:
order: 9
helpKeywords:
- clipboard
---
+10
View File
@@ -0,0 +1,10 @@
---
title: Network
manTitle: 5.10 Network
sidebar:
order: 10
helpKeywords:
- network
---
@@ -0,0 +1,10 @@
---
title: Pager and Logging
manTitle: 5.11 Pager and Logging
sidebar:
order: 11
helpKeywords:
- logging
---
@@ -0,0 +1,10 @@
---
title: AI and Developer Tools
manTitle: 5.12 AI and Developer Tools
sidebar:
order: 12
helpKeywords:
- ai
---
@@ -0,0 +1,10 @@
---
title: Media and Utilities
manTitle: 5.13 Media and Utilities
sidebar:
order: 13
helpKeywords:
- media
---
@@ -0,0 +1,10 @@
---
title: Miscellaneous
manTitle: 5.14 Miscellaneous
sidebar:
order: 14
helpKeywords:
- miscfns
---
+10
View File
@@ -0,0 +1,10 @@
---
title: Functions Reference
manTitle: 5. FUNCTIONS REFERENCE
sidebar:
order: 9
helpKeywords:
- functions
---
+94
View File
@@ -0,0 +1,94 @@
---
title: Dependency Catalog
manTitle: 6. DEPENDENCY CATALOG
sidebar:
order: 10
helpKeywords:
- catalog
- deps-catalog
---
fish-deps manages these tools. Run `fish-deps` to check status,
`fish-deps install` to install missing Required/Recommended ones, or add
`--optional`, `--terminals`, or `--all` to also include the Optional and/or
Terminal Emulators tiers.
## Required
| Tool | Description |
|---|---|
| `fish` | Fish shell >= 4.0 |
| `fzf` | Fuzzy finder |
## Recommended
| Tool | Description |
|---|---|
| `cargo` | Rust toolchain (via rustup); used by `fish-deps` to install Rust-based tools and to build fish from source. All paths are gated on `type -q cargo` and degrade gracefully. |
| `starship` | Cross-shell prompt; loaded via `type -q starship` guard. Without it the Catppuccin nim-style fallback prompt activates. |
| `uv` | Python package and project manager (Astral); used by the fish-from-source build path in `fish-deps`. All consumers degrade gracefully without it. |
| `direnv` | Per-directory environment loading; integration is fully guarded with `type -q direnv`. Without it the direnv hook is simply not loaded and auto-venv activates normally. |
| `paru` | AUR helper (Arch only; preferred); guarded throughout — non-Arch systems silently skip AUR-specific paths. |
| `yay` | AUR helper (Arch only; fallback to paru); same guards apply. |
| `eza` | Modern `ls` replacement |
| `zoxide` | Smart cd with frecency |
| `lsd` | `ls` replacement (fallback to `eza`) |
| `bat` | Syntax-highlighted `cat` |
| `ov` | Modern pager (replaces `less`); also backs the `logs` viewer. Not a Rust crate, despite the name collision with an unrelated `ov` crate on crates.io. Prefers `go install github.com/noborus/ov@latest` when `go` is available (always gets the latest release, and covers distros like Debian/Ubuntu that don't package `ov` in their base repos); falls back to the system PM (AUR on Arch) otherwise. |
| `ripgrep` | Fast line search |
| `trash` | Safe delete (`trash-cli`); backs the `rm` and `scrub` wrappers. |
| `python3` | Standalone interpreter — used by the `paru`/`yay` log cleaner. Note: `uv` does not provide `python3` on PATH, and Arch's base does not include it, so it is listed separately. All consumers degrade gracefully without it. |
## Optional
Single-purpose tools that back one wrapper function (or less) and only
matter if you already use that specific tool. Skipped by
`fish-deps install`/`sync` unless you pass `--optional`.
| Tool | Description |
|---|---|
| `btop` | Modern resource monitor; backs the `top` wrapper (falls back to system `top`). |
| `dust` | Disk usage tree (Rust); one of two backends for the `du` wrapper (falls back to system `du`). |
| `duf` | Disk usage/free overview; the other backend for the `du` wrapper (falls back to system `du`). |
| `prettyping` | Colorized ping wrapper; backs the `ping` wrapper (falls back to system `ping`). |
| `go` | Go toolchain; only used to install `ov` via `go install` (see below), which gets the latest release and doesn't depend on your distro packaging `ov`. Package name varies by distro (`go` on Arch/Homebrew, `golang`/`golang-go` on Debian/Fedora) — install manually if the listed package name doesn't resolve on your system. |
| `lazygit` | Terminal git UI; only referenced by the `lg` abbreviation. |
| `lazydocker` | Terminal docker UI; backs the `ld` wrapper. |
| `docker` | Container runtime; gates the Docker context indicator in the right prompt and backs the `ld` wrapper. Both consumers are guarded with `type -q docker` and degrade gracefully without it. Installing the daemon package does not enable/start the service — do that yourself if you want it running. |
| `yt-dlp` | Video/media downloader; backs the `yt-dlp` wrapper function. The wrapper falls back to the system `yt-dlp` and the rest of the config works without it. |
| `screen` | GNU screen; fallback backend for `jobrunner` when `tmux` is unavailable. |
## Terminal Emulators
GPU-accelerated terminal emulators. Only one is ever relevant to a given
user — the one matching `$TERM` — so neither is installed by default.
Skipped by `fish-deps install`/`sync` unless you pass `--terminals` (or
`--all`).
| Tool | Description |
|---|---|
| `kitty` | GPU-accelerated terminal; unlocks kitty-specific abbreviations and `--hyperlink-format=kitty` in the `rg` wrapper when `$TERM = xterm-kitty`. |
| `wezterm` | GPU-accelerated terminal; unlocks WezTerm-specific abbreviations when it's the active terminal. |
## Integrations
Opt-in third-party services that require their own account/setup.
| Tool | Description |
|---|---|
| `wakatime` | Developer time tracking |
| `tailscale` | Mesh VPN client |
## Install Methods
The install priority for each tool:
| Method | Packages |
|---|---|
| `cargo` | Rust tools (`eza`, `lsd`, `bat`, `dust`, `ripgrep`, `trashy`, `zoxide`, `starship`) — always gets the latest crate version |
| `go install` | `ov` — preferred over the system PM when `go` is available; always gets the latest release |
| system PM | `paru` / `apt` / `brew` / `dnf` / etc. — for tools without a crate or `go install` path |
| `git clone` | `fzf` — installed from GitHub to `~/.fzf/` |
| `curl` | `starship` installer, `fisher` bootstrap, `uv` installer |
---
+225
View File
@@ -0,0 +1,225 @@
---
title: Customization
manTitle: 7. CUSTOMIZATION
sidebar:
order: 11
helpKeywords:
- customization
- customize
---
This section explains how to adapt the configuration to your specific workflow, including local machine overrides and opinionated component toggles.
## Machine-local Configuration
Place machine-specific settings that should not be committed to git in:
$__fish_user_dots_path/local.fish
`__fish_user_dots_path` defaults to `~/.config/.user-dots/fish`. Set a
custom location with:
set -U __fish_user_dots_path /path/to/your/dots/fish
Typical uses: additional PATH entries, local aliases, hostname-specific env
vars, work-specific tool configs.
For convenience, a git-ignored `user-dots` symlink in the fish config
directory tracks `$__fish_user_dots_path` so the overlay can be browsed from
`~/.config/fish/`. It is created if missing and repointed if the path changes.
Opt out by setting `__fish_user_dots_symlink` to a falsy value, or toggling
"Dots link" off on the config-settings Paths page — this stops generation and
removes any existing link. It only ever manages a symlink and never clobbers a
real file or directory at that path.
## Secrets and API Keys
$__fish_user_dots_path/secrets.fish
Store API tokens, GPG keys, private credentials here. This file is never
committed. It is sourced by local.fish directly, not by config.fish.
`local.fish` is sourced at the end of config.fish on every interactive
session, so it and its companion secrets.fish can override anything set
earlier.
## Overriding Configuration Variables
Any variable set in local.fish after the main config loads takes effect.
Example: to increase the scrollback history limit:
# in local.fish
set -gx SCROLLBACK_HISTORY_MAX_FILES 200
## Fish Universal Variables
Some settings (fzf colors, theme) are stored in fish_variables via
`set -U`. These are machine-local and git-ignored. Do not commit
fish_variables.
## Opinionated Components (Minimal Mode)
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 — except for C5 logging, which
is opt-in (see below).
An explicit per-category truthy value takes precedence over the master
switch: setting `__fish_config_opinionated`=0 disables all unset categories,
but a category with an explicit truthy value remains enabled regardless.
C5 (logging) is the one exception to "unset means enabled". Because it
writes terminal output to disk, it is opt-in: unset means disabled, and the
master switch cannot enable it. Only an explicit truthy value turns logging
on.
Variable Disables
────────────────────────────────────────
__fish_config_op_aliases Command shadows and flag injection:
ls->eza, cat->bat, cd->zoxide,
rm->trash, less->ov, top->btop,
ping->prettyping, ssh->kitten,
du->duf/dust, mkdir/bash wrappers,
history timestamps, grep/cp/mv/wget
flag injection, help intercept, claude
AGENTS.md auto-link
__fish_config_op_autoexec Startup side-effects: Fisher
bootstrap, theme apply, paru/yay
wrapper generation, auto venv
activation, WakaTime hook
__fish_config_op_overrides Key and env overrides: Vi mode,
exit->smart_exit, PAGER/MANPAGER,
CDPATH, bang-bang system, autopair,
puffer, starship prompt, theme
colors, FZF_DEFAULT_OPTS, right
prompt
__fish_config_op_integrations Terminal/tool coupling: Kitty/
WezTerm window abbreviations, done
notifications, spwin/tab/split,
hist, logs, upgrade, WakaTime
__fish_config_op_logging Logging & capture (OPT-IN — this one
is off unless explicitly enabled):
scrollback capture on exit, paru/yay
AUR log wrappers, Kitty watcher
capture; sentinel file coordinates
cross-process state
__fish_config_op_greeting Greeting & first-run UI: per-session
fish_greeting override (defines empty
function late in config.fish to
suppress distro greetings such as
CachyOS fastfetch); first-run welcome
banner in conf.d/first_run.fish
Examples:
# Disable command shadows only (rm becomes plain rm again):
set -U __fish_config_op_aliases off
# Turn session logging on (opt-in; off until you do this):
set -U __fish_config_op_logging on
# Full minimal mode — disable all six categories at once:
set -U __fish_config_opinionated 0
# Re-enable everything (except C5 logging, which stays opt-in):
set -Ue __fish_config_opinionated
# Minimal mode but keep the greeting:
set -U __fish_config_opinionated 0
set -U __fish_config_op_greeting 1
# (erase both to go back to full-flavor defaults)
For an interactive alternative to setting these variables by hand, run
config-settings — a full-screen TUI that flips any category (including C5
logging) on or off, per session or universally. See its entry in Section 5.
NOTE:
- Command shadows (rm, cat, ls, ...) react immediately; conf.d-level components (bindings, prompt, abbreviations, hooks) take effect in new shells.
- With aliases disabled, rm falls back to bare `command rm` — files are deleted permanently, not trashed.
- Disabled integration commands (spwin, tab, split, hist, logs, upgrade) print an error naming the variable that disabled them.
- On CachyOS, the distro fish config's own aliases, history override, and bang-bang bindings are stripped per category as well.
### Sub-categories
Each of the six categories further sub-divides into two to six
sub-categories, each with its own `__fish_config_op_<category>_<subcategory>`
variable (e.g. `__fish_config_op_aliases_filesystem`). These follow the
exact same truthy/falsy/unset cascade one level deeper: an explicit
sub-category value overrides the master switch and the parent category's
setting, and an unset sub-category inherits from its parent category (which
in turn inherits from `__fish_config_opinionated`). Run config-settings and
press Enter on a category row to browse and toggle its sub-categories
interactively. See [Components Reference](/08-components-reference/) for the
full sub-category breakdown of every category.
## Prompt and Theme
### Starship
The primary prompt is Starship, initialized by conf.d/starship.fish.
Configure it via ~/.config/starship.toml.
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.
### Catppuccin Fallback Prompt
When Starship is absent or C3 overrides are disabled, a built-in nim-style
two-line prompt activates from functions/fish_prompt.fish. No external
dependencies — fish builtins only.
Layout:
┬─[user@host:~/path] (main)
╰─>$
Elements:
user Yellow (Catppuccin Yellow); red if root
@host Blue (local) or Teal (SSH)
~/path prompt_pwd abbreviation (Catppuccin Text)
(main) Current git branch in Catppuccin Pink; omitted outside repos
─[V:name] Active Python venv basename; omitted when none
─[N/I/R/V] Vi-mode indicator when vi bindings are active
┬─ / ╰─> Connector lines: Catppuccin Green on success, Red on failure
The right prompt (fish_right_prompt.fish) always renders, regardless of C3
state. On failure it shows a red ✘ and the exit code; on success it shows
only the dim timestamp. When starship is installed and C3 is enabled, the
active Docker context is also shown (if non-default):
✘ 1 󰡨 myctx Fri Jun 12 00:51:21 2026 ← failed, starship+C3 active
✘ 1 Fri Jun 12 00:51:21 2026 ← failed, fallback prompt
Fri Jun 12 00:51:21 2026 ← success (no ✘)
### FZF
FZF is themed to Catppuccin Mocha via FZF_DEFAULT_OPTS set in
integrations/fzf.fish. The colors applied:
Background: #1E1E2E (base) #313244 (surface0)
Foreground: #CDD6F4 (text)
Highlights: #F38BA8 (red) #CBA6F7 (mauve) #B4BEFE (lavender)
To customize, override FZF_DEFAULT_OPTS in local.fish.
### Catppuccin Mocha Syntax Highlighting
The Catppuccin Mocha theme ships with this config in themes/ and is applied
on first run via `conf.d/first_run.fish`. Colors are stored in fish_variables
(universal). To switch variants, install a different theme from themes/:
fish_config theme save "Catppuccin Latte"
`---`
@@ -0,0 +1,65 @@
---
title: C1 — Command Shadows
---
Disabling `__fish_config_op_aliases` restores standard system behavior for
all of these commands.
Command / Alias Active behavior Disabled fallback
───────────────────────────────────────────────────────────────────────────
ls eza -l -a --icons --hyperlink system ls
cat bat syntax-highlighted; dirs → ls /usr/bin/cat
cd zoxide frecency-based navigation fish builtin cd
rm moves files to trash (recoverable) command rm (permanent)
less $PAGER → ov → less → more → cat system less
du duf (disk overview) or dust (dir tree) system du
top btop resource monitor system top
ping prettyping --nolegend animation system ping
ssh kitten ssh in Kitty terminal system ssh
rg rg --hyperlink-format=kitty system rg
mkdir verbose path-tree display on creation mkdir -p silently
bash XDG bashrc + $SHELL reset on exit system bash
history timestamps prepended to every entry fish builtin history
cp / mv forced -i confirmation prompt cp / mv unmodified
wget forced --continue (resume downloads) system wget
grep/fgrep/egrep forced --color=auto system grep variants
dir / vdir forced --color=auto system dir / vdir
help config intercepts "help config" → config-help fish builtin help
claude auto-links AGENTS.md as CLAUDE.md before launch command claude
edit multi-editor launcher (GUI/term + fallbacks) $EDITOR/nvim/nano/vi
When C1 is disabled, `rm` uses bare `command rm` with no wrapper — files
are permanently deleted, not trashed. There is no intermediate safety net.
## Sub-categories
`__fish_config_op_aliases` sub-divides into six sub-categories, each with
its own `__fish_config_op_aliases_<slug>` toggle:
## filesystem
`ls`, `cat`, `cd`, `du`, `mkdir`, `rm`, `mv`, and `cd`/zoxide navigation --
the everyday filesystem-inspection and -modification shadows.
## search
`rg`, with its Kitty hyperlink formatting.
## network
`ping`, `ssh`, and `yt-dlp` -- shadows that talk to the network.
## monitor
`top` -> `btop`.
## shell-tools
`bash` (XDG bashrc + `$SHELL` reset), `less` (`$PAGER` fallback chain),
and the `help config` interception.
## dev-tools
`claude` (AGENTS.md/CLAUDE.md auto-linking) and `edit` (multi-editor
launcher), plus `agy`.
@@ -0,0 +1,70 @@
---
title: C2 — Startup Side-Effects
---
These run automatically without any user action. Disabling
`__fish_config_op_autoexec` prevents all of them.
Component Trigger What it does
───────────────────────────────────────────────────────────────────────────
Fisher bootstrap First shell only Downloads and installs fisher
Fisher update After bootstrap Installs all fish_plugins entries
Catppuccin Mocha theme First shell only Applies theme via fish_config
paru wrapper Every startup Writes ~/.local/bin/paru wrapper
yay wrapper Every startup Writes ~/.local/bin/yay wrapper
Python venv activation On every cd Sources .venv/bin/activate.fish
WakaTime command hook On every command Reports to WakaTime API
Auto-pull fast-forward On entering a repo Background ff-only git pull
user-dots symlink Every startup Links $__fish_config_dir/user-dots
to $__fish_user_dots_path
When C2 is disabled: no Fisher install, no theme application, no paru/yay
wrapper generation, no automatic venv activation, no WakaTime reporting,
no auto-pull (the PWD handler is never registered), and the user-dots
convenience symlink is not created. The symlink is git-ignored and only ever
managed as a symlink — a real file or directory at that path is left untouched.
The symlink has its own opt-out independent of C2: set `__fish_user_dots_symlink`
to a falsy value (or toggle "Dots link" off on the config-settings Paths page)
to stop generating it and remove any existing link — honoured even when C2 is
enabled. Managed by the `__fish_user_dots_link` helper.
The first-run completion marker (`__fish_config_first_run_complete`) is still
set so the init does not re-run on subsequent shells.
Python venv activation fires on every directory change. If a directory uses
direnv (`.envrc` present), direnv takes priority and auto-venv is skipped for
that directory.
Auto-pull fast-forwards opted-in repositories in the background when you cd
into them. The fish-config repo is always covered; other repos are added with
the `auto-pull` command (see its entry in the functions reference). It only
ever fast-forwards a clean repo whose branch has an upstream — never rebases,
merges, or overwrites work — so it is a no-op on dirty trees, divergent
branches, or repos without a remote. The handler fires once per repo entry
(not on every sub-directory `cd`). The registry is machine-local at
`$__fish_user_dots_path/auto-pull.list` (defaults to `~/.config/.user-dots/fish/auto-pull.list`) and is never committed.
## Sub-categories
`__fish_config_op_autoexec` sub-divides into five sub-categories, each
with its own `__fish_config_op_autoexec_<slug>` toggle:
## plugin-management
Fisher bootstrap on first run.
## pkg-wrappers
`paru`/`yay` wrapper generation.
## venv
Automatic Python virtualenv activation.
## telemetry
The WakaTime hook's startup bootstrap.
## sync
Auto-pull background fast-forward, and the user-dots convenience symlink.
@@ -0,0 +1,55 @@
---
title: C3 — Key and Environment Overrides
---
These change fundamental shell behavior: how keys work, which pager opens,
and what the prompt looks like. Disabling `__fish_config_op_overrides` removes
all of them.
Override What it replaces or sets
───────────────────────────────────────────────────────────────────────────
Vi mode fish_vi_key_bindings replaces default Emacs mode
PATH setup Prepends custom bin directories to the PATH
exit → smart_exit exit wrapper that captures scrollback before closing
PAGER=ov ov used by git, man, and all $PAGER-aware tools
EDITOR=nvim nvim fallback to vi for git commit, etc.
GPG_TTY Sets GPG_TTY to current terminal tty
MANPAGER=bat pipeline man pages rendered with syntax highlighting
CDPATH=. ~/projects ~ bare dir names resolve against ~/projects and ~
Bang-bang system ! and $ keys expand history; !^, !*, !-N, !?str?,
^old^new abbreviations; six expand_bang_* helpers
Autopair ( [ { " ' auto-close to (), [], {}, "", ''
Puffer key intercepts . ! $ * keys intercepted for smart expansion
Starship prompt fish_prompt replaced by Starship + OSC 133 markers
Catppuccin colors 30+ fish_color_* variables set to Mocha palette
FZF_DEFAULT_OPTS FZF themed to Catppuccin Mocha colors
Right prompt fish_right_prompt: exit code (on failure) + dim timestamp; always rendered; Docker context added when starship+C3 active
The bang-bang system spans `key_bindings.fish`, `abbr.fish`, `puffer.fish`, and
six `expand_bang_*.fish` functions. All are gated together — disabling C3
removes the entire bang-expansion system at once.
When C3 is disabled, `exit` falls back to `builtin exit` with no scrollback
capture, no Kitty IPC, and no file I/O on exit. The scrollback capture block
is independently controlled by C5 (see below).
## Sub-categories
`__fish_config_op_overrides` sub-divides into three sub-categories, each
with its own `__fish_config_op_overrides_<slug>` toggle:
## key-bindings
Vi mode, autopair, puffer key intercepts, bang-bang history expansion,
and `smart_exit`'s plain-exit path.
## environment
`$PATH`, `$PAGER`/`$EDITOR`/`$GPG_TTY`, and `$CDPATH`.
## prompt
Starship, the right prompt, Catppuccin syntax/prompt colors, and FZF
theming (`$FZF_DEFAULT_OPTS`) -- all driven by the same guard as a single
unit, not independently toggleable from each other.
@@ -0,0 +1,49 @@
---
title: C4 — Terminal and Tool Integration
---
These features couple the shell to specific external tools. Disabling
`__fish_config_op_integrations` disables all of them.
Component Requires
───────────────────────────────────────────────────────────────────────────
≈ 60 Kitty/WezTerm abbrs Active Kitty or WezTerm session
(:w, :wv, :wh, :t, etc.)
Done desktop notifications Graphical desktop with a notification daemon
spwin Kitty or WezTerm
tab Kitty, WezTerm, or Konsole
split Kitty or WezTerm
hist fzf + wl-copy (Wayland clipboard)
logs fzf + ov; reads from ~/.terminal_history/
upgrade paru or yay (Arch Linux only)
WakaTime hook wakatime CLI and a configured API key
Disabled integration commands (`spwin`, `tab`, `split`, `hist`, `logs`, `upgrade`) print
a colored error to stderr naming the variable that disabled them rather than
silently failing.
## Sub-categories
`__fish_config_op_integrations` sub-divides into five sub-categories,
each with its own `__fish_config_op_integrations_<slug>` toggle:
## terminal-abbrs
The Kitty/WezTerm abbreviation set.
## window-mgmt
`spwin`, `tab`, `split`.
## notifications
`done`'s completion notifications, and the WakaTime activity hook.
## history-logs
`hist`, `logs`.
## pkg-upgrade
`upgrade`.
@@ -0,0 +1,133 @@
---
title: C5 — Logging and Capture
---
Five components capture shell output to disk. Unlike every other category,
C5 is opt-in: it stays off until `__fish_config_op_logging` is set to an
explicit truthy value, and a truthy master switch does not enable it. While
it is off, all capture is skipped and the logging wrappers are removed.
CAUTION: This configuration is capable of silently recording terminal output and secrets directly to disk. See below for details on how this capture mechanism works, where files are stored, and how to manage its state.
# Turn it on (persistently, in every shell):
set -U __fish_config_op_logging on
# Turn it back off:
set -U __fish_config_op_logging off # or: set -Ue __fish_config_op_logging
Component What it captures
───────────────────────────────────────────────────────────────────────────
Scrollback capture Terminal session output saved to:
`~/.terminal_history/scrollback_YYYY-MM-DD_HH-MM-SS.log`
tmux pane capture Continuous pane stream via pipe-pane, saved to:
`~/.terminal_history/tmux_<session>-w<win>-p<pane>_YYYY-MM-DD_HH-MM-SS.log`
zellij pane capture Pane scrollback snapshot on shell exit, saved to:
`~/.terminal_history/zellij_<session>-p<pane>_YYYY-MM-DD_HH-MM-SS.log`
paru wrapper All paru/AUR output captured to:
`~/.terminal_history/paru_YYYY-MM-DD_HH-MM-SS.log`
yay wrapper All yay/AUR output captured to:
`~/.terminal_history/yay_YYYY-MM-DD_HH-MM-SS.log`
Kitty watcher `watcher.py` captures scrollback when Kitty closes
NOTE: **Turning off logging does not delete any existing logs.**
They remain in `$SCROLLBACK_HISTORY_DIR` (defaults to: `~/.terminal_history/`)
until you remove them manually.
The tmux capture starts automatically when fish launches inside any tmux
pane (`$TMUX` is set). It uses tmux's native pipe-pane to stream all pane
output directly to disk without an intermediate process. Each fish shell
session gets its own log file; a new log is created on each shell start
(including exec fish and new splits). Before each new log, the oldest
`tmux_*.log` files are pruned (by modification time) to keep the total within
`SCROLLBACK_HISTORY_MAX_FILES`, matching the paru/yay wrapper behaviour.
The zellij capture works differently: Zellij has no live output-streaming
facility like pipe-pane, so the log is taken as a one-shot snapshot when the
shell exits, via `zellij action dump-screen --full --ansi` (the `--ansi` flag
preserves color). The dump is captured on the fish process's stdout and
written to the log file by fish itself (not via `--path`, which would make the
zellij server write the file). A fish_exit handler (registered whenever
`$ZELLIJ` is set) writes the pane's full scrollback and then prunes old
`zellij_*.log` files the same way. Because the capture happens at exit, toggling
`__fish_config_op_logging` takes effect on the next exit with no restart or
sentinel coordination needed — the C5 guard is re-checked when the handler
fires.
LIMITATION — zellij capture only fires on a clean shell exit (typing `exit`,
Ctrl-D, or a logout), because that is when the fish_exit handler runs. It does
NOT capture when you close a pane or quit zellij through zellij itself:
- Closing a pane signals the shell and tears the pane down concurrently, so
even if the handler runs, `dump-screen` may find the pane buffer already
gone.
- Quitting zellij kills the zellij server, and `dump-screen` needs a live
server to read from — there is nothing left to snapshot.
This is a structural difference from tmux, NOT a bug. tmux streams pane output
to disk continuously via pipe-pane, so whatever was printed is already saved
no matter how the pane dies. Zellij can only snapshot, and the only reliable
snapshot point from the shell is a clean exit. To guarantee a zellij pane is
logged, end the session with `exit` or Ctrl-D rather than zellij's close-pane
or quit actions.
The Kitty watcher is managed by the kitty-logging command: it symlinks the
watcher (`fish-config-watcher.py`) into the Kitty config directory and wires it
into `kitty.conf` via a managed block. Inside Kitty, a non-blocking
per-session reminder points first-time users at `kitty-logging install` until
they install or run `kitty-logging dismiss`; the reminder is itself gated on
C5, so it stays silent until you enable logging. Install affects new Kitty
windows only; runtime disable is still handled by the `.logging_disabled`
sentinel.
Logging coordination via sentinel file
C5 uses a sentinel file to synchronize state between the shell and
out-of-process components (the Kitty watcher and all running shells):
~/.config/fish/.logging_disabled
Because C5 is off by default, the sentinel is present on a fresh install —
the startup sync in `conf.d/logging-events.fish` reconciles it on every shell
start, so it appears without any action on your part.
Disabling `__fish_config_op_logging` (or leaving it unset):
1. Creates the sentinel immediately in every open shell.
2. Removes `~/.local/bin/paru` and `~/.local/bin/yay` logging wrappers;
bare `/usr/bin/paru` and `/usr/bin/yay` are used instead.
3. Kitty's `watcher.py` reads the sentinel on each save attempt and
skips capture — no Kitty restart required.
4. smart_exit stops saving scrollback logs.
5. Stops `tmux pipe-pane` capture in every open fish shell inside tmux.
Enabling `__fish_config_op_logging`:
1. Removes the sentinel in every open shell.
2. Regenerates paru/yay logging wrappers in `~/.local/bin/`.
3. Kitty watcher resumes capture on the next session exit.
4. Restarts tmux pipe-pane capture in every open fish shell inside tmux.
Changes propagate to all running shells through an event handler that fires
whenever `__fish_config_op_logging` changes — no shell restart needed.
Note: C3 and C5 compose independently. C3 controls whether the smart_exit
wrapper is active at all; C5 controls only the scrollback-capture block
inside it. With C3 disabled, exit is plain builtin exit regardless of C5.
## Sub-categories
`__fish_config_op_logging` sub-divides into three sub-categories, each
with its own `__fish_config_op_logging_<slug>` toggle (all still opt-in
by default, inherited from C5's own opt-in behavior -- see §3 of the
design spec):
## terminal-capture
Kitty watcher scrollback capture, and `smart_exit`'s logging-guard path.
## multiplexer-capture
tmux `pipe-pane` and zellij `dump-screen` capture.
## pkg-logs
`paru`/`yay` AUR log wrappers.
@@ -0,0 +1,28 @@
---
title: C6 — Greeting and First-Run UI
---
Component What it shows
───────────────────────────────────────────────────────────────────────────
First-run welcome banner One-time message on first interactive session
fish_greeting override Empty function defined late in config.fish to
suppress distro greetings (e.g. CachyOS sets
fish_greeting to fastfetch by default)
When C6 is disabled, no greeting is printed by this config. Any greeting
set by the distro or other configs runs normally — this config simply does
not override it.
## Sub-categories
`__fish_config_op_greeting` sub-divides into two sub-categories, each
with its own `__fish_config_op_greeting_<slug>` toggle:
## first-run
The first-run welcome banner.
## greeting-message
The per-session `fish_greeting` override.

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