Author SHA1 Message Date
rootiest f6ead99f48 feat(help): header-driven --help for development functions, plus the wiring guard
bd-pull, branch, check_fish_deps, claude-docs, claude-pr, fast, poke, qr
and parur take the standard call site. fish-deps instead routes -h/--help
to its existing __fish_deps_help, which previously answered only via the
unknown-subcommand path, printing "Unknown subcommand: --help" and
exiting 1.

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

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

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

$__help_exempt is the single machine-readable exemption record; a second
assertion fails if an exempt name stops being a published function, so a
rename or deletion upstream cannot silently exempt nothing.
2026-09-07 20:09:30 -04:00
rootiest 3d826c5407 feat(help): header-driven --help for terminal and session functions
spwin, tab, hist, bkg, wake-lock and fc take the standard first-arg-only
call site, so `wake-lock rsync --help` still runs rsync.

split takes --help only: its own ARGUMENTS documents -h as --horizontal,
so a literal test replaces the renderer's own flag check. Verified that
`split -h` still selects a horizontal split and never prints help.
2026-09-07 20:07:25 -04:00
rootiest 3399149cba feat(help): header-driven --help for system-info functions
gip, gip4, gip6, ports, swapstat, sbver and steam-dl. All ignored $argv,
so --help previously ran the query or the launcher. sbver keeps its own
--brief flag: only argv[1] is inspected and --brief is not a help flag,
so the body still runs for it.
2026-09-07 20:06:23 -04:00
rootiest 71574b5030 feat(help): header-driven --help for listing presets
lD, lsr, lss, lstree, lt, ltr, lx and ld. None shadows a real binary, so
there is no disabled-fallback contract to honour, and `eza --help`
documented eza rather than the preset that is these functions' entire
content. First-arg-only interception leaves `lt -la --help` passing
through to eza untouched.
2026-09-07 20:05:15 -04:00
rootiest 037588ecf6 fix(help): stop eight functions executing on --help
These eight ignore $argv entirely, so passing --help ran the command
instead of describing it. The new check shadows every external binary
they reach with a recording stub on PATH and fails if anything is
invoked. Before the fix it reported, verbatim:

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

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

Each now answers --help from its own comment header. The call site is the
first statement of the body, above the C4 guard, so help stays reachable
when the component is disabled and nothing side-effecting runs first.
2026-09-07 20:04:02 -04:00
rootiest b424b26700 test(help): pin the renderer's degraded-path contract
A missing or label-less header must still print and exit 0. Returning 1
would hand control back to the caller's body, which for upgrade(1) is a
full system upgrade.

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

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

The mutation was reverted before this commit.
2026-09-07 19:59:50 -04:00
rootiest 9077d9837e feat(help): add __fish_help_header runtime renderer
Parses a function's own man-page comment header at call time and prints
it as a help menu on stdout, so the documentation that already generates
Section 5 of the manual becomes reachable from the shell.

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

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

Nothing calls it yet.
2026-09-07 14:59:05 -04:00
rootiest 8a2731d411 revert: untrack the spec
AGENTS/ is gitignored upstream; a tracked file there pollutes
git diff main..work, which is what the user reads when choosing
which job to merge. Spec stays on disk, browsable, out of history.
2026-09-07 07:22:51 -04:00
rootiest 21a02fd0e4 docs(specs): add header-driven --help design
Design for making the man-page-style comment header above each function
reachable at runtime via -h/--help, instead of hand-writing 40 more menus.

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

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

Note: AGENTS/ is gitignored upstream, so this file is force-added.
2026-09-07 03:06:30 -04:00
74 changed files with 721 additions and 375 deletions
+7 -1
View File
@@ -38,7 +38,13 @@ function __config_settings_draw
set -l cur_scope $argv[2]
set -l vars $argv[3..]
__fish_palette
set -l c_ok (set_color green)
set -l c_err (set_color red)
set -l c_dim (set_color brblack)
set -l c_sel (set_color --bold magenta)
set -l c_hi (set_color --bold white)
set -l c_head (set_color --bold cyan)
set -l c_reset (set_color normal)
set -l labels Aliases Auto-exec Overrides Integrations Logging Greeting Master
+6 -1
View File
@@ -41,7 +41,12 @@ function __config_settings_draw_subcat
set -l cur_scope $argv[2]
set -l category_var $argv[3]
__fish_palette
set -l c_ok (set_color green)
set -l c_err (set_color red)
set -l c_dim (set_color brblack)
set -l c_sel (set_color --bold magenta)
set -l c_head (set_color --bold cyan)
set -l c_reset (set_color normal)
set -l rows (__config_settings_subcats $category_var)
set -l n (count $rows)
+6 -1
View File
@@ -33,7 +33,12 @@ function __config_settings_draw_value
set -l edit_mode $argv[3]
set -l edit_buf $argv[4]
__fish_palette
set -l c_ok (set_color green)
set -l c_err (set_color red)
set -l c_dim (set_color brblack)
set -l c_sel (set_color --bold magenta)
set -l c_head (set_color --bold cyan)
set -l c_reset (set_color normal)
# ── Page row metadata (parallel lists) ────────────────────────────────
set -l title
+2 -1
View File
@@ -27,7 +27,8 @@ function __config_settings_pagetab
set -l active $argv[1]
set -l iw $argv[2]
__fish_palette
set -l c_hi (set_color --bold white)
set -l c_reset (set_color normal)
set -l names Universal Session Sponge Paths
set -l strip ' '
+141
View File
@@ -0,0 +1,141 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# SYNOPSIS
# __fish_help_header <name> [args...]
#
# DESCRIPTION
# Prints <name>'s man-page comment header as a help menu on stdout.
# Intended as the first statement of a user-facing function's body:
#
# __fish_help_header (status current-function) $argv; and return 0
#
# Returns 1 -- printing nothing -- ONLY when args[1] is not a help flag.
# Every other outcome, including an unreadable or headerless source
# file, prints something and returns 0. That asymmetry is load-bearing:
# a return of 1 means "run the real body", and the real body of upgrade
# is `paru -Syu --noconfirm`. A parse failure must never return 1.
#
# Only args[1] is inspected, never the whole list. wake-lock, bkg,
# split and spwin take a command to run as their arguments, so
# scanning all of $argv would make `wake-lock rsync --help` print
# wake-lock's own help instead of running rsync.
#
# The header is read from the caller's source at call time rather than
# from the generated manual, so it cannot go stale between a header
# edit and a docs rebuild.
#
# ARGUMENTS
# name The calling function's name, from (status current-function)
# args... The caller's $argv, forwarded verbatim
#
# EXIT STATUS
# 0 Help was printed, including the degraded fallback
# 1 args[1] is not -h/--help; the caller should carry on
#
# EXAMPLE
# __fish_help_header (status current-function) $argv; and return 0
#
# NOTES
# Section labels are those of the manual SSOT parser in
# docs/manualtools.py. CATEGORY, COMPONENT and DEPENDENCIES are build
# metadata and are suppressed; SYNOPSIS renders as USAGE and EXAMPLE as
# EXAMPLES.
function __fish_help_header --argument-names name
# First argument only -- see DESCRIPTION.
contains -- "$argv[2]" -h --help; or return 1
set -l c_ttl (set_color --bold)
set -l c_sec (set_color --bold brblue)
set -l c_rst (set_color normal)
set -l miss " No documentation header found. Try: help config $name"
set -l file (functions -D -- $name 2>/dev/null)
if not test -f "$file"
# Quoted: set_color yields an EMPTY LIST under TERM=dumb, and an
# unquoted empty list in a concatenation annihilates the whole
# word -- the title line would silently vanish wherever colour is
# off, which is exactly where a test would be reading it.
echo "$c_ttl$name$c_rst"
echo $miss
return 0
end
# Collect the contiguous comment run directly above `function <name>`,
# walking backwards. This resolves multi-header files (fish-deps, gi,
# y) without reimplementing manualtools._block_identity, and is more
# accurate at runtime: in dops.fish it finds the header above
# `function docker` rather than attributing it to the file stem.
# One blank separator line is tolerated -- sponge_filter_secrets.fish
# is the only file that has one, and JOB-BRIEF-FINDINGS.md records it
# so this skip is not mistaken for dead code.
set -l lines (string split \n -- (command cat $file))
set -l pat '^\s*function\s+'(string escape --style=regex -- $name)'(\s|$)'
set -l start 0
for i in (seq (count $lines))
if string match -qr -- $pat $lines[$i]
set start $i
break
end
end
set -l header
if test $start -gt 1
set -l j (math $start - 1)
if test -z (string trim -- "$lines[$j]")
set j (math $j - 1)
end
while test $j -ge 1; and string match -q '#*' -- $lines[$j]
set -p header $lines[$j]
set j (math $j - 1)
end
end
# Render. Comment lines before the first `# LABEL` -- the copyright
# preamble -- carry no label and are dropped, matching
# manualtools._header_blocks.
set -l skip CATEGORY COMPONENT DEPENDENCIES
set -l label ""
set -l out
for line in $header
set -l m (string match -r -- '^#\s+([A-Z][A-Z ]*[A-Z])\s*$' $line)
if set -q m[2]
set label $m[2]
contains -- $label $skip; and continue
set -l shown (string replace SYNOPSIS USAGE -- $label)
set shown (string replace EXAMPLE EXAMPLES -- $shown)
# One blank line before a heading, never two: the header's own
# `#` separator has usually already emitted one.
if set -q out[1]; and test -n (string trim -- "$out[-1]")
set -a out ""
end
set -a out "$c_sec$shown$c_rst"
continue
end
test -n "$label"; or continue
contains -- $label $skip; and continue
set -l body (string sub -s 2 -- $line)
if string match -q ' *' -- $body
set -a out " "(string sub -s 4 -- $body)
else
set -a out (string trim -- $body)
end
end
# Trim the trailing blank separator, mirroring
# manualtools._trailing_blanks.
while set -q out[-1]; and test -z (string trim -- "$out[-1]")
set -e out[-1]
end
echo "$c_ttl$name$c_rst"
if test (count $out) -eq 0
echo $miss
else
# out[1] is always a heading -- a body line cannot precede the
# first label -- so this blank is never doubled.
echo ""
printf '%s\n' $out
end
return 0
end
-63
View File
@@ -1,63 +0,0 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# SYNOPSIS
# __fish_palette
#
# DESCRIPTION
# Defines the shared terminal-output colour roles used by the
# user-facing functions in this configuration. Declared
# --no-scope-shadowing and using a bare `set`, so the variables are
# created in the CALLER's scope -- a consumer just calls it and then
# interpolates $c_head, $c_err and friends exactly as it did when the
# declarations were inline.
#
# Call it where the local declarations used to sit, once per contiguous
# block that needs the palette. set_color runs at call time, so the
# values track $TERM exactly as inline declarations did. (Measured:
# set_color output is identical across every TERM tested except
# TERM=dumb, which yields empty strings, and is unaffected by whether
# stdout is a tty or a pipe.)
#
# A role is a semantic slot, not a colour. c_flag and c_warn are both
# yellow but stay separate, as do c_ok and c_accent (both green) --
# merging either pair would foreclose ever restyling one without the
# other. c_accent is the command name in logs and smart_exit, which
# style it green where the rest of the config styles it bold.
#
# ARGUMENTS
# none
#
# EXIT STATUS
# 0 always
#
# EXAMPLE
# function mytool
# __fish_palette
# echo "$c_head""Usage:$c_reset $c_cmd""mytool$c_reset"
# end
#
# NOTES
# Calling this at top level (outside any function) creates GLOBAL
# variables. Every consumer calls it from inside a function, where the
# variables stay function-local and do not leak.
#
# functions/fish_prompt.fish deliberately does NOT use this palette. Its
# c_* values are Catppuccin hex strings passed as ARGUMENTS to set_color
# (`set_color --bold $c_green`), not captured escape sequences -- colour
# inputs rather than rendered output, a different concern.
function __fish_palette --no-scope-shadowing --description 'Define the shared output colour palette in the caller scope'
set c_reset (set_color normal)
set c_head (set_color --bold cyan)
set c_cmd (set_color --bold)
set c_arg (set_color cyan)
set c_flag (set_color yellow)
set c_warn (set_color yellow)
set c_err (set_color red)
set c_ok (set_color green)
set c_accent (set_color green)
set c_dim (set_color brblack)
set c_sel (set_color --bold magenta)
set c_hi (set_color --bold white)
end
+2 -1
View File
@@ -31,7 +31,8 @@
# EXAMPLE
# _agents_init_ensure_gitignore /home/user/myproject "agents-init" "AGENTS/" "/AGENTS.md"
function _agents_init_ensure_gitignore
__fish_palette
set -l c_ok (set_color green)
set -l c_reset (set_color normal)
if test (count $argv) -lt 3
echo (set_color red)"_agents_init_ensure_gitignore: requires <root> <label> <pattern>..."(set_color normal) >&2
+8 -1
View File
@@ -85,7 +85,14 @@
# agents-init --plugins
# agents-init --quiet
function agents-init --description 'scaffold AGENTS/ sub-repo with agent spec files and plugin dirs'
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_ok (set_color green)
set -l c_warn (set_color yellow)
set -l c_dim (set_color brblack)
set -l c_err (set_color red)
set -l c_reset (set_color normal)
argparse h/help a/agents p/plugins v/verbose q/quiet s/silent -- $argv
or return 1
+8 -1
View File
@@ -186,7 +186,14 @@
# throwaway directory and leave a dangling symlink behind, which is
# strictly worse than having had no backup at all.
function agents-vault --description 'track curated agent memory in a host-scoped vault repo'
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_ok (set_color green)
set -l c_warn (set_color yellow)
set -l c_err (set_color red)
set -l c_dim (set_color brblack)
set -l c_reset (set_color normal)
argparse h/help link push restore status 'adopt=' 'remote=' \
v/verbose q/quiet s/silent -- $argv
+8 -1
View File
@@ -42,7 +42,14 @@
# auto-pull list
# auto-pull remove qmk_firmware
function auto-pull --description 'Manage the auto-pull repository registry'
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_ok (set_color green)
set -l c_warn (set_color yellow)
set -l c_err (set_color red)
set -l c_dim (set_color brblack)
set -l c_reset (set_color normal)
set -q __fish_config_dir; or set -l __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"
+2
View File
@@ -23,6 +23,8 @@
# bd-pull myuser/myproject
# bd-pull rootiest/fish-config
function bd-pull --description 'Pull new Gitea issues into local Beads and link them'
__fish_help_header (status current-function) $argv; and return 0
if not set -q argv[1]; echo "Need repo owner/name"; return 1; end
if not set -q GITEA_TOKEN; echo "\$GITEA_TOKEN not set"; return 1; end
+6 -1
View File
@@ -23,9 +23,14 @@
# EXAMPLE
# bkg firefox
function bkg --description 'Execute bkg'
__fish_help_header (status current-function) $argv; and return 0
# Check if a command was provided as an argument.
if test -z "$argv[1]"
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_arg (set_color cyan)
set -l c_reset (set_color normal)
echo "$c_head""Usage:$c_reset $c_cmd""bkg$c_reset $c_arg""<command> [arguments...]$c_reset"
return 1
end
+2
View File
@@ -21,6 +21,8 @@
# EXAMPLE
# branch feature/new-ui
function branch --description 'Switch to or create a git branch'
__fish_help_header (status current-function) $argv; and return 0
if not git rev-parse --is-inside-work-tree >/dev/null 2>&1
echo "Not a git repo."
return 1
+2
View File
@@ -14,5 +14,7 @@
# EXAMPLE
# check_fish_deps
function check_fish_deps --description 'Check all fish-related dependencies'
__fish_help_header (status current-function) $argv; and return 0
fish-deps status
end
+2
View File
@@ -15,5 +15,7 @@
# EXAMPLE
# claude-docs
function claude-docs --description 'Claude-code: Sync README with recent changes'
__fish_help_header (status current-function) $argv; and return 0
claude "Analyze the recent changes and update the README.md to ensure all features, setup instructions, and examples are 100% accurate. Prune any obsolete information."
end
+2
View File
@@ -15,5 +15,7 @@
# EXAMPLE
# claude-pr
function claude-pr --description 'Claude-code: New branch, commit, push, and PR'
__fish_help_header (status current-function) $argv; and return 0
claude "Act as a senior engineer. Execute this sequence: 1. Create a new git branch (kebab-case). 2. Stage changes and write a Conventional Commit message. 3. Self-verify the changes by running relevant build/test commands or linting. 4. Push to remote. 5. Create a PR to 'main' including a summary of changes and a 'Manual Verification' section containing a Markdown checklist (- [ ]) of specific, bite-sized steps required to manually verify the functionality."
end
+2
View File
@@ -14,6 +14,8 @@
# EXAMPLE
# cleanup
function cleanup --description 'Log orphans to ~/.removed_orphans and remove them'
__fish_help_header (status current-function) $argv; and return 0
set -l orphans (pacman -Qtdq)
if test -n "$orphans"
echo "📝 Logging orphans to ~/.removed_orphans..."
+6 -1
View File
@@ -69,7 +69,12 @@
# EXAMPLE
# config-settings
function config-settings --description 'Interactive TUI for managing fish config settings'
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_dim (set_color brblack)
set -l c_err (set_color red)
set -l c_reset (set_color normal)
# ── Argument parsing ──────────────────────────────────
for arg in $argv
+8 -1
View File
@@ -27,7 +27,14 @@
# config-update --dry-run
# config-update --force
function config-update --description 'Pull latest fish config from upstream'
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_ok (set_color green)
set -l c_warn (set_color yellow)
set -l c_err (set_color red)
set -l c_dim (set_color brblack)
set -l c_reset (set_color normal)
set -l REMOTE_URL https://git.rootiest.dev/rootiest/fish-config.git
set -l CONFIG_DIR ~/.config/fish
+5 -1
View File
@@ -25,7 +25,11 @@
# EXAMPLE
# detach rsync -a ./data remote:/backup/
function detach --description 'Execute detach'
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_arg (set_color cyan)
set -l c_reset (set_color normal)
set -l show_help 0
set -l args
+5 -1
View File
@@ -38,7 +38,11 @@ function dng2avif --description 'Convert DNG raw to 10-bit HDR AVIF'
# Help Screen
if set -q _flag_help; or test (count $argv) -eq 0 -a -z "$_flag_input"
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_dim (set_color brblack)
set -l c_reset (set_color normal)
echo "$c_head""Usage:$c_reset $c_cmd""dng2avif$c_reset $c_flag""[options]$c_reset $c_dim""[input.dng]$c_reset"
echo ""
echo "$c_head""Options:$c_reset"
+5 -1
View File
@@ -30,7 +30,11 @@ function dockup --description 'Pull and restart docker compose containers'
# Handle help flags
if contains -- -h $argv; or contains -- --help $argv
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_dim (set_color brblack)
set -l c_reset (set_color normal)
echo "$c_head""Usage:$c_reset $c_cmd""dockup$c_reset $c_dim""[DIRECTORY]$c_reset"
echo ""
echo "$c_head""Options:$c_reset"
+6 -1
View File
@@ -45,7 +45,12 @@
# edit --editor=code --clipboard
# edit --text="hello world"
function edit --description 'Open files in a terminal or GUI editor with fallbacks'
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_err (set_color red)
set -l c_dim (set_color brblack)
set -l c_reset (set_color normal)
# Opinionated guard (C1): fall back to the legacy bare-editor behavior.
if not __fish_config_op_enabled (status current-function)
+2
View File
@@ -36,6 +36,8 @@
# EXAMPLE
# fast
function fast --description 'Placeholder for future fast utility'
__fish_help_header (status current-function) $argv; and return 0
# ANSI Escape Codes (Standard 16-color palette)
set -l bold "\e[1m"
set -l italic "\e[3m"
+2
View File
@@ -24,6 +24,8 @@
# fc
# fc git
function fc --description 'Edit and execute the last command (Bash-style fc)'
__fish_help_header (status current-function) $argv; and return 0
set -l tmpfile (mktemp /tmp/fish_fc.XXXXXX).fish
if count $argv >/dev/null
+12 -1
View File
@@ -66,6 +66,13 @@ function fish-deps --description 'Manage fish shell dependencies'
_fish_deps_status
case install
_fish_deps_install $flags
case -h --help
# Reuse the existing menu rather than the header renderer: it
# is richer, and it is already the text the unknown-subcommand
# path prints. Previously --help fell into `case '*'` and
# exited 1 with "Unknown subcommand: --help".
__fish_deps_help
return 0
case update
_fish_deps_update
case sync
@@ -93,7 +100,11 @@ end
# EXAMPLE
# __fish_deps_help
function __fish_deps_help
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_dim (set_color brblack)
set -l c_reset (set_color normal)
echo "$c_head""fish-deps$c_reset — manage fish shell dependencies"
echo ""
+2
View File
@@ -14,6 +14,8 @@
# EXAMPLE
# fzf-update
function fzf-update --description 'Install or upgrade fzf from git HEAD'
__fish_help_header (status current-function) $argv; and return 0
if test -d ~/.fzf
echo "Updating fzf..."
git -C ~/.fzf pull --ff-only
+2
View File
@@ -14,6 +14,8 @@
# EXAMPLE
# gip
function gip --description 'Show all public IP addresses'
__fish_help_header (status current-function) $argv; and return 0
echo -n "IPv4: "
curl -4 -s --max-time 2 https://icanhazip.com || echo "Not detected"
echo -n "IPv6: "
+2
View File
@@ -13,5 +13,7 @@
# EXAMPLE
# gip4
function gip4 --wraps='curl' --description 'Get public IPv4 address'
__fish_help_header (status current-function) $argv; and return 0
curl -4 -s https://icanhazip.com
end
+2
View File
@@ -21,6 +21,8 @@
# EXAMPLE
# gip6
function gip6 --description 'Get public IPv6 address'
__fish_help_header (status current-function) $argv; and return 0
# Use -6 to force IPv6 and --fail to catch network errors
set -l ip (curl -6 -s --fail https://icanhazip.com 2>/dev/null)
+4 -1
View File
@@ -17,9 +17,12 @@
# EXAMPLE
# hist
function hist --description 'Search fish history and put it in the prompt'
__fish_help_header (status current-function) $argv; and return 0
# Opinionated guard (C4): integrations disabled
if not __fish_config_op_enabled (status current-function)
__fish_palette
set -l c_err (set_color red)
set -l c_reset (set_color normal)
echo "$c_err"'hist: disabled by __fish_config_op_integrations'"$c_reset" >&2
return 1
end
+8 -1
View File
@@ -51,7 +51,14 @@
# redirections must be wrapped explicitly, e.g.
# jobrunner run sync fish -c 'a | b'.
function jobrunner --description 'Manage detached background jobs with tmux or GNU screen'
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_arg (set_color cyan)
set -l c_flag (set_color yellow)
set -l c_ok (set_color green)
set -l c_err (set_color red)
set -l c_dim (set_color brblack)
set -l c_reset (set_color normal)
set -l subcmds run list attach kill logs help \
-r --run -l --list -a --attach -k --kill -o --output -h --help
+8 -1
View File
@@ -38,7 +38,14 @@
# kitty-logging install
# kitty-logging status
function kitty-logging --description 'Install/manage the fish-config Kitty scrollback watcher'
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_ok (set_color green)
set -l c_warn (set_color yellow)
set -l c_err (set_color red)
set -l c_dim (set_color brblack)
set -l c_reset (set_color normal)
set -l cmd $argv[1]
+2
View File
@@ -17,6 +17,8 @@
# EXAMPLE
# lD ~/projects
function lD --description 'List directories only'
__fish_help_header (status current-function) $argv; and return 0
if which eza >/dev/null 2>&1
eza --only-dirs --long --icons --color=auto --hyperlink $argv
else if which lsd >/dev/null 2>&1
+2
View File
@@ -17,6 +17,8 @@
# EXAMPLE
# ld
function ld --description 'Run lazydocker on the current Docker context'
__fish_help_header (status current-function) $argv; and return 0
if not type -q docker
echo "ld: docker is not installed" >&2
return 1
+2
View File
@@ -16,6 +16,8 @@
# EXAMPLE
# limine-edit
function limine-edit --description 'Safely edit and re-verify Limine configuration'
__fish_help_header (status current-function) $argv; and return 0
# 1. Open the config with sudoedit
sudoedit /boot/limine.conf
+2
View File
@@ -13,5 +13,7 @@
# EXAMPLE
# lock
function lock --wraps='loginctl' --description 'alias lock=loginctl'
__fish_help_header (status current-function) $argv; and return 0
loginctl lock-session
end
+13 -9
View File
@@ -39,7 +39,8 @@
function logs --description 'Browse terminal log files interactively with fzf'
# Opinionated guard (C4): integrations disabled
if not __fish_config_op_enabled (status current-function)
__fish_palette
set -l c_err (set_color red)
set -l c_reset (set_color normal)
echo "$c_err"'logs: disabled by __fish_config_op_integrations'"$c_reset" >&2
return 1
end
@@ -49,21 +50,24 @@ function logs --description 'Browse terminal log files interactively with fzf'
or return 1
if set -q _flag_help
__fish_palette
echo "Usage: "$c_accent"logs"$c_reset" ["$c_arg"OPTIONS"$c_reset"]"
set -l c_accent (set_color green)
set -l c_primary (set_color cyan)
set -l c_bold (set_color --bold)
set -l c_reset (set_color normal)
echo "Usage: "$c_accent"logs"$c_reset" ["$c_primary"OPTIONS"$c_reset"]"
echo ""
echo "Browse and open terminal log files interactively."
echo "Logs sorted newest-first. Type to fuzzy-filter by date or category."
echo ""
echo "Options:"
echo " "$c_arg"-h, --help"$c_reset" Show this help"
echo " "$c_arg"-c, --category"$c_reset" Limit to one category: scrollback, paru, yay"
echo " "$c_primary"-h, --help"$c_reset" Show this help"
echo " "$c_primary"-c, --category"$c_reset" Limit to one category: scrollback, paru, yay"
echo ""
echo "Keys in fzf:"
echo " "$c_arg"Enter"$c_reset" Open in \$PAGER"
echo " "$c_arg"Ctrl-E"$c_reset" Open in \$EDITOR"
echo " "$c_arg"Ctrl-D"$c_reset" Delete selected log"
echo " "$c_arg"Ctrl-C"$c_reset" Quit"
echo " "$c_primary"Enter"$c_reset" Open in \$PAGER"
echo " "$c_primary"Ctrl-E"$c_reset" Open in \$EDITOR"
echo " "$c_primary"Ctrl-D"$c_reset" Delete selected log"
echo " "$c_primary"Ctrl-C"$c_reset" Quit"
return 0
end
+2
View File
@@ -17,6 +17,8 @@
# EXAMPLE
# lsr ~/projects
function lsr --description 'Reversed time-sorted listing'
__fish_help_header (status current-function) $argv; and return 0
if which eza >/dev/null 2>&1
eza --oneline --sort=modified --reverse --icons --color=auto --hyperlink $argv
else if which lsd >/dev/null 2>&1
+2
View File
@@ -17,6 +17,8 @@
# EXAMPLE
# lss ~/downloads
function lss --description 'Size-sorted listing'
__fish_help_header (status current-function) $argv; and return 0
if which eza >/dev/null 2>&1
eza --oneline --long --all --sort=size --icons --color=auto --hyperlink --color-scale=size --color-scale-mode=gradient $argv
else if which lsd >/dev/null 2>&1
+2
View File
@@ -17,6 +17,8 @@
# EXAMPLE
# lstree ~/projects/myapp
function lstree --description 'Full recursive tree listing'
__fish_help_header (status current-function) $argv; and return 0
if which eza >/dev/null 2>&1
eza --tree --icons --color=auto --hyperlink=auto $argv
else if which lsd >/dev/null 2>&1
+2
View File
@@ -17,6 +17,8 @@
# EXAMPLE
# lt ~/projects
function lt --description 'Tree listing, depth 2'
__fish_help_header (status current-function) $argv; and return 0
if which eza >/dev/null 2>&1
eza --tree --level=2 --icons --color=auto --hyperlink $argv
else if which lsd >/dev/null 2>&1
+2
View File
@@ -18,6 +18,8 @@
# EXAMPLE
# ltr ~/projects
function ltr --description 'Reversed time-sorted listing'
__fish_help_header (status current-function) $argv; and return 0
if which eza >/dev/null 2>&1
eza --long --all --sort=modified --icons --hyperlink --color=auto --color-scale=age --color-scale-mode=gradient $argv
else if which lsd >/dev/null 2>&1
+2
View File
@@ -17,6 +17,8 @@
# EXAMPLE
# lx ~/projects
function lx --description 'Extension-sorted listing'
__fish_help_header (status current-function) $argv; and return 0
if which eza >/dev/null 2>&1
eza --long --all --sort=extension --icons --color=auto --hyperlink $argv
else if which lsd >/dev/null 2>&1
+21 -13
View File
@@ -26,23 +26,31 @@
# mkcd ~/projects/myapp
# mkcd ~/projects/newapp/src
function mkcd --description 'Create a directory (with parents) and cd into it'
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_arg (set_color cyan)
set -l c_flag (set_color yellow)
set -l c_ok (set_color green)
set -l c_warn (set_color yellow)
set -l c_err (set_color red)
set -l c_dim (set_color brblack)
set -l c_rst (set_color normal)
if contains -- -h $argv; or contains -- --help $argv; or test (count $argv) -eq 0
echo "$c_head""Usage:$c_reset $c_cmd""mkcd$c_reset $c_arg""<dir>$c_reset"
echo "$c_head""Usage:$c_rst $c_cmd""mkcd$c_rst $c_arg""<dir>$c_rst"
echo
echo " Create $c_arg""<dir>$c_reset (including missing parents) and cd into it."
echo " Create $c_arg""<dir>$c_rst (including missing parents) and cd into it."
echo
echo "$c_head""Arguments:$c_reset"
echo " $c_arg""<dir>$c_reset Directory to create and enter"
echo "$c_head""Arguments:$c_rst"
echo " $c_arg""<dir>$c_rst Directory to create and enter"
echo
echo "$c_head""Flags:$c_reset"
echo " $c_flag-h$c_reset, $c_flag--help$c_reset Show this help message"
echo " $c_flag-s$c_reset, $c_flag--silent$c_reset Suppress directory creation output"
echo "$c_head""Flags:$c_rst"
echo " $c_flag-h$c_rst, $c_flag--help$c_rst Show this help message"
echo " $c_flag-s$c_rst, $c_flag--silent$c_rst Suppress directory creation output"
echo
echo "$c_head""Examples:$c_reset"
echo " $c_cmd""mkcd$c_reset $c_arg~/projects/myapp$c_reset"
echo " $c_cmd""mkcd$c_reset $c_arg~/projects/myapp$c_reset""$c_dim""; git init$c_reset"
echo "$c_head""Examples:$c_rst"
echo " $c_cmd""mkcd$c_rst $c_arg~/projects/myapp$c_rst"
echo " $c_cmd""mkcd$c_rst $c_arg~/projects/myapp$c_rst""$c_dim""; git init$c_rst"
return 0
end
@@ -69,8 +77,8 @@ function mkcd --description 'Create a directory (with parents) and cd into it'
or return $status
if test $is_new -eq 1
echo "$c_ok""$c_reset Created and entered $c_arg$dir$c_reset"
echo "$c_ok""$c_rst Created and entered $c_arg$dir$c_rst"
else
echo "$c_warn""$c_reset $c_arg$dir$c_reset already exists — entered"
echo "$c_warn""$c_rst $c_arg$dir$c_rst already exists — entered"
end
end
+5 -1
View File
@@ -41,7 +41,11 @@
# NOTES
# Typo abbreviation: url-open (expands to open-url on space/enter).
function open-url --description 'Open a URL in the best available web browser'
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_arg (set_color cyan)
set -l c_reset (set_color normal)
argparse h/help s/silent v/verbose -- $argv
or return 1
+5 -1
View File
@@ -28,7 +28,11 @@
function p --description 'Put from clipboard'
# Check for help flag
if contains -- -h $argv; or contains -- --help $argv
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_dim (set_color brblack)
set -l c_reset (set_color normal)
echo "$c_head""Usage:$c_reset $c_cmd""p$c_reset $c_flag""[OPTIONS]$c_reset"
echo ""
echo " Pastes content from the system clipboard to stdout."
+2
View File
@@ -19,6 +19,8 @@
# EXAMPLE
# parur
function parur --description 'Interactively search and remove an installed package using fzf'
__fish_help_header (status current-function) $argv; and return 0
set -l aur ""
if type -q paru
set aur paru
+8 -1
View File
@@ -46,7 +46,14 @@ function pkg --description 'Install or remove packages via the system package ma
end
# ── Colour palette ───────────────────────────────────────────
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_ok (set_color green)
set -l c_warn (set_color yellow)
set -l c_err (set_color red)
set -l c_dim (set_color brblack)
set -l c_reset (set_color normal)
# ── Installed-check helper ───────────────────────────────────
# Uses only its own arguments — safe to define as an inner function.
+5 -1
View File
@@ -36,7 +36,11 @@
# play-media
# play-media --player mpv
function play-media --description 'Pick audio/video files with fzf and play them'
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_dim (set_color brblack)
set -l c_reset (set_color normal)
argparse h/help p/player= -- $argv
or return 1
+2
View File
@@ -21,6 +21,8 @@
# EXAMPLE
# poke ~/projects/new/src/main.fish
function poke --description 'touch with automatic parent directory creation'
__fish_help_header (status current-function) $argv; and return 0
if test (count $argv) -eq 0
echo (set_color red)"poke: no file specified"(set_color normal) >&2
return 1
+2
View File
@@ -14,5 +14,7 @@
# EXAMPLE
# ports
function ports --wraps='sudo' --description 'Show active network listeners'
__fish_help_header (status current-function) $argv; and return 0
sudo lsof -iTCP -sTCP:LISTEN -P -n
end
+14 -9
View File
@@ -32,21 +32,26 @@
if type -q aichat
function qc --wraps aichat --description 'Quick-chat wrapper around aichat (cli role)'
if contains -- -h $argv; or contains -- --help $argv
__fish_palette
set -l c_ttl (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_txt (set_color normal)
set -l c_dim (set_color brblack)
set -l c_rst (set_color normal)
set -l w 59
set -l bar (string repeat -n $w)
# Title line, padded to the box width (plain form drives the math).
set -l title " qc — quick-chat: a thin aichat wrapper"
set -l pad (string repeat -n (math $w - (string length -- $title)) ' ')
echo "$c_dim$bar$c_reset"
echo "$c_dim$c_reset $c_head""qc$c_reset $c_dim$c_reset quick-chat: a thin $c_cmd""aichat$c_reset wrapper$pad$c_dim$c_reset"
echo "$c_dim$bar$c_reset"
echo " Defaults to the $c_flag'cli'$c_reset role — an AI system prompt tuned"
echo " for concise, $c_reset""terminal-friendly$c_reset output."
echo "$c_dim$bar$c_rst"
echo "$c_dim$c_rst $c_ttl""qc$c_rst $c_dim$c_rst quick-chat: a thin $c_cmd""aichat$c_rst wrapper$pad$c_dim$c_rst"
echo "$c_dim$bar$c_rst"
echo " Defaults to the $c_flag'cli'$c_rst role — an AI system prompt tuned"
echo " for concise, $c_txt""terminal-friendly$c_rst output."
echo
echo " Accepts every $c_cmd""aichat$c_reset flag; passing $c_flag--role$c_reset/$c_flag-r$c_reset overrides"
echo " the default role. $c_cmd""aichat$c_reset's own help follows:"
echo "$c_dim$bar$c_reset"
echo " Accepts every $c_cmd""aichat$c_rst flag; passing $c_flag--role$c_rst/$c_flag-r$c_rst overrides"
echo " the default role. $c_cmd""aichat$c_rst's own help follows:"
echo "$c_dim$bar$c_rst"
aichat --help | string replace -a aichat qc
return 0
end
+2
View File
@@ -19,6 +19,8 @@
# qr "https://example.com"
# echo "hello" | qr
function qr --description 'Generate a QR code from text or pipe'
__fish_help_header (status current-function) $argv; and return 0
if type -q qrencode
if set -q argv[1]
echo $argv | qrencode -t utf8
+18 -14
View File
@@ -38,27 +38,31 @@
# Falls back to random choice if GNU shuf is missing, but shuf is
# much faster for files with >1000 lines.
function rand_string --description 'Generate random, memorable strings from curated word databases'
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_arg (set_color cyan)
set -l c_flag (set_color yellow)
set -l c_rst (set_color normal)
if set -q argv[1]; and contains -- $argv[1] -h --help
echo "$c_head""Usage:$c_reset $c_cmd""rand_string$c_reset $c_arg""[COMPONENTS/MODIFIERS]...$c_reset"
echo "$c_head""Usage:$c_rst $c_cmd""rand_string$c_rst $c_arg""[COMPONENTS/MODIFIERS]...$c_rst"
echo
echo " Generate random, memorable strings from curated word databases."
echo
echo "$c_head""Components:$c_reset"
echo " $c_arg<category>$c_reset A bundled word list (e.g. adjective, animal, color, name, noun, verb)"
echo " $c_arg""digits=<N>$c_reset N random digits (e.g. digits=3 -> 842)"
echo " $c_arg""literal=<text>$c_reset A static string component for prefixes/suffixes (e.g. literal=TEST)"
echo "$c_head""Components:$c_rst"
echo " $c_arg<category>$c_rst A bundled word list (e.g. adjective, animal, color, name, noun, verb)"
echo " $c_arg""digits=<N>$c_rst N random digits (e.g. digits=3 -> 842)"
echo " $c_arg""literal=<text>$c_rst A static string component for prefixes/suffixes (e.g. literal=TEST)"
echo
echo "$c_head""Modifiers:$c_reset"
echo " $c_flag-s$c_reset, $c_flag--separator=<sep>$c_reset Delimiter for subsequent words (dash, underscore, dot, none)"
echo " $c_flag-c$c_reset, $c_flag--case=<casing>$c_reset Casing for subsequent words (lower, upper, title)"
echo " $c_flag-h$c_reset, $c_flag--help$c_reset Show usage help"
echo "$c_head""Modifiers:$c_rst"
echo " $c_flag-s$c_rst, $c_flag--separator=<sep>$c_rst Delimiter for subsequent words (dash, underscore, dot, none)"
echo " $c_flag-c$c_rst, $c_flag--case=<casing>$c_rst Casing for subsequent words (lower, upper, title)"
echo " $c_flag-h$c_rst, $c_flag--help$c_rst Show usage help"
echo
echo "$c_head""Examples:$c_reset"
echo " $c_cmd""rand_string$c_reset adjective animal"
echo " $c_cmd""rand_string$c_reset --case=title color animal --separator=dot digits=4"
echo " $c_cmd""rand_string$c_reset literal=TEST --separator=underscore verb noun"
echo "$c_head""Examples:$c_rst"
echo " $c_cmd""rand_string$c_rst adjective animal"
echo " $c_cmd""rand_string$c_rst --case=title color animal --separator=dot digits=4"
echo " $c_cmd""rand_string$c_rst literal=TEST --separator=underscore verb noun"
return 0
end
+5 -1
View File
@@ -27,7 +27,11 @@ function replay --description 'Run Bash commands replaying changes in Fish'
case -v --version
echo "replay, version 1.2.1"
case "" -h --help
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_arg (set_color cyan)
set -l c_reset (set_color normal)
echo "$c_head""Usage:$c_reset $c_cmd""replay$c_reset $c_arg""<commands>$c_reset Run Bash commands replaying changes in Fish"
echo "$c_head""Options:$c_reset"
echo " $c_flag-v$c_reset or $c_flag--version$c_reset Print version"
+4 -1
View File
@@ -52,7 +52,10 @@
# NOTES
# Typo abbreviation: open-repo (expands to repo-open on space/enter).
function repo-open --description 'Open the origin remote of the current repo in a browser'
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_reset (set_color normal)
argparse -X 0 h/help p/print r/root -- $argv
or return 1
+2
View File
@@ -24,6 +24,8 @@
# sbver
# sbver --brief
function sbver --description 'Verifies Secure Boot status of EFI binaries using sbctl'
__fish_help_header (status current-function) $argv; and return 0
if not type -q sbctl
echo "Error: 'sbctl' is not installed."
return 1
+2
View File
@@ -14,6 +14,8 @@
# EXAMPLE
# screensleep
function screensleep --description 'Turn off the display using KDE PowerDevil'
__fish_help_header (status current-function) $argv; and return 0
# Optional: 1-second delay to ensure no keystrokes wake it immediately
sleep 1
busctl --user call \
+4 -1
View File
@@ -63,7 +63,10 @@ function scrub --description 'Recursively purge OS, editor, and compiler garbage
# Helper function for help menu text
function _scrub_help
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_reset (set_color normal)
echo "$c_head""Usage:$c_reset $c_cmd""scrub$c_reset $c_flag""[options]$c_reset"
echo
+9 -5
View File
@@ -44,16 +44,20 @@ function smart_exit --description 'Capture colorized scrollback before exiting,
argparse $options -- $argv
or return 1
__fish_palette
set -l c_primary (set_color cyan)
set -l c_accent (set_color green)
set -l c_warn (set_color yellow)
set -l c_bold (set_color --bold)
set -l c_reset (set_color normal)
if set -q _flag_help
echo -e "Usage: $c_accent"exit"$c_reset [$c_arg""OPTIONS""$c_reset]"
echo -e "Usage: $c_accent"exit"$c_reset [$c_primary""OPTIONS""$c_reset]"
echo ""
echo "Closes the current shell session, automatically archiving the window scrollback."
echo ""
echo "Options:"
echo -e " $c_arg""-h, --help""$c_reset Show this help message"
echo -e " $c_arg""-n, --no-log""$c_reset Exit immediately $c_cmd""without""$c_reset saving a scrollback history log"
echo -e " $c_primary""-h, --help""$c_reset Show this help message"
echo -e " $c_primary""-n, --no-log""$c_reset Exit immediately $c_bold""without""$c_reset saving a scrollback history log"
return 0
end
@@ -108,7 +112,7 @@ function smart_exit --description 'Capture colorized scrollback before exiting,
end
end
else
echo -e "$c_warn""➔""$c_reset Exiting discreetly; $c_cmd""no history logs saved.""$c_reset"
echo -e "$c_warn""➔""$c_reset Exiting discreetly; $c_bold""no history logs saved.""$c_reset"
sleep 0.4
end
+5 -1
View File
@@ -29,7 +29,11 @@ function spark --description 'Sparklines'
if set --query _flag_version[1]
echo "spark, version 1.1.0"
else if set --query _flag_help[1]
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_flag (set_color yellow)
set -l c_arg (set_color cyan)
set -l c_reset (set_color normal)
echo "$c_head""Usage:$c_reset $c_cmd""spark$c_reset $c_arg""<numbers ...>$c_reset"
echo " stdin | $c_cmd""spark$c_reset"
echo "$c_head""Options:$c_reset"
+6 -1
View File
@@ -29,9 +29,14 @@
# split
# split -v nvim README.md
function split --description 'Run a command in a new terminal split'
# -h is --horizontal here (see this function's own ARGUMENTS),
# so only the long form may reach the renderer.
test "$argv[1]" = --help; and __fish_help_header (status current-function) --help; and return 0
# Opinionated guard (C4): integrations disabled
if not __fish_config_op_enabled (status current-function)
__fish_palette
set -l c_err (set_color red)
set -l c_reset (set_color normal)
echo "$c_err"'split: disabled by __fish_config_op_integrations'"$c_reset" >&2
return 1
end
+4 -1
View File
@@ -24,9 +24,12 @@
# EXAMPLE
# spwin
function spwin --wraps='~/.config/kitty/spawn-window.sh' --description 'spawn window in kitty or wezterm'
__fish_help_header (status current-function) $argv; and return 0
# Opinionated guard (C4): integrations disabled
if not __fish_config_op_enabled (status current-function)
__fish_palette
set -l c_err (set_color red)
set -l c_reset (set_color normal)
echo "$c_err"'spwin: disabled by __fish_config_op_integrations'"$c_reset" >&2
return 1
end
+2
View File
@@ -14,6 +14,8 @@
# EXAMPLE
# steam-dl
function steam-dl --description 'Run Steam while inhibiting system sleep'
__fish_help_header (status current-function) $argv; and return 0
echo "Inhibiting sleep while Steam downloads..."
systemd-inhibit --why="Active Download" --who="User" --what=idle:sleep steam
end
+2
View File
@@ -19,6 +19,8 @@
# EXAMPLE
# sudo-toggle
function sudo-toggle --description 'Toggle sudo password requirement on/off'
__fish_help_header (status current-function) $argv; and return 0
# Check the file size using sudo stat to see if our bypass rule is active
set -l file_size (sudo stat -c %s /etc/sudoers.d/nofail-toggle 2>/dev/null)
+2
View File
@@ -15,6 +15,8 @@
# EXAMPLE
# swapstat
function swapstat --description 'View colorized zRAM and swappiness status'
__fish_help_header (status current-function) $argv; and return 0
set -l swappiness (sysctl -n vm.swappiness)
set -l zdata (zramctl --bytes --noheadings --output DATA,TOTAL /dev/zram0 2>/dev/null)
+4 -1
View File
@@ -25,9 +25,12 @@
# EXAMPLE
# tab
function tab --description 'Spawn a new tab in the current terminal'
__fish_help_header (status current-function) $argv; and return 0
# Opinionated guard (C4): integrations disabled
if not __fish_config_op_enabled (status current-function)
__fish_palette
set -l c_err (set_color red)
set -l c_reset (set_color normal)
echo "$c_err"'tab: disabled by __fish_config_op_integrations'"$c_reset" >&2
return 1
end
+2
View File
@@ -14,6 +14,8 @@
# EXAMPLE
# tmux-clean
function tmux-clean --description 'Kill all tmux sessions except the current one'
__fish_help_header (status current-function) $argv; and return 0
# Get a list of all session names that are NOT currently attached
set sessions (tmux list-sessions -F '#{session_name} #{session_attached}' | string match -rv ' 1$' | string split -f1 ' ')
+4 -1
View File
@@ -21,9 +21,12 @@
# EXAMPLE
# upgrade
function upgrade --description 'Full system upgrade via paru or yay'
__fish_help_header (status current-function) $argv; and return 0
# Opinionated guard (C4): integrations disabled
if not __fish_config_op_enabled (status current-function)
__fish_palette
set -l c_err (set_color red)
set -l c_reset (set_color normal)
echo "$c_err"'upgrade: disabled by __fish_config_op_integrations'"$c_reset" >&2
return 1
end
+6 -1
View File
@@ -22,8 +22,13 @@
# EXAMPLE
# wake-lock rsync -avz src/ dest/
function wake-lock --description 'Run a command while inhibiting system sleep'
__fish_help_header (status current-function) $argv; and return 0
if test (count $argv) -eq 0
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_arg (set_color cyan)
set -l c_reset (set_color normal)
echo "$c_head""Usage:$c_reset $c_cmd""wake-lock$c_reset $c_arg""[command] [args...]$c_reset"
return 1
end
+5 -1
View File
@@ -25,7 +25,11 @@
function y --description 'Yank to clipboard'
# Check for help flag
if contains -- -h $argv; or contains -- --help $argv
__fish_palette
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold)
set -l c_arg (set_color cyan)
set -l c_dim (set_color brblack)
set -l c_reset (set_color normal)
echo "$c_head""Usage:$c_reset $c_cmd""y$c_reset $c_arg""[TEXT]$c_reset or $c_arg""[COMMAND]$c_reset | $c_cmd""y$c_reset"
echo ""
echo "$c_head""Examples:$c_reset"
+251 -67
View File
@@ -97,78 +97,262 @@ function test_vault_dir_honors_override
test "$got" = /tmp/vault-override-check
end
function test_palette_roles_defined
functions -q __fish_palette
or begin
echo " __fish_palette is not defined"
return 1
end
# Called from inside a function, the palette must land in THIS scope.
__fish_palette
set -l missing
for role in c_reset c_head c_cmd c_arg c_flag c_warn c_err c_ok \
c_accent c_dim c_sel c_hi
if not set -q $role; or test -z "$$role"
set -a missing $role
end
end
if test (count $missing) -gt 0
echo " palette roles empty or unset: $missing"
return 1
end
# Nothing may leak to global scope.
if set -q -g c_reset
echo " __fish_palette leaked c_reset into global scope"
return 1
end
return 0
# ── Header-driven --help ─────────────────────────────────────────────
# Helper: run `<fn> $argv` in a throwaway fish that can see both $dir and
# the loaded session's function path, so a fixture function can call the
# real __fish_help_header. Paths here are mktemp -d output, never spaced.
function _help_probe --argument-names dir
env TERM=dumb fish --no-config -c \
"set -g fish_function_path $dir $fish_function_path; $argv[2..]"
end
# Every user-facing function that renders a coloured --help must still emit
# escape sequences.
#
# This is deliberately a RUNTIME check, never a static grep for
# __fish_palette. Measured on a deliberately broken functions/logs.fish --
# the palette call de-duplicated per indentation depth instead of per
# contiguous run, so the --help block lost its declarations without gaining
# a call:
#
# fish tests/palette-bytes.fish
# FAIL logs --help stdout=DIFF stderr=ok
# baseline 431 B -> broken 150 B (every escape stripped)
#
# fish -n functions/logs.fish -> exit 0 (lint PASSES)
# grep -c '__fish_palette' logs.fish -> 1 (grep PASSES)
#
# Both cheap checks are green on a file whose help output has lost all of
# its colour. Only running the function and looking for an \e byte catches
# it. The full test suite was also green throughout.
#
# functions/fish_prompt.fish is excluded BY NAME. It interpolates $c_dim
# from its own Catppuccin hex palette -- those are colour arguments passed
# to set_color, not captured escapes -- so it legitimately never calls
# __fish_palette and would otherwise look unconverted forever.
#
# qc is absent from the list on purpose: its --help shells out to aichat,
# which is not installed in CI, so its colour path is unreachable here.
# tests/palette-bytes.fish stubs aichat and does cover it.
function test_functions_keep_their_palette
set -l colored agents-init agents-vault auto-pull config-settings \
config-update detach dng2avif dockup edit jobrunner kitty-logging \
logs mkcd open-url p pkg play-media rand_string replay repo-open \
scrub smart_exit spark y
set -l uncolored
for fn in $colored
functions -q $fn; or continue
if not $fn --help 2>&1 | string match -qr \e
set -a uncolored $fn
function test_help_renderer
set -l tmp (mktemp -d)
printf '%s\n' \
'# Copyright (C) 2026 Rootiest' \
'' \
'# CATEGORY' \
'# 99-fixture' \
'#' \
'# SYNOPSIS' \
'# fixturefn [options]' \
'#' \
'# DESCRIPTION' \
'# First paragraph.' \
'#' \
'# Second paragraph.' \
'#' \
'# ARGUMENTS' \
'# -x Do the thing' \
'# more Indented continuation' \
'#' \
'# EXAMPLE' \
'# fixturefn -x' \
'function fixturefn' \
' __fish_help_header (status current-function) $argv; and return 0' \
' echo RAN-BODY' \
'end' >$tmp/fixturefn.fish
set -l out (_help_probe $tmp 'fixturefn --help')
set -l code $status
set -l text (string join \n $out)
rm -rf $tmp
set -l failed 0
if test $code -ne 0
echo " renderer exited $code, expected 0"
set failed 1
end
if contains -- RAN-BODY $out
echo " body executed despite --help"
set failed 1
end
if not contains -- USAGE $out
echo " missing USAGE heading (SYNOPSIS should render as USAGE)"
set failed 1
end
if contains -- CATEGORY $out
echo " CATEGORY leaked into the menu"
set failed 1
end
if not string match -q '* more Indented continuation*' -- $text
echo " nested ARGUMENTS indentation lost"
set failed 1
end
# Index-based, not a glob: fish's `string match` glob `*` does not
# span newlines, so a pattern straddling two lines silently never
# matches and the assertion would pass for the wrong reason.
set -l i (contains -i -- " First paragraph." $out)
if test -z "$i"
echo " DESCRIPTION body missing entirely"
set failed 1
else
# Indices hoisted: a command substitution inside a quoted index
# ("$out[(math ...)]") is a fish parse error, not an expansion.
set -l gap (math $i + 1)
set -l nxt (math $i + 2)
if test -n "$out[$gap]"
echo " multi-paragraph DESCRIPTION lost its blank line"
set failed 1
else if test "$out[$nxt]" != " Second paragraph."
echo " second paragraph missing after the blank"
set failed 1
end
end
if test (count $uncolored) -gt 0
echo " --help lost its colour: $uncolored"
return 1
test $failed -eq 0
end
function test_help_renderer_degrades_safely
# The renderer must return 1 ONLY when argv[1] is not a help flag.
# A missing or label-less header must still print and exit 0, because
# returning 1 hands control back to the caller's body -- and the body
# of upgrade(1) is `paru -Syu --noconfirm`.
set -l tmp (mktemp -d)
printf '%s\n' \
'function headerless' \
' __fish_help_header (status current-function) $argv; and return 0' \
" touch $tmp/BODY-RAN" \
'end' >$tmp/headerless.fish
# A comment run carrying no `# LABEL` line at all.
printf '%s\n' \
'# just an ordinary comment, no labels here' \
'function malformed' \
' __fish_help_header (status current-function) $argv; and return 0' \
" touch $tmp/BODY-RAN" \
'end' >$tmp/malformed.fish
set -l failed 0
for fn in headerless malformed
set -l out (_help_probe $tmp "$fn --help")
set -l code $status
if test $code -ne 0
echo " $fn --help exited $code, expected 0"
set failed 1
end
if test (count $out) -eq 0
echo " $fn --help printed nothing"
set failed 1
end
if not contains -- $fn $out
echo " $fn --help did not name the function"
set failed 1
end
if test -e $tmp/BODY-RAN
echo " $fn executed its body despite --help"
set failed 1
rm -f $tmp/BODY-RAN
end
end
return 0
# The inverse: no help flag must return 1 and let the body run.
_help_probe $tmp headerless >/dev/null 2>&1
if not test -e $tmp/BODY-RAN
echo " body did NOT run when no help flag was passed"
set failed 1
end
rm -rf $tmp
# Explicit, never a trailing `if`: standing gotcha #5 -- an if with no
# branch taken resolves $status to 0 and the test would pass silently.
test $failed -eq 0
end
function test_help_never_executes_destructive_path
# These eight ignore $argv entirely, so before the header-driven help
# landed, `upgrade --help` ran `paru -Syu --noconfirm`. The check has
# to prove --help does NOT reach the destructive path *without* ever
# running it: every external binary the eight can reach is shadowed by
# a recording stub on PATH, and the recorder must stay empty.
#
# WARNING: a silent pass here means a MISSING STUB, not success. If a
# function shows neither an EXECUTED line nor its own help, its
# command is absent from the stub list below -- add it. A test that
# cannot fail proves nothing about a body that runs sudo pacman -Rns.
set -l root (realpath (dirname (status filename))/..)
set -l tmp (mktemp -d)
mkdir -p $tmp/bin
set -l log $tmp/invoked.log
touch $log
for b in sudo pacman paru yay loginctl busctl tmux systemd-inhibit \
sudoedit limine-enroll-config limine-mkinitcpio sbctl git fzf steam
printf '#!/bin/sh\necho "$(basename "$0") $*" >> %s\n' $log >$tmp/bin/$b
chmod +x $tmp/bin/$b
end
set -l failed 0
for fn in cleanup fzf-update limine-edit lock screensleep sudo-toggle \
tmux-clean upgrade
set -l out (env TERM=dumb PATH="$tmp/bin:$PATH" HOME=$tmp \
fish --no-config -c \
"set -g fish_function_path $root/functions $fish_function_path
$fn --help" 2>/dev/null)
set -l code $status
if test $code -ne 0
echo " $fn --help exited $code, expected 0"
set failed 1
end
if not contains -- $fn $out
echo " $fn --help did not print its own help"
set failed 1
end
set -l ran (string trim -- (command cat $log))
if test -n "$ran"
echo " $fn --help EXECUTED: $ran"
set failed 1
end
echo -n "" >$log
end
rm -rf $tmp
test $failed -eq 0
end
# Functions published in the manual that are exempt from the -h/--help
# rule. Rationale per entry: AGENTS/specs/2026-09-07-header-driven-help-design.md
# §4. This array is the ONLY machine-readable copy of the exempt set.
#
# EXEMPT-A -- shadows a same-named binary, or forwards $argv to one named
# tool that owns its own --help. Intercepting would hide that tool's help,
# and for the C1-guarded shadows it also breaks the disabled-fallback
# contract, where the bare tool is supposed to answer.
set -g __help_exempt \
agy antigravity-ide bash cat cdi cffetch cheat claude clone clonet \
config-toggle copy docker du dusize fast-cli ffetch gitui gitup jr \
joplin less ls mkdir mv paste ping rawfish rg rm search ssh top \
view yt-dlp
# EXEMPT-B -- invoked by fish, never typed by a user.
set -a __help_exempt fish_prompt fish_right_prompt fish_mode_prompt \
sponge_filter_secrets
function test_every_user_facing_function_has_help
set -l root (realpath (dirname (status filename))/..)
set -l failed 0
set -l published
for f in $root/functions/*.fish
set -l lines (string split \n -- (command cat $f))
# Published == carries a `# CATEGORY` block, matching
# manualtools.parse_functions.
contains -- "# CATEGORY" (string trim -- $lines); or continue
# Resolve the real defined name; the file stem can disagree
# (dops.fish defines `docker` -- see JOB-BRIEF-FINDINGS.md §1).
set -l name (string match -rg '^\s*function\s+(\S+)' -- $lines)[1]
test -n "$name"; or continue
set name (string trim -c "'\"" -- $name)
string match -q '_*' -- $name; and continue
set -a published $name
contains -- $name $__help_exempt; and continue
# Body == everything from the `function` line down, comment lines
# dropped, so a header that merely mentions --help cannot pass.
set -l body
set -l in_body 0
for l in $lines
test $in_body -eq 1; or string match -qr '^\s*function\s' -- $l; and set in_body 1
test $in_body -eq 1; or continue
string match -qr '^\s*#' -- $l; and continue
set -a body $l
end
if not string match -qr -- '__fish_help_header|_flag_help|h/help|--help' \
(string join \n -- $body)
echo " $name: no -h/--help handling and not in \$__help_exempt"
set failed 1
end
end
# Guard against a stale exempt list: every exempt name must still be a
# published function. Catches renames and deletions.
for e in $__help_exempt
if not contains -- $e $published
echo " \$__help_exempt lists '$e', which is no longer published"
set failed 1
end
end
test $failed -eq 0
end
function functional_test_main
-162
View File
@@ -1,162 +0,0 @@
#!/usr/bin/env fish
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
#
# Byte-identity harness for the shared output palette (__fish_palette).
#
# Compares rendered output of every colour-bearing function between a
# pristine checkout of a baseline git ref and the current working tree.
# This is a one-time acceptance harness, not part of run-tests.fish's
# permanent suite -- the permanent check lives in tests/functional.fish.
#
# Usage:
# fish tests/palette-bytes.fish [--baseline REF] byte-diff stdout+stderr
# fish tests/palette-bytes.fish --structural diff-shape assertion
# fish tests/palette-bytes.fish --startup startup medians
#
# Both sandboxes get an isolated XDG_CONFIG_HOME carrying a copy of the
# working tree's fish_variables. That file is gitignored, so `git archive`
# omits it; without it __fish_config_op_enabled is unresolvable and every
# opinionated-guarded function silently short-circuits.
set -l repo (realpath (dirname (status filename))/..)
set -l mode bytes
set -l baseline main
for i in (seq (count $argv))
switch $argv[$i]
case --structural; set mode structural
case --startup; set mode startup
case --baseline; set baseline $argv[(math $i + 1)]
end
end
set -l tmp (mktemp -d)
function __pb_cleanup --on-event fish_exit --inherit-variable tmp
test -n "$tmp"; and rm -rf $tmp
end
# ── Build the two sandboxes ────────────────────────────────────────────
set -l A $tmp/base/fish # pristine baseline ref
set -l B $tmp/work/fish # current working tree
mkdir -p $A $B
git -C $repo archive $baseline | tar -x -C $A
or begin
echo "palette-bytes: cannot archive baseline ref '$baseline'" >&2
exit 2
end
for d in functions conf.d completions integrations themes data
test -d $repo/$d; and cp -r $repo/$d $B/
end
cp $repo/config.fish $B/ 2>/dev/null
# fish_variables is gitignored -- copy it into BOTH sandboxes by hand.
for d in $A $B
cp $repo/fish_variables $d/ 2>/dev/null
end
# qc --help shells out to aichat; stub it so its colour path is reachable.
set -l stub $tmp/stub
mkdir -p $stub
printf '#!/bin/sh\necho "aichat stub"\n' >$stub/aichat
chmod +x $stub/aichat
# ── The cases ──────────────────────────────────────────────────────────
# 25 --help paths (every converted function that has one) plus 4 error
# paths, two of which write to stderr. Side-effect-free by construction:
# --help returns before doing work, and each error path fails on argument
# validation. Do NOT add a case that mutates the filesystem.
set -l cases \
"agents-init --help" "agents-vault --help" "auto-pull --help" \
"config-settings --help" "config-update --help" "detach --help" \
"dng2avif --help" "dockup --help" "edit --help" "jobrunner --help" \
"kitty-logging --help" "logs --help" "mkcd --help" "open-url --help" \
"p --help" "pkg --help" "play-media --help" "qc --help" \
"rand_string --help" "replay --help" "repo-open --help" "scrub --help" \
"smart_exit --help" "spark --help" "y --help" \
"mkcd" "auto-pull remove __no_such_repo__" \
"agents-init --no-such-flag" "pkg __no_such_subcommand__"
function __pb_run --argument-names cfg stub cmd out
env XDG_CONFIG_HOME=(dirname $cfg) PATH="$stub:$PATH" TERM=xterm-256color \
HOME=$HOME fish -c "$cmd" >$out.out 2>$out.err
end
# ── Mode: bytes ────────────────────────────────────────────────────────
if test $mode = bytes
echo "== palette byte-identity vs $baseline =="
set -l failed 0
set -l n 0
for cmd in $cases
set n (math $n + 1)
__pb_run $A $stub "$cmd" $tmp/a$n
__pb_run $B $stub "$cmd" $tmp/b$n
set -l so ok
set -l se ok
cmp -s $tmp/a$n.out $tmp/b$n.out; or set so DIFF
cmp -s $tmp/a$n.err $tmp/b$n.err; or set se DIFF
if test $so = DIFF -o $se = DIFF
set failed (math $failed + 1)
printf ' FAIL %-34s stdout=%s stderr=%s\n' "$cmd" $so $se
test $so = DIFF; and diff -u (xxd $tmp/a$n.out | psub) (xxd $tmp/b$n.out | psub) | head -12
test $se = DIFF; and diff -u (xxd $tmp/a$n.err | psub) (xxd $tmp/b$n.err | psub) | head -12
else
printf ' ok %-34s (%s B out, %s B err)\n' "$cmd" (wc -c <$tmp/a$n.out | string trim) (wc -c <$tmp/a$n.err | string trim)
end
end
echo (math $n - $failed)"/$n cases byte-identical"
test $failed -eq 0
exit $status
end
# ── Mode: structural ───────────────────────────────────────────────────
# For files converted WITHOUT drift renames, the whole diff must be
# declaration removals plus inserted __fish_palette calls. If that holds,
# the file's output strings are provably untouched.
if test $mode = structural
echo "== structural diff shape vs $baseline =="
set -l bad 0
for f in (git -C $repo diff --name-only $baseline -- functions/)
# fish_prompt.fish keeps its own hex palette -- see Task 10.
string match -q '*fish_prompt.fish' $f; and continue
# __fish_palette.fish is the palette itself: a new file, so its diff
# is 100% additions and can never be "purely structural". Skipping it
# is not a loosening -- it declares the colours rather than rendering
# any, and tests/functional.fish asserts its 12 roles directly.
string match -q '*__fish_palette.fish' $f; and continue
set -l offenders
for line in (git -C $repo diff -U0 $baseline -- $f | string match -r '^[+-][^+-].*')
set -l body (string sub -s 2 -- $line)
string match -qr '^\s*set -l c_[a-z]+\s+\(set_color[^)]*\)\s*$' -- $body; and continue
string match -qr '^\s*__fish_palette\s*$' -- $body; and continue
set -a offenders $line
end
if test (count $offenders) -gt 0
set bad (math $bad + 1)
echo " NOT PURELY STRUCTURAL $f"
printf ' %s\n' $offenders[1..3]
end
end
if test $bad -eq 0
echo " all changed files are purely structural"
else
echo " $bad file(s) changed rendering text -- expected only for the drift-rename batch"
end
test $bad -eq 0
exit $status
end
# ── Mode: startup ──────────────────────────────────────────────────────
echo "== fish -c true, 31 interleaved pairs, median =="
set -l ta
set -l tb
for i in (seq 31)
set -l s (date +%s%N)
env XDG_CONFIG_HOME=$tmp/base fish -c true >/dev/null 2>&1
set -a ta (math "("(date +%s%N)" - $s) / 1000")
set s (date +%s%N)
env XDG_CONFIG_HOME=$tmp/work fish -c true >/dev/null 2>&1
set -a tb (math "("(date +%s%N)" - $s) / 1000")
end
set -l sa (printf '%s\n' $ta | sort -n)
set -l sb (printf '%s\n' $tb | sort -n)
printf ' baseline median=%.2f ms p10=%.2f p90=%.2f\n' (math $sa[16]/1000) (math $sa[4]/1000) (math $sa[28]/1000)
printf ' working median=%.2f ms p10=%.2f p90=%.2f\n' (math $sb[16]/1000) (math $sb[4]/1000) (math $sb[28]/1000)
echo " (p10-p90 spread is ~15 ms; treat any delta inside it as noise)"