Compare commits

...

552 Commits

Author SHA1 Message Date
Gitea Actions fc420fad72 chore(docs): regenerate manual and man page 2026-08-06 20:32:45 +00:00
rootiest dfdc1063ba Merge pull request 'docs(manual): format plugins and installation pages' (#100) from docs-format-plugins-installation into main
Generate documentation / build-docs (push) Successful in 3m32s
Reviewed-on: #100
2026-08-06 20:29:18 +00:00
rootiest 4ff120cc5d docs(manual): format plugins and installation pages 2026-08-06 16:28:13 -04:00
Gitea Actions 7c99b475e3 chore(docs): regenerate manual and man page 2026-08-06 20:14:19 +00:00
rootiest 262b53c6c4 Merge pull request 'docs: dynamic abbreviations with markdown tables' (#99) from feature/dynamic-abbreviations-docs into main
Generate documentation / build-docs (push) Successful in 3m30s
Reviewed-on: #99
2026-08-06 20:10:55 +00:00
rootiest 0ff6be3f81 Merge branch 'main' into feature/dynamic-abbreviations-docs 2026-08-06 20:10:18 +00:00
rootiest 86d20105e5 ci: move workflow to .github to increase hosting compatibility 2026-08-06 16:09:57 -04:00
rootiest 6790bf1430 ci: remove obsoleted docs-drift workflow 2026-08-06 16:09:28 -04:00
rootiest e76668d3b1 docs: fix abbreviations file ordering and capitalization for tests 2026-08-06 16:07:08 -04:00
rootiest 204b13781d docs: use indented text tables for abbreviations and strip CardGrid from concat 2026-08-06 16:00:48 -04:00
Gitea Actions 0b9cf5a928 chore(docs): regenerate manual and man page 2026-08-06 19:48:00 +00:00
rootiest 93831564a8 Merge pull request 'feat: implement __rand_string generator and update jobrunner backend' (#98) from feature/rand-string-generator into main
Generate documentation / build-docs (push) Successful in 3m44s
Offline docs drift reminder / remind (push) Successful in 15s
Reviewed-on: #98
2026-08-06 19:44:25 +00:00
rootiest 82d761b026 docs: restructure abbreviations into individual pages for sidebar 2026-08-06 15:38:15 -04:00
rootiest 742fd7941d docs: use markdown tables for abbreviations
Generates actual markdown tables instead of indented text blocks to ensure MDX/Starlight correctly renders abbreviations.
2026-08-06 15:04:06 -04:00
rootiest cb74cd84e2 fix: change jobrunner auto-naming to adjective-animal 2026-08-02 05:47:29 -04:00
rootiest 89fdfc8e72 refactor: use -n flag for explicit jobrunner names 2026-08-02 05:45:35 -04:00
rootiest 0e9c3b4b27 feat: implement jobrunner auto-naming fallback 2026-08-02 05:41:48 -04:00
rootiest d5535a38ad feat: add verb dictionary and preserve literal string casing in rand_string 2026-08-02 05:37:06 -04:00
rootiest 01553b71fd refactor: drop __ prefix and add -h flag to rand_string 2026-08-02 05:32:33 -04:00
rootiest ffff95f3b9 feat: implement __rand_string generator and update jobrunner to use tmux 2026-08-02 05:21:29 -04:00
rootiest 674a50ea05 feat(jobrunner): add named background job manager backed by GNU screen
Adds jobrunner (short alias jr) for running, listing, inspecting,
re-attaching to, and terminating detached background tasks. Unlike bkg
and detach, which discard output, a jobrunner job keeps a live terminal
that survives closing the shell and can be restored later with attach.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

- Add per-category component tables (C1–C6) under a new "Component
  Reference" subsection in "Opinionated Components (Minimal Mode)"
- Document the C5 sentinel-file coordination mechanism and how
  __fish_config_logging_changed propagates changes to all open shells
- Document C3/C5 composition (smart_exit wrapper vs capture block)
- Document bang-bang system atomicity across its multiple source files
- Add rg function entry to Section 5.1 (Kitty hyperlink wrapper)
- Update fish-config.index with keywords for all new headings
2026-06-10 23:36:24 -04:00
Gitea Actions e4bcbd3da2 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-11 03:10:26 +00:00
rootiest 4bef8f9c91 Merge pull request 'feat(guards): per-category variable overrides master in __fish_config_op_enabled' (#41) from feat/per-category-master-override into main
Generate documentation / build-docs (push) Successful in 34s
Offline docs drift reminder / remind (push) Successful in 10s
Reviewed-on: #41
2026-06-11 03:09:51 +00:00
rootiest e776e7fba6 docs(guards): document per-category master override in fish-config.md 2026-06-10 23:02:16 -04:00
rootiest a170d82086 docs(guards): document per-category master override in README Minimal Mode 2026-06-10 23:00:23 -04:00
rootiest c04c1a4bc2 docs(guards): fold no-arg edge case into RETURNS status-1 line 2026-06-10 22:59:49 -04:00
rootiest 4c989a45c1 refactor(guards): remove what-comments; document no-arg edge case in RETURNS 2026-06-10 22:59:11 -04:00
rootiest cccef17031 feat(guards): category variable overrides master in __fish_config_op_enabled 2026-06-10 22:57:01 -04:00
Gitea Actions b0debaa421 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-11 02:48:40 +00:00
rootiest 6edeb5bdd1 Merge pull request 'feat(greeting): add C6 — Greeting & First-Run UI opinionated guard' (#40) from feat/greeting-toggle-c6 into main
Generate documentation / build-docs (push) Successful in 35s
Offline docs drift reminder / remind (push) Successful in 11s
Reviewed-on: #40
2026-06-11 02:48:05 +00:00
rootiest b64e7d4f3c docs(greeting): note C6 guard on first-run welcome in Fisher Plugins section 2026-06-10 22:42:34 -04:00
rootiest 251f512806 docs(greeting): fix remaining five→six count in fish-config.md Minimal Mode 2026-06-10 22:35:31 -04:00
rootiest 43135aef02 docs(greeting): add C6 __fish_config_op_greeting to fish-config.md Minimal Mode 2026-06-10 22:34:46 -04:00
rootiest c909a4f054 docs(greeting): add C6 __fish_config_op_greeting to README Minimal Mode 2026-06-10 22:33:55 -04:00
rootiest 5394a6d494 docs(greeting): add C5 and C6 to __fish_config_op_enabled ARGUMENTS docstring 2026-06-10 22:30:26 -04:00
rootiest c9ac952553 feat(greeting): add late-running C6 fish_greeting override to config.fish 2026-06-10 22:27:00 -04:00
rootiest 85be47582b feat(greeting): add C6 greeting guard to first_run.fish welcome message 2026-06-10 22:25:10 -04:00
Gitea Actions 8de2cf229b chore(docs): regenerate man page, HTML docs, and wiki 2026-06-11 02:05:41 +00:00
rootiest 0cced863f8 Merge pull request 'feat(logging): add C5 — Logging & Capture opinionated guard' (#39) from feat/logging-toggle-c5 into main
Generate documentation / build-docs (push) Successful in 32s
Offline docs drift reminder / remind (push) Successful in 10s
Reviewed-on: #39
2026-06-11 02:05:06 +00:00
rootiest 7fcf268fc7 fix(logging): suppress Kitty watcher capture when C5 logging is disabled
When smart_exit skips fish-side capture due to the C5 guard, it now sets
logged_by_shell=true on the Kitty window before calling builtin exit. This
prevents watcher.py's on_close handler from capturing the scrollback even
if the sentinel file is absent, providing a second layer of protection.

Also restructures the capture block to be flat (no wrapper if-true) after
the early-exit guard.
2026-06-10 21:59:52 -04:00
rootiest 76349ad94b fix(logging): register C5 event handlers in conf.d for reliable startup
--on-variable handlers in functions/ are only autoloaded on explicit call,
so they never fire when a universal variable changes. Moving the definitions
to conf.d/logging-events.fish ensures they are registered at shell init.

Also adds a startup __fish_config_sync_logging call so pre-set variable
values (e.g. set before this shell was opened) take effect immediately
without requiring a re-set.
2026-06-10 21:54:56 -04:00
rootiest eb1b780a80 docs(logging): add C5 logging toggle to Minimal Mode in README 2026-06-10 21:49:47 -04:00
rootiest 2ce41d0c55 docs(logging): fix 'four' → 'five' category count in fish-config.md prose 2026-06-10 21:46:14 -04:00
rootiest e30ccbc633 docs(logging): document C5 logging guard in fish-config.md
Add __fish_config_op_logging (C5 — Logging & Capture) to the opinionated
components variable table and update the master-disable example comment
from "four categories" to "five categories".

AGENTS.md and opinionated_catalog.md are git-ignored per project policy;
those files were updated on disk but cannot be tracked in this repo.
2026-06-10 21:43:46 -04:00
rootiest 7e266cb61a feat(logging): gate paru/yay wrapper generation under C5 guard (Tasks 5-6)
Add C5 (Logging & Capture) guard to wrapper generation in both
conf.d/paru-wrapper.fish and conf.d/yay-wrapper.fish. When C5 logging
is disabled, the guard removes any generated wrapper and returns early,
allowing the system to fall back to the bare binary.

Also replaces stale Task #4 comment references with C5 classification.
2026-06-10 21:33:54 -04:00
rootiest be3dd7494e feat(logging): gate scrollback capture in smart_exit under C5 guard 2026-06-10 21:29:52 -04:00
rootiest 0382d6ab9c feat(logging): add C5 --on-variable event handlers for real-time sync 2026-06-10 21:28:13 -04:00
rootiest f17229d0b8 feat(logging): add __fish_config_sync_logging shared C5 state sync 2026-06-10 21:26:40 -04:00
rootiest 621d67e89e chore(logging): add .logging_disabled sentinel to .gitignore 2026-06-10 21:20:54 -04:00
Gitea Actions f9ba0e20ea chore(docs): regenerate man page, HTML docs, and wiki 2026-06-10 15:43:37 +00:00
rootiest 6d15701ad4 Merge pull request 'feat(guards): opinionated components guard (Task #3)' (#38) from opinionated-components-guard into main
Generate documentation / build-docs (push) Successful in 37s
Offline docs drift reminder / remind (push) Successful in 10s
Reviewed-on: #38
2026-06-10 15:42:58 +00:00
rootiest e30fc7a15c docs(config-vars): cross-reference minimal mode from Section 1 Other 2026-06-10 11:41:04 -04:00
rootiest 7bd080769e docs(guards): document opinionated component toggles
Adds 'Opinionated Components (Minimal Mode)' to docs/fish-config.md
with index keywords (opinionated, minimal, minimal-mode, opt-out,
toggles) and a Minimal Mode section with toggle table to README.md.
AGENTS.md Task #3 checklist ticked locally (file is git-ignored).
2026-06-10 11:38:14 -04:00
rootiest dc97892a29 feat(guards): add in-function opinionated guards and CachyOS cleanup
C1 shadows (rm, cat, ls, less, du, bash, top, ping, ssh, rg, mkdir,
help) fall back to the bare command when __fish_config_op_aliases is
falsy; rm falls back to exact 'command rm' with no wrapper. C2 gates
the auto-venv PWD hook. C3 gates smart_exit (composing with Task #4
logging), fish_right_prompt, and all six expand_bang_*/expand_typo_sub
functions atomically with the bang-bang system. C4 integration commands
(spwin, tab, split, hist, logs, upgrade) refuse with a colored stderr
error when disabled. config.fish now also strips the CachyOS distro
config's own bang-bang bindings, history override, and alias opinions
per category, restoring fish stock functions where they exist.
2026-06-10 11:34:56 -04:00
rootiest ce84db593c feat(guards): add opinionated component guards to config.fish and conf.d
Adds __fish_config_op_enabled helper (master __fish_config_opinionated
evaluated first via __fish_variable_check, then the category variable)
and gates C1-C4 components: CachyOS surgical override, PAGER/MANPAGER,
CDPATH, Vi mode, exit override, bang-bang bindings, history/cp/mv/wget/
grep aliases, cd->z alias, Fisher bootstrap and theme apply, paru/yay
wrapper generation, WakaTime hook, custom key chords, puffer, autopair,
starship prompt, Catppuccin colors, FZF_DEFAULT_OPTS, done notifications,
and Kitty/WezTerm window-management abbreviations.
2026-06-10 11:28:43 -04:00
rootiest cdf850f2e7 fix(config-help): quote +/pattern in MANPAGER to prevent word-splitting on spaces 2026-06-08 23:18:31 -04:00
rootiest c5d6e35afc fix(config-help): add -- separator before -+ regex pattern in string replace 2026-06-08 23:16:44 -04:00
Gitea Actions 17dcc99fc2 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-09 03:15:49 +00:00
rootiest 831c7beb4d feat(config-help): add section linking for HTML and man page
Generate documentation / build-docs (push) Successful in 30s
Offline docs drift reminder / remind (push) Successful in 10s
- Section keyword is now extracted early and shared across all three
  output modes (pager, HTML, man) rather than duplicated per branch
- --html with a section keyword resolves the heading to a pandoc anchor
  ID and looks it up in docs/html/sitemap.json; handles both sub-section
  fragment paths and top-level sections that are their own page
- --man with a section keyword overrides MANPAGER to `less +/pattern`
  so the page opens at the nearest heading match
- --help output updated to show [section] in USAGE and section+flag
  examples (help config keybindings --html, help config pkg --man)
- docs/fish-config.md §5.14 synopsis, flags, and examples updated
- docs/fish-config.md §11 "Viewing" sections updated for both HTML and
  man page to document the section+flag invocation
- README table updated with section+html and section+man rows
2026-06-08 23:15:17 -04:00
Gitea Actions f4157fb4ba chore(docs): regenerate man page, HTML docs, and wiki 2026-06-09 03:05:21 +00:00
rootiest 79f8445e25 docs(help): prefer help config syntax; add NOTES to config-help doc block
Generate documentation / build-docs (push) Successful in 35s
Offline docs drift reminder / remind (push) Successful in 10s
- help.fish: expand SYNOPSIS/DESCRIPTION to document -w/--html, -m/--man,
  -h/--help flags; note flags are only intercepted when 'config' is argv[1]
- config-help.fish: add # NOTES section explaining help config as the
  preferred invocation; update --help banner to show both names; update
  --help USAGE/EXAMPLES output to use `help config` syntax throughout
- docs/fish-config.md: update §5.14 synopsis/examples and "Viewing" sections
  to use `help config` as primary form; inline note for direct config-help use
- README.md: update docs table to show `help config --html` / `--man`
2026-06-08 23:04:39 -04:00
Gitea Actions e86b537f6d chore(docs): regenerate man page, HTML docs, and wiki 2026-06-09 02:38:35 +00:00
rootiest 23e2f43447 docs: add sponge_privacy.fish to conf.d listing in fish-config.md
Generate documentation / build-docs (push) Successful in 30s
2026-06-08 22:38:03 -04:00
Gitea Actions 32630443a8 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-09 02:32:06 +00:00
rootiest 21126012dc Merge pull request 'docs(fisher): clarify bundled vs fisher-managed plugins; add sponge' (#37) from docs/fisher-plugins-bundled into main
Generate documentation / build-docs (push) Successful in 37s
Offline docs drift reminder / remind (push) Successful in 12s
Reviewed-on: #37
2026-06-09 02:31:31 +00:00
rootiest 13eb93ce12 fix(sponge): escape leading -- in auth-flag pattern; purge stale -- patterns on load 2026-06-08 22:29:20 -04:00
rootiest 8911146d3f fix(sponge): guard set -q value[1] before string length to handle unset vars 2026-06-08 22:26:00 -04:00
rootiest 1637dc3122 fix(sponge): use $$var[1] to avoid test arg-count error on array vars 2026-06-08 22:24:31 -04:00
rootiest bceff8f4ec feat(sponge): add three-layer privacy filtering for shell history
conf.d/sponge_privacy.fish registers patterns and filters that prevent
credentials from reaching fish history:

  Layer 1 (static regex, universal): auth flags, env assignments,
  credential-bearing URLs, Authorization headers, sshpass, docker
  login, openssl -passin/-passout

  Layer 2 (dynamic values, session globals): on the first prompt, after
  secrets.fish has loaded, reads the literal values of all exported
  credential-named vars (TOKEN, PASSWORD, SECRET, etc.), escapes them
  for regex, and merges them with the static patterns as a session
  global — auto-refreshes on login so rotated tokens are never stale

  Layer 3 (per-command filter, sponge_filter_secrets): catches
  credentials in variables exported mid-session (e.g. project .env)

Also exempts functions/sponge_filter_secrets.fish from the sponge_*
gitignore glob so our custom filter is committed alongside the config.
2026-06-08 22:23:29 -04:00
rootiest d21aa4ed4b chore: remove requirements.md (superseded by §6 dependency catalog and fish-deps) 2026-06-08 22:03:24 -04:00
rootiest 43123ff390 feat: add sponge via fisher; gitignore fisher-managed files
meaningful-ooo/sponge is now the one true Fisher-managed plugin,
giving the bootstrap a concrete purpose. Its files (and functions/fisher.fish,
completions/fisher.fish) are gitignored so Fisher owns them exclusively —
no committed/managed conflict possible.

Updates docs, index, requirements, and README to distinguish
Fisher-managed plugins from bundled customized ones.
2026-06-08 22:01:30 -04:00
rootiest 8e7e450a9d docs: clarify that plugin functionality is bundled, not managed by fisher
Only jorgebucaran/fisher itself is in fish_plugins. The functionality
from catppuccin/fish, fzf.fish, done, autopair, and puffer-fish is
bundled directly with this config in modified form and must not be
installed or updated via fisher.

Removes sponge (not present), corrects file path mappings for bundled
components, fixes stale "Plugin sync failed" message in first_run.fish,
and expands fish-config.index with missing sections 9–11.
2026-06-08 21:51:27 -04:00
rootiest d53237f53c docs(readme): make wiki link prominent as a standalone heading
Offline docs drift reminder / remind (push) Successful in 13s
2026-06-08 17:15:46 -04:00
Gitea Actions 8ad10c41d7 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-08 21:09:54 +00:00
rootiest 2f199066f8 chore(docs): remove stale wiki files from previous section numbering
Generate documentation / build-docs (push) Successful in 34s
Offline docs drift reminder / remind (push) Successful in 14s
2026-06-08 16:48:43 -04:00
rootiest f444bfa464 docs: move Viewing This Manual to last position (§11)
Reorder sections so Installation (§9) and Personalization (§10) precede
Viewing This Manual (§11). Update TABLE OF CONTENTS and regenerate wiki;
old 9-viewing-this-manual.md replaced by 11-viewing-this-manual.md.
2026-06-08 16:48:37 -04:00
rootiest 345d0086a5 docs: add Installation and Personalization sections; fix wiki index
- docs/fish-config.md: add §10 Installation (clone, sentinel guard,
  config-update usage) and §11 Personalization (secrets.fish /
  local.fish examples); update TABLE OF CONTENTS
- docs/split-wiki.py: strip trailing thematic break from DESCRIPTION
  body so index.md no longer renders a double --- separator
- Regenerate docs/wiki/ with 11-installation.md and
  12-personalization.md; all nav bars updated
2026-06-08 16:46:48 -04:00
rootiest 8e32196a79 docs: slim README to overview+docs pointer; expand offline manual
- README now contains only Overview, Documentation, Installation,
  Personalization, Attribution, and License; all detailed reference
  content has been removed since it is covered in the wiki
- Add Documentation section above Installation pointing to docs/wiki/
- docs/fish-config.md: add §4.11 Shell Aliases (navigation dots, color
  overrides, safety wrappers, archives, system logs)
- docs/fish-config.md: add Prompt and Theme subsection to §7 with
  Starship OSC 133 marker detail and FZF Catppuccin color values
- Regenerate docs/wiki/ with all new content
2026-06-08 16:44:15 -04:00
Gitea Actions 38bdc3df65 chore(docs): regenerate man page, HTML docs, and wiki 2026-06-08 20:28:13 +00:00
rootiest 21437d1881 feat(docs): add auto-generated Markdown wiki
Generate documentation / build-docs (push) Successful in 32s
Offline docs drift reminder / remind (push) Successful in 10s
Adds docs/split-wiki.py, a Python script that splits fish-config.md
into a multi-page Markdown wiki under docs/wiki/:

- index.md: DESCRIPTION intro + full section ToC
- one file per numbered section (1-configuration-variables.md … 9-viewing-this-manual.md)
- each section page has a nav bar at the top linking to every other section

The build-docs.yml workflow now runs the script alongside pandoc so all
three formats (man page, HTML, wiki) are regenerated together from a
single source in one CI run.

README slimmed down to a pointer to the wiki; docs/fish-config.md §9
gains an "As a wiki" subsection.
2026-06-08 16:27:35 -04:00
rootiest fe6670f188 chore(docs): reset fish-config.md to stock format
Generate documentation / build-docs (push) Successful in 31s
2026-06-08 15:39:55 -04:00
Gitea Actions 27fd6e4e05 chore(docs): regenerate man page and HTML docs 2026-06-08 19:38:21 +00:00
rootiest 9cb9fff5ce ci: touch docs to trigger build-docs action
Generate documentation / build-docs (push) Successful in 32s
2026-06-08 15:37:44 -04:00
rootiest a9ce4b9ada ci(docs): merge man-page and html-docs workflows into build-docs
Both workflows triggered on the same path change, installed pandoc
separately, and raced to commit — the second always failed on push
due to new commits from the first. A single job installs pandoc once,
generates both outputs, and commits them together.
2026-06-08 15:36:31 -04:00
Gitea Actions 5e1fa470cb chore(docs): regenerate offline HTML docs 2026-06-08 19:31:34 +00:00
rootiest bf2ad2f1e7 Merge pull request 'feat(config-help): add --html and --man flags; add config-update function' (#36) from feat/config-help-flags-and-updater into main
Offline docs drift reminder / remind (push) Successful in 11s
Generate HTML docs / build-html-docs (push) Successful in 27s
Generate man page / build-manpage (push) Failing after 29s
Reviewed-on: #36
2026-06-08 19:30:52 +00:00
rootiest de07040c16 feat(config-help): add --html and --man flags; add config-update function
config-help gains two new flags:
- --html / -w: opens docs/html/index.html in the default browser using
  smart browser detection (xdg-mime https scheme handler → known binaries
  → xdg-open fallback) to avoid MIME-type mismatches with non-browser apps
- --man / -m: opens the compiled docs/fish-config.1 man page via man -l

config-update is a new function that pulls the latest fish config from the
hard-coded upstream URL without requiring a configured git remote. Suppresses
git output and reports status with colored messages. Supports --dry-run and
--force flags.

README updated to document all new commands.
2026-06-08 15:29:57 -04:00
rootiest 9795164eda feat(docs): add dark-mode HTML styling and drop per-page ToC
- Add docs/html-style.html with Catppuccin Latte/Mocha palette,
  auto-selected via prefers-color-scheme
- Update html-docs workflow: embed stylesheet via --include-in-header,
  remove --toc so per-page sidebar is gone (index.html remains the ToC)
- Touch docs/fish-config.md to trigger the HTML generation workflow

fix(ci): clear docs/html/ before pandoc to avoid directory-exists error

fix(docs): restore toc on index, hide it on section pages via JS, fix
full-page bg

fix(docs): fix nav alignment by grouping label+link pairs as flex units

chore(docs): regenerate offline HTML docs
2026-06-08 11:57:04 -04:00
Gitea Actions c098498f0c chore(docs): regenerate offline HTML docs 2026-06-08 11:28:28 -04:00
rootiest 8ea448adb8 ci(html-docs): add automatically generated html docs 2026-06-08 11:28:28 -04:00
rootiest 8541ef2658 chore(gitignore): ignore agent planning artifacts 2026-06-07 01:14:48 -04:00
rootiest 761ac9eb1b docs(welcome): update offline doc command and add deps check instruction 2026-06-06 23:44:55 -04:00
rootiest 9779dcc8ec docs(readme): Keep intro text line length under 80 characters
Offline docs drift reminder / remind (push) Successful in 5s
2026-06-06 23:24:56 -04:00
rootiest ea1aa20ac7 Merge pull request 'fix(ci): replace nonexistent gitea-issue-create action with curl API call' (#35) from fix/docs-drift-workflow-action into main
Reviewed-on: #35
2026-06-07 03:20:53 +00:00
rootiest b6aa81f3b1 fix(ci): replace nonexistent gitea-issue-create action with curl API call
The `actions/gitea-issue-create@v1` action does not exist on GitHub,
causing the docs-drift workflow to fail at clone time. Replace it with
a direct call to the Gitea REST API using curl. Also corrects the label
from `documentation` to `Kind/Documentation`.
2026-06-06 23:20:18 -04:00
rootiest 91ee993302 docs(readme): fix minor table alignment formatting
Offline docs drift reminder / remind (push) Failing after 3s
2026-06-06 23:15:58 -04:00
Gitea Actions 97b65c56a8 chore(docs): regenerate fish-config.1 man page 2026-06-07 03:14:43 +00:00
rootiest 9959bd4dc6 Merge pull request 'feat: first-run initialization routine' (#34) from feat/first-run-init into main
Offline docs drift reminder / remind (push) Failing after 0s
Generate man page / build-manpage (push) Successful in 17s
Reviewed-on: #34
2026-06-07 03:14:13 +00:00
rootiest 278ceb2c06 docs(readme): document first_run.fish and update Fisher bootstrap reference 2026-06-06 23:12:30 -04:00
rootiest 945b8ddabf docs: add first-run initialization design spec 2026-06-06 23:09:10 -04:00
rootiest bc8339895a docs: document first-run initialization in fish-config.md 2026-06-06 23:09:00 -04:00
rootiest c9d360809d fix: improve error handling in first_run.fish 2026-06-06 23:09:00 -04:00
rootiest e2738f2ab4 feat: add first_run.fish for one-time shell initialization 2026-06-06 23:09:00 -04:00
rootiest d4f99a79fe refactor: move Fisher bootstrap to first_run.fish 2026-06-06 23:09:00 -04:00
rootiest b03ec287b2 docs: add first-run implementation plan 2026-06-06 23:09:00 -04:00
Gitea Actions 0959d82018 chore(docs): regenerate fish-config.1 man page 2026-06-07 02:34:25 +00:00
rootiest fe1ef6f2ee Merge pull request 'feat(help): integrate config-help into fish's help command' (#33) from feat/help-config-integration into main
Offline docs drift reminder / remind (push) Failing after 0s
Generate man page / build-manpage (push) Successful in 18s
Reviewed-on: #33
2026-06-07 02:32:19 +00:00
rootiest 569d17a342 feat(help): integrate config-help into fish's help command
Rename config_help → config-help and add a help wrapper that
intercepts 'help config [section]', forwarding sub-topics to
config-help. Update README and docs to use 'help config' as the
preferred interface so offline docs feel like a natural extension
of fish's built-in help system.
2026-06-06 22:31:24 -04:00
Gitea Actions cf56f58dcd chore(docs): regenerate fish-config.1 man page 2026-06-06 08:39:18 +00:00
rootiest 4117b0ddb6 feat(tricks): auto-create fish-config.1 symlink on shell start
Offline docs drift reminder / remind (push) Failing after 3s
Generate man page / build-manpage (push) Successful in 16s
The symlink from ~/.local/share/man/man1/fish-config.1 to
docs/fish-config.1 is now created automatically alongside the
existing MANPATH setup, making `man fish-config` work out of the
box on any machine after cloning. Simplified docs accordingly.
2026-06-06 04:37:58 -04:00
Gitea Actions b2dd199e2f chore(docs): regenerate fish-config.1 man page 2026-06-06 08:35:39 +00:00
rootiest 7359c12e79 docs: document man fish-config and fish_config naming distinction
Offline docs drift reminder / remind (push) Failing after 4s
Generate man page / build-manpage (push) Successful in 17s
Adds man page viewing instructions to README Offline Documentation
section and to docs/fish-config.md section 9, including a note that
fish-config (hyphen) is this config's man page while fish_config
(underscore) is fish's built-in browser tool.
2026-06-06 04:35:21 -04:00
rootiest c9a5577c11 feat(manpath): expose user-local man pages for man fish-config
Adds ~/.local/share/man to MANPATH so the generated fish-config.1
(symlinked from docs/) is accessible via `man fish-config`.
2026-06-06 04:31:48 -04:00
rootiest 329dae0f08 docs(readme): add docs/ directory to Structure section
Offline docs drift reminder / remind (push) Failing after 3s
Co-documents fish-config.md and fish-config.index in the repo layout.
2026-06-06 04:27:02 -04:00
Gitea Actions dbddc4c1de chore(docs): regenerate fish-config.1 man page 2026-06-06 08:26:01 +00:00
rootiest 103f99b9f7 Merge pull request 'feat(docs): offline documentation, config_help viewer, and CI pipelines' (#32) from feat/offline-documentation into main
Offline docs drift reminder / remind (push) Failing after 1m22s
Generate man page / build-manpage (push) Successful in 1m26s
Reviewed-on: #32
2026-06-06 08:24:34 +00:00
rootiest ba92267a80 feat(config_help): colorize --help output
Section headers in bold blue, argument/flag names in yellow, command
examples in green, navigation keys in cyan, fallback chain numbers
dimmed. All reset to normal after each colored span.
2026-06-06 04:23:58 -04:00
rootiest cb4d74423a feat(config_help): add --help flag and persistent nav hint header
- config_help --help / -h prints full usage, section keyword examples,
  ov navigation key reference, and the pager fallback chain.
- Prepend a dim nav hint line to the ov input stream and pin it with
  --header 1 so "Space=next section  ^=prev  Alt+u=sections  /=search
  q=quit" is always visible at the top of the screen.
2026-06-06 04:16:13 -04:00
rootiest 368b714a98 fix(config_help): reliable section lookup and jump via index + tail-slice
- Add docs/fish-config.index mapping 100+ keyword aliases to exact heading
  text; config_help looks up here first, falls back to normalized heading
  scan (strips non-alphanumeric, lowercases both sides) for unknown terms.
- Resolve line numbers at runtime with grep -F so the index never goes
  stale from doc edits — only heading renames require an update.
- Fix section jump: --section-header pins delimiter lines as sticky headers
  removing them from ov pattern-search scope. Replace --pattern with
  tail -n +$start_line piped before ov; the target section is the first
  line so no search is needed and forward section nav still works.
- Fix empty sections sidebar: ov matches --section-delimiter against
  logical (ANSI-stripped) text, so "^#" is correct for bat-colored output;
  the previous ANSI escape-sequence regex never matched anything.
2026-06-06 04:09:12 -04:00
rootiest 02c27c6907 feat(docs): add offline documentation, config_help viewer, and CI pipelines
- docs/fish-config.md: curated terminal-optimized manual covering all
  public functions, keybindings, abbreviations, configuration variables,
  dependency catalog, and customization guide. Written for ov/bat/less
  readability rather than browser rendering — no callouts, no hyperlinks.
  Pandoc-compatible YAML front matter for man page compilation.

- functions/config_help.fish: viewer function with fallback chain
  ov -> bat -> man -l -> less -> cat. Accepts an optional section
  keyword to jump directly to the first matching heading.

- .gitea/workflows/man-page.yml: compiles docs/fish-config.md to
  docs/fish-config.1 via pandoc on every push to main that touches the
  source doc, then commits the result automatically.

- .gitea/workflows/docs-drift.yml: opens a reminder issue whenever
  README.md changes without a corresponding docs/fish-config.md update
  in the same push.

- README.md: documents config_help and the offline manual.
- AGENTS.md: adds Convention 10 requiring offline doc to be updated
  alongside any function, keybinding, or config change.
2026-06-06 03:14:36 -04:00
rootiest b37f5c1d74 Merge pull request 'feat(pkg): cross-platform package manager support' (#31) from feat/cross-platform-pkg-manager into main
Reviewed-on: #31
2026-06-06 06:49:07 +00:00
rootiest 014a8c3515 remove(functions): drop claude.fish wrapper
Remote-control is now enabled directly in the Claude Code config,
making the shell wrapper redundant.
2026-06-06 02:41:26 -04:00
rootiest 00055a7c38 feat(pkg): add cross-platform package manager support
Refactor pkg.fish to auto-detect the system package manager via
_fish_deps_detect_pm instead of hard-requiring paru/yay. Supports
install, uninstall, and auto (toggle) modes across paru, yay, pacman,
apt, dnf, zypper, yum, brew, and pkg. Package installed-checks now use
the correct query tool per PM (pacman -Qi, dpkg -s, rpm -q, etc.).

Also adds zypper to the _fish_deps_detect_pm detection priority list.
2026-06-06 02:41:10 -04:00
rootiest 0dfd75923d Merge pull request 'docs(functions): standardize all function doc blocks to UNIX man-page style' (#30) from docs/standardize-function-doc-blocks into main
Reviewed-on: #30
2026-06-06 00:20:17 +00:00
rootiest 1341e2559e docs(functions): standardize all function doc blocks to UNIX man-page style
Replace all ad-hoc inline comments between license headers and function
declarations with consistent SYNOPSIS / DESCRIPTION / ARGUMENTS / RETURNS /
EXAMPLE blocks across all 99 project-owned functions/ files. No executable
logic, variable names, or exit codes were modified.

Completes Task #6 from AGENTS.md (Retroactive Function Documentation
Standardization).
2026-06-05 20:18:49 -04:00
rootiest 0396d685fd Merge pull request 'feat(shell): add fzf inline picker, variable-check utility, and PATH cleanup' (#29) from feat/fzf-inline-picker-and-config-utilities into main
Reviewed-on: #29
2026-06-05 23:49:03 +00:00
rootiest 90a813c9d3 refactor(config): annotate PATH entries and fix cargo append flag
Adds inline comments to all fish_add_path entries for self-documentation.
Removes the unused $HOME/Applications path. Changes cargo bin flag from
-mg to -mga so the cargo bin directory is appended to PATH rather than
prepended, avoiding conflicts with system-installed Rust tools.
2026-06-05 19:48:14 -04:00
rootiest 8b9daf40c5 feat(shell): add __fish_variable_check utility function
Provides a reusable helper for evaluating configuration variable
truthiness. Returns 0 (true), 1 (false), 2 (empty/unset), or
3 (unrecognized value) — enables future strict-mode and opinionated-
components guards without repeating inline logic.
2026-06-05 19:47:05 -04:00
rootiest 2a08e1acef feat(shell): add fzf inline picker bound to @@
Adds __fzf_inline_picker function and @@ keybinding (Emacs + all Vi
modes). Opens an fzf session and injects the selected item at the
cursor position in the current command line. Includes SYNOPSIS/
DESCRIPTION doc block per project conventions. Updates README with
new binding in the User Bindings table.
2026-06-05 19:46:54 -04:00
rootiest fe1905ec85 Merge pull request 'feat(shell): add poke, _fish_mkdir_p utility, and update fish-deps for ov/yay' (#28) from feat/poke-and-fish-deps-ov-yay into main
Reviewed-on: #28
2026-06-04 03:31:24 +00:00
rootiest 13b9ba5828 docs(readme): update mkdir, mkcd, poke entries for _fish_mkdir_p integration 2026-06-03 23:26:21 -04:00
rootiest c2afa1201f feat(shell): integrate _fish_mkdir_p into mkdir and mkcd
- mkdir: loop over path args calling _fish_mkdir_p --path; falls back
  to command mkdir -p when flag args (e.g. -m 755) are present
- mkcd: default to _fish_mkdir_p --tree for new dirs; add -s/--silent
  flag to suppress tree output (mkcd's own status message still prints)
2026-06-03 23:22:30 -04:00
rootiest 4df10a7a2c fix(shell): clarify poke tree header to 'Created missing directories:' 2026-06-03 23:11:02 -04:00
rootiest e063763c0e refactor(shell): extract _fish_mkdir_p utility; improve poke output
- Add _fish_mkdir_p: reusable mkdir -p with three output modes:
  --path (default): "Created: ~/full/path/" on one line
  --tree: dimmed existing anchor + cyan tree of newly-created dirs
  --silent: no output
  HOME is substituted with ~ in all output paths
- Refactor poke to delegate to _fish_mkdir_p --tree; removes inline
  mkdir/echo logic and gains ~ substitution and per-dir tree output
2026-06-03 23:08:56 -04:00
rootiest c97c2290eb feat(shell): add poke function and update fish-deps for ov and yay
- Add poke: touch with automatic parent directory creation; prints
  colored notice when new dirs are created; handles multiple file args
- Refactor config.fish CachyOS override block: consolidate copy into
  the erase+source loop alongside ls/lt/cleanup
- fish-deps: replace most with ov (cargo crate + AUR pkg); add yay as
  rec dep with yay-build special (paru -S yay or AUR makepkg); add
  update handling for yay-build in _fish_deps_update
- README: document poke in Directory & File Listing table
2026-06-03 22:52:49 -04:00
rootiest 40021dcc21 Merge pull request 'fix(shell): preserve scrollback prompt colors in ov sticky headers' (#27) from feat/preserve-scrollback-header-colors into main
Reviewed-on: #27
2026-06-04 01:39:37 +00:00
rootiest 7610a4121d docs(readme): simplify return sentinel callout wording 2026-06-03 21:11:34 -04:00
rootiest fd1ddddbf0 fix(shell): preserve scrollback prompt colors in ov sticky headers
Use a per-invocation temp ov config to set SectionLine Background/Foreground
to empty strings, preventing ov from overriding the ANSI colors embedded in
the starship prompt when it is pinned as a sticky section header.

Also adds a second return sentinel inside the interactive block of config.fish
to guard against tool-injected init lines that target the inner scope, and
updates README accordingly.
2026-06-03 20:43:00 -04:00
rootiest 15596bae5f Merge pull request 'feat(shell): enhance log browser, add yay wrapper, and integrate starship OSC prompt markers' (#26) from feat/log-browser-yay-ov-and-starship-osc into main
Reviewed-on: #26
2026-06-03 05:04:00 +00:00
rootiest db33d9cff7 feat(shell): enhance log browser, add yay wrapper, and integrate starship OSC prompt markers
- logs.fish: add yay category, ov-powered viewing for paru/yay (section
  headers, color highlights, ==> AUR build markers) and scrollback logs
  (OSC 133;A sticky prompt headers); add fzf Ctrl-D delete with Y/n
  confirm and list refresh, ? toggleable help overlay; run
  _scrollback_prune_junk before building file list
- _scrollback_prune_junk: new utility to remove empty, single-line, and
  Kitty tab-rename noise logs before display and before max-file pruning;
  called from both logs and smart_exit
- smart_exit: call _scrollback_prune_junk before counting toward max files
- conf.d/yay-wrapper.fish: auto-generate ~/.local/bin/yay logging wrapper
  mirroring paru-wrapper; tees output to timestamped logs, prunes old ones
- conf.d/starship.fish: move fish_prompt from config.fish; emit OSC 133;A
  after the prompt's leading newline so the marker lands on the info-bar
  line rather than the blank line above it; guard with type -q starship so
  clean fish sessions use built-in markers unchanged
- config.fish: remove inline fish_prompt block (now in conf.d/starship.fish);
  add return sentinel at EOF to prevent tool-injected init lines from running
- completions/ov.fish: add ov tab completions
- README.md: document all of the above
2026-06-03 01:02:55 -04:00
rootiest 3bc28fd9d5 Merge pull request 'feat(shell): replace pager with ov, add logs browser, and auto-generate paru wrapper' (#25) from feat/ov-pager-logs-and-wrappers into main
Reviewed-on: #25
2026-06-01 00:41:55 +00:00
rootiest f97272d0ec feat(shell): replace pager with ov, add logs browser, and auto-generate paru wrapper
- Set $PAGER to ov in config.fish (falls back to less); remove LESS=-R
- Rewrite less wrapper with full hierarchy: $PAGER → ov → less → more → cat
- Simplify view.fish fallback to delegate to the less wrapper
- Add logs function: fzf browser for scrollback and paru logs, opens in $PAGER
- Add claude wrapper: auto-injects --remote-control unless already present
- Add conf.d/paru-wrapper.fish: generates ~/.local/bin/paru on first run,
  versioned so future template changes auto-propagate on next shell start
- Sync README.md and requirements.md to document all of the above
2026-05-31 20:39:52 -04:00
rootiest 0298e5a483 Merge pull request 'feat(shell): add scrollback history capture on shell exit' (#24) from feat/scrollback-history-on-exit into main
Reviewed-on: #24
2026-05-30 05:21:47 +00:00
rootiest 378cb6b221 feat(shell): add scrollback history capture on shell exit
- Add smart_exit function: captures Kitty scrollback to a timestamped
  log file on exit; --no-log/-n skips capture; auto-prunes oldest logs
  once count exceeds SCROLLBACK_HISTORY_MAX_FILES
- Wire exit → smart_exit in config.fish for interactive sessions;
  export SCROLLBACK_HISTORY_DIR and SCROLLBACK_HISTORY_MAX_FILES with
  sane defaults (~/.terminal_history and 100 respectively)
- Update cat to detect files in SCROLLBACK_HISTORY_DIR or containing
  raw ANSI escape sequences and pass them through command cat instead
  of bat, preserving color output
- Remove redundant alias rm="rm -i" from tricks.fish (superseded by
  functions/rm.fish trash-aware wrapper)
- Sync README: new Scrollback History integration section, smart_exit
  added to System functions table, cat description updated, stale rm
  Safety Wrapper entry and note removed
2026-05-30 01:20:40 -04:00
rootiest 9bff3f3c69 Merge pull request 'feat(shell): expand tricks.fish with system aliases, bat man pages, and done plugin' (#23) from feat/tricks-system-aliases-and-done into main
Reviewed-on: #23
2026-05-29 18:08:10 +00:00
rootiest 1ef4bb9f0a feat(shell): expand tricks.fish with system aliases, bat man pages, and done plugin
- Add system aliases: dot-navigation (.., ..., etc.), color overrides for
  grep/dir/vdir, safety wrappers (cp/mv/rm -i), archive shortcuts
  (tarnow, untar), wget resume, tb (termbin), and jctl
- Set MANPAGER/MANROFFOPT to render man pages through bat when available
- Configure franciscolourenco/done notification plugin settings
  (__done_min_cmd_duration=10s, __done_notification_urgency_level=low)
- Add psmem/psmem10 memory-monitoring helpers
- Switch PATH setup to fish_add_path (handles deduplication automatically)
- Add conf.d/done.fish (done plugin v1.19.1)
- Source tricks.fish explicitly after CachyOS base config in config.fish
- Sync README with all new functions, aliases, and integrations
2026-05-29 14:04:03 -04:00
rootiest a88800f94f Merge pull request 'feat(shell): add CachyOS-derived tricks.fish and copy utilities' (#22) from feat/cachyos-base-utilities into main
Reviewed-on: #22
2026-05-29 17:38:16 +00:00
rootiest e4743bc8e2 feat(shell): add CachyOS-derived tricks.fish and copy utilities
Adds conf.d/tricks.fish (PATH additions for ~/.local/bin and depot_tools,
bang-bang key bindings, history timestamp override, backup utility) and
functions/copy.fish (smarter cp wrapper that strips trailing slashes from
source directories, fixing a CachyOS-specific cp quirk).

Updates config.fish to explicitly source copy.fish on startup and refactors
several conditional blocks to single-line style for consistency. Syncs
README.md to document all new utilities.
2026-05-29 13:36:03 -04:00
rootiest 06b9210cc5 Merge pull request 'feat(navigation): add mkcd function' (#21) from feat/mkcd into main
Reviewed-on: #21
2026-05-27 19:31:07 +00:00
rootiest 2e7f2d07e4 feat(navigation): add mkcd function
Creates a directory (including all missing parents) and immediately
cd's into it. Supports -h/--help, distinguishes new vs existing dirs
in feedback, and uses set_color for consistent colored output.
2026-05-27 15:30:08 -04:00
rootiest 013cf95478 Merge pull request 'feat: pkg install/remove toggle and sudo-toggle function' (#20) from feat/pkg-toggle-and-sudo-toggle into main
Reviewed-on: #20
2026-05-26 17:10:49 +00:00
rootiest 724c631cd0 feat(system): add sudo-toggle function
Toggles sudo password enforcement on/off by writing or
truncating a NOPASSWD rule in /etc/sudoers.d/nofail-toggle.
Useful for temporarily bypassing FIDO key prompts during
batch admin tasks without permanently weakening sudoers.
2026-05-26 13:09:41 -04:00
rootiest 31a1c4089a feat(pkg): add install/remove toggle with force flags
pkg now auto-detects whether each package is installed and
installs or removes accordingly. Explicit -i/--install and
-u/--uninstall flags override the auto-detection. Adds help
output when invoked without arguments.
2026-05-26 13:09:22 -04:00
rootiest d7afc7dd6b chore(ignore): add fish patterns to gitignore 2026-05-23 00:11:56 -04:00
rootiest 9f917be2b2 fix(gi): soften boilerplate errors and add empty-prompt message
- Missing GITIGNORE_BOILERPLATE var/file now prints error but continues
  to the API prompt instead of exiting the function
- Empty Enter at the pattern prompt now prints "No patterns selected.
  Skipping API fetch." instead of silently returning
2026-05-23 00:07:57 -04:00
rootiest 08ae7cbd5e Merge pull request 'feat(gi): merge gitig into gi with prompt, dedup, and boilerplate support' (#19) from feat/git-ignorer into main
Reviewed-on: #19
2026-05-23 03:50:05 +00:00
rootiest ed11877ff4 docs(readme): sync README with gi/gitig merge and magic-enter removal
- Remove magic-enter.fish from plugins table (plugin removed)
- Add gi function to Git functions table with all flags documented
- Add gitig/git-ignore abbreviations to Git abbreviations table
- Add GITIGNORE_BOILERPLATE env var example to local.fish personalization block
2026-05-22 23:48:20 -04:00
rootiest 508f0798fa feat(function): adds a gi function that generates gitignore patterns 2026-05-22 23:44:21 -04:00
rootiest abbed56813 chore(ignore): implement new gitignore pattern format 2026-05-22 23:43:49 -04:00
rootiest 4a9ff30519 fix(fisher): remove magic-enter and clean up fisher plugin handling 2026-05-22 23:42:50 -04:00
rootiest af979db1b0 docs(readme): add scrub function to Miscellaneous table 2026-05-20 21:01:52 -04:00
rootiest 55dc402b3b Merge pull request 'fix(ai): migrate gemini-cli → antigravity-cli (agy) and antigravity → antigravity-ide' (#18) from fix/antigravity into main
Reviewed-on: #18
2026-05-21 00:52:35 +00:00
rootiest 1d71323cc8 chore(ai): remove old gemini-resume and save_gemini_session files
Completes the rename started in the previous commit; these files were
superseded by antigravity-resume and save_antigravity_session.
2026-05-20 20:43:17 -04:00
rootiest e075c40c9d feat(ai): migrate gemini-cli references to antigravity-cli (agy)
Rename gemini-resume → antigravity-resume and save_gemini_session →
save_antigravity_session; update all session files from .gemini_session
to .antigravity_session and LAST_GEMINI_SESSION → LAST_ANTIGRAVITY_SESSION.
Replace gemini/gemini-cli binary calls with agy throughout superpowers,
code-resume, and the resume function. Add antigravity-ide wrapper for the
renamed IDE binary; update abbr v → antigravity-ide (VSCode-equivalent)
and update README/requirements to reflect the new tool names.
2026-05-20 20:41:04 -04:00
rootiest b643c9195b chore(ignore): ignore all ai/llm session files 2026-05-20 20:37:44 -04:00
rootiest a95bc4a11c feat(function): add scrub function to recursively purge environment garbage
Adds a robust `scrub` utility function to safely and recursively clean
up common OS metadata, development caches, editor artifacts, and slicer
cruft using `fd`.

Features:
- Hierarchical deletion fallback system: checks for a custom `rm`
  function, falls back to `trashy` (trash put), then `trash-cli`,
  and drops to standard `rm -rf` as a final measure.
- Safe `-d/--dry-run` modes to preview matched targets.
- An advanced `-a/--aggressive` mode for wiping heavy project caches
  (node_modules), local logs, and custom AI runtime config histories.
- Full flag validation and colorized help menus.
2026-05-20 20:37:43 -04:00
rootiest 0e766b3326 Merge pull request 'feat(deps): add fish-deps unified dependency management command' (#17) from feat/fish-deps into main
Reviewed-on: #17
2026-05-19 03:53:51 +00:00
rootiest a7510cc8ea fix(fish-deps): filter fish-* tags only; fix starship sh -s flag
git tag --list 'fish-*' replaces for-each-ref so old pre-Rust tags like
pre_whitespace_fix (which have no Cargo.toml) are never selected.

starship update: sh -s -- --yes correctly passes --yes to the piped
install script instead of treating it as a filename for sh to open.
2026-05-18 23:46:34 -04:00
rootiest a351e62a17 feat(fish-deps): add uv as managed dep; install before cargo and fish
uv is now listed first in the catalog (before cargo and fish) so it is
installed automatically before the fish source build is attempted.
Install uses the official curl script; update uses `uv self update`.

Catalog order is now: uv → cargo → fish → … ensuring prerequisites are
in place before any dependent install method runs.

README updated: uv and cargo added to the Required table, warning callout
and dependency management note reflect the automatic install flow.
2026-05-18 23:34:49 -04:00
rootiest 7936a0966e feat(fish-deps): build fish from source via git + cargo when upgrading
Adds a git-cargo-fish install method that clones fish-shell, checks out
the latest tag, and runs `uv run --no-managed-python cargo install --path .`.
This is offered first in `fish-deps install` (requires cargo + uv) and
used automatically by `fish-deps update`, falling back to the system PM
when cargo or uv are absent.

Removes the stale `cargo install fish` README note (that crate is a
library, not the shell binary).
2026-05-18 23:29:55 -04:00
rootiest fee2d99bea feat(fish-deps): warn on fish < 4.0 in status; prompt upgrade in install
fish-deps status now shows ⚠ with the current version when fish < 4.0.
fish-deps install prompts to upgrade fish when the installed version is
below 4.0, using the same install methods (cargo/PM) and printing a
restart reminder on success.
2026-05-18 23:17:51 -04:00
rootiest 7d4e33bc7e feat(deps): add curl installer for lazydocker and binary download for wakatime
lazydocker: prefer the official install_update_linux.sh curl script over
system PM. The same script handles updates, so fish-deps update re-runs it.

wakatime: replace pipx with a direct binary download from github releases.
Detects architecture (amd64/arm64/arm) via uname -m, downloads the zip,
extracts the binary to ~/.config/wakatime/wakatime, chmods it, and
symlinks it to ~/.local/bin/wakatime. fish-deps update re-downloads and
replaces the binary in place.

Both new specials are added to the preferred-method block so they appear
before the system PM and are the default when prompted.
2026-05-18 23:04:35 -04:00
rootiest 782ef833c2 fix(deps): correct trash cargo crate name to trashy 2026-05-18 22:48:33 -04:00
rootiest 8917442089 fix(deps): update PATH immediately after rustup install
After the rustup installer runs, add the cargo bin dir to PATH in the
current session so subsequent installs in the same fish-deps run can
find cargo without a shell restart. Checks CARGO_HOME/bin first (set
in config.fish), then falls back to the rustup default ~/.cargo/bin.
Warns the user if cargo still isn't detectable after the path update.
2026-05-18 22:40:35 -04:00
rootiest 8d9e7ae43f fix(deps): validate method choice is numeric before comparing 2026-05-18 22:29:50 -04:00
rootiest 9e7539d863 feat(deps): support upgrading fish itself via cargo install fish
Fish 4.x is a Rust rewrite published to crates.io as 'fish'. Added the
crate to the catalog so fish-deps update will run cargo install --force
fish to upgrade it. A yellow restart reminder is printed after the
upgrade since the new binary won't take effect until the shell restarts.

README warning updated to mention cargo install fish as the upgrade
path for users stuck on Fish 3.x.
2026-05-18 22:23:10 -04:00
rootiest 6fd1e3221e docs(readme): require Fish >= 4.0 and add Rust/cargo to dependencies 2026-05-18 22:20:16 -04:00
rootiest df7c921bc6 feat(deps): add cargo as a managed dependency with rustup installer
cargo is now the second entry in the catalog (after fish) so it is
installed before any Rust tool that depends on it. Install preference:
rustup installer (curl | sh) first, system PM as fallback. Update
runs rustup update when rustup is available.

The rustup-installer special is evaluated before the system PM in the
method list so it is always option 1 / the default for cargo.
2026-05-18 22:18:57 -04:00
rootiest abbbf20b40 fix(deps): restore paru install gated on pacman presence
On Arch-based systems (pacman present), paru-build offers yay or
makepkg as install methods. On non-Arch systems neither pacman nor yay
exist, so no methods are built and the dep is silently skipped — no
prompt shown to the user.
2026-05-18 22:14:45 -04:00
rootiest a70e88c344 fix(deps): remove paru install, enforce cargo preference for Rust tools
Catalog: clear paru's pm and special install entries so it appears in
status but fish-deps install skips it (it's a package manager, not a
managed dep).

Install: cargo is now always attempted first for Rust tools. When cargo
is absent but a crate exists, a note is printed suggesting rustup.
When only one method is available the chosen method is shown so the user
can see whether cargo or the system PM is being used. Method prompt now
shows the default label inline for clarity.

Removed dead paru-build switch case from the install executor.
2026-05-18 22:13:13 -04:00
rootiest a7c6b9097d fix(deps): consolidate install prompt into read -P to prevent display race 2026-05-18 22:07:50 -04:00
rootiest 0e7e824085 fix(deps): fix autoloading and Fish 4.x test compatibility
Split _fish_deps_pm.fish into one file per function so Fish can
autoload each by name (_fish_deps_detect_pm, _fish_deps_pm_install,
_fish_deps_pm_upgrade). A single file with multiple functions only
autoloads under the filename, leaving the others unreachable.

Replace all `test -a`/`test -o` binary operators with `; and`/`; or`
chains throughout _fish_deps_install and _fish_deps_update. Fish 4.x
removed support for -a/-o in test, causing the "unexpected argument"
errors seen on Debian.

Also consolidate paru/yay cases in pm_install and pm_upgrade since
both helpers use identical flags.
2026-05-18 22:05:56 -04:00
rootiest a3d99eec3f fix(aur): fall back to yay when paru is unavailable
upgrade, pkg, search, and parur now detect paru first, then yay, and
print a clear error if neither is installed. Removes the hard dependency
on paru specifically across all AUR-wrapper functions.
2026-05-18 22:01:00 -04:00
rootiest a86f797627 fix(deps): demote paru from required to recommended
paru is an AUR helper only available on Arch-based distros and is not
required for the config to function. Moved to recommended tier alongside
yay. README updated accordingly.
2026-05-18 21:59:56 -04:00
rootiest 1a6f1f3f2c feat(deps): add status symbols to fish-deps status output
Installed deps show a green ✓. Missing required/integration deps show
a red ✗. Missing recommended deps show a yellow ⚠ since they are
optional, distinguishing severity at a glance.
2026-05-18 21:56:50 -04:00
rootiest b82766ad52 feat(deps): add yay as supported AUR helper alongside paru
yay uses the same -S --noconfirm interface as paru. Detection priority
is paru > yay > pacman so paru is preferred when both are present.
When installing paru itself via paru-build special, yay -S paru is
offered as a method when yay is available, in addition to the
makepkg-from-source fallback.
2026-05-18 21:52:56 -04:00
rootiest 9b342114aa feat(deps): add fish-deps unified dependency management command
Introduces `fish-deps` with four subcommands:
- status: colored installed/missing report per tier (required/integrations/recommended)
- install: interactively install each missing dep, prompts method when multiple exist
- update: update all installed deps using their preferred method
- sync: install missing then update installed

Install method priority: cargo (Rust tools get latest crate) > system PM
(paru/pacman/apt/brew/pkg/dnf/yum) > git clone (fzf via fzf-update) >
curl installer (starship, fisher) > pipx (wakatime).

Splits into focused helper files:
- _fish_deps_catalog.fish: parallel-array dep catalog with tiers, cargo crates, PM names, special install keys
- _fish_deps_pm.fish: PM detection and install/upgrade helpers
- _fish_deps_status.fish: tier-grouped colored status display
- _fish_deps_install.fish: per-dep interactive install with method selection
- _fish_deps_update.fish: per-dep update using known install method

check_fish_deps becomes a thin wrapper delegating to `fish-deps status`.
README updated with Dependency Management section.
2026-05-18 21:51:22 -04:00
rootiest f09006846b fix(fzf): drop focus/resize bind entirely on older fzf builds
Older fzf (pre-0.62) does not support the focus and resize events in
bind actions, causing a startup error when --fish or the bundled
integration is sourced. Split the FZF_DEFAULT_OPTS preview block into
an if/else: newer fzf gets the dynamic bg-transform bind with wrap-word;
older fzf gets a static preview window with plain wrap and no event bind.
2026-05-18 21:47:20 -04:00
rootiest 2df665a537 feat(fzf): use fzf --fish integration and add fzf-update function
- config.fish: add ~/.fzf/bin to PATH for git-installed fzf
- config.fish: prefer fzf --fish | source (fzf >= 0.48, always
  version-matched) with fallback to integrations/fzf.fish for
  older builds; erase plugin bindings reliably when fzf is absent
- functions/fzf-update.fish: install or upgrade fzf from git HEAD
  using --bin so shell config files are not modified
2026-05-18 21:17:13 -04:00
rootiest 46be262f92 fix(fzf): erase fzf bindings in config.fish when fzf is absent
conf.d/fzf.fish is owned by Fisher and gets restored to the plugin's
original on fisher update, so any guard placed there is unreliable.
config.fish is never touched by Fisher, making it the right place to
call _fzf_uninstall_bindings after conf.d has already run and set up
the fzf key bindings on machines where fzf is not installed.
2026-05-18 21:06:09 -04:00
rootiest a442315312 Merge pull request 'fix(keybinds): guard bindings on required binaries and fix fzf compat' (#16) from fix/fzf-keybind-guards into main
Reviewed-on: #16
2026-05-19 00:56:29 +00:00
rootiest 6530935652 fix(fzf): omit toggle-raw bind on older fzf builds
toggle-raw is unavailable in fzf 0.60 devel. Gate it alongside
preview-wrap-sign using the existing _fzf_transform_action check,
consolidating both version-conditional variables into one block.
2026-05-18 20:54:10 -04:00
rootiest bdbdf2e8e0 fix(fzf): omit --preview-wrap-sign on older fzf builds
preview-wrap-sign is unavailable in fzf 0.60 devel. Reuse the
existing _fzf_transform_action gate to conditionally append it
to the history widget base options, keeping parity with the
wrap-word and bg-transform fallbacks.
2026-05-18 20:52:44 -04:00
rootiest d7471e2eca fix(fzf): fall back to plain wrap on older fzf lacking wrap-word
wrap-word in --preview-window was added alongside bg-transform.
Reuse the existing _fzf_transform_action variable (already inherited
by fzf-history-widget) to select wrap-word on newer fzf and plain
wrap on older builds — no additional version check needed.
2026-05-18 20:50:48 -04:00
rootiest 7acd099b3e fix(fzf): prefer bg-transform, fall back to transform on older fzf
Detect fzf version once at shell startup inside fzf_key_bindings.
Use bg-transform (non-blocking) on fzf >= 0.62 and the synchronous
transform on older builds (e.g. 0.60 devel which lacks bg-transform).
The chosen action is captured into fzf-history-widget via fish's
--inherit-variable so the check runs once, not on every Ctrl+R press.
2026-05-18 20:37:18 -04:00
rootiest e502cff8cb fix(keybinds): guard bindings on required binaries and fix fzf bg-transform
- conf.d/fzf.fish: skip fzf_configure_bindings if fzf is not in PATH
- key_bindings.fish: only bind Ctrl+Alt+= when qalc is installed
- _qalc_eval: return 1 early if qalc is absent so callers can react
- _smart_execute: fall back to normal execute when _qalc_eval returns 1
- integrations/fzf.fish: replace bg-transform with transform (available
  since fzf 0.53; bg-transform requires a newer version and caused
  "unknown action" errors on fzf 0.60 devel)
2026-05-18 20:34:00 -04:00
rootiest 50979acc1f Merge pull request 'feat(path): add resend to PATH' (#15) from feat/resend into main
Reviewed-on: #15
2026-05-19 00:21:36 +00:00
rootiest 4aea2f4e2c feat(path): add resend to PATH 2026-05-18 20:21:01 -04:00
rootiest be051daf1e Merge pull request 'fix(zoxide): restore CDPATH support in cd/z execution' (#14) from fix/cdpath-cd-execution into main
Reviewed-on: #14
2026-05-12 04:45:47 +00:00
rootiest 05139354cf fix(zoxide): restore CDPATH support in cd/z execution
The CDPATH regression was introduced when unifying completions: the `z`
function only checked `test -d` (absolute path existence) before falling
through to zoxide query, silently ignoring CDPATH-relative directories.
Now mirrors the completion logic — checks direct path, then each CDPATH
prefix, then zoxide — so `cd subdir` resolves correctly when `subdir`
lives under a CDPATH entry.
2026-05-12 00:43:59 -04:00
rootiest d2e7c799c4 docs(readme): use callouts for notes/tips
Use callouts and clearer wording in the Integrations section.
2026-05-12 00:08:00 -04:00
rootiest 233d75434c Merge pull request 'feat(completions): unify cd/z completions across CWD, CDPATH, and zoxide' (#13) from cd-completions into main
Reviewed-on: #13
2026-05-12 03:58:41 +00:00
rootiest 520217d4a9 fix(zoxide): suppress missing-zoxide startup message
Silent degradation is cleaner; the shell already handles the
missing binary gracefully without any output.
2026-05-11 23:57:46 -04:00
rootiest 4e255f4502 chore(license): add copyright/SPDX headers to zoxide files
- Add copyright + SPDX header to functions/zoxide.fish and
  conf.d/zoxide.fish (modified from original, owned by Rootiest)
- Add sourced-from attribution to completions/zoxide.fish
  (unmodified from icezyclon/zoxide.fish, MIT)
2026-05-11 23:47:27 -04:00
rootiest 6d91f49521 fix(completions): add cdi function as alias for zi
cdi was documented and expected to work as an interactive zoxide
directory picker but was never defined as a function, causing it
to silently fail. Wraps zi so completions are inherited correctly.
2026-05-11 23:37:21 -04:00
rootiest 2e3230974c feat(completions): unify cd/z completions across CWD, CDPATH, and zoxide
Previous to this commit, tab completion and auto-suggestions for cd/z
were inconsistent — only one or two of: CWD, CDPATH, and zoxide frecency
results would work at a time, with different sourced matches shown in
tab completion, shown in auto-suggest, and execution after pressing
<Enter>.

- Add _zoxide_z_complete in functions/zoxide.fish that merges all three
  sources into a single completion list (CWD via __fish_complete_cd,
  CDPATH via __fish_complete_directories, zoxide via query -l capped at
25)
- Wire the new completer to both z and cd via complete directives in
  conf.d/zoxide.fish, replacing the previous incomplete approach
- Add completions/zoxide.fish for full tab completion of the zoxide CLI
  itself (add, query, remove, import, init subcommands)
- Update README to document the unified completion behavior and fix
  structural issues in Personalization/Attribution/Dependencies sections
2026-05-11 23:28:59 -04:00
rootiest f93f9844dc build(ignore): add case-insensitive patterns for local testing and temporary files
Consolidates and expands the .gitignore to ignore various temporary and
testing directories. This allows for local experimentation with new
ideas
and the preservation of disabled functions without the risk of
accidentally committing them to the repository.
2026-05-11 23:22:18 -04:00
rootiest 9467d2c206 Merge pull request 'feat(functions,bindings): add smart-execute, fast-cli; refactor qalc and rm' (#12) from feat/smart-execute-fast-cli into main
Reviewed-on: #12
2026-05-10 05:40:06 +00:00
rootiest b62c2476da feat(functions,bindings): add smart-execute, fast-cli; refactor qalc and rm
- Add _smart_execute: context-aware Ctrl+Enter that routes to qalc when
  the buffer ends with '=', or falls through to standard execute otherwise
- Refactor qalc_eval → _qalc_eval (private helper, same behavior)
- Bind Ctrl+Enter to _smart_execute in all vi modes
- Add fast-cli wrapper (fast.com speed test) and fast placeholder with
  a friendly ANSI redirect message
- Add speedtest-fast abbreviation expanding to fast-cli
- Enhance _replace_command_token to handle sudo-prefixed commands: places
  cursor at index 5 (between sudo and the replacement slot)
- Improve rm error reporting: colored output, culprit-path listing, and
  cleaned technical detail for non-missing-file errors
- Add SPDX copyright headers to cat, ld, claude-docs, claude-pr functions
- Update README: Ctrl+Enter binding, fast-cli/fast functions, speedtest-fast abbr
2026-05-10 01:36:14 -04:00
rootiest 4dff7632cd Merge pull request 'refactor(config): use $__fish_config_dir, quote paths, add dot_fish var' (#11) from refactor/config-path-quoting-portability into main
Reviewed-on: #11
2026-05-08 20:30:02 +00:00
rootiest f70dccdc65 refactor(config): use \$__fish_config_dir, quote paths, add dot_fish var
Replace hardcoded \$HOME/.config/fish paths with the canonical
\$__fish_config_dir variable for portability. Add proper quoting around
all path strings. Introduce a dot_fish local variable to reduce
repetition in user-dots sourcing blocks. Add LESS=-R for color support
in the pager.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 16:29:05 -04:00
rootiest 9f524694cb Merge pull request 'feat(functions): add claude-docs and claude-pr helper functions' (#10) from feat/claude-helper-functions into main
Reviewed-on: #10
2026-05-08 17:39:40 +00:00
rootiest 37f35ce0a0 feat(functions): add claude-docs and claude-pr helper functions
Add two Claude Code helper functions to streamline common dev workflows:
- `claude-docs`: triggers Claude to sync README.md with recent session changes
- `claude-pr`: triggers Claude to create a branch, commit, push, and open a PR

Also add `.claude` to .gitignore and document both functions in README.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 13:37:41 -04:00
rootiest b08a3d364e Merge pull request 'docs(readme): add Ctrl+Alt+= qalc_eval keybinding to User Bindings table' (#9) from docs/keymaps into main
Reviewed-on: #9
2026-05-08 04:59:44 +00:00
rootiest 95f26eadc1 docs(readme): add Ctrl+Alt+= qalc_eval keybinding to User Bindings table
Documents the new inline Qalculate! evaluator shortcut added in the
recent config refactor, so users know it exists and how to use it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 00:57:38 -04:00
rootiest 337fb10cd4 Merge pull request 'feat(config): refactor config.fish, add XDG compliance, new functions, and keybindings' (#8) from feat/config-refactor-and-new-functions into main
Reviewed-on: #8
2026-05-08 04:52:49 +00:00
rootiest d8bd2b32ab feat(config): refactor config.fish, add XDG compliance, new functions, and keybindings
Restructure and expand the Fish shell configuration for better XDG compliance,
interactive-session gating, modularity, and ergonomics.

config.fish:
- Add full XDG Base Directory variable block (XDG_CONFIG_HOME, XDG_CACHE_HOME,
  XDG_DATA_HOME, XDG_STATE_HOME) and redirect tool caches/configs accordingly
  (cargo, rustup, go, bun, npm, gnupg, wakatime, wget, nvidia, codeium, etc.)
- Add editor setup with `type -q nvim` guard and NVIM_APPNAME
- Add CDPATH block (., ~/projects, ~) with explanatory comments
- Gate all interactive-only setup (key bindings, FZF, direnv, starship, secrets,
  local overrides, CLAUDE_CODE_NO_FLICKER) behind `status is-interactive`
- Guard FZF integration source behind a file-existence check
- Move secrets.fish and local.fish sourcing into the interactive block as overrides
- Remove obsolete universal `cdp` variable and duplicate PATH/editor blocks
- Update PATH entries to use XDG-resolved $CARGO_HOME and $BUN_INSTALL

conf.d/theme.fish:
- Move FZF_DEFAULT_OPTS (Catppuccin Mocha palette) from config.fish into theme.fish
  so all theming lives in one place
- Add section header for FZF colors; condense file header comment

conf.d/abbr.fish:
- Add `/exit` abbreviation as a vim-style alias for the `exit` builtin

conf.d/key_bindings.fish:
- Bind Ctrl+Alt+= to new `qalc_eval` function (inline Qalculate! evaluation)
- Add binding in both normal and all Vi modes
- Add descriptive comment block explaining the keybinding purpose

functions/bash.fish:
- Pass `--rcfile "$XDG_CONFIG_HOME/bash/bashrc"` so bash respects XDG config location

functions/cat.fish:
- Extend cat wrapper: detect directory arguments and delegate to `ls` instead of bat
- Preserve stdin-passthrough behavior when no arguments are provided

functions/__auto_source_fallback_venv.fish (new):
- Extract auto-venv PWD watcher from config.fish into its own autoloaded function file
- Skips activation when direnv manages the directory (.envrc present or DIRENV_DIR set)
- Deactivates venv when leaving its project tree

functions/ld.fish (new):
- Wrapper for lazydocker that injects the active Docker context's DOCKER_HOST,
  enabling correct context-aware operation

functions/joplin.fish (new):
- Joplin CLI wrapper function

functions/qalc_eval.fish (new):
- Inline Qalculate! evaluator: reads the current commandline buffer, passes it to
  `qalc`, prints the result, and clears the buffer for rapid-fire math in the shell

README.md:
- Remove stale `cdp` variable example from the local.fish documentation section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 00:45:02 -04:00
278 changed files with 35603 additions and 1513 deletions
+82
View File
@@ -0,0 +1,82 @@
name: Generate documentation
on:
push:
branches:
- main
paths:
- "docs/manual/**"
- "docs/build-manual.py"
- "docs/manualtools.py"
- "docs/verify-manual.py"
- "docs/site/**"
- "functions/**"
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 pandoc python3-yaml
- 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
git diff --cached --quiet && echo "No changes to commit" && exit 0
git commit -m "chore(docs): regenerate manual and man page"
git push
+294 -22
View File
@@ -1,37 +1,309 @@
# GitIgnore for Fish-config # GitIgnore for Fish-config
# id: gitig-boilerplate-7f0528027e23f210196ae4583c408e5b
# ╭──────────────────────────────────────────────────────────╮
# │ GitIgnore Boilerplate Template │
# ╰──────────────────────────────────────────────────────────╯
#
# ──────────────────── OS-Generated Files ────────────────────
# automatic backup files created by some editors (e.g., Vim, Emacs)
*~
# temporary files created if a process still has a handle to a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# MacOS junk
.DS_Store
# Linux trash folder which might appear on any partition or disk
.Trash-*
# files created when an open file is removed but is still being accessed
.nfs*
# ─────────────────── Debug/Temporary/Testing ────────────────
# Matches OLD / .OLD
[Oo][Ll][Dd]/
.[Oo][Ll][Dd]/
# Matches DISABLE / .DISABLE
[Dd][Ii][Ss][Aa][Bb][Ll][Ee]/
.[Dd][Ii][Ss][Aa][Bb][Ll][Ee]/
# Matches DISABLED / .DISABLED
[Dd][Ii][Ss][Aa][Bb][Ll][Ee][Dd]/
.[Dd][Ii][Ss][Aa][Bb][Ll][Ee][Dd]/
# Matches DEBUG / .DEBUG
[Dd][Ee][Bb][Uu][Gg]/
.[Dd][Ee][Bb][Uu][Gg]/
# Matches TMP / .TMP
[Tt][Mm][Pp]/
.[Tt][Mm][Pp]/
# Matches TEMP / .TEMP
[Tt][Ee][Mm][Pp]/
.[Tt][Ee][Mm][Pp]/
# Matches TEMPORARY / .TEMPORARY
[Tt][Ee][Mm][Pp][Oo][Rr][Aa][Rr][Yy]/
.[Tt][Ee][Mm][Pp][Oo][Rr][Aa][Rr][Yy]/
# Matches TESTING / .TESTING
[Tt][Ee][Ss][Tt][Ii][Nn][Gg]/
.[Tt][Ee][Ss][Tt][Ii][Nn][Gg]/
# ──────────────────── Planning Artifacts ───────────────────
# Catalog files generated by pre-implementation analysis passes
opinionated_catalog.md
.superpowers
docs/superpowers
docs/specs
docs/plans
# ──────────────────── Runtime State Files ───────────────────
# Sentinel file written/removed at runtime to coordinate logging state
# across the fish config and the Kitty Python watcher. Never committed.
.logging_disabled
# ──────────────── Fisher-Managed Plugin Files ───────────────
# Fisher writes these into the repo directory on install/update.
# They are owned by Fisher — do not commit them.
functions/fisher.fish
completions/fisher.fish
conf.d/sponge.fish
functions/_sponge*.fish
functions/sponge_*.fish
!functions/sponge_filter_secrets.fish
# ─────────────────── AI Sessions and Rules ──────────────────
# Matches CLAUDE.md, .claud*, etc.
[Cc][Ll][Aa][Uu][Dd][Ee].[Mm][Dd]
.[Cc][Ll][Aa][Uu][Dd]*
# Matches GEMINI.md, .gemin*, etc.
[Gg][Ee][Mm][Ii][Nn][Ii].[Mm][Dd]
.[Gg][Ee][Mm][Ii][Nn]*
# Matches ANTIGRAVITY.md, .antigrav*, etc.
[Aa][nN][Tt][Ii][Gg][Rr][Aa][Vv][Ii][Tt][Yy].[Mm][Dd]
.[Aa][Nn][Tt][Ii][Gg][Rr][Aa][Vv]*
# Matches AGENTS.md, .remember, etc.
[Aa][Gg][Ee][Nn][Tt][Ss].[Mm][Dd]
.[Rr][Ee][Mm][Ee][Mm][Bb][Ee][Rr]
# ──────────────────────────────────────────────────────────────
# id: gi-patterns-a62e4f6489ac26edaabdfc550334800a
# Created by https://www.toptal.com/developers/gitignore/api/fish
# Edit at https://www.toptal.com/developers/gitignore?templates=fish
### Fish ### ### Fish ###
fishd.* fishd.*
fish_history fish_history
fish_variables fish_variables
config.local.fish config.local.fish
### Linux ### # End of https://www.toptal.com/developers/gitignore/api/fish
*~
# temporary files which can be created if a process still has a handle open of a deleted file # id: gi-patterns-e390e9c720b3dda36906a2b4cb76ffdd
.fuse_hidden* # Created by https://www.toptal.com/developers/gitignore/api/python
# Edit at https://www.toptal.com/developers/gitignore?templates=python
# KDE directory preferences ### Python ###
.directory # Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# Linux trash folder which might appear on any partition or disk # C extensions
.Trash-* *.so
# .nfs files are created when an open file is removed but is still being accessed # Distribution / packaging
.nfs* .Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# Debug Files/Folders # PyInstaller
OLD/ # Usually these files are written by a python script from a template
*.OLD # before PyInstaller builds the exe, so as to inject date/other infos into it.
*.DISABLE *.manifest
*.DISABLED *.spec
*_old
# AI Session IDs # Installer logs
.claude_session pip-log.txt
.gemini_session pip-delete-this-directory.txt
.remember/
# Auto-managed by fish; contains machine-local state and universal vars # Unit test / coverage reports
fish_variables htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
### Python Patch ###
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
poetry.toml
# ruff
.ruff_cache/
# LSP config files
pyrightconfig.json
# End of https://www.toptal.com/developers/gitignore/api/python
# ──────────────── Added by agents-init ──────────────────
# agents-init --agents
AGENTS/
# ────────────────────────────────────────────────────────
# ──────────────── Added by agents-init ──────────────────
# agents-init --plugins
docs/devlogs
# ────────────────────────────────────────────────────────
/.cache_ggshield
user-dots
# ──────────────────── Generated Docs Site ───────────────────
docs/site/node_modules/
docs/site/dist/
docs/site/.astro/
docs/site/src/content/docs/
docs/site/src/sidebar.json
+192 -449
View File
@@ -1,21 +1,21 @@
# Fish Shell Configuration # Fish Shell Configuration
A feature-rich Fish shell configuration for CachyOS (Arch Linux), 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. A feature-rich Fish shell configuration for CachyOS (Arch Linux),
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 ## Table of Contents
- [Overview](#overview) - [Overview](#overview)
- [Structure](#structure) - [Session Logging](#session-logging)
- [Plugins](#plugins) - [Documentation](#documentation)
- [Theme & Prompt](#theme--prompt)
- [Integrations](#integrations)
- [Key Bindings](#key-bindings)
- [Functions](#functions)
- [Abbreviations](#abbreviations)
- [Dependencies](#dependencies)
- [Installation](#installation) - [Installation](#installation)
- [Personalization](#personalization) - [Personalization](#personalization)
- [Full Requirements](#full-requirements) - [Minimal Mode](#minimal-mode)
- [Attribution](#attribution)
- [License](#license) - [License](#license)
--- ---
@@ -24,462 +24,141 @@ A feature-rich Fish shell configuration for CachyOS (Arch Linux), built around a
This config layers on top of the CachyOS base Fish configuration and adds: This config layers on top of the CachyOS base Fish configuration and adds:
- **Catppuccin Mocha** theming throughout (prompt, FZF, Zellij) - **Catppuccin Mocha** theming throughout (prompt, FZF, syntax highlighting)
- **Starship** prompt with VI key bindings - **Starship** prompt with VI key bindings; Catppuccin Mocha nim-style fallback prompt when Starship is absent or C3 overrides are disabled
- **Fisher** plugin management with FZF key bindings and Catppuccin syntax colors - **Fisher** plugin manager bootstrapped automatically; manages `sponge` (failed-command history filter); FZF bindings, Catppuccin theme, done, autopair, and puffer-fish are bundled directly with the config as customized versions
- **Smart CLI wrappers** that prefer modern tools (`eza`, `bat`, `btop`, `dust`, `prettyping`) with graceful fallbacks - **Smart CLI wrappers** that prefer modern tools (`eza`, `bat`, `btop`, `dust`, `prettyping`) with graceful fallbacks
- **Auto Python venv** activation on directory change (direnv-aware) - **Auto Python venv** activation on directory change (direnv-aware)
- **Kitty terminal** deep integration for splits, tabs, and SSH - **Kitty terminal** deep integration for splits, tabs, and SSH
- **AI workflow** helpers for Claude and Gemini session management - **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 - **WakaTime** shell activity tracking
- **Opt-out toggles** for every opinionated component — see [Minimal Mode](#minimal-mode)
> [!CAUTION]
> **This configuration *can* log your terminal sessions to disk.** Logging is
> **off by default** — but once enabled it silently captures terminal output to
> `~/.terminal_history`: Kitty scrollback when a window closes, live tmux pane
> streams, zellij pane snapshots on exit, and full `paru`/`yay` output. These
> logs can contain command output, file contents, and anything else printed to
> your terminal. Nothing is sent off your machine, but the files persist
> locally until pruned.
>
> To turn logging on, set the C5 category variable:
>
> ```fish
> set -U __fish_config_op_logging on
> ```
>
> Or run **`config-settings`** for an interactive menu to flip logging (and any
> other opinionated category) on or off — no variable names to remember.
>
> This takes effect immediately in every open shell. See [Session Logging](#session-logging)
> for exactly what is captured and where, and [Minimal Mode](#minimal-mode) for the
> full set of opt-out toggles.
--- ---
## Structure ## Session Logging
``` This config can capture terminal output to `~/.terminal_history` (override with
~/.config/fish/ `$SCROLLBACK_HISTORY_DIR`) so you can search back through past sessions. It is
├── config.fish # Main entry point **off by default** — opt in with `set -U __fish_config_op_logging on`. Once
├── fish_plugins # Fisher plugin list enabled, five sources feed it:
├── fish_variables # Universal variables
├── conf.d/ # Auto-sourced configuration fragments
│ ├── abbr.fish # All abbreviations
│ ├── cheat.fish # cheat.sh completions
│ ├── key_bindings.fish # Custom key bindings
│ ├── fzf.fish # FZF key binding initialization
│ ├── tailscale.fish # Tailscale CLI completions
│ ├── theme.fish # Theme syntax highlighting colors
│ ├── wakatime.fish # WakaTime shell hook
│ └── zoxide.fish # Zoxide z/zi aliases
├── functions/ # Custom functions (one per file)
├── completions/ # Custom tab completions
├── integrations/ # Integration scripts
│ └── fzf.fish # FZF theme and binding config
└── themes/ # Catppuccin theme files
├── Catppuccin Mocha.theme
├── Catppuccin Macchiato.theme
├── Catppuccin Frappe.theme
└── Catppuccin Latte.theme
```
--- | Source | When it captures | Log file |
## Plugins
Managed via [Fisher](https://github.com/jorgebucaran/fisher):
| Plugin | Purpose |
|---|---|
| `jorgebucaran/fisher` | Plugin manager |
| `patrickf1/fzf.fish` | FZF key bindings for history, files, processes, git |
| `catppuccin/fish` | Catppuccin Mocha syntax highlighting |
| `jorgebucaran/autopair.fish` | Auto-close brackets, quotes, and other pairs |
| `jorgebucaran/replay.fish` | Run bash commands in fish without losing state |
| `nickeb96/puffer-fish` | Expand `...` to `../..`, `!!` to last command, etc. |
| `mattmc3/magic-enter.fish` | Smart Enter: runs `ls` / `git status` on blank line |
| `jorgebucaran/spark.fish` | Sparkline bar charts in the terminal |
Fisher and all listed plugins are installed automatically by the bootstrap script in `config.fish` upon launching the shell for the first time.
---
## Theme & Prompt
### Starship
The primary prompt is [Starship](https://starship.rs/), initialized in `config.fish`. Configure it via `~/.config/starship.toml`.
### FZF
FZF is themed to Catppuccin Mocha with the following colors set via `FZF_DEFAULT_OPTS`:
- Background: `#1E1E2E` / `#313244`
- Foreground: `#CDD6F4`
- Highlights: `#F38BA8` (red), `#CBA6F7` (mauve), `#B4BEFE` (lavender)
See [FZF Bindings](#fzf-bindings) under Key Bindings for the default FZF shortcuts.
---
## Integrations
> **Note:** All integrations listed below are designed to gracefully fallback to basic commands or safely ignore their configuration if their required external dependencies are not installed on the system.
### Zoxide
Smart `cd` replacement. `cd` (or `z`) `<keyword>` jumps to the best frecency match; `cdi` (or `zi`) opens an interactive selector.
### DirEnv
Automatically loads `.envrc` files on directory change. Takes priority over the built-in auto-venv logic.
### Auto Python Venv
When entering a directory containing a `.venv/`, the virtualenv is automatically activated. It is deactivated when you leave the project tree. DirEnv-managed directories are skipped to avoid conflicts.
### WakaTime
Every shell command is reported to WakaTime for time-tracking. Disable by setting `FISH_WAKATIME_DISABLED=1`.
### Tailscale
Full tab completion for the `tailscale` CLI is provided via `conf.d/tailscale.fish`.
---
## Key Bindings
### FZF Bindings
These are the default FZF bindings (from `fzf.fish`):
| Binding | Action |
|---|---|
| `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 |
### User Bindings
Beyond standard shell and FZF bindings, these custom interactive shortcuts are available:
| Binding | Action | Description |
|---|---|---| |---|---|---|
| `Ctrl+G` | Previous Path Head | Behaves like `!$:h` in Bash. Inserts the directory part of the previous command's last argument. | | Kitty scrollback | When a Kitty window/tab closes | `scrollback_<timestamp>.log` |
| `Ctrl+F` | Interactive History Substitution | Behaves like `!!:s/old/new/` in Bash. Performs substitution on the previous command using `old/new` syntax. When no text is entered, prepends `sudo` to the previous command. The `old/new/n` syntax will perform substitution on the command `n` lines previous in the history. | | tmux pane | Continuously while the pane is open (`pipe-pane`) | `tmux_<session>-w<win>-p<pane>_<timestamp>.log` |
| `Ctrl+Alt+U` | Replace Command Token | Strips the first token (the command) from the current line. **If the line is empty**, it pulls the previous command and strips its first token, placing the cursor at the start for a quick replacement (e.g., changing `mkdir` to `cd` while keeping the paths). | | 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.
## Functions > **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.
### Modern CLI Replacements **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.
These functions wrap modern alternatives with graceful fallbacks to standard tools. All of it is controlled by a single universal variable:
| Function | Replaces | Tool |
|---|---|---|
| `ls` | `ls` | `eza` (falls back to `lsd`, then system `ls`) |
| `cat` | `cat` | `bat` (plain, no pager) |
| `less` | `less` | `most` |
| `ping` | `ping` | `prettyping --nolegend` |
| `top` | `top` | `btop` |
| `rg` | `rg` | ripgrep with `--hyperlink-format=kitty` |
| `ssh` | `ssh` | `kitten ssh` when inside Kitty |
| `du` | `du` | `duf` (disks) / `dust` (directories) — auto-detected by argument |
| `mkdir` | `mkdir` | Always passes `-p` in interactive mode |
#### `du` — Smart Disk Usage
```fish ```fish
du # → duf (disk overview) set -U __fish_config_op_logging on # enable; takes effect in every open shell
du /some/dir # → dust (directory breakdown) set -U __fish_config_op_logging off # disable again
du --disk # → duf (force disk view) set -Ue __fish_config_op_logging # erase — back to the default (off)
du --dir # → dust (force directory view)
du --dua # → dua (interactive mode)
``` ```
#### `rm` — Trash-Aware Remove Unlike the other categories, C5 is opt-in: an unset variable means off, and
`__fish_config_opinionated` cannot turn it on for you.
```fish Prefer an interactive interface? Run **`config-settings`** for a full-screen
rm # List current trash contents picker that flips logging — and every other opinionated category — on or off
rm file.txt # Move to trash (recoverable) per session or universally, without memorizing variable names.
rm -r dir/ # Move directory to trash
rm -e # Empty all trash
rm -e --within 2weeks # Empty trash older than 2 weeks
rm -S file.txt # Permanent secure delete + fstrim
rm -f file.txt # Falls through to standard rm -f
```
### Directory & File Listing 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.
| Function | Description | 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 |
|---|---| |---|---|
| `ls` | `eza` — long listing, all files, icons, color, hyperlinks | | `kitty-logging install` | Symlink the watcher into your Kitty config and wire it into `kitty.conf` |
| `lss` | `eza` — size-sorted long listing with gradient color scale | | `kitty-logging uninstall` | Remove the managed block and the watcher symlink |
| `lsr` | `eza` — reversed time-sorted oneline listing | | `kitty-logging status` | Show whether it's wired, the watcher version, and C5 state |
| `ltr` | `eza` — long listing, reversed modification time, age color scale | | `kitty-logging dismiss` | Stop the per-session reminder without installing |
| `lD` | `eza` — directories only |
| `lx` | `eza` — long listing sorted by extension |
| `lt` | `eza` — tree listing, depth 2 |
| `lstree` | `eza` — full recursive tree |
### Git `install` adds a clearly-marked managed block to `kitty.conf` and comments out
any conflicting `watcher` line. It affects **new** Kitty windows (existing
| Function | Description | windows keep their current watcher until restarted). With C5 logging off the
|---|---| watcher is inert without needing to be uninstalled, and the reminder stays
| `branch` | Switch to or create a git branch | silent until you enable logging.
| `gitup` | Fetch updates and show git status |
| `git-clean` | Fetch, prune, update current branch, delete orphaned local branches |
| `git-clean --force` | Same but force-deletes unmerged orphaned branches |
| `clone` | `clone-in-kitty` wrapper |
| `gitui` | Fast terminal Git UI |
### Package Management (Arch / paru)
| Function | Description |
|---|---|
| `pkg <name>` | Install package: `paru -S <name>` |
| `search <query>` | Search/install interactively: `paru <query>` |
| `upgrade` | Full system upgrade: `paru -Syu --noconfirm` |
| `cleanup` | Log and remove orphaned packages |
### Docker
| Function | Description |
|---|---|
| `ld` / `lzd` | Launch LazyDocker using the currently active Docker context |
| `dockup [dir]` | Pull latest images and restart docker compose services |
| `docker ps` | Intercepted to use `dops` for a prettier process listing |
### Network
| Function | Description |
|---|---|
| `gip` | Show both public IPv4 and IPv6 addresses |
| `gip4` | Show public IPv4 address only |
| `gip6` | Show public IPv6 address (or error if unavailable) |
| `ports` | List all active TCP listeners via `lsof` |
### Clipboard
| Function | Description |
|---|---|
| `y <text>` | Copy text to clipboard (Wayland `wl-copy` or X11 `xclip`) |
| `cb <text>` | Copy to clipboard (alias for `y`) |
| `paste` | Paste from clipboard to stdout |
### Terminal
| Function | Description |
|---|---|
| `split [-h\|-v] [cmd]` | Open a new split pane, optionally running a command |
| `spwin` | Spawn a new OS window |
| `detach <cmd>` | Run a command fully detached (`nohup`), no output |
| `bkg <cmd>` | Background a command, discarding all output |
### System
| Function | Description |
|---|---|
| `lock` | Lock the session via `loginctl lock-session` |
| `screensleep` | Turn off the display via KDE PowerDevil |
| `wake-lock <cmd>` | Run a command with `systemd-inhibit` to prevent sleep |
| `swapstat` | Colorized zRAM compression ratio, swappiness, and swap priority report |
| `tmux-clean` | Kill all detached tmux sessions |
| `limine-edit` | Safely edit and re-verify Limine bootloader configuration |
| `sbver` | Verify bootloader signing status for Secure Boot |
### Media & Utilities
| Function | Description |
|---|---|
| `dng2avif` | Convert DNG raw images to 10-bit HDR AVIF |
| `steam-dl` | Run Steam while inhibiting system sleep |
### Editors & Development
| Function | Description |
|---|---|
| `edit` / `e` | Open in Neovim (or `$EDITOR`) |
| `view` | Open in Neovim read-only mode |
| `fc` | Edit and execute the last command (Bash-style `fc`) |
| `nvimup` | Update Neovim headlessly |
| `nlazyup` | Sync Lazy.nvim plugins headlessly |
### AI Assistants
| Function | Description |
|---|---|
| `claude-resume` | Resume Claude Code session from `.claude_session` in CWD |
| `gemini-resume` | Resume Gemini CLI session from `.gemini_session` in CWD |
| `code-resume` | Smart resume — tries Claude then Gemini, falls back to picker |
| `superpowers [on\|off]` | Enable/disable the Superpowers extension for Claude and Gemini |
### Fetch & Info
| Function | Description |
|---|---|
| `ffetch` | Run fastfetch with `~/.fastfetch.jsonc` if present |
| `cffetch` | Clear screen then run fastfetch |
| `hist` | FZF history search — selected command is placed in the prompt and copied to clipboard |
| `qr <text>` | Generate a terminal QR code |
### Miscellaneous
| Function | Description |
|---|---|
| `upgrade` | System upgrade via paru |
| `zellij` | Zellij with `--theme catppuccin-mocha` |
| `antigravity` | Wrapper that suppresses a noisy deprecation warning |
| `bash` | Drop into bash (raw Fish session via `rawfish`) |
--- ---
## Abbreviations ## Documentation
Abbreviations expand in-place as you type, keeping your history clean. ### [📖 Documentation Site](https://fish.rootiest.fyi/)
### History Expansions (Bash-style) 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.
These abbreviations replicate Bash's bang-style history expansions. They expand anywhere in the command line when a trigger key (like `Space` or `Enter`) is pressed. Contributing to the docs? There are two sources, split by content type:
| Abbr | Expansion | Description | - **Function documentation** comes from the man-page-style comment header
|---|---|---| above each function in `functions/*.fish`. Edit the function; the entry
| `!^` | First argument | Expands to the first argument of the previous command | and its site page are generated from the header.
| `!*` | All arguments | Expands to all arguments of the previous command | - **Everything else** lives under `docs/manual/**`.
| `!-n` | n-th previous | Expands to the n-th previous command in history (e.g., `!-2`) |
| `!string` | Prefix search | Expands to the most recent command starting with `string` |
| `!?string?` | Contains search | Expands to the most recent command containing `string` |
| `^old^new` | Quick substitution | Replaces `old` with `new` in the previous command and expands to it |
### Editors Never edit the generated `docs/fish-config.md` — it's rebuilt from both
sources and any hand-edits are discarded.
| Abbr | Expands To | To browse the docs from the terminal:
| Command | Description |
|---|---| |---|---|
| `n`, `nv` | `nvim` | | `help config` | Open the terminal manual in the best available pager |
| `e` | `edit` | | `help config <keyword>` | Jump directly to a section matching the keyword |
| `se` | `sudoedit` | | `help config --html` | Open the documentation site in the default browser |
| `v` | `antigravity` (VSCode-equivalent) | | `help config --man` | Open the compiled man page via `man -l` |
| `k` | `kate` | | `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) |
### Listing The pager falls back through: **ov****bat****man -l****less****cat**.
| Abbr | Expands To | > **Note:** `fish-config` (hyphen) is this configuration's man page. `fish_config` (underscore) is fish's built-in browser-based configuration tool — a completely separate command. Don't mix them up.
|---|---|
| `l` | `ls` |
| `lS` | `lss` (size-sorted) |
| `lsR` | `lsr` (reversed time) |
| `lX` | `lx` (extension-sorted) |
| `lT` | `lt` (tree, depth 2) |
| `lsT` | `lstree` (full tree) |
### Navigation
| Abbr | Expands To |
|---|---|
| `cdnv` | `cd ~/.config/nvim` |
| `:cdf` | `cd ~/.config/fish/` |
| `:cdk` | `cd ~/.config/kitty/` |
| `:cdh` | `cd ~` |
| `:cdp` | `cd ~/projects/` (with cursor placement) |
| `:cdcz` | `cd ~/.local/share/chezmoi/` |
### Git
| Abbr | Expands To |
|---|---|
| `g` | `git` |
| `lg` | `lazygit` |
### Chezmoi
| Abbr | Expands To |
|---|---|
| `cm` / `cz` | `chezmoi` |
| `cmcd` | `chezmoi cd` |
| `cme` | `chezmoi edit` |
| `cmad` | `chezmoi add` |
| `cmap` | `chezmoi apply` |
| `cmf` | `chezmoi forget` |
| `cmi` | `chezmoi init` |
### Kitty / WezTerm Window Management
These abbreviations mirror Vim/tmux ergonomics for managing terminal splits, tabs, and windows. They automatically detect whether you are using Kitty or WezTerm and execute the appropriate terminal CLI commands.
| Abbr | Action |
|---|---|
| `:q` | Close active pane |
| `:Q` | Close active tab |
| `:w` | New OS window |
| `:t` | New tab |
| `:wv` | Horizontal split |
| `:wh` | Vertical split |
| `:tp` / `:tn` | Navigate tabs left/right |
| `:tl "Title"` | Rename current tab |
| `:tgn` | New tab in `~/.config/nvim` |
| `:tgf` | New tab in `~/.config/fish` |
| `:tgp` | New tab in `~/projects` |
| `:tgr` | New root tab (`sudo -i`) |
### SSH
Machine-specific SSH abbreviations (e.g. `sshr`, `sshrt`) live in `~/.config/.user-dots/fish/local.fish`.
(See [Personalization](#personalization) for examples)
### Docker
| Abbr | Expands To |
|---|---|
| `dcl` | `docker context use default` |
| `dcls` | `docker context ls` |
| `lzd` | `ld` (LazyDocker) |
Named context shortcuts (e.g. `dcr`, `dck`) live in `~/.config/.user-dots/fish/local.fish`.
(See [Personalization](#personalization) for examples)
### Systemctl
| Abbr | Expands To |
|---|---|
| `sc` | `systemctl` |
| `ssc` | `sudo systemctl` |
| `scu` | `systemctl --user` |
| `st` | `systemctl status` |
| `scs` | `systemctl start` |
| `scr` | `systemctl restart` |
| `ssct` | `sudo systemctl status` |
| `sscs` | `sudo systemctl start` |
| `sscr` | `sudo systemctl restart` |
### Beads (bd)
| Abbr | Expands To |
|---|---|
| `bl` | `bd list` |
| `bs` | `bd sync` |
| `bC` | `bd create --title` |
| `bsh` | `bd show` |
| `lb` | `lazybeads` |
---
## Dependencies
### Required
| Tool | Purpose |
|---|---|
| [Fish](https://fishshell.com/) | Shell |
| [Fisher](https://github.com/jorgebucaran/fisher) | Plugin manager |
| [Starship](https://starship.rs/) | Prompt |
| [fzf](https://github.com/junegunn/fzf) | Fuzzy finder |
| [zoxide](https://github.com/ajeetdsouza/zoxide) | Smart directory jumper |
| [direnv](https://direnv.net/) | Per-directory env loading |
| [paru](https://github.com/Morganamilo/paru) | AUR helper |
### Recommended
| Tool | Replaces |
|---|---|
| [eza](https://github.com/eza-community/eza) | `ls` (preferred) |
| [lsd](https://github.com/lsd-rs/lsd) | `ls` (fallback) |
| [bat](https://github.com/sharkdp/bat) | `cat` |
| [btop](https://github.com/aristocratsupply/btop) | `top` |
| [dust](https://github.com/bootandy/dust) | `du` (directories) |
| [duf](https://github.com/muesli/duf) | `du` (disks) |
| [prettyping](https://github.com/denilsonsa/prettyping) | `ping` |
| [most](https://www.jedsoft.org/most/) | `less` |
| [ripgrep](https://github.com/BurntSushi/ripgrep) | `grep` |
| [lazygit](https://github.com/jesseduffield/lazygit) | git TUI |
| [lazydocker](https://github.com/jesseduffield/lazydocker) | Docker TUI |
| [trash-cli](https://github.com/andreafrancia/trash-cli) | Safe `rm` |
| [Kitty](https://sw.kovidgoyal.net/kitty/) / [WezTerm](https://wezfurlong.org/wezterm/) | Terminal emulator |
| [WakaTime](https://wakatime.com/) | Activity tracking |
--- ---
@@ -495,20 +174,39 @@ mv ~/.config/fish ~/.config/fish.bak
git clone https://git.rootiest.dev/rootiest/fish-config.git ~/.config/fish git clone https://git.rootiest.dev/rootiest/fish-config.git ~/.config/fish
``` ```
Then open a new Fish shell — Fisher and all plugins will be installed automatically on first launch, and the Catppuccin Mocha theme will be applied. 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.
### Updating the Config
Pull the latest changes from upstream without needing a configured git remote:
| Command | Description |
|---|---|
| `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 |
--- ---
## Personalization ## Personalization
Sensitive credentials and machine-specific paths are kept out of version control via a secondary private directory at `~/.config/.user-dots/fish/`. Two files are sourced automatically by `config.fish` if they exist: Sensitive credentials and machine-specific paths are kept out of version control via a private overlay directory. The path defaults to `~/.config/.user-dots/fish/` but can be changed by setting a universal variable:
```fish
set -U __fish_user_dots_path /path/to/your/dots/fish
```
`config.fish` sources `local.fish` from that directory. `local.fish` is responsible for sourcing its own `secrets.fish` companion:
``` ```
~/.config/.user-dots/fish/ $__fish_user_dots_path/
├── secrets.fish # API keys, tokens, passwords, personal identifiers ├── secrets.fish # API keys, tokens, passwords, personal identifiers
└── local.fish # Machine-specific paths and environment variables └── local.fish # Machine-specific paths, env vars, and sourcing secrets
``` ```
### secrets.fish ### secrets.fish
@@ -541,12 +239,12 @@ Use this file for paths and variables that are specific to one machine — thing
```fish ```fish
# ~/.config/.user-dots/fish/local.fish # ~/.config/.user-dots/fish/local.fish
# Project root for quick cd
set -gx cdp /home/youruser/projects
# CDPATH — directories searched by cd # CDPATH — directories searched by cd
set -gx CDPATH . /home/youruser/projects /home/youruser set -gx CDPATH . /home/youruser/projects /home/youruser
# Path to your shared .gitignore boilerplate (used by `gi -b` / `gi` default)
set -gx GITIGNORE_BOILERPLATE ~/.config/git/gitignore_boilerplate
### SSH ### ### SSH ###
# Quick shortcuts to your own servers # Quick shortcuts to your own servers
abbr -a sshr 'ssh you@your-server.local' abbr -a sshr 'ssh you@your-server.local'
@@ -560,25 +258,70 @@ abbr -a dcw 'docker context use work-server'
### How it works ### How it works
`config.fish` sources both files with an existence check so the public config works cleanly on any machine that doesn't have the private repo: `config.fish` sources only `local.fish` with an existence check so the public config works cleanly on any machine without the private repo. `local.fish` is responsible for sourcing its own `secrets.fish`:
```fish ```fish
if test -f $HOME/.config/.user-dots/fish/secrets.fish # config.fish resolves the path, then sources local.fish
source $HOME/.config/.user-dots/fish/secrets.fish set -q __fish_user_dots_path
end or set -l __fish_user_dots_path "$XDG_CONFIG_HOME/.user-dots/fish"
test -f "$__fish_user_dots_path/local.fish"
if test -f $HOME/.config/.user-dots/fish/local.fish and source "$__fish_user_dots_path/local.fish"
source $HOME/.config/.user-dots/fish/local.fish
end
``` ```
For convenience, a git-ignored `user-dots` symlink in the fish config directory is pointed at `$__fish_user_dots_path` on startup, so the overlay can be browsed from `~/.config/fish/`. It is recreated if missing and repointed if the path variable changes. Creation is a C2 startup side-effect (`__fish_config_op_autoexec`); it only ever manages a symlink and never clobbers a real file or directory at that path.
To opt out, set `__fish_user_dots_symlink` to a falsy value (or toggle **Dots link** off on the **Paths** page of `config-settings`). Disabling it stops the symlink being generated and removes any existing one immediately — honoured regardless of the C2 master switch.
`fish_variables` (which fish auto-manages and may contain universal variable state) is excluded from this repo via `.gitignore`. `fish_variables` (which fish auto-manages and may contain universal variable state) is excluded from this repo via `.gitignore`.
--- ---
## Full Requirements ## Minimal Mode
For a complete, categorized list of all non-standard tools required or used by this configuration, see [requirements.md](requirements.md). Everything opinionated in this config — command shadows, startup side-effects, key and environment overrides, terminal integrations, and the first-run greeting — is active by default but can be switched off. Logging (C5) is the exception: it is **opt-in**, off until you explicitly enable it.
> **The easy way — `config-settings`:** Run `config-settings` for an interactive TUI that manages settings across four pages — **Universal** and **Session** (the opinionated category toggles below, persistent or per-shell), **Sponge** (history-scrubbing: delay, exit codes, purge-on-exit, and extra sensitive variable names), and **Paths** (scrollback log dir, max files, and the user-dots path) — without typing a single variable name. Navigate with the arrow keys (or `h`/`j`/`k`/`l`); toggle rows step OFF ← DEFAULT → ON, value rows edit inline with `Enter` and 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, `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` | **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 — 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:
```fish
# Plain shell: disable everything opinionated
set -U __fish_config_opinionated 0
# Or pick a single category, e.g. keep integrations but drop command shadows
set -U __fish_config_op_aliases off
# Minimal mode but keep the greeting (per-category overrides master)
set -U __fish_config_opinionated 0
set -U __fish_config_op_greeting 1
# Opt in to session logging (C5 is off by default)
set -U __fish_config_op_logging on
# Back to full flavor
set -Ue __fish_config_opinionated
set -Ue __fish_config_op_greeting
```
Command shadows react immediately; bindings, prompt, and abbreviations take effect in new shells. With aliases disabled, `rm` deletes permanently again instead of trashing. See `help config opinionated` for the full component list.
---
## Attribution
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)'
+235
View File
@@ -0,0 +1,235 @@
# fish completion for ov -*- shell-script -*-
function __ov_debug
set -l file "$BASH_COMP_DEBUG_FILE"
if test -n "$file"
echo "$argv" >> $file
end
end
function __ov_perform_completion
__ov_debug "Starting __ov_perform_completion"
# Extract all args except the last one
set -l args (commandline -opc)
# Extract the last arg and escape it in case it is a space
set -l lastArg (string escape -- (commandline -ct))
__ov_debug "args: $args"
__ov_debug "last arg: $lastArg"
# Disable ActiveHelp which is not supported for fish shell
set -l requestComp "OV_ACTIVE_HELP=0 $args[1] __complete $args[2..-1] $lastArg"
__ov_debug "Calling $requestComp"
set -l results (eval $requestComp 2> /dev/null)
# Some programs may output extra empty lines after the directive.
# Let's ignore them or else it will break completion.
# Ref: https://github.com/spf13/cobra/issues/1279
for line in $results[-1..1]
if test (string trim -- $line) = ""
# Found an empty line, remove it
set results $results[1..-2]
else
# Found non-empty line, we have our proper output
break
end
end
set -l comps $results[1..-2]
set -l directiveLine $results[-1]
# For Fish, when completing a flag with an = (e.g., <program> -n=<TAB>)
# completions must be prefixed with the flag
set -l flagPrefix (string match -r -- '-.*=' "$lastArg")
__ov_debug "Comps: $comps"
__ov_debug "DirectiveLine: $directiveLine"
__ov_debug "flagPrefix: $flagPrefix"
for comp in $comps
printf "%s%s\n" "$flagPrefix" "$comp"
end
printf "%s\n" "$directiveLine"
end
# this function limits calls to __ov_perform_completion, by caching the result behind $__ov_perform_completion_once_result
function __ov_perform_completion_once
__ov_debug "Starting __ov_perform_completion_once"
if test -n "$__ov_perform_completion_once_result"
__ov_debug "Seems like a valid result already exists, skipping __ov_perform_completion"
return 0
end
set --global __ov_perform_completion_once_result (__ov_perform_completion)
if test -z "$__ov_perform_completion_once_result"
__ov_debug "No completions, probably due to a failure"
return 1
end
__ov_debug "Performed completions and set __ov_perform_completion_once_result"
return 0
end
# this function is used to clear the $__ov_perform_completion_once_result variable after completions are run
function __ov_clear_perform_completion_once_result
__ov_debug ""
__ov_debug "========= clearing previously set __ov_perform_completion_once_result variable =========="
set --erase __ov_perform_completion_once_result
__ov_debug "Successfully erased the variable __ov_perform_completion_once_result"
end
function __ov_requires_order_preservation
__ov_debug ""
__ov_debug "========= checking if order preservation is required =========="
__ov_perform_completion_once
if test -z "$__ov_perform_completion_once_result"
__ov_debug "Error determining if order preservation is required"
return 1
end
set -l directive (string sub --start 2 $__ov_perform_completion_once_result[-1])
__ov_debug "Directive is: $directive"
set -l shellCompDirectiveKeepOrder 32
set -l keeporder (math (math --scale 0 $directive / $shellCompDirectiveKeepOrder) % 2)
__ov_debug "Keeporder is: $keeporder"
if test $keeporder -ne 0
__ov_debug "This does require order preservation"
return 0
end
__ov_debug "This doesn't require order preservation"
return 1
end
# This function does two things:
# - Obtain the completions and store them in the global __ov_comp_results
# - Return false if file completion should be performed
function __ov_prepare_completions
__ov_debug ""
__ov_debug "========= starting completion logic =========="
# Start fresh
set --erase __ov_comp_results
__ov_perform_completion_once
__ov_debug "Completion results: $__ov_perform_completion_once_result"
if test -z "$__ov_perform_completion_once_result"
__ov_debug "No completion, probably due to a failure"
# Might as well do file completion, in case it helps
return 1
end
set -l directive (string sub --start 2 $__ov_perform_completion_once_result[-1])
set --global __ov_comp_results $__ov_perform_completion_once_result[1..-2]
__ov_debug "Completions are: $__ov_comp_results"
__ov_debug "Directive is: $directive"
set -l shellCompDirectiveError 1
set -l shellCompDirectiveNoSpace 2
set -l shellCompDirectiveNoFileComp 4
set -l shellCompDirectiveFilterFileExt 8
set -l shellCompDirectiveFilterDirs 16
if test -z "$directive"
set directive 0
end
set -l compErr (math (math --scale 0 $directive / $shellCompDirectiveError) % 2)
if test $compErr -eq 1
__ov_debug "Received error directive: aborting."
# Might as well do file completion, in case it helps
return 1
end
set -l filefilter (math (math --scale 0 $directive / $shellCompDirectiveFilterFileExt) % 2)
set -l dirfilter (math (math --scale 0 $directive / $shellCompDirectiveFilterDirs) % 2)
if test $filefilter -eq 1; or test $dirfilter -eq 1
__ov_debug "File extension filtering or directory filtering not supported"
# Do full file completion instead
return 1
end
set -l nospace (math (math --scale 0 $directive / $shellCompDirectiveNoSpace) % 2)
set -l nofiles (math (math --scale 0 $directive / $shellCompDirectiveNoFileComp) % 2)
__ov_debug "nospace: $nospace, nofiles: $nofiles"
# If we want to prevent a space, or if file completion is NOT disabled,
# we need to count the number of valid completions.
# To do so, we will filter on prefix as the completions we have received
# may not already be filtered so as to allow fish to match on different
# criteria than the prefix.
if test $nospace -ne 0; or test $nofiles -eq 0
set -l prefix (commandline -t | string escape --style=regex)
__ov_debug "prefix: $prefix"
set -l completions (string match -r -- "^$prefix.*" $__ov_comp_results)
set --global __ov_comp_results $completions
__ov_debug "Filtered completions are: $__ov_comp_results"
# Important not to quote the variable for count to work
set -l numComps (count $__ov_comp_results)
__ov_debug "numComps: $numComps"
if test $numComps -eq 1; and test $nospace -ne 0
# We must first split on \t to get rid of the descriptions to be
# able to check what the actual completion will be.
# We don't need descriptions anyway since there is only a single
# real completion which the shell will expand immediately.
set -l split (string split --max 1 \t $__ov_comp_results[1])
# Fish won't add a space if the completion ends with any
# of the following characters: @=/:.,
set -l lastChar (string sub -s -1 -- $split)
if not string match -r -q "[@=/:.,]" -- "$lastChar"
# In other cases, to support the "nospace" directive we trick the shell
# by outputting an extra, longer completion.
__ov_debug "Adding second completion to perform nospace directive"
set --global __ov_comp_results $split[1] $split[1].
__ov_debug "Completions are now: $__ov_comp_results"
end
end
if test $numComps -eq 0; and test $nofiles -eq 0
# To be consistent with bash and zsh, we only trigger file
# completion when there are no other completions
__ov_debug "Requesting file completion"
return 1
end
end
return 0
end
# Since Fish completions are only loaded once the user triggers them, we trigger them ourselves
# so we can properly delete any completions provided by another script.
# Only do this if the program can be found, or else fish may print some errors; besides,
# the existing completions will only be loaded if the program can be found.
if type -q "ov"
# The space after the program name is essential to trigger completion for the program
# and not completion of the program name itself.
# Also, we use '> /dev/null 2>&1' since '&>' is not supported in older versions of fish.
complete --do-complete "ov " > /dev/null 2>&1
end
# Remove any pre-existing completions for the program since we will be handling all of them.
complete -c ov -e
# this will get called after the two calls below and clear the $__ov_perform_completion_once_result global
complete -c ov -n '__ov_clear_perform_completion_once_result'
# The call to __ov_prepare_completions will setup __ov_comp_results
# which provides the program's completion choices.
# If this doesn't require order preservation, we don't use the -k flag
complete -c ov -n 'not __ov_requires_order_preservation && __ov_prepare_completions' -f -a '$__ov_comp_results'
# otherwise we use the -k flag
complete -k -c ov -n '__ov_requires_order_preservation && __ov_prepare_completions' -f -a '$__ov_comp_results'
+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'
+43
View File
@@ -0,0 +1,43 @@
# Sourced from icezyclon/zoxide.fish (MIT)
set -l commands add help import init query remove
# disable normal all-files completion
complete -c zoxide -f
# onyl show base options if none was used already
complete -c zoxide -n __fish_use_subcommand -a add -d "Add a new directory or increment its rank"
complete -c zoxide -n __fish_use_subcommand -a help -d "Prints this message or the help of the given subcommand(s)"
complete -c zoxide -n __fish_use_subcommand -a import -d "Import from z database"
complete -c zoxide -n __fish_use_subcommand -a init -d "Generates shell configuration"
complete -c zoxide -n __fish_use_subcommand -a query -d "Search for a directory"
complete -c zoxide -n __fish_use_subcommand -a remove -d "Remove a directory"
# zoxide add
complete -c zoxide -n "_zoxide_equals_first_token add" -n "__fish_is_nth_token 2" -a "(__fish_complete_directories)"
# zoxide help
complete -c zoxide -n "_zoxide_equals_first_token help" -n "__fish_is_nth_token 2" -a "$commands"
# zoxide import
complete -c zoxide -r -F -n "_zoxide_equals_first_token import" -n "__fish_is_nth_token 2"
complete -c zoxide -r -n "_zoxide_equals_first_token import" -l merge -d "Merge entries into existing database"
# zoxide init
set -l initshells bash fish posix powershell zsh
complete -c zoxide -n "_zoxide_equals_first_token init" -n "__fish_is_nth_token 2" -a "$initshells"
complete -c zoxide -n "_zoxide_equals_first_token init" -l cmd -d "Renames the 'z' command and corresponding aliases [default: z]"
complete -c zoxide -n "_zoxide_equals_first_token init" -l hook -a "none prompt pwd" -d "Chooses event on which an entry is added to the database [default: pwd]"
complete -c zoxide -n "_zoxide_equals_first_token init" -l no-aliases -d "Prevents zoxide from defining any commands other than 'z'"
# zoxide query
complete -c zoxide -r -n "_zoxide_equals_first_token query" -s i -l interactive -d "Opens an interactive selection menu using fzf"
complete -c zoxide -r -n "_zoxide_equals_first_token query" -s l -l list -d "List all matching directories"
complete -c zoxide -r -n "_zoxide_equals_first_token query" -s s -l score -d "Display score along with result"
# zoxide remove
complete -c zoxide -n "_zoxide_equals_first_token remove" -n "__fish_is_nth_token 2" -a "(zoxide query -l)"
# Always possible
complete -c zoxide -x -s h -l help -d "Prints help information"
complete -c zoxide -x -s V -l version -d "Prints version information"
+568 -183
View File
@@ -9,301 +9,686 @@
# It is sourced by Fish on startup. # It is sourced by Fish on startup.
# Neovim # Neovim
# @category Editors
# @desc nvim
abbr -a n nvim abbr -a n nvim
# @category Editors
# @desc nvim
abbr -a nv nvim abbr -a nv nvim
# @category Editors
# @desc nvim
abbr -a neovim nvim abbr -a neovim nvim
# @category Editors
# @desc cd ~/.config/nvim
abbr -a cdnv 'cd ~/.config/nvim # Neovim Config' abbr -a cdnv 'cd ~/.config/nvim # Neovim Config'
# @category Editors
# @desc cd ~/.config/nvim; nvim
abbr -a cdnvn 'cd ~/.config/nvim;nvim' abbr -a cdnvn 'cd ~/.config/nvim;nvim'
# VSCode # VSCode
abbr -a v antigravity # @category AI Assistants
# @desc antigravity-ide
abbr -a v antigravity-ide
# Kate # Kate
# @category Editors
# @desc kate
abbr -a k kate abbr -a k kate
# WezTerm SSH # WezTerm SSH
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category AI Assistants
# @desc wezterm ssh (WezTerm only)
abbr -a s wezterm ssh abbr -a s wezterm ssh
end end
# Neovim in a new tab # Neovim in a new tab
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Terminal Windows, Tabs, and Panes
# @desc Open new tab with nvim (terminal-aware)
abbr -a editt kitty @ launch --type=tab --cwd=current nvim # Kitty abbr -a editt kitty @ launch --type=tab --cwd=current nvim # Kitty
end end
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
# @category Terminal Windows, Tabs, and Panes
# @desc Open new tab with nvim (terminal-aware)
abbr -a editt wezterm cli spawn nvim # WezTerm abbr -a editt wezterm cli spawn nvim # WezTerm
end end
# LazyGit # LazyGit
# @category Git
# @desc lazygit
abbr -a lg lazygit abbr -a lg lazygit
# Sudo shell # Sudo shell
# @category Miscellaneous
# @desc sudo -s
abbr -a sudu sudo -s abbr -a sudu sudo -s
# Kitty # Kitty
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
# @category Miscellaneous
# @desc kitty (Kitty only)
abbr -a kt kitty abbr -a kt kitty
end end
# cat # cat
# @category Miscellaneous
# @desc cat
abbr -a c cat abbr -a c cat
# chezmoi # chezmoi
# @category Chezmoi
# @desc chezmoi
abbr -a cm chezmoi abbr -a cm chezmoi
# chezmoi cd # chezmoi cd
# @category Chezmoi
# @desc chezmoi cd
abbr -a cmcd chezmoi cd abbr -a cmcd chezmoi cd
# @category Chezmoi
# @desc chezmoi cd
abbr -a czcd chezmoi cd abbr -a czcd chezmoi cd
# @category Chezmoi
# @desc chezmoi cd
abbr -a cdcm chezmoi cd abbr -a cdcm chezmoi cd
# @category Chezmoi
# @desc chezmoi cd
abbr -a cdcz chezmoi cd abbr -a cdcz chezmoi cd
# chezmoi edit # chezmoi edit
# @category Chezmoi
# @desc chezmoi edit
abbr -a cme chezmoi edit abbr -a cme chezmoi edit
# @category Chezmoi
# @desc chezmoi edit
abbr -a cze chezmoi edit abbr -a cze chezmoi edit
# chezmoi add # chezmoi add
# @category Chezmoi
# @desc chezmoi add
abbr -a cmad chezmoi add abbr -a cmad chezmoi add
# @category Chezmoi
# @desc chezmoi add
abbr -a czad chezmoi add abbr -a czad chezmoi add
# chezmoi apply # chezmoi apply
# @category Chezmoi
# @desc chezmoi apply
abbr -a cmap chezmoi apply abbr -a cmap chezmoi apply
# @category Chezmoi
# @desc chezmoi apply
abbr -a czap chezmoi apply abbr -a czap chezmoi apply
# chezmoi rm # chezmoi rm
# @category Chezmoi
# @desc chezmoi forget
abbr -a cmrm chezmoi forget abbr -a cmrm chezmoi forget
# @category Chezmoi
# @desc chezmoi forget
abbr -a cmf chezmoi forget abbr -a cmf chezmoi forget
# @category Chezmoi
# @desc chezmoi forget
abbr -a czrm chezmoi forget abbr -a czrm chezmoi forget
# @category Chezmoi
# @desc chezmoi forget
abbr -a czf chezmoi forget abbr -a czf chezmoi forget
# chezmoi init # chezmoi init
# @category Chezmoi
# @desc chezmoi init
abbr -a cmi chezmoi init abbr -a cmi chezmoi init
# @category Chezmoi
# @desc chezmoi init
abbr -a czi chezmoi init abbr -a czi chezmoi init
# Edit # Edit
# @category Editors
# @desc edit
abbr -a e edit abbr -a e edit
# Sudoedit # Sudoedit
# @category Editors
# @desc sudoedit
abbr -a se sudoedit abbr -a se sudoedit
# Git # Git
# @category Git
# @desc git
abbr -a g git abbr -a g git
# @category Git
# @desc generate .gitignore
abbr -a gitig gi
# @category Git
# @desc generate .gitignore
abbr -a git-ignore gi
# Antigravity # Antigravity
abbr -a ag antigravity # @category AI Assistants
abbr -a ag. antigravity . # @desc agy
abbr -a ag agy
# @category AI Assistants
# @desc agy .
abbr -a ag. agy .
# Quit # Quit
if test "$TERM" = xterm-kitty # @category Miscellaneous
abbr -a :q kitty @ close-window # Kitty (Closes the active split/pane) # @desc exit
abbr -a :Q kitty @ close-tab # Kitty (Closes the whole tab) abbr -a /exit exit
end # Window-management abbreviations are opinionated (C4 integrations)
if test "$TERM_PROGRAM" = WezTerm if __fish_config_op_enabled __fish_config_op_integrations
abbr -a :q wezterm cli kill-pane # WezTerm if test "$TERM" = xterm-kitty
abbr -a :Q wezterm cli kill-pane # WezTerm # @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 end
######### Alternates ########## ######### Alternates ##########
### ls alternates ### ls alternates
# List all files # List all files
# @category Navigation and Listing
# @desc ls
abbr -a l ls abbr -a l ls
# List all files by size # List all files by size
# @category Navigation and Listing
# @desc lss (sort by size)
abbr -a lS lss abbr -a lS lss
# List all files by reverse modified time # List all files by reverse modified time
# @category Navigation and Listing
# @desc lsr (sort by time, oldest first)
abbr -a lsR lsr abbr -a lsR lsr
# List by extension # List by extension
# @category Navigation and Listing
# @desc lx (sort by extension)
abbr -a lX lx abbr -a lX lx
# Tree listing (depth 2) # Tree listing (depth 2)
# @category Navigation and Listing
# @desc lt (tree, depth 2)
abbr -a lT lt abbr -a lT lt
# Full tree listing # Full tree listing
# @category Navigation and Listing
# @desc lstree (full recursive tree)
abbr -a lsT lstree abbr -a lsT lstree
### speed-test alternates
# Speedtest using fast.com
# @category Miscellaneous
# @desc fast-cli
abbr -a speedtest-fast fast-cli
# Window Creation (OS Windows) # Kitty/WezTerm window-management abbreviations are opinionated (C4
if test "$TERM" = xterm-kitty # integrations): they assume an active Kitty or WezTerm session.
abbr -a :w kitty @ launch --type=os-window # Kitty if __fish_config_op_enabled __fish_config_op_integrations
end # Window Creation (OS Windows)
if test "$TERM_PROGRAM" = WezTerm if test "$TERM" = xterm-kitty
abbr -a :w wezterm cli spawn --new-window # WezTerm # @category Terminal Windows, Tabs, and Panes
end # @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) # Window Splits (Panes)
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
abbr -a :wv kitty @ launch --location=hsplit # Kitty (Horizontal split) # @category Terminal Windows, Tabs, and Panes
abbr -a :wh kitty @ launch --location=vsplit # Kitty (Vertical split) # @desc Split pane horizontally (new pane below)
end abbr -a :wv kitty @ launch --location=hsplit # Kitty (Horizontal split)
if test "$TERM_PROGRAM" = WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :wv wezterm cli split-pane --bottom # WezTerm # @desc Split pane vertically (new pane to the right)
abbr -a :wh wezterm cli split-pane --right # WezTerm abbr -a :wh kitty @ launch --location=vsplit # Kitty (Vertical split)
end 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) # Window Detach (Move Pane)
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
abbr -a :wo kitty @ detach-window --target-tab=new # Kitty (Moves pane to new tab) # @category Terminal Windows, Tabs, and Panes
abbr -a :wot kitty @ detach-window # Kitty (Same as above, default behavior) # @desc Detach current window to its own OS window
end abbr -a :wo kitty @ detach-window --target-tab=new # Kitty (Moves pane to new tab)
if test "$TERM_PROGRAM" = WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :wo wezterm cli move-pane-to-new-tab --new-window # WezTerm # @desc Move current pane to a new tab
abbr -a :wot wezterm cli move-pane-to-new-tab # WezTerm abbr -a :wot kitty @ detach-window # Kitty (Same as above, default behavior)
end 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 # Tab Creation
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
abbr -a :t kitty @ launch --type=tab # Kitty # @category Terminal Windows, Tabs, and Panes
end # @desc New tab
if test "$TERM_PROGRAM" = WezTerm abbr -a :t kitty @ launch --type=tab # Kitty
abbr -a :t wezterm cli spawn # WezTerm end
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 # Rename Tab
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
abbr -a :tl "kitty @ set-tab-title" # Kitty -> Usage: :tl "New Title" # @category Terminal Windows, Tabs, and Panes
end # @desc Set tab title
if test "$TERM_PROGRAM" = WezTerm abbr -a :tl "kitty @ set-tab-title" # Kitty -> Usage: :tl "New Title"
abbr -a :tl wezterm cli set-tab-title # WezTerm end
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 # Rename Window
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
abbr -a :tw "kitty @ set-window-title" # Kitty # @category Terminal Windows, Tabs, and Panes
end # @desc Set window title
if test "$TERM_PROGRAM" = WezTerm abbr -a :tw "kitty @ set-window-title" # Kitty
abbr -a :tw wezterm cli set-window-title # WezTerm end
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 # Rename Workspace
if test "$TERM_PROGRAM" = WezTerm if test "$TERM_PROGRAM" = WezTerm
abbr -a :twk wezterm cli rename-workspace # WezTerm # @category Terminal Windows, Tabs, and Panes
end # @desc Rename workspace (WezTerm only)
# Kitty does not have a direct CLI equivalent for renaming a dynamic "workspace" session. 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 # Tab Navigation
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
abbr -a :tp "kitty @ focus-tab --match neighbor:left" # Kitty # @category Terminal Windows, Tabs, and Panes
abbr -a :tn "kitty @ focus-tab --match neighbor:right" # Kitty # @desc Focus previous tab
end abbr -a :tp "kitty @ focus-tab --match neighbor:left" # Kitty
if test "$TERM_PROGRAM" = WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :tp wezterm cli activate-tab --tab-relative -1 # WezTerm # @desc Focus next tab
abbr -a :tn wezterm cli activate-tab --tab-relative 1 # WezTerm abbr -a :tn "kitty @ focus-tab --match neighbor:right" # Kitty
end 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) # Specialty Tab Shortcuts (New Tab in specific dir)
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
abbr -a :tgk kitty @ launch --type=tab --cwd ~/.config/kitty # Kitty # @category Terminal Windows, Tabs, and Panes
abbr -a :tgn kitty @ launch --type=tab --cwd ~/.config/nvim # Kitty # @desc New tab at ~/.config/kitty
abbr -a :tgf kitty @ launch --type=tab --cwd ~/.config/fish # Kitty abbr -a :tgk kitty @ launch --type=tab --cwd ~/.config/kitty # Kitty
abbr -a :tgh kitty @ launch --type=tab --cwd ~ # @category Terminal Windows, Tabs, and Panes
abbr -a :tgcz kitty @ launch --type=tab --cwd ~/.local/share/chezmoi # Kitty # @desc New tab at ~/.config/nvim
abbr -a :tgcm kitty @ launch --type=tab --cwd ~/.config/chezmoi # Kitty abbr -a :tgn kitty @ launch --type=tab --cwd ~/.config/nvim # Kitty
abbr -a :tgp kitty @ launch --type=tab --cwd ~/projects # Kitty # @category Terminal Windows, Tabs, and Panes
abbr -a :tgr kitty @ launch --type=tab -- sudo -i # @desc New tab at ~/.config/fish
end abbr -a :tgf kitty @ launch --type=tab --cwd ~/.config/fish # Kitty
if test "$TERM_PROGRAM" = WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :tgk wezterm cli spawn --cwd ~/.config/kitty # WezTerm # @desc New tab at ~
abbr -a :tgn wezterm cli spawn --cwd ~/.config/nvim # WezTerm abbr -a :tgh kitty @ launch --type=tab --cwd ~
abbr -a :tgf wezterm cli spawn --cwd ~/.config/fish # WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :tgh wezterm cli spawn --cwd ~ # WezTerm # @desc New tab at ~/.local/share/chezmoi
abbr -a :tgcz wezterm cli spawn --cwd ~/.local/share/chezmoi # WezTerm abbr -a :tgcz kitty @ launch --type=tab --cwd ~/.local/share/chezmoi # Kitty
abbr -a :tgcm wezterm cli spawn --cwd ~/.config/chezmoi # WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :tgp wezterm cli spawn --cwd ~/projects # WezTerm # @desc New tab at ~/.config/chezmoi
abbr -a :tgr wezterm cli spawn -- sudo -i # WezTerm abbr -a :tgcm kitty @ launch --type=tab --cwd ~/.config/chezmoi # Kitty
end # @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) # Specialty Window Shortcuts (New OS Window in specific dir)
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
abbr -a :wgk kitty @ launch --type=os-window --cwd ~/.config/kitty # Kitty # @category Terminal Windows, Tabs, and Panes
abbr -a :wgn kitty @ launch --type=os-window --cwd ~/.config/nvim # Kitty # @desc New OS window at ~/.config/kitty
abbr -a :wgf kitty @ launch --type=os-window --cwd ~/.config/fish # Kitty abbr -a :wgk kitty @ launch --type=os-window --cwd ~/.config/kitty # Kitty
abbr -a :wgh kitty @ launch --type=os-window --cwd ~ # @category Terminal Windows, Tabs, and Panes
abbr -a :wgzd kitty @ launch --type=os-window --cwd ~/.local/share/chezmoi # Kitty # @desc New OS window at ~/.config/nvim
abbr -a :wgcz kitty @ launch --type=os-window --cwd ~/.config/chezmoi # Kitty abbr -a :wgn kitty @ launch --type=os-window --cwd ~/.config/nvim # Kitty
abbr -a :wgp kitty @ launch --type=os-window --cwd ~/projects # Kitty # @category Terminal Windows, Tabs, and Panes
abbr -a :wgr kitty @ launch --type=os-window -- sudo -i # Kitty # @desc New OS window at ~/.config/fish
end abbr -a :wgf kitty @ launch --type=os-window --cwd ~/.config/fish # Kitty
if test "$TERM_PROGRAM" = WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :wgk wezterm cli spawn --new-window --cwd ~/.config/kitty # WezTerm # @desc New OS window at ~
abbr -a :wgn wezterm cli spawn --new-window --cwd ~/.config/nvim # WezTerm abbr -a :wgh kitty @ launch --type=os-window --cwd ~
abbr -a :wgf wezterm cli spawn --new-window --cwd ~/.config/fish # WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :wgh wezterm cli spawn --new-window --cwd ~ # WezTerm # @desc New OS window at ~/.local/share/chezmoi
abbr -a :wgzd wezterm cli spawn --new-window --cwd ~/.local/share/chezmoi # WezTerm abbr -a :wgzd kitty @ launch --type=os-window --cwd ~/.local/share/chezmoi # Kitty
abbr -a :wgcz wezterm cli spawn --new-window --cwd ~/.config/chezmoi # WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :wgp wezterm cli spawn --new-window --cwd ~/projects # WezTerm # @desc New OS window at ~/.config/chezmoi
abbr -a :wgr wezterm cli spawn --new-window -- sudo -i # WezTerm abbr -a :wgcz kitty @ launch --type=os-window --cwd ~/.config/chezmoi # Kitty
end # @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) # Specialty Window Vertical Shortcuts (Split Bottom)
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
abbr -a :wvgk kitty @ launch --location=hsplit --cwd ~/.config/kitty # Kitty # @category Terminal Windows, Tabs, and Panes
abbr -a :wvgn kitty @ launch --location=hsplit --cwd ~/.config/nvim # Kitty # @desc Split bottom at ~/.config/kitty
abbr -a :wvgf kitty @ launch --location=hsplit --cwd ~/.config/fish # Kitty abbr -a :wvgk kitty @ launch --location=hsplit --cwd ~/.config/kitty # Kitty
abbr -a :wvgh kitty @ launch --location=hsplit --cwd ~ # Kitty # @category Terminal Windows, Tabs, and Panes
abbr -a :wvgcz kitty @ launch --location=hsplit --cwd ~/.local/share/chezmoi # Kitty # @desc Split bottom at ~/.config/nvim
abbr -a :wvgcm kitty @ launch --location=hsplit --cwd ~/.config/chezmoi # Kitty abbr -a :wvgn kitty @ launch --location=hsplit --cwd ~/.config/nvim # Kitty
abbr -a :wvgp kitty @ launch --location=hsplit --cwd ~/projects # Kitty # @category Terminal Windows, Tabs, and Panes
abbr -a :wvgr kitty @ launch --location=hsplit -- sudo -i # Kitty # @desc Split bottom at ~/.config/fish
end abbr -a :wvgf kitty @ launch --location=hsplit --cwd ~/.config/fish # Kitty
if test "$TERM_PROGRAM" = WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :wvgk wezterm cli split-pane --bottom --cwd ~/.config/kitty # WezTerm # @desc Split bottom at ~
abbr -a :wvgn wezterm cli split-pane --bottom --cwd ~/.config/nvim # WezTerm abbr -a :wvgh kitty @ launch --location=hsplit --cwd ~ # Kitty
abbr -a :wvgf wezterm cli split-pane --bottom --cwd ~/.config/fish # WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :wvgh wezterm cli split-pane --bottom --cwd ~ # WezTerm # @desc Split bottom at ~/.local/share/chezmoi
abbr -a :wvgcz wezterm cli split-pane --bottom --cwd ~/.local/share/chezmoi # WezTerm abbr -a :wvgcz kitty @ launch --location=hsplit --cwd ~/.local/share/chezmoi # Kitty
abbr -a :wvgcm wezterm cli split-pane --bottom --cwd ~/.config/chezmoi # WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :wvgp wezterm cli split-pane --bottom --cwd ~/projects # WezTerm # @desc Split bottom at ~/.config/chezmoi
abbr -a :wvgr wezterm cli split-pane --bottom -- sudo -i # WezTerm abbr -a :wvgcm kitty @ launch --location=hsplit --cwd ~/.config/chezmoi # Kitty
end # @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) # Specialty Window Horizontal Shortcuts (Split Right)
if test "$TERM" = xterm-kitty if test "$TERM" = xterm-kitty
abbr -a :whgk kitty @ launch --location=vsplit --cwd ~/.config/kitty # Kitty # @category Terminal Windows, Tabs, and Panes
abbr -a :whgn kitty @ launch --location=vsplit --cwd ~/.config/nvim # Kitty # @desc Split right at ~/.config/kitty
abbr -a :whgf kitty @ launch --location=vsplit --cwd ~/.config/fish # Kitty abbr -a :whgk kitty @ launch --location=vsplit --cwd ~/.config/kitty # Kitty
abbr -a :whgh kitty @ launch --location=vsplit --cwd ~ # Kitty # @category Terminal Windows, Tabs, and Panes
abbr -a :whgcz kitty @ launch --location=vsplit --cwd ~/.local/share/chezmoi # Kitty # @desc Split right at ~/.config/nvim
abbr -a :whgcm kitty @ launch --location=vsplit --cwd ~/.config/chezmoi # Kitty abbr -a :whgn kitty @ launch --location=vsplit --cwd ~/.config/nvim # Kitty
abbr -a :whgp kitty @ launch --location=vsplit --cwd ~/projects # Kitty # @category Terminal Windows, Tabs, and Panes
abbr -a :whgr kitty @ launch --location=vsplit --cwd current sudo -i # Kitty -> Specialty cd Shortcuts # @desc Split right at ~/.config/fish
abbr -a :cdk 'cd ~/.config/kitty/ # Kitty Config' abbr -a :whgf kitty @ launch --location=vsplit --cwd ~/.config/fish # Kitty
abbr -a :cdkn 'cd ~/.config/kitty;nvim' # @category Terminal Windows, Tabs, and Panes
end # @desc Split right at ~
if test "$TERM_PROGRAM" = WezTerm abbr -a :whgh kitty @ launch --location=vsplit --cwd ~ # Kitty
abbr -a :whgk wezterm cli split-pane --bottom --cwd ~/.config/kitty # WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :whgn wezterm cli split-pane --bottom --cwd ~/.config/nvim # WezTerm # @desc Split right at ~/.local/share/chezmoi
abbr -a :whgf wezterm cli split-pane --bottom --cwd ~/.config/fish # WezTerm abbr -a :whgcz kitty @ launch --location=vsplit --cwd ~/.local/share/chezmoi # Kitty
abbr -a :whgh wezterm cli split-pane --bottom --cwd ~ # WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :whgcz wezterm cli split-pane --bottom --cwd ~/.local/share/chezmoi # WezTerm # @desc Split right at ~/.config/chezmoi
abbr -a :whgcm wezterm cli split-pane --bottom --cwd ~/.config/chezmoi # WezTerm abbr -a :whgcm kitty @ launch --location=vsplit --cwd ~/.config/chezmoi # Kitty
abbr -a :whgp wezterm cli split-pane --bottom --cwd ~/projects # WezTerm # @category Terminal Windows, Tabs, and Panes
abbr -a :whgr wezterm cli split-pane --bottom -- sudo -i # WezTerm # @desc Split right at ~/projects
end abbr -a :whgp kitty @ launch --location=vsplit --cwd ~/projects # Kitty
abbr -a :cdn cd '~/.config/nvim/ # Neovim Config' # @category Terminal Windows, Tabs, and Panes
abbr -a :cdnn 'cd ~/.config/nvim;nvim' # @desc Split right at / (root)
abbr -a :cdf 'cd ~/.config/fish/ # Fish Config' abbr -a :whgr kitty @ launch --location=vsplit --cwd current sudo -i # Kitty -> Specialty cd Shortcuts
abbr -a :cdfn 'cd ~/.config/fish;nvim' # @category Terminal Windows, Tabs, and Panes
abbr -a :cdh 'cd ~ # Home Directory' # @desc cd ~/.config/kitty
abbr -a :cdhn 'cd ~;nvim' abbr -a :cdk 'cd ~/.config/kitty/ # Kitty Config'
abbr -a :cdcz cd '~/.local/share/chezmoi/ # Chezmoi Source' # @category Terminal Windows, Tabs, and Panes
abbr -a :cdczn 'cd ~/.local/share/chezmoi;nvim' # @desc cd ~/.config/kitty; nvim
abbr -a :cdcm 'cd ~/.config/chezmoi/ # Chezmoi Config' abbr -a :cdkn 'cd ~/.config/kitty;nvim'
abbr -a :cdcmn 'cd ~/.config/chezmoi;nvim' end
abbr -a :cdp --regex ':cdp' --set-cursor 'cd ~/projects/%' if test "$TERM_PROGRAM" = WezTerm
# abbr -a cdp_slash --position anywhere --regex ':cdp/' --set-cursor 'cd ~/projects/%' # @category Terminal Windows, Tabs, and Panes
abbr -a :cdpn 'cd ~/projects;nvim' # @desc Split right at ~/.config/kitty
abbr -a :cdw 'cd ~/.config/wezterm/ # WezTerm Config' abbr -a :whgk wezterm cli split-pane --bottom --cwd ~/.config/kitty # WezTerm
abbr -a :cdwn 'cd ~/.config/wezterm;nvim' # @category Terminal Windows, Tabs, and Panes
if test "$TERM" = xterm-kitty # @desc Split right at ~/.config/nvim
abbr -a editt kitty @ launch --type tab nvim abbr -a :whgn wezterm cli split-pane --bottom --cwd ~/.config/nvim # WezTerm
end # @category Terminal Windows, Tabs, and Panes
# Spawn window # @desc Split right at ~/.config/fish
if test "$TERM" = xterm-kitty abbr -a :whgf wezterm cli split-pane --bottom --cwd ~/.config/fish # WezTerm
abbr -a :sw spwin # @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 end
### Docker ### ### Docker ###
# @category Docker
# @desc docker context use default
abbr -a dcl 'docker context use default # Local Host' abbr -a dcl 'docker context use default # Local Host'
# @category Docker
# @desc ld (lazydocker)
abbr -a lzd ld abbr -a lzd ld
# @category Docker
# @desc docker context ls
abbr -a dcls 'docker context ls' abbr -a dcls 'docker context ls'
### Beads ### ### Beads ###
# @category Miscellaneous
# @desc bd list
abbr -a bl 'bd list' abbr -a bl 'bd list'
# @category Miscellaneous
# @desc bd sync
abbr -a bs 'bd sync' abbr -a bs 'bd sync'
# @category Miscellaneous
# @desc bd create --title
abbr -a bC 'bd create --title' abbr -a bC 'bd create --title'
# @category Miscellaneous
# @desc bd show
abbr -a bsh 'bd show' abbr -a bsh 'bd show'
# @category Miscellaneous
# @desc lazybeads
abbr -a lb lazybeads abbr -a lb lazybeads
### Systemctl ### ### Systemctl ###
# @category Systemctl
# @desc systemctl
abbr -a sc systemctl abbr -a sc systemctl
# @category Systemctl
# @desc sudo systemctl
abbr -a ssc 'sudo systemctl' abbr -a ssc 'sudo systemctl'
# @category Systemctl
# @desc systemctl --user
abbr -a scu 'systemctl --user' abbr -a scu 'systemctl --user'
# @category Systemctl
# @desc systemctl status
abbr -a st 'systemctl status' abbr -a st 'systemctl status'
# @category Systemctl
# @desc systemctl start
abbr -a scs 'systemctl start' abbr -a scs 'systemctl start'
# @category Systemctl
# @desc systemctl restart
abbr -a scr 'systemctl restart' abbr -a scr 'systemctl restart'
# @category Systemctl
# @desc sudo systemctl status
abbr -a ssct 'sudo systemctl status' abbr -a ssct 'sudo systemctl status'
# @category Systemctl
# @desc sudo systemctl start
abbr -a sscs 'sudo systemctl start' abbr -a sscs 'sudo systemctl start'
# @category Systemctl
# @desc sudo systemctl restart
abbr -a sscr 'sudo systemctl restart' abbr -a sscr 'sudo systemctl restart'
### Alternate command names ###
# Expand to the canonical function name so muscle-memory typos still work,
# while surfacing the real command instead of silently forwarding to it.
# @category Miscellaneous
# @desc repo-open
abbr -a open-repo repo-open
# @category Miscellaneous
# @desc open-url
abbr -a url-open open-url
### History Expansions and Substitutions ### ### History Expansions and Substitutions ###
abbr -a !^ --position anywhere --function expand_bang_caret # Bash-style history expansion is opinionated (C3 overrides), gated atomically
abbr -a '!*' --position anywhere --function expand_bang_all # with conf.d/tricks.fish, conf.d/puffer.fish, and functions/expand_*.fish.
abbr -a typo_sub --position anywhere --regex '\^([^^]+)\^([^^]*)' --function expand_typo_sub if __fish_config_op_enabled __fish_config_op_overrides
abbr -a bang_string --position anywhere --regex '![\w.-]+' --function expand_bang_string # @category History Expansion
abbr -a bang_search --position anywhere --regex '!\?[\w.-]+\??' --function expand_bang_search # @name !^
abbr -a bang_minus_n --position anywhere --regex '!-(\d+)' --function expand_bang_minus_n # @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
+62
View File
@@ -0,0 +1,62 @@
# 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 __fish_config_op_autoexec; or exit
# 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
View File
@@ -1,5 +1,9 @@
status is-interactive || exit status is-interactive || exit
# 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
set --global autopair_left "(" "[" "{" '"' "'" set --global autopair_left "(" "[" "{" '"' "'"
set --global autopair_right ")" "]" "}" '"' "'" set --global autopair_right ")" "]" "}" '"' "'"
set --global autopair_pairs "()" "[]" "{}" '""' "''" set --global autopair_pairs "()" "[]" "{}" '""' "''"
+138
View File
@@ -0,0 +1,138 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# 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 __fish_config_op_overrides; 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 __fish_config_op_overrides; 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 __fish_config_op_overrides; 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 __fish_config_op_overrides; 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 __fish_config_op_overrides; 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 __fish_config_op_overrides; 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
+344
View File
@@ -0,0 +1,344 @@
# MIT License
# Copyright (c) 2016 Francisco Lourenço & Daniel Wehner
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# 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.
if not status is-interactive
exit
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
set -g __done_version 1.19.1
function __done_run_powershell_script
set -l powershell_exe (command --search "powershell.exe")
if test $status -ne 0
and command --search wslvar
set -l powershell_exe (wslpath (wslvar windir)/System32/WindowsPowerShell/v1.0/powershell.exe)
end
if string length --quiet "$powershell_exe"
and test -x "$powershell_exe"
set cmd (string escape $argv)
eval "$powershell_exe -Command $cmd"
end
end
function __done_windows_notification -a title -a message
if test "$__done_notify_sound" -eq 1
set soundopt "<audio silent=\"false\" src=\"ms-winsoundevent:Notification.Default\" />"
else
set soundopt "<audio silent=\"true\" />"
end
__done_run_powershell_script "
[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null
[Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
\$toast_xml_source = @\"
<toast>
$soundopt
<visual>
<binding template=\"ToastText02\">
<text id=\"1\">$title</text>
<text id=\"2\">$message</text>
</binding>
</visual>
</toast>
\"@
\$toast_xml = New-Object Windows.Data.Xml.Dom.XmlDocument
\$toast_xml.loadXml(\$toast_xml_source)
\$toast = New-Object Windows.UI.Notifications.ToastNotification \$toast_xml
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier(\"fish\").Show(\$toast)
"
end
function __done_get_focused_window_id
if type -q lsappinfo
lsappinfo info -only bundleID (lsappinfo front | string replace 'ASN:0x0-' '0x') | cut -d '"' -f4
else if test -n "$SWAYSOCK"
and type -q jq
swaymsg --type get_tree | jq '.. | objects | select(.focused == true) | .id'
else if test -n "$HYPRLAND_INSTANCE_SIGNATURE"
hyprctl activewindow | awk '/^\tpid: / {print $2}'
else if begin
test "$XDG_SESSION_DESKTOP" = gnome; and type -q gdbus
end
gdbus call --session --dest org.gnome.Shell --object-path /org/gnome/Shell --method org.gnome.Shell.Eval 'global.display.focus_window.get_id()'
else if type -q xprop
and test -n "$DISPLAY"
# Test that the X server at $DISPLAY is running
and xprop -grammar >/dev/null 2>&1
xprop -root 32x '\t$0' _NET_ACTIVE_WINDOW | cut -f 2
else if uname -a | string match --quiet --ignore-case --regex microsoft
__done_run_powershell_script '
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class WindowsCompat {
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
}
"@
[WindowsCompat]::GetForegroundWindow()
'
else if set -q __done_allow_nongraphical
echo 12345 # dummy value
end
end
function __done_is_tmux_window_active
set -q fish_pid; or set -l fish_pid %self
# find the outermost process within tmux
# ppid != "tmux" -> pid = ppid
# ppid == "tmux" -> break
set tmux_fish_pid $fish_pid
while set tmux_fish_ppid (ps -o ppid= -p $tmux_fish_pid | string trim)
# remove leading hyphen so that basename does not treat it as an argument (e.g. -fish), and return only
# the actual command and not its arguments so that basename finds the correct command name.
# (e.g. '/usr/bin/tmux' from command '/usr/bin/tmux new-session -c /some/start/dir')
and ! string match -q "tmux*" (basename (ps -o command= -p $tmux_fish_ppid | string replace -r '^-' '' | string split ' ')[1])
set tmux_fish_pid $tmux_fish_ppid
end
# tmux session attached and window is active -> no notification
# all other combinations -> send notification
tmux list-panes -a -F "#{session_attached} #{window_active} #{pane_pid}" | string match -q "1 1 $tmux_fish_pid"
end
function __done_is_screen_window_active
string match --quiet --regex "$STY\s+\(Attached" (screen -ls)
end
function __done_is_process_window_focused
# Return false if the window is not focused
if set -q __done_allow_nongraphical
return 1
end
if set -q __done_kitty_remote_control
kitty @ --password="$__done_kitty_remote_control_password" ls | jq -e ".[].tabs[] | select(any(.windows[]; .is_self)) | .is_focused" >/dev/null
return $status
end
set __done_focused_window_id (__done_get_focused_window_id)
if test "$__done_sway_ignore_visible" -eq 1
and test -n "$SWAYSOCK"
string match --quiet --regex "^true" (swaymsg -t get_tree | jq ".. | objects | select(.id == "$__done_initial_window_id") | .visible")
return $status
else if test -n "$HYPRLAND_INSTANCE_SIGNATURE"
set window_pid (hyprctl activewindow | awk '/^\tpid: / {print $2}')
if test -n "$window_pid"
and test $__done_initial_window_id -eq $window_pid
return $status
else
return 1
end
else if test "$__done_initial_window_id" != "$__done_focused_window_id"
return 1
end
# If inside a tmux session, check if the tmux window is focused
if type -q tmux
and test -n "$TMUX"
__done_is_tmux_window_active
return $status
end
# If inside a screen session, check if the screen window is focused
if type -q screen
and test -n "$STY"
__done_is_screen_window_active
return $status
end
return 0
end
function __done_humanize_duration -a milliseconds
set -l seconds (math --scale=0 "$milliseconds/1000" % 60)
set -l minutes (math --scale=0 "$milliseconds/60000" % 60)
set -l hours (math --scale=0 "$milliseconds/3600000")
if test $hours -gt 0
printf '%s' $hours'h '
end
if test $minutes -gt 0
printf '%s' $minutes'm '
end
if test $seconds -gt 0
printf '%s' $seconds's'
end
end
# verify that the system has graphical capabilities before initializing
if test -z "$SSH_CLIENT" # not over ssh
and count (__done_get_focused_window_id) >/dev/null # is able to get window id
set __done_enabled
end
if set -q __done_allow_nongraphical
and set -q __done_notification_command
set __done_enabled
end
if set -q __done_enabled
set -g __done_initial_window_id ''
set -q __done_min_cmd_duration; or set -g __done_min_cmd_duration 5000
set -q __done_exclude; or set -g __done_exclude '^git (?!push|pull|fetch)'
set -q __done_notify_sound; or set -g __done_notify_sound 0
set -q __done_sway_ignore_visible; or set -g __done_sway_ignore_visible 0
set -q __done_tmux_pane_format; or set -g __done_tmux_pane_format '[#{window_index}]'
set -q __done_notification_duration; or set -g __done_notification_duration 3000
function __done_started --on-event fish_preexec
set __done_initial_window_id (__done_get_focused_window_id)
end
function __done_ended --on-event fish_postexec
set -l exit_status $status
# backwards compatibility for fish < v3.0
set -q cmd_duration; or set -l cmd_duration $CMD_DURATION
if test $cmd_duration
and test $cmd_duration -gt $__done_min_cmd_duration # longer than notify_duration
and not __done_is_process_window_focused # process pane or window not focused
# don't notify if command matches exclude list
for pattern in $__done_exclude
if string match -qr $pattern $argv[1]
return
end
end
# Store duration of last command
set -l humanized_duration (__done_humanize_duration "$cmd_duration")
set -l title "Done in $humanized_duration"
set -l wd (string replace --regex "^$HOME" "~" (pwd))
set -l message "$wd/ $argv[1]"
set -l sender $__done_initial_window_id
if test $exit_status -ne 0
set title "Failed ($exit_status) after $humanized_duration"
end
if test -n "$TMUX_PANE"
set message (tmux lsw -F"$__done_tmux_pane_format" -f '#{==:#{pane_id},'$TMUX_PANE'}')" $message"
end
if set -q __done_notification_command
eval $__done_notification_command
if test "$__done_notify_sound" -eq 1
echo -e "\a" # bell sound
end
else if set -q KITTY_WINDOW_ID
printf "\x1b]99;i=done:d=0;$title\x1b\\"
printf "\x1b]99;i=done:d=1:p=body;$message\x1b\\"
else if type -q terminal-notifier # https://github.com/julienXX/terminal-notifier
if test "$__done_notify_sound" -eq 1
# pipe message into terminal-notifier to avoid escaping issues (https://github.com/julienXX/terminal-notifier/issues/134). fixes #140
echo "$message" | terminal-notifier -title "$title" -sender "$__done_initial_window_id" -sound default
else
echo "$message" | terminal-notifier -title "$title" -sender "$__done_initial_window_id"
end
else if type -q osascript # AppleScript
# escape double quotes that might exist in the message and break osascript. fixes #133
set -l message (string replace --all '"' '\"' "$message")
set -l title (string replace --all '"' '\"' "$title")
osascript -e "display notification \"$message\" with title \"$title\""
if test "$__done_notify_sound" -eq 1
osascript -e "display notification \"$message\" with title \"$title\" sound name \"Glass\""
else
osascript -e "display notification \"$message\" with title \"$title\""
end
else if type -q notify-send # Linux notify-send
# set urgency to normal
set -l urgency normal
# use user-defined urgency if set
if set -q __done_notification_urgency_level
set urgency "$__done_notification_urgency_level"
end
# override user-defined urgency level if non-zero exitstatus
if test $exit_status -ne 0
set urgency critical
if set -q __done_notification_urgency_level_failure
set urgency "$__done_notification_urgency_level_failure"
end
end
notify-send --hint=int:transient:1 --urgency=$urgency --icon=utilities-terminal --app-name=fish --expire-time=$__done_notification_duration "$title" "$message"
if test "$__done_notify_sound" -eq 1
echo -e "\a" # bell sound
end
else if type -q notify-desktop # Linux notify-desktop
set -l urgency
if test $exit_status -ne 0
set urgency "--urgency=critical"
end
notify-desktop $urgency --icon=utilities-terminal --app-name=fish "$title" "$message"
if test "$__done_notify_sound" -eq 1
echo -e "\a" # bell sound
end
else if uname -a | string match --quiet --ignore-case --regex microsoft
__done_windows_notification "$title" "$message"
else # anything else
echo -e "\a" # bell sound
end
end
end
end
function __done_uninstall -e done_uninstall
# Erase all __done_* functions
functions -e __done_ended
functions -e __done_started
functions -e __done_get_focused_window_id
functions -e __done_is_tmux_window_active
functions -e __done_is_screen_window_active
functions -e __done_is_process_window_focused
functions -e __done_windows_notification
functions -e __done_run_powershell_script
functions -e __done_humanize_duration
# Erase __done variables
set -e __done_version
end
+72
View File
@@ -0,0 +1,72 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# ╭──────────────────────────────────────────────────────────╮
# │ First-Run Initialization │
# ╰──────────────────────────────────────────────────────────╯
#
# Runs exactly once on the first interactive fish session after install.
# To reset for testing, run: set -Ue __fish_config_first_run_complete
# Exit early in non-interactive shells (scripts, completions, subshells)
if not status is-interactive
return
end
# Skip if this shell has already been initialized
if set -q __fish_config_first_run_complete
return
end
# Set the flag immediately — before actions — so a mid-run crash doesn't
# leave the shell in a state that re-triggers everything next session.
set -U __fish_config_first_run_complete 1
# ──────────────────────────── Man page symlink ──────────────────────────
# Install fish-config.1 into the user man database once, like an install step.
# Unconditional: standard enough that no category gate is warranted.
set -l _man1 ~/.local/share/man/man1
set -l _src ~/.config/fish/docs/fish-config.1
if test -f $_src; and not test -L $_man1/fish-config.1
mkdir -p $_man1
ln -sf $_src $_man1/fish-config.1
end
# ──────────────────────────── Welcome message ───────────────────────────
# 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
echo ""
echo " Welcome to your fish shell configuration!"
echo " Run 'help config' for offline documentation."
echo " Run 'fish-deps' to check and install dependencies."
echo ""
end
# ─────────────────────── Opinionated auto-exec guard ────────────────────
# 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
return
end
# ──────────────────────────── Bootstrap Fisher ──────────────────────────
if not type -q fisher
echo " [first-run] Installing Fisher plugin manager..."
if curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source
echo " [first-run] Fisher installed."
if not fisher update 2>/dev/null
echo " [first-run] Fisher update failed — run 'fisher update' manually." >&2
end
else
echo " [first-run] Fisher install failed — run 'fisher update' manually." >&2
end
end
# ───────────────────────────── Apply theme ──────────────────────────────
# Catppuccin Mocha theme ships with this config in themes/; it is always available.
if not fish_config theme choose "Catppuccin Mocha" 2>/dev/null
echo " [first-run] Could not apply Catppuccin Mocha theme — set manually with 'fish_config theme choose'." >&2
end
+2 -1
View File
@@ -9,7 +9,8 @@ end
# This variable is global so that it can be referenced by fzf_configure_bindings and in tests # This variable is global so that it can be referenced by fzf_configure_bindings and in tests
set --global _fzf_search_vars_command '_fzf_search_variables (set --show | psub) (set --names | psub)' set --global _fzf_search_vars_command '_fzf_search_variables (set --show | psub) (set --names | psub)'
# Install the default bindings, which are mnemonic and minimally conflict with fish's preset bindings # Install the default bindings only if fzf is available
type -q fzf || exit
fzf_configure_bindings fzf_configure_bindings
# Doesn't erase autoloaded _fzf_* functions because they are not easily accessible once key bindings are erased # Doesn't erase autoloaded _fzf_* functions because they are not easily accessible once key bindings are erased
+67
View File
@@ -0,0 +1,67 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# ╭──────────────────────────────────────────────────────────╮
# │ help config wrapper │
# ╰──────────────────────────────────────────────────────────╯
#
# 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 __fish_config_op_aliases
__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
+22
View File
@@ -36,14 +36,31 @@
# If the current command text is empty, the previous command's first token will be used instead. # If the current command text is empty, the previous command's first token will be used instead.
# ────────────────────────────────────────────────────────────────────── # ──────────────────────────────────────────────────────────────────────
# ────────────── Bind Quick Qalc Evaluation to Ctrl+Alt+= ──────────────
# Passes the current command line buffer to the Qalculate! CLI (qalc)
#
# Example: If you type `150 * 1.08` and press Ctrl+Alt+=,
# it will print the result (162) and clear the command line.
# This allows for rapid-fire math without leaving the current shell.
# ──────────────────────────────────────────────────────────────────────
function fish_user_key_bindings 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
# ───────────────────────────── Set Bindings ───────────────────────────── # ───────────────────────────── Set Bindings ─────────────────────────────
# #
# Set Emacs mode bindings: # Set Emacs mode bindings:
bind ctrl-g __insert_previous_path_head bind ctrl-g __insert_previous_path_head
bind ctrl-f __interactive_history_sub bind ctrl-f __interactive_history_sub
bind ctrl-alt-u _replace_command_token bind ctrl-alt-u _replace_command_token
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: # Set bindings for all Vi modes:
# 'default' is Vi-Command, 'insert' is Vi-Insert, 'visual' is Vi-Visual # 'default' is Vi-Command, 'insert' is Vi-Insert, 'visual' is Vi-Visual
@@ -51,5 +68,10 @@ function fish_user_key_bindings
bind --mode $mode ctrl-g __insert_previous_path_head bind --mode $mode ctrl-g __insert_previous_path_head
bind --mode $mode ctrl-f __interactive_history_sub bind --mode $mode ctrl-f __interactive_history_sub
bind --mode $mode ctrl-alt-u _replace_command_token bind --mode $mode ctrl-alt-u _replace_command_token
type -q qalc && bind --mode $mode ctrl-alt-= _qalc_eval
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
end end
+21
View File
@@ -0,0 +1,21 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# 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 __fish_config_op_logging; 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"
+27
View File
@@ -0,0 +1,27 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# C5 — Logging & Capture: registers --on-variable event handlers at shell
# startup so that changes to __fish_config_op_logging or the master
# __fish_config_opinionated take effect immediately in every running shell.
# Also calls __fish_config_sync_logging once to reconcile sentinel-file and
# wrapper state with any variable values that were pre-set before this shell
# started.
#
# These functions must be defined in conf.d (not functions/) because fish
# only autoloads from functions/ on explicit call — event handlers that live
# solely in functions/ are never registered and their --on-variable triggers
# never fire.
function __fish_config_logging_changed --on-variable __fish_config_op_logging \
--description 'C5 event handler: sync logging state when __fish_config_op_logging changes'
__fish_config_sync_logging
end
function __fish_config_opinionated_changed --on-variable __fish_config_opinionated \
--description 'C5 event handler: sync logging state when master opinionated switch changes'
__fish_config_sync_logging
end
# Sync once at startup so pre-set variable values take effect without a re-set
__fish_config_sync_logging
-25
View File
@@ -1,25 +0,0 @@
function magic-enter-cmd --description "Print the command to run when no command was given"
set -l cmd ls
if command git rev-parse --is-inside-work-tree &>/dev/null
set cmd "git status -sb"
end
echo $cmd
end
function magic-enter
set -l cmd (commandline)
if test -z "$cmd"
commandline -r (magic-enter-cmd)
commandline -f suppress-autosuggestion
end
commandline -f execute
end
function magic-enter-bindings --description "Bind magic-enter for default and vi key bindings"
bind \r magic-enter
if functions -q fish_vi_key_bindings
bind -M insert \r magic-enter
bind -M default \r magic-enter
end
end
magic-enter-bindings
+81
View File
@@ -0,0 +1,81 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Generates ~/.local/bin/paru on first run (and on version bump) when
# 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.
# 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
# C5 — Logging & Capture: remove generated wrapper and skip when logging is off
if not __fish_config_op_enabled __fish_config_op_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"
end
return
end
# 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 6
# Skip entirely if the real paru binary isn't present
test -x "$_paru_real"; or return
# Check if wrapper already exists at the expected version
if test -f $_paru_wrapper
and grep -q "# paru-wrapper-version: $_paru_wrapper_version" $_paru_wrapper 2>/dev/null
set --erase _paru_real _paru_wrapper _paru_wrapper_version
return
end
mkdir -p (dirname $_paru_wrapper)
printf '%s\n' \
'#!/usr/bin/env bash' \
"# paru-wrapper-version: $_paru_wrapper_version" \
'# Auto-generated by conf.d/paru-wrapper.fish — do not edit by hand.' \
'# Runs paru in a PTY via script(1) so progress bars are preserved on screen,' \
'# then renders the captured terminal animation to a clean static log.' \
'' \
'log_dir="${SCROLLBACK_HISTORY_DIR:-$HOME/.terminal_history}"' \
'mkdir -p "$log_dir"' \
'log_file="$log_dir/paru_$(date +%Y-%m-%d_%H-%M-%S).log"' \
'' \
'# Build a safely-quoted command string for script(1).' \
'# script(1) allocates a PTY so paru detects a real terminal and shows progress.' \
"cmd_str=\"$_paru_real\"" \
'for arg in "$@"; do' \
' cmd_str+=" $(printf '"'"'%q'"'"' "$arg")"' \
'done' \
'script -q -e -c "$cmd_str" "$log_file"' \
'exit_code=$?' \
'' \
'# Render the captured terminal animation (progress bars repaint in place via' \
'# cursor moves) down to its final static frame, preserving ANSI color. Falls' \
'# back to dropping only the script(1) header/footer when python3 is missing.' \
'cleaner="${XDG_CONFIG_HOME:-$HOME/.config}/fish/scripts/clean_progress_log.py"' \
'if command -v python3 >/dev/null 2>&1 && [[ -f "$cleaner" ]]; then' \
' python3 "$cleaner" < "$log_file" > "${log_file}.tmp" 2>/dev/null && mv "${log_file}.tmp" "$log_file" || rm -f "${log_file}.tmp"' \
'else' \
' sed -i "/^Script \(started\|done\) on /d" "$log_file" 2>/dev/null || true' \
'fi' \
'' \
'max_files="${SCROLLBACK_HISTORY_MAX_FILES:-100}"' \
'mapfile -t logs < <(ls -1t "$log_dir"/paru_*.log 2>/dev/null)' \
'excess=$(( ${#logs[@]} - max_files ))' \
'for (( i = ${#logs[@]} - 1; i >= ${#logs[@]} - excess && i >= 0; i-- )); do' \
' rm -f "${logs[$i]}"' \
'done' \
'' \
'exit $exit_code' \
> $_paru_wrapper
chmod +x $_paru_wrapper
set --erase _paru_real _paru_wrapper _paru_wrapper_version
+17
View File
@@ -1,5 +1,10 @@
status is-interactive || exit status is-interactive || exit
# 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
function _puffer_fish_key_bindings --on-variable fish_key_bindings function _puffer_fish_key_bindings --on-variable fish_key_bindings
set -l modes set -l modes
if test "$fish_key_bindings" = fish_default_key_bindings if test "$fish_key_bindings" = fish_default_key_bindings
@@ -8,9 +13,21 @@ function _puffer_fish_key_bindings --on-variable fish_key_bindings
set modes insert default set modes insert default
end end
# @category History Expansion
# @name !.
# @desc Expand .. to ../.. and so on
bind --mode $modes[1] '.' _puffer_fish_expand_dot bind --mode $modes[1] '.' _puffer_fish_expand_dot
# @category History Expansion
# @name !!
# @desc Expand to the previous command
bind --mode $modes[1] '!' _puffer_fish_expand_bang bind --mode $modes[1] '!' _puffer_fish_expand_bang
# @category History Expansion
# @name !$
# @desc Expand to the last argument of the previous command
bind --mode $modes[1] '$' _puffer_fish_expand_buck bind --mode $modes[1] '$' _puffer_fish_expand_buck
# @category History Expansion
# @name !*
# @desc Expand to all arguments of the previous command
bind --mode $modes[1] '*' _puffer_fish_expand_star bind --mode $modes[1] '*' _puffer_fish_expand_star
bind --mode $modes[2] --erase '.' '!' '$' '*' bind --mode $modes[2] --erase '.' '!' '$' '*'
end end
+137
View File
@@ -0,0 +1,137 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# ╭──────────────────────────────────────────────────────────╮
# │ Sponge Privacy Pattern Registration │
# ╰──────────────────────────────────────────────────────────╯
#
# Two-layer approach to keeping credentials out of shell history:
#
# Layer 1 — Static patterns (registered as universal, persistent):
# Covers structural signatures: auth flags, env var assignments,
# credential-bearing URLs, Authorization headers, sshpass, etc.
# Patterns are added idempotently; user additions are preserved.
#
# Layer 2 — Dynamic secret values (registered as session globals):
# On the first prompt (after secrets.fish has loaded), reads the
# literal values of all exported variables whose names indicate
# credentials (TOKEN, PASSWORD, SECRET, KEY, etc.) and adds them
# as a session-scoped pattern overlay. Refreshes automatically
# each login, so rotated tokens never leave stale patterns behind.
#
# Layer 3 — Per-command filter (sponge_filter_secrets):
# Catches mid-session variables set after login — e.g. a token
# exported interactively or sourced from a project .env file.
#
# To add your own persistent patterns:
# set -U -a sponge_regex_patterns 'your-regex-here'
if not status is-interactive
return
end
# Only register if sponge is loaded
if not set -q sponge_version
return
end
# ──────────────────── Layer 1: Static patterns ────────────────────
set -l _privacy_patterns
# Common auth flags with values: --password x, --token x, --passphrase x, --api-key x
# Use \- to avoid the pattern string starting with --, which string match
# would misinterpret as an unknown option flag.
set -a _privacy_patterns '\-\-(?:password|passwd|passphrase|token|secret|api[-_]key)(?:\s+|=)\S+'
# Inline env var assignments with sensitive names: GITHUB_TOKEN=xxx, MY_API_KEY=abc
set -a _privacy_patterns '(?i)\b[A-Z][A-Z0-9_]*(?:PASSWORD|PASSWD|SECRET|TOKEN|API_KEY|PRIVATE_KEY|ACCESS_KEY|AUTH_KEY|CREDENTIAL)[A-Z0-9_]*=\S+'
# Fish set with sensitive variable names: set -gx GITHUB_TOKEN xxx, set -U MY_SECRET yyy
set -a _privacy_patterns '(?i)set\s+-\S+\s+\S*(?:password|passwd|token|secret|api.?key|private.?key|access.?key|credential)\S*\s+\S+'
# URLs with embedded credentials: https://user:password@host
set -a _privacy_patterns 'https?://[^:@\s]+:[^@\s]+@'
# HTTP Authorization headers: curl -H "Authorization: Bearer xxx"
set -a _privacy_patterns 'curl\s.*[Aa]uthorization:'
# Basic auth flags: curl -u user:pass, wget --user user --password pass
set -a _privacy_patterns '(?:curl|wget)\s.*(?:-u|--user)\s+\S+:\S+'
# sshpass — exposes credentials as a CLI argument by design
set -a _privacy_patterns '\bsshpass\b'
# Docker login with inline password
set -a _privacy_patterns 'docker\s+login\s.*(?:-p|--password)\s+\S+'
# openssl passphrase arguments: -passin pass:xxx, -passout env:VAR
set -a _privacy_patterns 'openssl\s.*-pass(?:in|out)\s+\S+'
# Remove any previously stored patterns that begin with -- ; string match
# passes patterns before its own -- sentinel and would treat them as flags.
for _i in (seq (count $sponge_regex_patterns) -1 1)
if string match --quiet -- '--*' $sponge_regex_patterns[$_i]
set -Ue sponge_regex_patterns[$_i]
end
end
# Idempotent registration into universal sponge_regex_patterns
for _pattern in $_privacy_patterns
if not contains -- $_pattern $sponge_regex_patterns
set -U -a sponge_regex_patterns $_pattern
end
end
# ──────────── Layer 2: Dynamic secret values (session globals) ────────────
# Runs once on the first prompt — by which point config.fish and secrets.fish
# have fully loaded, so all secret env vars are in scope.
# Builds a session-scoped global that combines the universal static patterns
# with the literal values of any credential-holding env vars. Globals shadow
# universals in Fish, so the combined list is what sponge sees for this session.
function __sponge_register_secret_values --on-event fish_prompt
functions --erase __sponge_register_secret_values # run exactly once
set -l secret_values
# 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.
set -l value $$var[1]
# If the var is unset or holds an empty list, value has no elements;
# set -q catches that before string length receives zero arguments.
set -q value[1]; or continue
test (string length -- $value) -gt 8; or continue
string match --quiet --regex '^[/~]' -- $value; and continue
set -a secret_values (string escape --style=regex -- $value)
end
if test (count $secret_values) -gt 0
# Merge static universals + dynamic values into a session global
set -g sponge_regex_patterns $sponge_regex_patterns $secret_values
end
end
# ──────────── Layer 3: Mid-session filter (sponge_filter_secrets) ─────────
# Catches credentials in variables exported after login (e.g. project .env files).
# Only register if not already in sponge_filters.
if functions --query sponge_filter_secrets
if not contains -- sponge_filter_secrets $sponge_filters
set -U -a sponge_filters sponge_filter_secrets
end
end
+29
View File
@@ -0,0 +1,29 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# 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
type -q starship; or return
function fish_prompt
set -l last_status $status
# Blank line between output and next prompt, skipped at the top of a cleared screen
if not test "$fish_private_mode" = true; and test (commandline) = ""
echo
end
# OSC 133;A here (after the blank line) puts the marker on the prompt line itself,
# not the blank line — required for ov's section-delimiter to pin the right line.
printf "\x1b]133;A\x07"
set -g STARSHIP_CMD_STATUS $last_status
command starship prompt --status=$last_status --pipestatus=$pipestatus --jobs=(count (jobs -p))
printf "\x1b]133;B\x07"
end
+20 -3
View File
@@ -4,10 +4,19 @@
# ╭──────────────────────────────────────────────────────────╮ # ╭──────────────────────────────────────────────────────────╮
# │ Fish Theme │ # │ Fish Theme │
# ╰──────────────────────────────────────────────────────────╯ # ╰──────────────────────────────────────────────────────────╯
# # Catppuccin Mocha
# Catppuccin Mocha syntax highlighting colors.
# These variables were migrated from the universal scope to global scope.
# 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 set -q FZF_DEFAULT_OPTS; and string match -q '*#1E1E2E*' -- "$FZF_DEFAULT_OPTS"
set --erase FZF_DEFAULT_OPTS
end
return
end
# ────────────────────── Syntax highlighting colors ──────────────────────
set --global fish_color_autosuggestion 6c7086 set --global fish_color_autosuggestion 6c7086
set --global fish_color_cancel f38ba8 set --global fish_color_cancel f38ba8
set --global fish_color_command 89b4fa set --global fish_color_command 89b4fa
@@ -47,3 +56,11 @@ set --global fish_pager_color_selected_background
set --global fish_pager_color_selected_completion set --global fish_pager_color_selected_completion
set --global fish_pager_color_selected_description set --global fish_pager_color_selected_description
set --global fish_pager_color_selected_prefix set --global fish_pager_color_selected_prefix
# ─────────────────────────── FZF theme colors ───────────────────────────
set -Ux FZF_DEFAULT_OPTS "\
--color=bg+:#313244,bg:#1E1E2E,spinner:#F5E0DC,hl:#F38BA8 \
--color=fg:#CDD6F4,header:#F38BA8,info:#CBA6F7,pointer:#F5E0DC \
--color=marker:#B4BEFE,fg+:#CDD6F4,prompt:#CBA6F7,hl+:#F38BA8 \
--color=selected-bg:#45475A \
--color=border:#6C7086,label:#CDD6F4"
+14
View File
@@ -0,0 +1,14 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# 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
status is-interactive; or exit
type -q tmux; or exit
set -q TMUX; or exit
_tmux_pipe_log
+170
View File
@@ -0,0 +1,170 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# ────── Borrowed and modified from CachyOS config ─────────
# ╭──────────────────────────────────────────────────────────╮
# │ Provides PATH additions, bang-bang helpers, │
# │ system aliases, and history/backup utilities │
# ╰──────────────────────────────────────────────────────────╯
## Environment setup
# Apply .profile: use this to put fish compatible .profile stuff in
if test -f ~/.fish_profile
source ~/.fish_profile
end
# Append unique directories to $PATH (fish_add_path handles duplicates automatically)
fish_add_path ~/.local/bin
fish_add_path ~/Applications/depot_tools
# Expose user-local man pages
if not contains ~/.local/share/man $MANPATH
set -gx MANPATH ~/.local/share/man $MANPATH
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
set -gx MANROFFOPT -c
set -gx MANPAGER "sh -c 'col -bx | bat -l man -p'"
end
# Set settings for https://github.com/franciscolourenco/done
set -gx __done_min_cmd_duration 10000
set -gx __done_notification_urgency_level low
## Functions
# 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
function __history_previous_command
switch (commandline -t)
case "!"
commandline -t $history[1]
commandline -f repaint
case "*"
commandline -i !
end
end
function __history_previous_command_arguments
switch (commandline -t)
case "!"
commandline -t ""
commandline -f history-token-search-backward
case "*"
commandline -i '$'
end
end
# 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
# 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
function history
builtin history --show-time='%F %T '
end
end
# Quick file backup utility
function backup --argument filename
cp $filename $filename.bak
end
# Memory monitoring helpers
function psmem
ps auxf | sort -nr -k 4
end
function psmem10
ps auxf | sort -nr -k 4 | head -10
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
# 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
alias wget='wget -c '
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
View File
@@ -5,6 +5,12 @@
# see: https://github.com/ik11235/wakatime.fish # see: https://github.com/ik11235/wakatime.fish
### ###
# 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
function __register_wakatime_fish_before_exec -e fish_postexec function __register_wakatime_fish_before_exec -e fish_postexec
if set -q FISH_WAKATIME_DISABLED if set -q FISH_WAKATIME_DISABLED
return 0 return 0
+81
View File
@@ -0,0 +1,81 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Generates ~/.local/bin/yay on first run (and on version bump) when
# 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.
# 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
# C5 — Logging & Capture: remove generated wrapper and skip when logging is off
if not __fish_config_op_enabled __fish_config_op_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"
end
return
end
# 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 6
# Skip entirely if the real yay binary isn't present
test -x "$_yay_real"; or return
# Check if wrapper already exists at the expected version
if test -f $_yay_wrapper
and grep -q "# yay-wrapper-version: $_yay_wrapper_version" $_yay_wrapper 2>/dev/null
set --erase _yay_real _yay_wrapper _yay_wrapper_version
return
end
mkdir -p (dirname $_yay_wrapper)
printf '%s\n' \
'#!/usr/bin/env bash' \
"# yay-wrapper-version: $_yay_wrapper_version" \
'# Auto-generated by conf.d/yay-wrapper.fish — do not edit by hand.' \
'# Runs yay in a PTY via script(1) so progress bars are preserved on screen,' \
'# then renders the captured terminal animation to a clean static log.' \
'' \
'log_dir="${SCROLLBACK_HISTORY_DIR:-$HOME/.terminal_history}"' \
'mkdir -p "$log_dir"' \
'log_file="$log_dir/yay_$(date +%Y-%m-%d_%H-%M-%S).log"' \
'' \
'# Build a safely-quoted command string for script(1).' \
'# script(1) allocates a PTY so yay detects a real terminal and shows progress.' \
"cmd_str=\"$_yay_real\"" \
'for arg in "$@"; do' \
' cmd_str+=" $(printf '"'"'%q'"'"' "$arg")"' \
'done' \
'script -q -e -c "$cmd_str" "$log_file"' \
'exit_code=$?' \
'' \
'# Render the captured terminal animation (progress bars repaint in place via' \
'# cursor moves) down to its final static frame, preserving ANSI color. Falls' \
'# back to dropping only the script(1) header/footer when python3 is missing.' \
'cleaner="${XDG_CONFIG_HOME:-$HOME/.config}/fish/scripts/clean_progress_log.py"' \
'if command -v python3 >/dev/null 2>&1 && [[ -f "$cleaner" ]]; then' \
' python3 "$cleaner" < "$log_file" > "${log_file}.tmp" 2>/dev/null && mv "${log_file}.tmp" "$log_file" || rm -f "${log_file}.tmp"' \
'else' \
' sed -i "/^Script \(started\|done\) on /d" "$log_file" 2>/dev/null || true' \
'fi' \
'' \
'max_files="${SCROLLBACK_HISTORY_MAX_FILES:-100}"' \
'mapfile -t logs < <(ls -1t "$log_dir"/yay_*.log 2>/dev/null)' \
'excess=$(( ${#logs[@]} - max_files ))' \
'for (( i = ${#logs[@]} - 1; i >= ${#logs[@]} - excess && i >= 0; i-- )); do' \
' rm -f "${logs[$i]}"' \
'done' \
'' \
'exit $exit_code' \
> $_yay_wrapper
chmod +x $_yay_wrapper
set --erase _yay_real _yay_wrapper _yay_wrapper_version
+24
View File
@@ -0,0 +1,24 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# C5 — Logging & Capture: registers a fish_exit handler that dumps the current
# Zellij pane's scrollback to a log file when the shell exits. Unlike tmux
# (streamed live via pipe-pane), Zellij has no continuous-capture facility, so
# we snapshot once on exit via `zellij action dump-screen --full`.
#
# The handler is registered whenever fish runs inside Zellij; the C5 logging
# guard is evaluated inside _zellij_dump_log at exit time, so toggling
# __fish_config_op_logging takes effect on the next exit without a restart
# (no sync_logging coordination needed, since there is no live stream to stop).
#
# Event-handler functions must be defined at startup (conf.d) so the --on-event
# binding is registered; autoloaded functions in functions/ never register.
status is-interactive; or exit
type -q zellij; or exit
set -q ZELLIJ; or exit
function __zellij_dump_on_exit --on-event fish_exit \
--description 'C5 event handler: dump Zellij pane scrollback on shell exit'
_zellij_dump_log
end
+78 -97
View File
@@ -1,106 +1,87 @@
# ============================================================================= # Copyright (C) 2026 Rootiest
# # SPDX-License-Identifier: AGPL-3.0-or-later
# # Adapted from icezyclon/zoxide.fish (MIT)
# Utility functions for zoxide. # Heavily customized for Fish 4.x compatibility and performance
#
if not type -q zoxide if status is-interactive
return
end
# pwd based on the value of _ZO_RESOLVE_SYMLINKS. if type -q zoxide
function __zoxide_pwd
builtin pwd -L
end
# A copy of fish's internal cd function. This makes it possible to use # -------------
# `alias cd=z` without causing an infinite loop. # 'zoxide init fish' is very different for different versions of zoxide
if ! builtin functions --query __zoxide_cd_internal # to guarantee the same behavior we define these functions ourself,
string replace --regex -- '^function cd\s' 'function __zoxide_cd_internal ' <$__fish_data_dir/functions/cd.fish | source # especially because the apt package is so old
end # most of these functions were taken from https://github.com/ajeetdsouza/zoxide
# from version 0.8.1
# cd + custom logic based on the value of _ZO_ECHO. if ! builtin functions -q _zoxide_cd
function __zoxide_cd if builtin functions -q cd
if set -q __zoxide_loop builtin functions -c cd _zoxide_cd
builtin echo "zoxide: infinite loop detected" else
builtin echo "Avoid aliasing `cd` to `z` directly, use `zoxide init --cmd=cd fish` instead" alias _zoxide_cd='builtin cd'
return 1 end
end
function _zoxide_hook --on-variable PWD
test -z "$fish_private_mode"
and command zoxide add -- (builtin pwd -L)
end
function z
set argc (count $argv)
if test $argc -eq 0
_zoxide_cd $HOME
else if test "$argv" = -
_zoxide_cd -
else
# Check if the argument is a directory (respecting CDPATH)
set -l is_dir 1
if test -d $argv[-1]
set is_dir 0
else if not string match -rq '^\.?\.?/' -- $argv[-1]
for i in $CDPATH
if test -n "$i" -a -d "$i/$argv[-1]"
set is_dir 0
break
end
end
end
if test $is_dir -eq 0
_zoxide_cd $argv[-1]
else
set -l result (command zoxide query -- $argv)
and _zoxide_cd $result
end
end
end
function zi
set -l result (command zoxide query -i -- $argv)
and _zoxide_cd $result
end
# -------------
# Shadowing cd with zoxide is opinionated (C1 aliasing); z and zi
# remain available either way.
if __fish_config_op_enabled __fish_config_op_aliases
alias cd=z
end
# use custom completion
complete -c z -f # disable files by default
complete -c z -x -a '(_zoxide_z_complete)'
end end
__zoxide_loop=1 __zoxide_cd_internal $argv
end end
# ============================================================================= function _zoxide_uninstall --on-event zoxide_uninstall
# if alias | grep "alias cd z" >/dev/null
# Hook configuration for zoxide. functions -e cd
# end
if builtin functions -q _zoxide_cd && not functions -q cd
# Initialize hook to add new entries to the database. # restore old cd
function __zoxide_hook --on-variable PWD builtin functions -c _zoxide_cd cd
test -z "$fish_private_mode"
and command zoxide add -- (__zoxide_pwd)
end
# =============================================================================
#
# When using zoxide with --no-cmd, alias these internal functions as desired.
#
# Jump to a directory using only keywords.
function __zoxide_z
set -l argc (builtin count $argv)
if test $argc -eq 0
__zoxide_cd $HOME
else if test "$argv" = -
__zoxide_cd -
else if test $argc -eq 1 -a -d $argv[1]
__zoxide_cd $argv[1]
else if test $argc -eq 2 -a $argv[1] = --
__zoxide_cd -- $argv[2]
else
set -l result (command zoxide query --exclude (__zoxide_pwd) -- $argv)
and __zoxide_cd $result
end end
end end
# Completions.
function __zoxide_z_complete
set -l tokens (builtin commandline --current-process --tokenize)
set -l curr_tokens (builtin commandline --cut-at-cursor --current-process --tokenize)
if test (builtin count $tokens) -le 2 -a (builtin count $curr_tokens) -eq 1
# If there are < 2 arguments, use `cd` completions.
complete --do-complete "'' "(builtin commandline --cut-at-cursor --current-token) | string match --regex -- '.*/$'
else if test (builtin count $tokens) -eq (builtin count $curr_tokens)
# If the last argument is empty, use interactive selection.
set -l query $tokens[2..-1]
set -l result (command zoxide query --exclude (__zoxide_pwd) --interactive -- $query)
and __zoxide_cd $result
and builtin commandline --function cancel-commandline repaint
end
end
complete --command __zoxide_z --no-files --arguments '(__zoxide_z_complete)'
# Jump to a directory using interactive search.
function __zoxide_zi
set -l result (command zoxide query --interactive -- $argv)
and __zoxide_cd $result
end
# =============================================================================
#
# Commands for zoxide. Disable these using --no-cmd.
#
abbr --erase z &>/dev/null
alias z=__zoxide_z
abbr --erase zi &>/dev/null
alias zi=__zoxide_zi
abbr --erase cdi &>/dev/null
alias cdi=__zoxide_zi
# =============================================================================
# Initialize zoxide:
zoxide init --cmd=cd fish | source
+249 -112
View File
@@ -5,133 +5,270 @@
# │ Fish Configuration │ # │ Fish Configuration │
# ╰──────────────────────────────────────────────────────────╯ # ╰──────────────────────────────────────────────────────────╯
# ───────────────────── Opinionated component guards ─────────────────────
# Opinionated components (AGENTS.md Task #3) are wrapped in
# __fish_config_op_enabled <category> 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
# __fish_config_op_autoexec C2 — startup side-effects
# __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
# ──────────────────────── Source CachyOS configs ──────────────────────── # ──────────────────────── Source CachyOS configs ────────────────────────
if test -f /usr/share/cachyos-fish-config/cachyos-config.fish if test -f /usr/share/cachyos-fish-config/cachyos-config.fish
source /usr/share/cachyos-fish-config/cachyos-config.fish source /usr/share/cachyos-fish-config/cachyos-config.fish
# CachyOS defines aliases for ls/lt/cleanup that shadow our function files. # Surgically overriding the distro config is opinionated (C3 overrides):
# Erase them and immediately source our versions. # skip it entirely when overrides are disabled, keeping CachyOS defaults.
for _fname in ls lt cleanup if __fish_config_op_enabled __fish_config_op_overrides
functions --erase $_fname # Source our tricks over the cachyOS config
source $__fish_config_dir/functions/$_fname.fish test -f "$__fish_config_dir/conf.d/tricks.fish"
and source "$__fish_config_dir/conf.d/tricks.fish"
# Erase CachyOS aliases/functions that shadow our versions, then
# re-source our versions since functions --erase removes autoload entries.
for _fname in ls lt cleanup copy
functions --erase $_fname
source "$__fish_config_dir/functions/$_fname.fish"
end
end
# 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
for _fname in grep fgrep egrep dir vdir wget
functions -q $_fname; and functions --erase $_fname
end
# Restore fish's stock versions where they exist (erasing alone would
# also block autoloading the stock function).
for _fname in history ls
functions -q $_fname; and functions --erase $_fname
test -f $__fish_data_dir/functions/$_fname.fish
and source $__fish_data_dir/functions/$_fname.fish
end
end
if not __fish_config_op_enabled __fish_config_op_overrides
for _fname in __history_previous_command __history_previous_command_arguments
functions -q $_fname; and functions --erase $_fname
end
bind --erase ! 2>/dev/null
bind --erase '$' 2>/dev/null
bind -M insert --erase ! 2>/dev/null
bind -M insert --erase '$' 2>/dev/null
end end
end end
set --erase _fname set --erase _fname
# ──────────────────────────── Bootstrap Fisher ────────────────────────── # ───────────────────────────── XDG variables ────────────────────────────
if not type -q fisher # XDG Base Directory variables (standard practice)
echo "Fisher plugin manager not found." # We set these unconditionally to ensure a consistent baseline, but only if
read -l -P "Install Fisher and plugins now? [Y/n] " _fisher_reply # they are not already defined by the system/user.
if test -z "$_fisher_reply" -o "$_fisher_reply" = Y -o "$_fisher_reply" = y set -q XDG_CONFIG_HOME; or set -gx XDG_CONFIG_HOME $HOME/.config # Sets default config dir to ~/.config
echo "Installing Fisher..." set -q XDG_CACHE_HOME; or set -gx XDG_CACHE_HOME $HOME/.cache # Sets default cache dir to ~/.cache
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source set -q XDG_DATA_HOME; or set -gx XDG_DATA_HOME $HOME/.local/share # Sets default data dir to ~/.local/share
fisher update set -q XDG_STATE_HOME; or set -gx XDG_STATE_HOME $HOME/.local/state # Sets default state dir to ~/.local/state
fish_config theme choose "Catppuccin Mocha"
else # Attempt to keep various config/cache files out of the home directory root
echo "Skipping Fisher install. Some features may be unavailable." 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, $EDITOR, and $GPG_TTY is opinionated (C3 overrides)
if __fish_config_op_enabled __fish_config_op_overrides
if type -q ov
set -gx PAGER ov
else if type -q less
set -gx PAGER less
end end
set --erase _fisher_reply
# ─────────────────────────── 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)
end end
# ───────────────────────── Source user secrets ────────────────────────── # ───────────────────────── Scrollback History ──────────────────────────
if test -f $HOME/.config/.user-dots/fish/secrets.fish # Optional fish-style source of truth (set -U via config-settings); exported
source $HOME/.config/.user-dots/fish/secrets.fish # for the POSIX wrappers (paru/yay/tmux/zellij/_prune_terminal_logs) that read
end # them. We export the default unconditionally, then override from the universal
# var only if set — deliberately NOT creating a global, which would shadow the
# universal and stop live edits (config-settings → Paths) from taking effect.
set -gx SCROLLBACK_HISTORY_DIR "$HOME/.terminal_history"
set -q __fish_scrollback_history_dir
and set -gx SCROLLBACK_HISTORY_DIR $__fish_scrollback_history_dir
# ─────────────────────── Source machine-local config ───────────────────── set -gx SCROLLBACK_HISTORY_MAX_FILES 100
if test -f $HOME/.config/.user-dots/fish/local.fish set -q __fish_scrollback_history_max_files
source $HOME/.config/.user-dots/fish/local.fish 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
function exit --description 'Safe interactive exit'
# If the smart_exit file exists in our function path, invoke it explicitly
if functions -q smart_exit
smart_exit $argv
else
# Absolute fallback to protect shell mechanics
builtin exit $argv
end
end
end end
# ──────────────────────────── PATH variables ──────────────────────────── # ──────────────────────────── PATH variables ────────────────────────────
fish_add_path ~/.local/bin # Adds common user bin directories to the PATH. The -mg --move option for cargo ensures that
fish_add_path ~/Applications # the cargo bin directory is moved to the end of the PATH, which can help avoid conflicts
fish_add_path ~/scripts # with system-installed Rust tools while still allowing user-installed cargo binaries to be found.
fish_add_path -mg --move ~/.cargo/bin # PATH setup is opinionated (C3 overrides)
fish_add_path ~/.npm-global/bin if __fish_config_op_enabled __fish_config_op_overrides
fish_add_path ~/.lmstudio/bin 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
# ─────────────────────────── Editor variables ─────────────────────────── fish_add_path $HOME/Applications # User-installed applications and standalone apps
if command -v nvim >/dev/null fish_add_path $HOME/scripts # Custom personal shell scripts and automation
set -gx EDITOR (command -s nvim) fish_add_path -mga $CARGO_HOME/bin # Rust binaries and tools installed via Cargo
else fish_add_path $BUN_INSTALL/bin # Bun runtime executables and globally installed packages
set -gx EDITOR (command -s vi) 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 end
set -gx VISUAL $EDITOR
set -gx SUDO_EDITOR $EDITOR
# ──────────────────────────── GPG variables ─────────────────────────────
set -gx GPG_TTY (tty)
# ────────────────────────────── Key bindings ────────────────────────────
set -g fish_key_bindings fish_vi_key_bindings
# ──────────────────────── Source FZF integration ────────────────────────
source ~/.config/fish/integrations/fzf.fish
# Configure FZF theme
set -Ux FZF_DEFAULT_OPTS "\
--color=bg+:#313244,bg:#1E1E2E,spinner:#F5E0DC,hl:#F38BA8 \
--color=fg:#CDD6F4,header:#F38BA8,info:#CBA6F7,pointer:#F5E0DC \
--color=marker:#B4BEFE,fg+:#CDD6F4,prompt:#CBA6F7,hl+:#F38BA8 \
--color=selected-bg:#45475A \
--color=border:#6C7086,label:#CDD6F4"
# ──────────────────────────────── DirENV ────────────────────────────────
# Tool to handle automatic environment loading in directories and their children
# Use when children need to load venv as well.
#
# The Auto-Venv script above will ignore directories with a
# .envrc file (direnv configuration) to prevent conflicts.
if type -q direnv
direnv hook fish | source
end
# ────────────────────────────── Auto-Venv ───────────────────────────────
# Auto-activate Python venv on directory change
function __auto_source_fallback_venv --on-variable PWD
status --is-command-substitution; and return
# 1. Skip if direnv is already managing this directory
if set -q DIRENV_DIR; or test -e ".envrc"
return
end
# 2. If we are already in a venv, check if we've left its tree
if set -q VIRTUAL_ENV
# Check if the current PWD is still within the directory that owns the venv
# (Assuming the venv is at the root of the project)
set -l venv_root (string replace -r '/.venv$' '' $VIRTUAL_ENV)
if not string match -q "$venv_root*" "$PWD"
type -q deactivate; and deactivate
end
return
end
# 3. Only source the venv if we aren't already in one
if test -e ".venv/bin/activate.fish"
source .venv/bin/activate.fish
end
end
# ──────────────────── Docker Contexts for LazyDocker ────────────────────
function ld --description 'Run lazydocker on the current Docker context'
# Fetch the host endpoint of the currently active Docker context
set -l current_host (docker context inspect --format '{{.Endpoints.docker.Host}}')
# Run lazydocker with the DOCKER_HOST variable set for this command only
env DOCKER_HOST=$current_host lazydocker
end
# ────────────────────── Claude Code Env Variables ───────────────────────
set -gx CLAUDE_CODE_NO_FLICKER 1
# ───────────────────── Directory shortcut variables ─────────────────────
set -U cdp ~/projects
# ───────────────────────── CDPATH projects dir ────────────────────────── # ───────────────────────── CDPATH projects dir ──────────────────────────
# Allows cd-ing to projects automatically from anywhere # Allows cd-ing to directories within $HOME/projects or $HOME without needing to specify the full path.
set -U CDPATH . ~/projects ~ # For example, if you have a project at $HOME/projects/myproject,
# you can simply run 'cd myproject' from anywhere and it will take you there.
# 'cd' command prioritizes directories in CDPATH, so if you have a directory with
# the same name in both $HOME/projects and $HOME, it will take you to the one in $HOME/projects first.
# Additionally, directories inside the CWD will still take precedence over CDPATH,
# 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
set -gx CDPATH . $HOME/projects $HOME
end
# ─────────────────────────── Starship prompt ──────────────────────────── # ──────────────────────────── Bootstrap Fisher ──────────────────────────
# STARSHIP_START # Fisher is bootstrapped automatically on first run via conf.d/first_run.fish
starship init fish | source
# STARSHIP_END # ─────────────────────── Visual/Interactive setup ───────────────────────
# Run only if we're in an interactive session (not a script or non-interactive shell)
if status is-interactive
# ────────────────────────────── Key bindings ────────────────────────────
# Helps ensure that key bindings are consistent with the Vi editing mode set below.
# 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
set -g fish_key_bindings fish_vi_key_bindings
end
# ──────────────────────── Source FZF integration ────────────────────────
# Prefer fzf's own fish integration (fzf --fish, available since fzf 0.48)
# which is always version-matched to the installed binary. Fall back to our
# bundled integrations/fzf.fish for older builds.
# Run `fzf-update` to install/upgrade fzf from git HEAD.
if type -q fzf
set -l _fzf_minor (fzf --version | string match -r '^\d+\.(\d+)')[2]
if test -n "$_fzf_minor" -a "$_fzf_minor" -ge 48
fzf --fish | source
else
test -f "$__fish_config_dir/integrations/fzf.fish"
and source "$__fish_config_dir/integrations/fzf.fish"
end
else
# conf.d/fzf.fish is managed by Fisher and may be restored on fisher
# update, so this is the reliable place to strip its bindings when
# fzf is not installed.
functions -q _fzf_uninstall_bindings; and _fzf_uninstall_bindings
end
# ──────────────────────────────── DirENV ────────────────────────────────
# Tool to handle automatic environment loading in directories and their children
# Use when children need to load venv as well.
#
# The Auto-Venv script above will ignore directories with a
# .envrc file (direnv configuration) to prevent conflicts.
type -q direnv; and direnv hook fish | source
# Helps ensure that Claude Code's terminal output is clean and doesn't have flickering issues.
set -gx CLAUDE_CODE_NO_FLICKER 1
# ╭────────────────────────────── OVERRIDES ─────────────────────────────╮
# │ Run these last so they can override any previous settings. │
# │ This is useful for machine-specific behavior or configurations. │
# ╰────────────────────────────── OVERRIDES ─────────────────────────────╯
#
# 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 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
function fish_greeting
end
end
#
# ╭──────────────────────────── END OVERRIDES ──────────────────────────╮
# │ End of override section. │
# ╰──────────────────────────── END OVERRIDES ──────────────────────────╯
end
return # <-- Do not remove this line.
# ╭──────────────────────────────── !!!NOTE!!! ───────────────────────────────╮
# │ Tools like starship, zoxide, etc. append init lines below this point │
# │ via their setup commands. We manage these integrations through │
# │ conf.d/ instead, so we return here to prevent duplicate or conflicting
# │ inits from being executed. │
# │ │
# │ If a tool's shell integration appears to do nothing, │
# │ check whether its setup command appended an init line here, │
# │ then create a conf.d/<tool>.fish instead and place the init in that file. │
# ╰───────────────────────────────────────────────────────────────────────────╯
+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
+862
View File
@@ -0,0 +1,862 @@
#!/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
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")
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())
+4871
View File
File diff suppressed because it is too large Load Diff
+326
View File
@@ -0,0 +1,326 @@
# Fish Config Help Index
# Format: keyword=exact heading text as it appears in fish-config.md
# Multiple keywords may map to the same heading.
# Update this file whenever headings are added, removed, or renamed.
# config-help uses this for fast exact lookups; unknown keywords fall back
# to a normalized heading scan automatically.
# ── Top-level ─────────────────────────────────────────────────
name=# NAME
synopsis=# SYNOPSIS
description=# DESCRIPTION
toc=# TABLE OF CONTENTS
contents=# TABLE OF CONTENTS
autopair=# DESCRIPTION
puffer=# DESCRIPTION
puffer-fish=# DESCRIPTION
logging-events=# DESCRIPTION
# ── Section 1: Configuration Variables ───────────────────────
variables=# 1. CONFIGURATION VARIABLES
config=# 1. CONFIGURATION VARIABLES
xdg=## Environment Directories (XDG)
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
# ── Section 3: Key Bindings ───────────────────────────────────
keybindings=# 3. KEY BINDINGS
bindings=# 3. KEY BINDINGS
key-bindings=# 3. KEY BINDINGS
keys=# 3. KEY BINDINGS
fzf-bindings=## FZF Bindings (bundled from PatrickF1/fzf.fish)
fzf=## FZF Bindings (bundled from PatrickF1/fzf.fish)
# ── Section 4: Abbreviations ──────────────────────────────────
abbreviations=# 4. ABBREVIATIONS
abbr=# 4. ABBREVIATIONS
abbrs=# 4. ABBREVIATIONS
editors-abbr=## 4.1 Editors
nav=## 4.2 Navigation and Listing
navigation=## 4.2 Navigation and Listing
listing=## 4.2 Navigation and Listing
git-abbr=## 4.3 Git
terminal=## 4.4 Terminal Windows, Tabs, and Panes
panes=## 4.4 Terminal Windows, Tabs, and Panes
windows=## 4.4 Terminal Windows, Tabs, and Panes
tabs=## 4.4 Terminal Windows, Tabs, and Panes
chezmoi=## 4.5 Chezmoi
docker=## 4.6 Docker
systemctl=## 4.7 Systemctl
systemd=## 4.7 Systemctl
ai-abbr=## 4.8 AI Assistants
history=## 4.9 History Expansion
misc-abbr=## 4.10 Miscellaneous
# ── Section 5: Functions ──────────────────────────────────────
functions=# 5. FUNCTIONS REFERENCE
files=## 5.1 File and Directory
cat=### cat
copy=### copy
du=### du
dusize=### dusize
ls=### ls
lsr=### lsr
lss=### lss
lstree=### lstree
lt=### lt
ltr=### ltr
lx=### lx
mkdir=### mkdir
mkcd=### mkcd
poke=### poke
rm=### rm
rg=### rg
scrub=### scrub
nav-fns=## 5.2 Navigation
cdi=### cdi
clone=### clone
clonet=### clonet
editors=## 5.3 Editors and Viewers
edit=### edit
fc=### fc
less=### less
rawfish=### rawfish
view=### view
git=## 5.4 Git and Version Control
auto-pull=### auto-pull
branch=### branch
gi=### gi
gitignore=### gi
git-clean=### git-clean
gitup=### gitup
gitui=### gitui
hist=### hist
pkg=### pkg
package=### pkg
package-manager=## 5.5 Package Management
packages=## 5.5 Package Management
search=### search
upgrade=### upgrade
cleanup=### cleanup
parur=### parur
deps=## 5.6 Dependency Management
fish-deps=### fish-deps
check-deps=### check_fish_deps
system=## 5.7 System and Monitoring
top=### top
swapstat=### swapstat
sbver=### sbver
ports=### ports
screensleep=### screensleep
lock=### lock
sudo-toggle=### sudo-toggle
limine=### limine-edit
terminal-mgmt=## 5.8 Terminal Management
tab=### tab
split=### split
spwin=### spwin
detach=### detach
bkg=### bkg
jobrunner=### jobrunner
jr=### jr
ssh=### ssh
clipboard=## 5.9 Clipboard
copy-fn=### y
paste=### paste
network=## 5.10 Network
gip=### gip
ping=### ping
qr=### qr
logging=## 5.11 Pager and Logging
logs=### logs
smart-exit=### smart_exit
ai=## 5.12 AI and Developer Tools
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-docs=### claude-docs
claude-pr=### claude-pr
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-settings=### config-settings
config-toggle=### config-settings
toggle=### config-settings
bash=### bash
cheat=### cheat
dockup=### dockup
joplin=### joplin
replay=### replay
tmux=### tmux-clean
wake-lock=### wake-lock
# ── 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
deps-catalog=# 6. DEPENDENCY CATALOG
required=## Required
integrations=## Integrations
recommended=## Recommended
install-methods=## Install Methods
# ── Section 7: Customization ──────────────────────────────────
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
opinionated=## Opinionated Components (Minimal Mode)
minimal=## Opinionated Components (Minimal Mode)
minimal-mode=## Opinionated Components (Minimal Mode)
opt-out=## Opinionated Components (Minimal Mode)
toggles=## Opinionated Components (Minimal Mode)
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=## C5 — Logging and Capture
zellij-logging=## C5 — Logging and Capture
tmux-logging=## C5 — Logging and Capture
pipe-pane=## C5 — Logging and Capture
dump-screen=## C5 — Logging and Capture
c6=## C6 — Greeting and First-Run UI
greeting=## C6 — Greeting and First-Run UI
# ── Prompt and Theme ──────────────────────────────────────────
prompt-theme=## Prompt and Theme
starship=### Starship
fallback-prompt=### Catppuccin Fallback Prompt
catppuccin-prompt=### Catppuccin Fallback Prompt
nim-prompt=### Catppuccin Fallback Prompt
fzf-theme=### FZF
catppuccin-theme=### Catppuccin Mocha Syntax Highlighting
# ── Section 9: Fisher Plugins ─────────────────────────────────
plugins=# 9. FISHER PLUGINS
fisher=# 9. FISHER PLUGINS
fisher-managed=## Fisher-Managed Plugins
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 10: Installation ────────────────────────────────────
installation=# 10. INSTALLATION
install=# 10. INSTALLATION
sentinel=## Return Sentinel
updating=## Updating
# ── Section 11: Personalization ───────────────────────────────
personalization=# 11. PERSONALIZATION
personalize=# 11. PERSONALIZATION
secrets-file=## secrets.fish
local-config=## local.fish
# ── 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
+3751
View File
File diff suppressed because it is too large Load Diff
+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).
---
+62
View File
@@ -0,0 +1,62 @@
---
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
are active in Insert, Normal, and Visual modes unless noted.
Binding Action
─────────────────────────────────────────────────────────────────────
Ctrl+G Insert the head of the previous command's last path
argument. Equivalent to !$:h in Bash.
Example: previous = "cd /usr/local/bin"
Ctrl+G inserts "/usr/local"
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 = "echo this is a test"
type "this is/that was", press Ctrl+F
result = "echo that was a test"
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: "mkdir new_folder" -> " new_folder"
Ctrl+Alt+= Evaluate the current command line buffer with
Qalculate! (qalc) and print the result inline.
Requires qalc to be installed.
Example: type "150 * 1.08", 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.
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
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
---
@@ -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
---
+67
View File
@@ -0,0 +1,67 @@
---
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, or
`fish-deps install` to install missing ones.
## Required
| Tool | Description |
|---|---|
| `fish` | Fish shell >= 4.0 |
| `fzf` | Fuzzy finder |
## Integrations
| Tool | Description |
|---|---|
| `wakatime` | Developer time tracking |
| `tailscale` | Mesh VPN client |
## 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` |
| `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 `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. |
| `yt-dlp` | Video/media downloader; backs the `yt-dlp` wrapper function. Optional — the wrapper falls back to the system `yt-dlp` and the rest of the config works without it. |
## Install Methods
The install priority for each tool:
| Method | Packages |
|---|---|
| `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 |
---
+212
View File
@@ -0,0 +1,212 @@
---
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.
## 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,33 @@
---
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.
@@ -0,0 +1,45 @@
---
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.
@@ -0,0 +1,35 @@
---
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).
@@ -0,0 +1,24 @@
---
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.
@@ -0,0 +1,114 @@
---
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.
@@ -0,0 +1,15 @@
---
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.
@@ -0,0 +1,20 @@
---
title: Components Reference
manTitle: 8. COMPONENTS REFERENCE
sidebar:
order: 12
helpKeywords:
- componentsreference
---
The following tables detail every component in each category. Use this
reference to understand exactly which behaviors change when you toggle a
category variable.
Category Description
──────────────────────────────────────────────────────────────────────────
C1 [Command Shadows](/08-components-reference/01-c1-command-shadows/) — Wraps destructive commands (`rm`, `cp`) to be safe by default
C2 [Startup Side-Effects](/08-components-reference/02-c2-startup-side-effects/) — Bootstraps Fisher, generates wrappers, auto-activates venvs
C3 [Overrides](/08-components-reference/03-c3-key-and-environment-overrides/) — Overrides `cd`, sets Vi mode, binds `<CR>` to `smart_enter`
C4 [Integrations](/08-components-reference/04-c4-terminal-and-tool-integration/) — Kitty/Wezterm integrations, starship hooks, fzf theme
C5 [Logging and Capture](/08-components-reference/05-c5-logging-and-capture/) — Session logs, command duration
C6 [Greeting & First-Run UI](/08-components-reference/06-c6-greeting-and-first-run-ui/) — Custom startup banner
+107
View File
@@ -0,0 +1,107 @@
---
title: Fisher Plugins
manTitle: 9. FISHER PLUGINS
sidebar:
order: 13
helpKeywords:
- plugins
- fisher
---
Fisher is bootstrapped automatically on the **first interactive session** via
`conf.d/first_run.fish`. 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.
To re-trigger first-run initialization (e.g., after a fresh install or for
testing), run:
set -Ue __fish_config_first_run_complete
Then open a new shell.
## Fisher-Managed Plugins
The following plugins are fully managed by Fisher. Their files are installed
into the repo directory by Fisher and are listed in `.gitignore` — do not
commit them. Fisher installs and updates them automatically.
- `jorgebucaran/fisher` — Plugin manager itself
- `meaningful-ooo/sponge` — Remove failed commands from history
## Sponge History Filtering
Sponge removes failed commands from history and, via conf.d/sponge_privacy.fish,
also filters privacy-sensitive commands through three layers:
Layer 1 — Static patterns (universal, persistent across sessions):
Commands matching any of these structural signatures are never recorded:
- `--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 "Authorization: ..."`
- Basic auth flags: `curl -u user:pass`
- `sshpass`, `docker login -p`, `openssl -passin/-passout`
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.
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.
To add your own persistent patterns:
set -U -a sponge_regex_patterns 'your-regex-here'
To mark additional variable NAMES as credential-bearing (so Layer 2 scrubs
their values), add name tokens — via `config-settings` → Sponge, or directly:
set -U -a __fish_sponge_extra_sensitive ACME_API VAULT_PW
Tokens are folded into the Layer 2 name match case-insensitively as substrings,
so ACME_API also covers ACME_API_KEY. (The match uses `--entire` to return the
full variable name, so partial-name tokens dereference the right value.)
The `config-settings` Sponge page also surfaces sponge's own tuning variables —
sponge_delay, sponge_successful_exit_codes, sponge_purge_only_on_exit, and
sponge_allow_previously_successful — so they can be changed without typing
variable names.
## Bundled Plugin Functionality
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.
Bundled components and their upstream origins:
- `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`
Do not run `fisher install` for these — it will overwrite the customized
versions. To update their behavior, edit the relevant bundled files directly.
## fish_plugins Manifest
The `fish_plugins` file at the config root:
- `jorgebucaran/fisher` — Plugin manager itself
- `meaningful-ooo/sponge` — Remove failed commands from history
To update all Fisher-managed plugins, run `fisher update` or `fish-deps
update` which calls it as its first step.
---
+41
View File
@@ -0,0 +1,41 @@
---
title: Installation
manTitle: 10. INSTALLATION
sidebar:
order: 14
helpKeywords:
- installation
- install
---
This configuration is managed as a git repository. To deploy on a new machine:
mv ~/.config/fish ~/.config/fish.bak # back up any existing config
git clone https://git.rootiest.dev/rootiest/fish-config.git ~/.config/fish
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.
## Return Sentinel
`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.
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.
## Updating
Pull the latest changes from the upstream repository without needing a
configured git remote:
- `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
All git output is suppressed. Run `exec fish` after a successful update to reload.
---
+69
View File
@@ -0,0 +1,69 @@
---
title: Personalization
manTitle: 11. PERSONALIZATION
sidebar:
order: 15
helpKeywords:
- personalization
- personalize
---
Sensitive credentials and machine-specific settings are kept out of version
control in a private directory. The path defaults to
`~/.config/.user-dots/fish/` but can be overridden:
set -U __fish_user_dots_path /path/to/your/dots/fish
Or use the interactive TUI — run `config-settings` and navigate to the
"Dots Path" row (last row). Press Enter to type a new path, or ← / h to
reset to the default.
config.fish sources local.fish from that directory on every interactive
session. local.fish is responsible for sourcing its own secrets.fish:
$__fish_user_dots_path/
├── secrets.fish API keys, tokens, passwords, personal identifiers
└── local.fish Machine-specific paths, env vars, and sourcing secrets
fish_variables (auto-managed by fish) is excluded from this repo via
.gitignore. Do not commit it.
## secrets.fish
Store anything you would not commit to a public repo: API keys, auth tokens,
passwords, and personal identifiers.
# secrets.fish
set -gx MY_NAME "Your Name"
set -gx MY_EMAIL "you@example.com"
set -gx GPG_RECIPIENT "you@example.com"
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
## local.fish
Store paths and variables specific to one machine — things that would be
wrong on any other system.
# 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 'ssh you@your-server.local'
abbr -a sshw 'ssh you@work-server.example.com'
# Docker context shortcuts
abbr -a dcr 'docker context use my-remote-server'
abbr -a dcw 'docker context use work-server'
local.fish is sourced at the end of config.fish with an existence check so
the public config works cleanly on any machine without the private repo.
local.fish in turn sources secrets.fish when it exists.
---
+242
View File
@@ -0,0 +1,242 @@
---
title: Troubleshooting
manTitle: 12. TROUBLESHOOTING
sidebar:
order: 16
helpKeywords:
- troubleshooting
- troubleshoot
- faq
- help
- uninstall
- revert
---
This section covers common issues, their solutions, and how to safely revert changes or uninstall the configuration entirely.
## Uninstalling and Reverting to Backup
The installation step backs up any existing config to `~/.config/fish.bak`.
To revert:
rm -rf ~/.config/fish
mv ~/.config/fish.bak ~/.config/fish
If no backup exists, remove the directory and let Fish regenerate a default
config on next launch:
rm -rf ~/.config/fish
fish -c 'fish_config theme choose "Fish default"'
Clean up files generated outside the config directory:
rm -f ~/.local/bin/paru ~/.local/bin/yay # AUR log wrappers
rm -f ~/.local/share/man/man1/fish-config.1 # man page symlink
rm -f ~/.config/fish/.logging_disabled # C5 sentinel
Erase universal variables set by this config:
for v in (set -Un | string match '__fish_config*')
set -Ue $v
end
for v in __done_min_cmd_duration __done_notification_urgency_level
set -Ue $v
end
for v in (set -Un | string match 'sponge_*')
set -Ue $v
end
The `~/.terminal_history/` log directory contains your session logs. Remove
it only if you do not want to keep them.
## Fish Version Requirement
This config requires Fish 4.x or newer. Check your version:
fish --version
Run `fish-deps` to see a status report — an outdated Fish shows ⚠ with an
upgrade message.
Upgrading Fish by distribution:
# Arch / AUR
pacman -S fish # or paru -S fish
# Ubuntu / Debian (PPA)
sudo apt-add-repository ppa:fish-shell/release-4
sudo apt update && sudo apt install fish
# Fedora
sudo dnf install fish
# macOS
brew install fish
For other systems or building from source, see https://fishshell.com.
## Enable or Disable Session Logging
Session logging is opt-in: it is off until you turn it on. To enable all
logging and capture (scrollback, tmux/zellij pane logs, AUR helper wrappers,
Kitty watcher):
set -U __fish_config_op_logging on
Or toggle it interactively: run `config-settings` and flip the Logging row.
Disable it again — either an explicit falsy value or erasing the variable
returns you to the default off state:
set -U __fish_config_op_logging off
set -Ue __fish_config_op_logging
This takes effect immediately in all running shells — no restart needed. The
sentinel file, wrapper removal, and pipe-pane teardown happen automatically.
See [C5 — Logging and Capture](/08-components-reference/05-c5-logging-and-capture/) for the full component breakdown.
## Change or Disable the Greeting
This config suppresses the distro greeting (e.g. CachyOS fastfetch) by
default. To let the distro greeting through:
set -U __fish_config_op_greeting off
To set a custom greeting, define fish_greeting in your local.fish:
# in $__fish_user_dots_path/local.fish
function fish_greeting
echo "Hello, world!"
end
The first-run welcome banner runs exactly once. To re-trigger it (e.g. for
testing):
set -Ue __fish_config_first_run_complete
See [C6 — Greeting and First-Run UI](/08-components-reference/06-c6-greeting-and-first-run-ui/) for details.
## Secrets and Machine-Local Configuration
Machine-specific config goes in `$__fish_user_dots_path/local.fish` (defaults
to `~/.config/.user-dots/fish/local.fish`). Secrets go in `secrets.fish` in
the same directory.
If local.fish is not loading, verify the path:
echo $__fish_user_dots_path
test -f "$__fish_user_dots_path/local.fish"; and echo exists; or echo missing
Change the path via variable or TUI:
set -U __fish_user_dots_path /new/path/to/dots/fish
Or run `config-settings`, navigate to the Paths page, and edit "Dots path".
The `user-dots` convenience symlink in the config directory tracks this path.
Disable it with:
set -U __fish_user_dots_symlink false
See [Personalization](/11-personalization/) for the full `local.fish` / `secrets.fish`
layout.
## Tool Init Does Nothing (Return Sentinel)
Symptom: you ran a tool's setup command (e.g.
`starship init fish >> ~/.config/fish/config.fish`) and nothing changed.
Cause: `config.fish` ends with a `return` guard. Any lines appended after it
are never executed.
Fix: create a dedicated `conf.d/` file instead of appending to `config.fish`:
# ~/.config/fish/conf.d/mytool.fish
mytool init fish | source
All existing integrations (starship, zoxide, direnv) already have `conf.d/`
files. See [Return Sentinel](/10-installation/#return-sentinel) for background.
## Missing Dependencies
Run `fish-deps` (defaults to `fish-deps status`) to see what is installed
and what is missing. Common symptoms and their missing tools:
Symptom Missing tool
─────────────────────────────────────────────────────
ls output has no icons or colors eza (or lsd)
cd does not remember directories zoxide
cat shows no syntax highlighting bat
fzf keybindings do nothing fzf
Starship prompt not appearing starship
Install missing dependencies interactively:
fish-deps install
Or install everything missing and update what is installed:
fish-deps sync
See [Dependency Catalog](/06-dependency-catalog/) for the full list grouped by tier
(required, integrations, recommended).
## Vi Mode Keybindings
This config enables Vi mode by default (via C3 overrides), replacing the
standard Emacs-style bindings. If Vi mode interferes with your workflow,
override it in `local.fish` (See [Personalization](/11-personalization/)):
# $__fish_user_dots_path/local.fish
fish_default_key_bindings
This restores Emacs-style bindings without disabling the rest of C3
(bang-bang, autopair, starship prompt, pager settings, etc.).
To disable the entire C3 category (Vi mode and all other key/environment
overrides):
set -U __fish_config_op_overrides off
See [C3 — Key and Environment Overrides](/08-components-reference/03-c3-key-and-environment-overrides/) for the full list of
what C3 controls.
## What's with the C1-C6 stuff?
This configuration groups its opinionated behaviors into six categories (C1C6), allowing you to selectively disable features that conflict with your workflow. The **C**ategory numbers are used as shorthand when referencing these. Disabling all of them leaves you with a "Minimal Mode" shell that only manages basic features like `XDG` variables, and your `local.fish` overrides.
Category Description
──────────────────────────────────────────────────────────────────────────
C1 [Command Shadows](/08-components-reference/01-c1-command-shadows/) — Wraps destructive commands (`rm`, `cp`) to be safe by default
C2 [Startup Side-Effects](/08-components-reference/02-c2-startup-side-effects/) — Bootstraps Fisher, generates wrappers, auto-activates venvs
C3 [Overrides](/08-components-reference/03-c3-key-and-environment-overrides/) — Overrides `cd`, sets Vi mode, binds `<CR>` to `smart_enter`
C4 [Integrations](/08-components-reference/04-c4-terminal-and-tool-integration/) — Kitty/Wezterm integrations, starship hooks, fzf theme
C5 [Logging and Capture](/08-components-reference/05-c5-logging-and-capture/) — Session logs, command duration
C6 [Greeting & First-Run UI](/08-components-reference/06-c6-greeting-and-first-run-ui/) — Custom startup banner
Disable all opinionated features at once (Minimal Mode):
set -U __fish_config_opinionated 0
Disable a single category:
set -U __fish_config_op_aliases off # C1
set -U __fish_config_op_autoexec off # C2
set -U __fish_config_op_overrides off # C3
set -U __fish_config_op_integrations off # C4
set -U __fish_config_op_logging off # C5 (already off by default)
set -U __fish_config_op_greeting off # C6
Keep one category active under a master disable:
set -U __fish_config_opinionated 0
set -U __fish_config_op_aliases 1 # only C1 stays on
Re-enable everything:
set -Ue __fish_config_opinionated
For an interactive alternative to setting these variables by hand, run `config-settings`.
---
+96
View File
@@ -0,0 +1,96 @@
---
title: Viewing This Manual
manTitle: 13. VIEWING THIS MANUAL
sidebar:
order: 17
helpKeywords:
- viewing
- manual
---
There are four ways to read this manual.
## The documentation website
help config --html
Opens https://fish.rootiest.fyi/ in the default browser — the
Starlight-powered site built from `docs/manual/**` on every push to `main`.
It has a section sidebar and full-text search. Deep links to a specific
section aren't supported from the command line; once the site opens, use
its search box to jump straight to what you need.
## As a man page
help config --man
help config pkg --man
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:
man fish-config
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.
## In the terminal
help config
help config keybindings
Without a pager available beyond the basics, `help config [SECTION]` opens
the Markdown manual in the best available viewer, falling back through:
1. ov + bat section navigation + syntax highlighting (best)
2. ov alone section navigation, raw Markdown
3. bat alone syntax highlighting, use / to search
4. man -l pre-compiled man page (if available)
5. less plain text with line-jump
6. cat plain output
With ov, the Markdown renders with syntax highlighting and section-based
navigation:
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 'section')
q quit
If SECTION is given, the pager opens at the first heading that matches the
keyword (case-insensitive; checks `docs/fish-config.index` aliases first,
then falls back to a normalized heading scan):
help config keybindings
help config abbreviations
help config pkg
help config logs
help config fish-deps
## Reading the source directly
`docs/manual/**` is the single source of truth this manual, the man page,
and the website are all generated from. Numbered files and directories
correspond to the numbered sections in this manual — browse them in any
editor, or from a shell:
cd ~/.config/fish/docs/manual
grep -rn "keybindings" .
Section 5 is the exception. Function entries are generated from the
man-page-style comment header above each function in `functions/*.fish`,
so the documentation for a command lives beside the code that implements
it and cannot drift from it. To read the source for a single function, or
to correct its documentation, open the function itself:
functions/git-clean.fish
The files under `docs/manual/05-functions/` carry only the category
titles, ordering, and search keywords.
+16
View File
@@ -0,0 +1,16 @@
---
title: '404'
template: splash
editUrl: false
man: false
hero:
title: '404'
tagline: 'That page doesn''t exist. Check the URL, try using the search bar, or use one of the links below:'
---
<CardGrid>
<LinkCard title="Home" description="Return to the main manual page" href="/" />
<LinkCard title="Installation" description="Set up the configuration" href="/10-installation/" />
<LinkCard title="Troubleshooting" description="Fix common issues" href="/12-troubleshooting/" />
<LinkCard title="Function Reference" description="Browse all functions" href="/reference/" />
</CardGrid>
+5
View File
@@ -0,0 +1,5 @@
title: FISH-CONFIG
section: 7
header: Fish Shell Configuration User Manual
date: June 2026
author: Rootiest
+70
View File
@@ -0,0 +1,70 @@
---
title: Fish Shell Configuration
description: Reference manual for the rootiest fish configuration.
manTitle: DESCRIPTION
sidebar:
order: 3
helpKeywords:
- description
- autopair
- puffer
- puffer-fish
- logging-events
---
A production-grade Fish shell configuration targeting Fish 4.x. It provides:
- Drop-in replacements for common Unix tools (`ls`, `cat`, `rm`, `du`, `ping`, `less`)
- Deep Kitty and WezTerm terminal integration: tab/window/pane management from
the command line
- Optional session logging: terminal scrollback, tmux/zellij panes, and
paru/yay output captured to `~/.terminal_history` (off by default; see [C5 Logging](/08-components-reference/05-c5-logging-and-capture/))
- Automatic Python virtualenv activation on directory change
- Cross-platform package management via pkg and fish-deps
- AI scaffolding helpers for Claude Code and Antigravity
- Catppuccin Mocha color theme throughout
<LinkButton href="/10-installation/" icon="cloud-download" style="font-size: 1.25rem; padding: 1rem 1.5rem; margin-right: 1rem;">Install now</LinkButton>
<LinkButton href="/reference/" variant="secondary" style="font-size: 1.125rem; padding: 0.85rem 1.25rem;">Functions</LinkButton>
<LinkButton href="/08-components-reference/" variant="secondary" style="font-size: 1.125rem; padding: 0.85rem 1.25rem;">Components</LinkButton>
The configuration uses a structured file tree:
~/.config/fish/
├── config.fish Main entry point; sets env vars and PATH
├── conf.d/
│ ├── abbr.fish All abbreviations
│ ├── autopair.fish Auto-pair brackets and quotes
│ ├── cheat.fish cheat.sh tab completions
│ ├── done.fish Desktop notifications for long commands
│ ├── first_run.fish One-time init: Fisher bootstrap, theme
│ ├── key_bindings.fish Custom key bindings and Vi mode
│ ├── logging-events.fish C5 event handlers; syncs logging state
│ ├── kitty-watcher-reminder.fish C5 per-session Kitty watcher reminder
│ ├── paru-wrapper.fish Auto-generates paru logging wrapper
│ ├── puffer.fish !! / !$ / ./ expansion
│ ├── tmux-logging.fish C5 starts tmux pipe-pane capture
│ ├── zellij-logging.fish C5 fish_exit handler for zellij
│ ├── sponge_privacy.fish Sponge privacy patterns
│ ├── starship.fish fish_prompt shell-integration markers
│ ├── tailscale.fish Tailscale CLI tab completions
│ ├── theme.fish Catppuccin syntax highlight colors
│ ├── tricks.fish PATH, bang-bang helpers, bat man pages
│ ├── wakatime.fish WakaTime shell hook
│ ├── yay-wrapper.fish Auto-generates yay logging wrapper
│ └── zoxide.fish Zoxide z/zi integration; overrides cd
├── functions/ Custom functions, one per file
├── completions/ Tab completion scripts
├── integrations/
│ └── fzf.fish FZF Catppuccin theme and key bindings
├── scripts/
│ ├── clean_progress_log.py Strips typescript animations for clean logs
│ └── agents-tools/ AGENTS.md scripts and git hooks
└── docs/ Offline documentation and man page
├── fish-config.md Primary source manual
├── fish-config.1 Compiled man page (auto-generated)
├── fish-config.index Section index for help config
├── html/ Chunked HTML docs (auto-generated)
└── wiki/ Markdown wiki (auto-generated)
---
+214
View File
@@ -0,0 +1,214 @@
#!/usr/bin/env python3
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Shared helpers for the docs/manual SSOT pipeline.
Frontmatter parsing, deterministic tree ordering, heading level shifts, and
the `functions/*.fish` comment-header parser that is the SSOT for Section 5.
Used by build-manual.py and verify-manual.py.
"""
import re
from pathlib import Path
import yaml
FENCE_RE = re.compile(r"^\s*(```|~~~)")
HEADING_RE = re.compile(r"^(#{1,6})(\s)")
def parse(path: Path) -> tuple[dict, str]:
"""Split a markdown file into (frontmatter dict, body text).
Files without a leading `---` block yield an empty dict and the whole
text as body. Body is returned with trailing whitespace stripped.
"""
text = path.read_text()
if not text.startswith("---\n"):
return {}, text.rstrip()
end = text.find("\n---\n", 4)
if end == -1:
return {}, text.rstrip()
fm = yaml.safe_load(text[4:end]) or {}
return fm, text[end + 5 :].removeprefix("\n").rstrip()
def serialize(fm: dict, body: str) -> str:
"""Render a frontmatter dict and body back into markdown text."""
block = yaml.safe_dump(fm, sort_keys=False, allow_unicode=True).rstrip()
return f"---\n{block}\n---\n\n{body.rstrip()}\n"
def shift_headings(body: str, by: int) -> str:
"""Add `by` levels to every ATX heading, ignoring fenced code blocks.
Negative values promote headings. Level is clamped to [1, 6].
"""
if by == 0:
return body
out, in_fence = [], False
for line in body.split("\n"):
if FENCE_RE.match(line):
in_fence = not in_fence
if not in_fence:
line = HEADING_RE.sub(
lambda m: "#" * max(1, min(6, len(m.group(1)) + by)) + m.group(2), line
)
out.append(line)
return "\n".join(out)
HEADER_LABEL = re.compile(r"^#\s+([A-Z][A-Z ]*[A-Z])\s*$")
FUNC_DEF = re.compile(r"^\s*function\s+(\S+)")
SECTIONS = (
"CATEGORY",
"DEPENDENCIES",
"SYNOPSIS",
"DESCRIPTION",
"ARGUMENTS",
"EXIT STATUS",
"RETURNS",
"EXAMPLE",
"NOTES",
)
def _header_blocks(lines: list[str]) -> list[tuple[int, dict[str, list[str]]]]:
"""Find every man-page comment header in a file's lines.
Yields (index of the line that ended the block, {LABEL: body lines}).
Body lines keep any indentation deeper than the standard `# ` prefix,
which is what lets nested option tables survive into the rendered entry.
Comment runs carrying no `# LABEL` line at all (the copyright preamble,
ordinary inline comments) produce nothing.
"""
out: list[tuple[int, dict[str, list[str]]]] = []
cur: dict[str, list[str]] = {}
label: str | None = None
for i, line in enumerate(lines + [""]):
if not line.startswith("#"):
if cur:
out.append((i, cur))
cur, label = {}, None
continue
m = HEADER_LABEL.match(line)
if m:
label = m.group(1)
cur.setdefault(label, [])
elif label is not None:
body = line[1:]
cur[label].append(body[3:] if body.startswith(" ") else body.strip())
return out
def _trailing_blanks(lines: list[str]) -> int:
"""Count the blank `#` separator lines closing a section."""
n = 0
while n < len(lines) and not lines[len(lines) - 1 - n].strip():
n += 1
return n
def parse_functions(root: Path) -> dict[str, dict[str, list[str]]]:
"""Parse the comment header above every documented public function.
`root` is the repository's `functions/` directory. Returns
`{name: {LABEL: [lines]}}`.
`# CATEGORY` is the opt-in: a header without one produces no entry. That
keeps bundled-plugin and prompt internals (`fish_prompt`, `sponge_filter_*`,
`fisher`, ) out of the manual with no exclusion list to maintain.
A file carrying exactly one header is associated with its own stem, so a
`function` nested inside a `type -q` guard still resolves. Only files with
several headers walk forward to the next `function` definition.
"""
out: dict[str, dict[str, list[str]]] = {}
for path in sorted(root.glob("*.fish")):
lines = path.read_text(encoding="utf-8").split("\n")
blocks = _header_blocks(lines)
for end, sections in blocks:
if len(blocks) == 1:
name = path.stem
else:
after = (m.group(1) for ln in lines[end:] if (m := FUNC_DEF.match(ln)))
name = next(after, path.stem)
if name.startswith("_") or "CATEGORY" not in sections:
continue
out[name] = {
k: v[: len(v) - _trailing_blanks(v)] for k, v in sections.items()
}
return out
def parse_abbreviations(root: Path) -> dict[str, list[dict]]:
"""Parse annotated abbreviations from conf.d/.
Returns {category: [{"name": name, "desc": desc}, ...]}
"""
out: dict[str, list[dict]] = {}
for filename in ("abbr.fish", "tricks.fish", "puffer.fish"):
path = root / filename
if not path.exists():
continue
lines = path.read_text(encoding="utf-8").split("\n")
category = None
desc = None
name_override = None
for line in lines:
line = line.strip()
if line.startswith("# @category "):
category = line[12:].strip()
elif line.startswith("# @desc "):
desc = line[8:].strip()
elif line.startswith("# @name "):
name_override = line[8:].strip()
elif line.startswith("abbr -a ") or line.startswith("bind ") or line.startswith("alias "):
if category and desc:
if name_override:
name = name_override
elif line.startswith("abbr -a "):
name = line[8:].strip().split()[0].strip("'\"")
elif line.startswith("alias "):
name = line[6:].strip().split('=')[0]
else:
name = "unknown"
# Only add if we haven't added this name to this category yet
if not any(a["name"] == name for a in out.setdefault(category, [])):
out[category].append({
"name": name,
"desc": desc
})
category = None
desc = None
name_override = None
return out
def _sort_key(entry: Path) -> tuple:
"""Order by sidebar.order when present, else by filename. Stable."""
target = entry / "index.md" if entry.is_dir() else entry
order = None
if target.exists():
fm, _ = parse(target)
order = (fm.get("sidebar") or {}).get("order")
return (order is None, order if order is not None else 0, entry.name)
def walk(root: Path, depth: int = 0) -> list[tuple[Path, int]]:
"""Return ordered (path, depth) pairs for every markdown file under root.
A directory sorts at the position of its index.md and its children are
emitted immediately afterwards at depth+1.
"""
entries = [e for e in root.iterdir() if e.is_dir() or e.suffix == ".md"]
result: list[tuple[Path, int]] = []
for entry in sorted(entries, key=_sort_key):
if entry.is_dir():
index = entry / "index.md"
if index.exists():
result.append((index, depth))
result.extend(walk(entry, depth + 1))
elif entry.name != "index.md" or depth == 0:
result.append((entry, depth))
return result
+21
View File
@@ -0,0 +1,21 @@
# build output
dist/
# generated types
.astro/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store
+4
View File
@@ -0,0 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}
+11
View File
@@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}
+34
View File
@@ -0,0 +1,34 @@
# fish-config docs site
[Starlight](https://starlight.astro.build) site for the
[fish-config](https://git.rootiest.dev/rootiest/fish-config) manual.
## Generated, not authored
Everything under `src/content/docs/` is generated — **do not edit it
directly**, changes will be overwritten. The sources are:
- `docs/manual/**` — prose for every section except the functions reference
- `functions/*.fish` comment headers — the functions reference (Section 5)
Regenerate from the repo root:
```fish title="regenerate the site content"
python3 docs/build-manual.py --site
```
`docs/verify-manual.py` validates both sources before you build; run it
first if you've touched a header or a manual page.
## Development
```fish title="local dev server"
cd docs/site
npm install
npm run dev
```
## Deploy
Built and deployed to Cloudflare Pages by the Gitea Actions workflow on
every push to `main` — there's no manual deploy step.
+51
View File
@@ -0,0 +1,51 @@
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import starlightLinksValidator from 'starlight-links-validator';
import starlightCatppuccin from '@catppuccin/starlight';
import sidebar from './src/sidebar.json' with { type: 'json' };
export default defineConfig({
prerenderConflictBehavior: 'ignore',
site: 'https://fish.rootiest.fyi',
integrations: [
starlight({
title: 'Rootiest Fish Config',
description: 'Reference manual for the rootiest fish configuration.',
favicon: '/favicon.svg',
logo: {
src: './src/assets/logo.svg',
},
social: [
{
icon: 'code-branch',
label: 'Gitea',
href: 'https://git.rootiest.dev/rootiest/fish-config',
},
],
head: [
{
tag: 'script',
content: 'document.addEventListener("DOMContentLoaded", () => { document.querySelectorAll("starlight-file-tree").forEach(tree => { tree.querySelectorAll("details").forEach((d, i) => { if (i !== 0) d.removeAttribute("open"); }); }); });',
},
],
plugins: [
starlightLinksValidator(),
starlightCatppuccin({
dark: { flavor: "mocha", accent: "green" },
light: { flavor: "latte", accent: "sky" },
}),
],
expressiveCode: {
// Shiki ships both Catppuccin flavours; Starlight picks by the
// reader's colour scheme, matching the palette in catppuccin.css.
themes: ['catppuccin-mocha', 'catppuccin-latte'],
styleOverrides: {
borderRadius: '0.4rem',
borderColor: 'var(--sl-color-gray-5)',
codeFontSize: '0.875rem',
},
},
sidebar,
}),
],
});
+7062
View File
File diff suppressed because it is too large Load Diff

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