docs: generate the Functions Reference from function comment headers #74

Merged
rootiest merged 10 commits from docs-option-tables into main 2026-07-26 08:41:03 +00:00
116 changed files with 2347 additions and 1672 deletions
+12 -7
View File
@@ -122,14 +122,19 @@ the watcher inert without uninstalling it.
### [📖 Documentation Site](https://fish-config-docs.pages.dev/)
A Starlight-powered site generated from `docs/manual/**` — the single source
of truth — on every push to `main`. It covers configuration variables, key
bindings, abbreviations, all functions, the dependency catalog, customization,
and more, with full-text search.
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.
Contributing to the docs? Edit files under `docs/manual/**`, never the
generated `docs/fish-config.md` — it's rebuilt from the manual tree and any
hand-edits are discarded.
Contributing to the docs? There are two sources, split by content type:
- **Function documentation** comes from the man-page-style comment header
above each function in `functions/*.fish`. Edit the function; the entry
and its site page are generated from the header.
- **Everything else** lives under `docs/manual/**`.
Never edit the generated `docs/fish-config.md` — it's rebuilt from both
sources and any hand-edits are discarded.
To browse the docs from the terminal:
+206 -13
View File
@@ -18,6 +18,37 @@ 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 build_concat(root: Path) -> str:
@@ -32,6 +63,7 @@ def build_concat(root: Path) -> str:
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():
@@ -43,6 +75,8 @@ def build_concat(root: Path) -> str:
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)
if body:
chunks.append(mt.shift_headings(body, depth))
return "\n\n".join(chunks) + "\n"
@@ -73,19 +107,46 @@ def _jsx_attr_escape(value: str) -> str:
def _first_sentence(body: str) -> str:
"""Extract a one-line description from the start of an entry body.
`Synopsis:` lines are skipped: they restate the calling convention,
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.
"""
for line in body.split("\n"):
line = line.strip()
if not line or line.startswith(("#", "```", "|", "-", "*", ">")):
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
m = SENTENCE_RE.match(line)
return (m.group(1) if m else line)[:160]
return ""
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
@@ -140,6 +201,58 @@ def _is_shell(para: list[str], entry_name: str | None) -> bool:
return True
CELL_SPLIT = re.compile(r"\s{2,}")
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 _render_para(para: list[str], entry_name: str | None, deeper: bool) -> str:
"""Render one paragraph of a former indented block.
@@ -152,6 +265,9 @@ def _render_para(para: list[str], entry_name: str | None, deeper: bool) -> str:
if _is_shell(para, entry_name):
body = "\n".join(para)
return f"```fish\n{body}\n```"
table = _as_table(para)
if table is not None:
return table
return "\n".join(INDENT + line for line in para)
@@ -167,8 +283,12 @@ def _prettify_block(block: list[str], entry_name: str | None) -> str:
out: list[str] = []
if lines and lines[0].startswith(SYNOPSIS_PREFIX):
synopsis = lines.pop(0)[len(SYNOPSIS_PREFIX) :].strip()
out.append(f"```fish\n{synopsis}\n```")
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())
out.append("```fish\n" + "\n".join(synopsis) + "\n```")
para: list[str] = []
for line in lines + [""]:
@@ -213,6 +333,76 @@ def prettify(body: str, entry_name: str | None = None) -> str:
return "\n".join(out)
ENTRY_HEADS = {"ARGUMENTS": "Arguments:", "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 += [""] + 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}
@@ -260,6 +450,9 @@ def build_site(root: Path, out: Path) -> list[dict]:
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] = []
functions_group: dict = {}
for path, _depth in mt.walk(root):
@@ -286,7 +479,7 @@ def build_site(root: Path, out: Path) -> list[dict]:
# 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 = "reference"
slug_dir = SLUG_DIR
if rel.name == "index.md":
target = out / slug_dir / "index.md"
target.parent.mkdir(parents=True, exist_ok=True)
@@ -305,12 +498,12 @@ def build_site(root: Path, out: Path) -> list[dict]:
category = re.sub(r"^\d+-", "", rel.stem)
cat_dir = out / slug_dir / category
cat_dir.mkdir(parents=True, exist_ok=True)
intro, entries = _split_entries(body)
intro, page_entries = _split_entries(_with_entries(body, path, entries))
cards = []
links = []
for title, entry_body in entries:
entry_slug = re.sub(r"[^\w-]+", "-", title.strip().lower()).strip("-")
for title, entry_body in page_entries:
entry_slug = _entry_slug(title)
desc = _first_sentence(entry_body)
entry_fm = {"title": title}
if desc:
+1264 -550
View File
File diff suppressed because it is too large Load Diff
@@ -7,158 +7,4 @@ helpKeywords:
- files
---
## cat
Synopsis: cat [args...]
Wraps bat for files with syntax highlighting and line numbers.
Passes directories to ls. Falls back to /usr/bin/cat.
cat README.md
cat ~/projects/myapp
## copy
Synopsis: copy <source> <dest>
Wraps cp, stripping trailing slashes from source directories to
prevent unintended nesting inside the destination.
copy ./mydir/ ~/backup # copies mydir INTO backup, not backup/mydir/
## du
Synopsis: du [--disk|--dir|--dua] [args...]
Smart disk-usage dispatcher:
--disk force duf (disk-level free/used overview)
--dir force dust (per-directory tree breakdown)
--dua force dua (fast space analyzer)
Without flags, routes to the most appropriate tool by context.
du ~/Downloads
du --disk
## dusize
Synopsis: dusize [dir]
Human-readable disk usage for a directory via du -sh. Defaults to cwd.
dusize ~/Videos
## lD
Synopsis: lD [args...]
Lists directories only in long format with icons. Uses eza, falls back
to lsd, then system ls.
lD ~/projects
## ls
Synopsis: ls [args...]
Lists files in long format with icons and hyperlinks. Uses eza, falls
back to lsd, then system ls.
ls
ls -a ~/projects
## lsr
Synopsis: lsr [args...]
Lists files sorted by modification time, oldest first. Uses eza.
## lss
Synopsis: lss [args...]
Lists files sorted by size with gradient color scaling. Uses eza.
## lstree
Synopsis: lstree [args...]
Full recursive tree view with icons. Uses eza.
lstree ~/projects/myapp
## lt
Synopsis: lt [args...]
Tree view limited to depth 2 with icons. Uses eza.
lt ~/projects
## ltr
Synopsis: ltr [args...]
Lists files sorted by modification time, oldest first, long format with
age-based gradient scaling. Uses eza.
## lx
Synopsis: lx [args...]
Lists files sorted by extension, long format. Uses eza.
## mkdir
Synopsis: mkdir [args...]
Interactive mkdir that prints a tree of created directories.
Falls back to mkdir -p silently.
mkdir ~/projects/myapp/src
## mkcd
Synopsis: mkcd [-s] <dir>
Creates a directory (including parents) and cd into it. Prints a tree
of created dirs by default; -s/--silent suppresses output.
mkcd ~/projects/newapp/src
## poke
Synopsis: poke <file> [file...]
Creates files via touch, automatically creating any missing parent
directories first.
poke ~/projects/new/src/main.fish
## rm
Synopsis: rm [-e [opts] | -S | args...]
Safe rm wrapper routing to trash:
(no args) List current trash contents
-e/--empty Empty the trash (pass options to trash-empty)
-S/--secure Permanently delete via rm -rf + fstrim (irreversible)
-r/-R/--recursive Move to trash
<paths> Move to trash (safe delete)
Falls back to /usr/bin/rm when trash is unavailable.
rm file.txt # moves to trash
rm -e # empty trash
rm -S sensitive.pem # permanent delete
## rg
Synopsis: rg [args...]
In Kitty, wraps ripgrep with --hyperlink-format=kitty so search
results are clickable file links in the terminal. Falls back to
system rg in any other terminal. All other arguments pass through
unchanged.
rg "fish_greeting" ~/.config/fish/
rg -l "TODO" ~/projects/myapp
## scrub
Synopsis: scrub [-a] [-d] [-h]
Recursively removes OS metadata, editor artifacts, compiler output,
and dev caches using fd.
-a/--aggressive Also removes node_modules, logs, .cache, IDE dirs,
AI session artifacts
-d/--dry-run Print what would be removed without deleting
scrub
scrub -a
scrub -d
---
-22
View File
@@ -7,26 +7,4 @@ helpKeywords:
- nav-fns
---
## cdi
Synopsis: cdi [query]
Interactive directory picker combining zoxide frecency with fzf.
Equivalent to zi.
cdi myproject
## clone
Synopsis: clone [args...]
Clone a git repository into a new Kitty window. Kitty-only.
clone https://github.com/user/repo.git
## clonet
Synopsis: clonet [args...]
Clone a git repository into a new Kitty tab. Kitty-only.
clonet https://github.com/user/repo.git
---
@@ -7,65 +7,4 @@ helpKeywords:
- editors
---
## edit
Synopsis: edit [-V|-t] [-e EDITOR] [-c] [-x TEXT] [-n] [-v|-s] [FILE...]
Opens files in a text editor, choosing a terminal or GUI editor and
resolving a rich chain of fallbacks. With no --visual/--terminal flag the
mode is auto-detected: interactive terminals use the terminal editor
($EDITOR), while detached invocations (e.g. desktop shortcuts) use the GUI
editor ($VISUAL). Clipboard contents and literal strings can be opened as
throwaway temp files. Editor output is suppressed unless --verbose.
GUI fallback chain: zed → antigravity-ide → code → kate → kwrite →
gnome-text-editor → gedit
Terminal fallback chain: nvim → vim → micro → nano → vi
Options:
-V, --visual Force the GUI editor ($VISUAL or fallbacks)
-t, --terminal Force the terminal editor ($EDITOR or fallbacks)
-e, --editor=X Use a specific editor binary X
-c, --clipboard Open the clipboard contents (as a temp file)
-x, --text=STR Open STR as the contents of a new temp file
-n, --new Force a new window/instance (best-effort)
-v, --verbose Print the launch command and editor output
-s, --silent Suppress all output, including the editor's
-h, --help Show this help message
edit ~/.config/fish/config.fish
edit --visual notes.txt
edit --terminal --new todo.md
edit --editor=code --clipboard
edit --text="hello world"
## fc
Synopsis: fc [command_prefix]
Edit the last shell command (or one matching a prefix) in $EDITOR,
then execute the result. Bash-style fc behaviour.
fc
fc git
## less
Synopsis: less [args...]
Pager wrapper with fallback chain: $PAGER -> ov -> less -> more -> cat.
less /var/log/syslog
## rawfish
Synopsis: rawfish [args...]
Launches Fish with NO_TMUX=1, bypassing any tmux auto-attach logic.
Useful when you need a clean shell without session management.
## view
Synopsis: view [args...]
Opens files in nvim read-only mode (-R). Falls back to less.
view /etc/fstab
---
@@ -7,84 +7,4 @@ helpKeywords:
- git
---
## auto-pull
Synopsis: auto-pull [list]
auto-pull add [PATH]
auto-pull remove <NAME|PATH>
auto-pull status
Manages the registry of repositories that are background fast-forwarded
when you enter them (see "Auto-pull fast-forward" under the C2 component
reference). The fish-config repo is always covered as a baseline. The
registry is machine-local at `$__fish_user_dots_path/auto-pull.list` (defaults
to `~/.config/.user-dots/fish/auto-pull.list`), one absolute path per line,
and is never committed. Registry management works
even when C2 auto-execution is disabled; only the background sync is gated.
list Show registered repos (default)
add [PATH] Register PATH's git root (default: current repo)
remove <NAME|PATH> Unregister by basename or exact path
status Show enabled/disabled state, repo count, list path
cd ~/src/qmk_firmware; and auto-pull add
auto-pull add ~/work/api
auto-pull list
auto-pull remove qmk_firmware
## branch
Synopsis: branch <branch_name>
Switches to a local branch, or creates it if it does not exist.
branch feature/new-ui
## gi
Synopsis: gi [-h] [-b] [-p] [-s] [-l] [targets...]
Generates .gitignore content from the gitignore.io API with MD5-based
deduplication (patterns already present are not re-appended).
-b/--boilerplate Append generic boilerplate first
-p/--prompt Prompt interactively for targets
-s/--stdout Print to stdout instead of appending to .gitignore
-l/--list List all available targets
targets Comma-separated or space-separated target names
gi python,venv
gi -b -p
gi -s node > .gitignore
## git-clean
Synopsis: git-clean [-f]
Fetches and prunes the remote, fast-forwards the current branch, then
deletes local branches whose remote tracking branch has been deleted.
Switches to main/master automatically if the current branch is orphaned.
-f/--force Force-delete unmerged branches too
git-clean
git-clean --force
## gitup
Synopsis: gitup [args...]
Fetches updates from the remote and shows git status. Extra args are
forwarded to git fetch.
gitup
gitup --all
## gitui
Synopsis: gitui [args...]
Launches gitui with the Catppuccin Frappe theme pre-applied.
## hist
Synopsis: hist
Searches shell history with fzf, inserts the selection into the command
line, and copies it to the clipboard via wl-copy.
---
@@ -8,53 +8,4 @@ helpKeywords:
- packages
---
## pkg
Synopsis: pkg [-h] [-i|-u] <package> [package...]
Installs or removes packages using the detected system package manager.
Supports: paru, yay, pacman, apt, dnf, zypper, yum, brew, pkg.
(no flag) Auto mode: installs missing packages, removes installed ones
-i/--install Force install
-u/--uninstall Force uninstall
pkg firefox # auto: install if missing, remove if present
pkg -i ripgrep fd # force install
pkg -u cowsay # force uninstall
The package-installed check uses the correct query for each PM:
pacman/paru/yay pacman -Qi
apt dpkg -s
dnf/zypper/yum rpm -q
brew brew list
pkg pkg info
## search
Synopsis: search [args...]
Interactive AUR package search and install via paru or yay.
Arch Linux only.
search neovim
## upgrade
Synopsis: upgrade
Full system upgrade via paru -Syu --noconfirm or yay -Syu --noconfirm.
Arch Linux only.
## cleanup
Synopsis: cleanup
Lists and removes orphan packages via pacman, logging their names to
~/.removed_orphans. Arch Linux only.
## parur
Synopsis: parur
Opens an fzf picker of all installed packages (with pacman -Qi previews),
then removes the selected packages via paru or yay. Arch Linux only.
parur
---
@@ -7,41 +7,4 @@ helpKeywords:
- deps
---
## fish-deps
Synopsis: fish-deps [status|install|update|sync]
Unified command for managing all tools this configuration depends on.
status (default) Show installed/missing status grouped by tier
install Interactively install each missing dependency
update Update all installed dependencies
sync Install missing deps, then update all
Install method priority (highest to lowest):
1. git+cargo source build (fish shell itself)
2. cargo (Rust tools — gets latest crate version)
3. system PM (paru/apt/brew/etc.)
4. git clone (fzf)
5. curl installer (starship, fisher, uv)
When multiple methods are available you are prompted to choose.
Dependencies are grouped into three tiers:
Required fish, fzf, zoxide
Integrations wakatime, tailscale
Recommended cargo, starship, uv, direnv, paru, yay, eza, lsd, bat,
btop, dust, duf, prettyping, ov, ripgrep, lazygit,
lazydocker, trash, kitty, wezterm, python3, yt-dlp
fish-deps
fish-deps install
fish-deps update
fish-deps sync
## check_fish_deps
Synopsis: check_fish_deps
Backwards-compatibility alias for `fish-deps status`.
---
@@ -7,57 +7,4 @@ helpKeywords:
- system
---
## top
Synopsis: top [args...]
Launches btop as a modern resource monitor. Falls back to system top.
## swapstat
Synopsis: swapstat
Displays a colorized memory report: kernel swappiness, zRAM compression
ratio, zRAM device details, and active swap priorities.
## sbver
Synopsis: sbver [--brief]
Verifies Secure Boot signatures on all EFI binaries tracked by sbctl.
Color-codes results: green checkmark (verified), red X (unsigned).
Prints a pass/fail summary.
--brief Suppress per-file output, show only the summary
sbver
sbver --brief
## ports
Synopsis: ports
Lists active TCP listeners with lsof, showing port/address without
hostname resolution.
## screensleep
Synopsis: screensleep
Turns off the display via KDE PowerDevil's "Turn Off Screen" action,
invoked through busctl.
## lock
Synopsis: lock
Locks the current desktop session using loginctl lock-session.
## sudo-toggle
Synopsis: sudo-toggle
Toggles the sudo NOPASSWD rule on/off via /etc/sudoers.d/nofail-toggle.
Useful for automated tasks that would otherwise require password entry.
## limine-edit
Synopsis: limine-edit
Opens /boot/limine.conf in sudoedit, then automatically re-enrolls the
config hash, runs CachyOS boot hooks, and re-signs Secure Boot files.
Combines the edit and sign steps into a single command.
---
@@ -7,54 +7,4 @@ helpKeywords:
- terminal-mgmt
---
## tab
Synopsis: tab [args...]
Opens a new tab in Kitty (kitty @ launch --type=tab), WezTerm
(wezterm cli spawn), or Konsole. Uses current working directory,
or $cdto if set.
tab
## split
Synopsis: split [-h|-v] [command...]
Opens a new pane in Kitty or WezTerm, optionally running a command.
-h/--horizontal (default) Split below
-v/--vertical Split to the right
split
split -v nvim README.md
## spwin
Synopsis: spwin [args...]
Spawns a new terminal OS window in Kitty (via spawn-window.sh or
kitty @ launch --type=os-window) or WezTerm (wezterm cli spawn --new-window).
## detach
Synopsis: detach [-h] [--version] <command> [args...]
Runs a command fully detached via nohup with stdout/stderr discarded.
The command survives the current session.
detach rsync -a ./data remote:/backup/
## bkg
Synopsis: bkg <command> [args...]
Launches a command in the background via nohup with output discarded.
Simpler than detach; no version flag.
bkg firefox
## ssh
Synopsis: ssh [args...]
In Kitty, wraps ssh with kitten ssh for better terminal integration
(multiplexing, copy/paste support). Falls back to system ssh elsewhere.
ssh user@host
---
-22
View File
@@ -7,26 +7,4 @@ helpKeywords:
- clipboard
---
## y
Synopsis: y [text...]
Copies text to the clipboard via wl-copy (Wayland) or xclip (X11).
Reads from stdin if no arguments given.
y "hello world"
ls | y
cat file.txt | y
## p
Synopsis: p [args...]
Outputs clipboard contents to stdout.
p | grep foo
p > file.txt
## paste
Alias for p. Identical behaviour.
---
-34
View File
@@ -7,38 +7,4 @@ helpKeywords:
- network
---
## gip
Synopsis: gip
Fetches and prints both the public IPv4 and IPv6 address via
icanhazip.com.
## gip4
Synopsis: gip4
Fetches and prints the public IPv4 address.
## gip6
Synopsis: gip6
Fetches and prints the public IPv6 address. Returns 1 if IPv6 is
unavailable.
## ping
Synopsis: ping [args...]
Wraps prettyping with --nolegend. Pass --legend to show the legend.
Falls back to system ping.
ping google.com
## qr
Synopsis: qr [text...]
Generates a UTF-8 QR code from text or stdin. Uses qrencode locally;
falls back to the qrenco.de API.
qr "https://example.com"
echo "https://example.com" | qr
---
@@ -7,41 +7,4 @@ helpKeywords:
- logging
---
## logs
Synopsis: logs [-c <category>]
Interactively browses terminal log files sorted newest-first using fzf.
-c/--category Filter to: scrollback, paru, or yay
Keybindings inside the fzf browser:
Enter Open in $PAGER
Ctrl+E Open in $EDITOR
Ctrl+D Delete (with confirmation)
? Toggle keybind help overlay
Paru and yay logs open in ov with syntax highlighting and sticky section
headers. Scrollback logs open in ov with per-command sticky prompt headers
based on OSC 133 markers.
logs
logs -c paru
logs -c scrollback
## smart_exit
Synopsis: smart_exit [-n]
Closes the shell session. In Kitty, captures the terminal scrollback to
a timestamped log file in $SCROLLBACK_HISTORY_DIR before exiting.
Automatically prunes the oldest logs when the count exceeds
$SCROLLBACK_HISTORY_MAX_FILES.
-n/--no-log Exit without saving a scrollback log
The exit builtin is wired to smart_exit for interactive sessions.
Typing exit or Ctrl+D behaves identically to smart_exit.
smart_exit
smart_exit --no-log
---
@@ -7,110 +7,4 @@ helpKeywords:
- ai
---
## agy
Synopsis: agy [args...]
Wrapper for the agy Antigravity AI CLI. Before launching, delegates to
agents-init --agents to ensure AGENTS/ is scaffolded and CLAUDE.md is
symlinked to AGENTS/AGENTS.md in the current project, then forwards all
arguments verbatim to the real agy binary. Command shadow (C1): when
__fish_config_op_aliases (or the master) is disabled, the call is
passed through to the real agy binary unchanged.
agy chat
agy resume
## antigravity-ide
Synopsis: antigravity-ide [args...]
Runs the antigravity-ide editor with warnings filtered.
## agents-init
Synopsis: agents-init [--agents | --plugins]
Scaffold an AGENTS/ sub-repository for tracking agent specs, plans, specs,
and dev logs. Creates AGENTS/ as a standalone git repo, moves any existing
AGENTS.md into it, and replaces it with a relative symlink (plus
CLAUDE.md -> AGENTS/AGENTS.md so Claude Code picks up the shared agent
instructions). Consolidates plans/ and specs/ directly under AGENTS/
(merging any legacy docs/plans, docs/superpowers/plans, or old
AGENTS/plugins/ locations into the canonical AGENTS/<tgt>), creates
AGENTS/devlogs/, and wires docs/superpowers/{plans,specs} symlinks back to
them. Adds managed paths to .gitignore and auto-commits every change inside
the AGENTS/ sub-repo; pulls first when the sub-repo has an upstream.
Fully idempotent: a second run produces no output and no new commits.
Flags: --agents re-runs only the AGENTS.md / symlink step; --plugins
re-runs only the plans/specs/devlogs wiring step. Called automatically by
the claude and agy wrappers on every invocation.
Structure versioning: each AGENTS/ repo carries a self-contained version
bumper. AGENTS/.version holds MAJOR.MINOR.PATCH (seeded 1.0.0). Committed
git hooks under AGENTS/.agents-tools/ (wired via core.hooksPath) bump it on
every commit: MINOR (resetting PATCH) when the tracked directory set
changes, PATCH otherwise; MAJOR is manual-only. A prepare-commit-msg hook
appends "(vX.Y.Z)" to the commit subject. Downstream tooling can read
AGENTS/.version - a changed MINOR field signals a structure change. Because
core.hooksPath is a single setting, the local override would otherwise
shadow your global hooks; after bumping the version, each shim chains
(execs) to the global/system core.hooksPath hook of the same name so global
pre-commit / prepare-commit-msg hooks (e.g. ggshield, Git LFS) still run.
The script and hooks are shipped from scripts/agents-tools/ and refreshed
when their version marker is stale.
agents-init
agents-init --agents
agents-init --plugins
## claude
Synopsis: claude [args...]
Wrapper for the claude CLI. Before launching, delegates to agents-init
--agents to ensure AGENTS/ is scaffolded and CLAUDE.md is symlinked to
AGENTS/AGENTS.md in the current project, then forwards all arguments
verbatim to the real claude binary. Command shadow (C1): when
__fish_config_op_aliases (or the master) is disabled, the call is
passed through to the real claude binary unchanged.
claude
claude --resume
## claude-docs
Synopsis: claude-docs
Invokes Claude Code to analyze recent repository changes and update
README.md, ensuring all documented features and examples are accurate.
## claude-pr
Synopsis: claude-pr
Invokes Claude Code to run the full PR workflow: create branch,
conventional commit, verification, push, and open a PR with a manual
verification checklist.
## qc
Synopsis: qc [prompt...]
Quick-chat wrapper around the aichat LLM CLI that defaults to the "cli"
role - a system prompt tuned for concise, terminal-friendly output. On
first use it installs the bundled role by symlinking
scripts/cli-agent.md to $XDG_CONFIG_HOME/aichat/roles/cli.md (creating
the directory if needed). Inherits every aichat flag and tab completion
(--wraps aichat); passing --role/-r overrides the default role, so qc
forwards to aichat unchanged. The function is only defined when aichat
is installed. Run qc --help for aichat's full flag reference with the
command name rewritten to qc.
qc "how do I list open ports on linux?"
qc -m ollama:llama3 "explain this error"
qc --role coder "refactor this function"
## superpowers
Synopsis: superpowers [on|off] [-g]
Enables or disables the Superpowers plugin for Antigravity and Claude
Code at workspace/project scope (default) or user scope (-g/--global).
superpowers on
superpowers off -g
---
@@ -7,48 +7,4 @@ helpKeywords:
- media
---
## dng2avif
Synopsis: dng2avif [-i <file>] [-o <file>] [-q <n>] [-s <n>] [input.dng]
Converts a DNG raw image to a 10-bit HDR AVIF using an ImageMagick,
ffmpeg, avifenc pipeline with metadata sync via exiftool.
-i/--input Input file (or positional arg)
-o/--output Output file (default: same name, .avif extension)
-q/--quality Quality 0-100 (default 92)
-s/--speed Encoding speed 0-10 (default 3)
dng2avif photo.dng
dng2avif -q 85 -s 5 -i shot.dng -o out.avif
## steam-dl
Synopsis: steam-dl
Launches Steam under systemd-inhibit, preventing the system from going
idle or sleeping while a download is in progress.
## spark
Synopsis: spark [--min=<n>] [--max=<n>] [numbers...]
Renders a Unicode sparkline bar chart for a sequence of numbers.
Reads from stdin if no numbers are given.
spark 1 1 2 5 14 42
echo "3 7 2 9 1" | spark
## yt-dlp
Synopsis: yt-dlp [args...] URL [URL...]
Wraps yt-dlp, prepending sane defaults: --sponsorblock-remove all,
--embed-subs, --embed-metadata, and --embed-thumbnail. Each default
is suppressed when you already pass that flag, its alias, or its
negation (e.g. --no-embed-thumbnail drops the thumbnail default;
--no-sponsorblock or your own --sponsorblock-remove drops ours). All
other arguments pass through unchanged, and --help falls through to
real yt-dlp. Opinionated component (C1 aliases); when disabled it
passes straight through to the system yt-dlp.
yt-dlp dQw4w9WgXcQ
yt-dlp --no-embed-thumbnail dQw4w9WgXcQ
---
@@ -7,278 +7,4 @@ helpKeywords:
- miscfns
---
## config-help
Synopsis: config-help [SECTION]
config-help --html
config-help [SECTION] --man
config-help -h | --help
Opens the offline fish shell configuration manual. Without flags, opens
the Markdown source in the best available pager (ov > bat > man > less >
cat). If SECTION is given, jumps to the first heading matching that
keyword (case-insensitive; checks fish-config.index aliases first).
Flags:
--html / -w Open the published documentation website
(https://fish-config-docs.pages.dev/) in the default
browser via xdg-open. Deep links to a section aren't
supported; if SECTION is given, a note points you to the
site's search box instead.
--man / -m Open docs/fish-config.1 via man -l directly.
If SECTION is given, jumps to the nearest match.
--help / -h Print usage and navigation key reference.
config-help keybindings
config-help pkg
config-help --html
config-help --man
config-help pkg --man
Also available as: help config [SECTION] [FLAGS]
## open-url
Synopsis: open-url [-s|--silent] [-v|--verbose] <url>
open-url -h | --help
Opens a URL or file:// URI in the best available graphical web browser,
backgrounded so it never blocks the terminal. Resolves a real browser
binary rather than deferring to xdg-open, whose MIME dispatch can hand
local text/html files to non-browser apps (e.g. ebook readers).
Silent by default: prints nothing on success (errors always go to
stderr). Pass --verbose / -v to report which browser is launched;
--silent / -s is accepted for explicitness.
Resolution order:
1. $fish_help_browser (explicit override)
2. $BROWSER (validated; errors if not a command)
3. xdg-mime default handler for x-scheme-handler/https
4. First known browser binary found in a built-in list
5. xdg-open (last resort)
open-url https://git.rootiest.dev/rootiest/fish-config
open-url -v https://fish-config-docs.pages.dev/
Used internally by config-help --html.
Typo abbreviation: url-open (expands to open-url on space/enter).
## repo-open
Synopsis: repo-open [-p|--print] [-r|--root]
repo-open -h | --help
Opens the web page for the current repository's `origin` remote in a
browser (via open-url). Deep-links to the current branch when it exists
on the remote — falling back to the remote's default branch (main/master)
otherwise — and to the current sub-directory when run below the repo root.
The remote URL is normalized from HTTPS and SSH/scp forms
(git@host:owner/repo.git, ssh://…, https://…). The web path layout is
provider-specific; the provider is resolved in order:
1. git config browse.provider (per-repo or --global override)
2. Hostname heuristic (github / gitlab / gitea / bitbucket;
codeberg → gitea)
3. Default: github-style layout
Self-hosted hosts the heuristic can't classify (a Gitea/GitLab instance
on a custom domain) need a one-time override:
git config browse.provider gitea
Flags:
--print / -p Print the resolved URL instead of opening it.
--root / -r Ignore the current sub-directory; link to the repo root.
--help / -h Show usage.
repo-open
repo-open --print
repo-open --root
Typo abbreviation: open-repo (expands to repo-open on space/enter).
## config-update
Synopsis: config-update [-h] [-n] [-f]
Pulls the latest fish configuration from the upstream repository
into ~/.config/fish.
All git output is suppressed; colored messages report
fetch and merge status. After a successful pull, run `exec fish` to
reload.
Flags:
--dry-run / -n Fetch and show available commits without applying them.
--force / -f Stash local changes, pull, then restore the stash.
--help / -h Show usage.
config-update
config-update --dry-run
config-update --force
## config-settings
Synopsis: config-settings [-h]
Opens an interactive TUI for managing fish configuration settings across
four pages, without having to type or remember variable names. Tab cycles
forward through the pages; Shift-Tab cycles backward.
Universal — opinionated category toggles (C1C6) + master, persistent (set -U)
Session — the same toggles, current shell only (set -g)
Sponge — sponge history-scrubbing settings: delay, successful exit
codes, purge-only-on-exit, allow-previously-successful, and
extra sensitive variable-name tokens
Paths — scrollback log directory, scrollback max files, the
user-dots path, and the user-dots convenience symlink toggle
(Dots link)
Toggle rows use ← → (or h/l) along an OFF ← DEFAULT → ON scale; DEFAULT
erases the variable so the master switch / built-in default applies. Value
rows (the path/int/list settings on the Sponge and Paths pages) use Enter to
edit inline; ← / h clears the value back to its default. List rows (e.g.
Extra secret, OK codes) accept values separated by commas and/or whitespace
— "A, B", "A,B" and "A B" all yield the same two entries. Changes apply
immediately. Always available regardless of the __fish_config_opinionated
master state.
The Sponge and Paths pages always write universal variables — these are
persistent, set-and-forget settings with no per-session scope. Editing a
scrollback row updates both the __fish_scrollback_history_* source-of-truth
variables and the exported SCROLLBACK_HISTORY_* mirrors, so the AUR/tmux/
zellij log wrappers (which read the exported names) see the change in the
running session.
The panel adapts to the terminal width automatically, selecting from
four layout tiers (with a 6-column buffer on each side before stepping
up to the next tier) and horizontally centering the box. The panel
redraws within ~0.3 s of a terminal resize with no keypress required.
COLUMNS >= 90 → 78-wide panel (most detail)
COLUMNS >= 86 → 74-wide panel
COLUMNS >= 82 → 70-wide panel
COLUMNS < 82 → 52-wide panel (default)
Navigation:
↑ ↓ / k j Move cursor
← → / h l Toggle rows: OFF ← DEFAULT → ON
← / h Value rows: clear to default
Enter Value rows: edit inline (Sponge / Paths pages)
Tab / S-Tab Next / previous page
q / Escape Exit
Flags:
--help / -h Show usage.
config-settings
## config-toggle (deprecated)
Deprecated alias for config-settings. Prints a deprecation notice to
stderr, then delegates all arguments to config-settings.
config-toggle
## bash
Synopsis: bash [args...]
Switches to bash, with XDG config applied. On exit, $SHELL is reset
back to fish.
## bd-pull
Synopsis: bd-pull <owner/repo>
Fetches unlinked Gitea issues and creates local Beads entries, updating
issue titles with the assigned Beads IDs.
Requires $GITEA_TOKEN and $GITEA_URL to be set.
bd-pull rootiest/fish-config
## cheat
Synopsis: cheat <topic> [args...]
Displays a colorized cheatsheet using cheat -c, falls back to tldr,
then man.
cheat tar
cheat git
## cffetch / ffetch
Synopsis: cffetch [args...] / ffetch [args...]
Clears the screen and displays system information via fastfetch with
the custom config at ~/.fastfetch.jsonc. Falls back to neofetch.
## dockup
Synopsis: dockup [-h] [directory]
Pulls latest Docker images, restarts services in the given Docker
Compose project, and prunes dangling images.
dockup ~/myapp
## joplin
Synopsis: joplin [args...]
Runs the Joplin CLI with Node.js deprecation warnings suppressed.
joplin ls
## ld
Synopsis: ld
Launches lazydocker targeting the currently active Docker context,
detected via docker context inspect.
## replay
Synopsis: replay <commands>
Runs Bash commands and replays any resulting changes to environment
variables, aliases, and the working directory back into the current
Fish session. Useful for sourcing Bash scripts.
replay "source ~/.bashrc"
replay "export FOO=bar"
## kitty-logging
Synopsis: kitty-logging [install|uninstall|status|dismiss] [-h]
Manages the Kitty scrollback watcher that powers C5 logging. Ships a
canonical watcher and symlinks it into the Kitty config directory (so it
always tracks the source), wiring it into kitty.conf through a
sentinel-marked managed block. Commenting out any conflicting watcher line
avoids double-capture.
Commands:
install Symlink the watcher and add the managed block
uninstall Remove the managed block and the watcher symlink
status Show wiring, installed watcher version, and C5 state
dismiss Stop the per-session setup reminder
Runtime capture stays governed by the C5 .logging_disabled sentinel, so
disabling __fish_config_op_logging makes the watcher inert without
uninstalling. Install affects new Kitty windows only.
Example:
kitty-logging install
kitty-logging status
## tmux-clean
Synopsis: tmux-clean
Kills all detached (unattached) tmux sessions, leaving attached ones
running.
## wake-lock
Synopsis: wake-lock <command> [args...]
Runs a command under systemd-inhibit, preventing the system from going
idle or sleeping until the command completes.
wake-lock rsync -avz src/ dest/
---
+11
View File
@@ -83,3 +83,14 @@ 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.
+84 -1
View File
@@ -3,7 +3,8 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Shared helpers for the docs/manual SSOT pipeline.
Frontmatter parsing, deterministic tree ordering, and heading level shifts.
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.
"""
@@ -57,6 +58,88 @@ def shift_headings(body: str, by: int) -> str:
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",
"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 _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
+179 -8
View File
@@ -4,6 +4,7 @@
"""Verification checks for the docs/manual SSOT pipeline."""
import importlib.util
import re
import sys
import tempfile
from pathlib import Path
@@ -109,14 +110,113 @@ def test_manual_tree_exists():
assert len(cats) == 14, f"expected 14 function categories, got {len(cats)}: {cats}"
def test_function_entries_promoted_to_h2():
def test_function_stubs_carry_no_entries():
"""Category files are stubs: entries come from functions/*.fish headers.
An authored `##` entry here would be a second copy of a function's
documentation exactly the duplication the header-SSOT migration
removed and the generator would emit its own entry alongside it.
"""
root = Path(__file__).parent / "manual" / "05-functions"
for path in root.glob("*.md"):
if path.name == "index.md":
continue
_, body = mt.parse(path)
assert "\n### " not in f"\n{body}", f"{path.name} still has H3 entries"
assert "\n## " in f"\n{body}", f"{path.name} has no H2 function entries"
stray = [ln for ln in body.split("\n") if ln.startswith(("## ", "### "))]
assert not stray, f"{path.name} has authored entries: {stray}"
def _parsed_functions() -> dict[str, dict[str, list[str]]]:
return mt.parse_functions(Path(__file__).parent.parent / "functions")
def test_every_categorised_function_produces_one_entry():
import build_manual
functions = _parsed_functions()
entries = build_manual.build_entries(functions)
got = [name for names in entries.values() for name, _ in names]
assert sorted(got) == sorted(functions), (
f"entry/function mismatch: "
f"{sorted(set(functions) ^ set(got))}"
)
assert len(got) == len(set(got)), "a function produced more than one entry"
def test_entries_carry_the_required_sections():
missing = []
for name, fn in _parsed_functions().items():
absent = [s for s in ("SYNOPSIS", "DESCRIPTION", "EXAMPLE") if not fn.get(s)]
if absent:
missing.append(f"{name}: {', '.join(absent)}")
assert not missing, "headers missing required sections:\n " + "\n ".join(missing)
def test_every_category_resolves_to_a_stub():
root = Path(__file__).parent / "manual" / "05-functions"
stubs = {p.stem for p in root.glob("*.md") if p.name != "index.md"}
used = {}
for name, fn in _parsed_functions().items():
used.setdefault(" ".join(fn.get("CATEGORY", [])).strip(), []).append(name)
unknown = {c: v for c, v in used.items() if c not in stubs}
assert not unknown, f"# CATEGORY values with no stub: {unknown}"
empty = sorted(stubs - set(used))
assert not empty, f"category stubs generating zero entries: {empty}"
def test_dependencies_resolve():
"""Every declared # DEPENDENCIES name must be a real function or binary.
Catches typos, and catches stale entries when a dependency is renamed
or deleted. External binaries are accepted when some file in the tree
guards them with `type -q`, which is this repo's convention.
"""
repo = Path(__file__).parent.parent
functions = _parsed_functions()
known = {p.stem for p in (repo / "functions").glob("*.fish")} | set(functions)
for path in list(repo.glob("conf.d/*.fish")) + list((repo / "functions").glob("*.fish")):
known |= set(re.findall(r"type -q\s+(\S+)", path.read_text(encoding="utf-8")))
dangling = []
for name, fn in functions.items():
for dep in (d for d in re.split(r"[,\s]+", " ".join(fn.get("DEPENDENCIES", []))) if d):
if dep not in known:
dangling.append(f"{name} -> {dep}")
assert not dangling, "unresolvable # DEPENDENCIES:\n " + "\n ".join(dangling)
def warn_public_functions_without_category():
"""Warn — never fail — on a public function carrying no `# CATEGORY`.
Bundled plugin and prompt internals will always lack one, so this
cannot be a hard failure; a genuinely new user-facing function going
undocumented still needs to be visible in CI output.
"""
repo = Path(__file__).parent.parent
documented = set(_parsed_functions())
orphans = sorted(
p.stem
for p in (repo / "functions").glob("*.fish")
if not p.stem.startswith("_")
and p.stem not in documented
and "# SYNOPSIS" in p.read_text(encoding="utf-8")
)
if orphans:
print(f" WARN {len(orphans)} documented function(s) lack # CATEGORY:")
print(" " + ", ".join(orphans))
def _without_section_5(text: str) -> str:
"""Drop `# 5. FUNCTIONS REFERENCE` through the start of section 6.
Section 5 is generated from `functions/*.fish` headers, so it
legitimately differs from the pre-migration snapshot. The round-trip
guard covers the authored sections either side of it.
"""
start = text.find("\n# 5. ")
if start == -1:
return text
end = text.find("\n# 6. ", start)
return text[:start] + (text[end:] if end != -1 else "")
def _normalise(text: str) -> str:
@@ -128,6 +228,11 @@ def _normalise(text: str) -> str:
def test_concat_roundtrips_original():
"""The concat of manual/ must reproduce the original fish-config.md exactly.
Section 5 is excluded: it is generated from `functions/*.fish` headers
and so legitimately differs from the snapshot. This test guarded the
*format* migration; the header-SSOT change is a *content* migration,
covered instead by the structural checks above.
Prefers docs/fish-config.md.orig (a snapshot of the pre-migration file)
when present. Once that snapshot is deleted post-migration,
docs/fish-config.md IS the concat output regenerated in Step 5, so
@@ -149,8 +254,8 @@ def test_concat_roundtrips_original():
if not original.exists():
original = docs / "fish-config.md"
label = "fish-config.md"
got = build_manual.build_concat(docs / "manual")
want = original.read_text()
got = _without_section_5(build_manual.build_concat(docs / "manual"))
want = _without_section_5(original.read_text())
if got != want:
norm_got = _normalise(got)
norm_want = _normalise(want)
@@ -237,14 +342,79 @@ def test_prettify_splits_an_entry_block():
assert "```fish\nrm file.txt" in out, "examples were not fenced as fish"
assert out.count("```") == 4, f"expected exactly two fences, got:\n{out}"
assert "\nSafe rm wrapper routing to trash:" in out, "description stayed indented"
assert (
"\n (no args) List current trash contents" in out
), "option table lost its indentation"
assert "| `(no args)` | List current trash contents |" in out, (
"option table was not converted to a markdown table"
)
assert (
"\nFalls back to /usr/bin/rm when trash is unavailable." in out
), "trailing prose stayed indented"
def test_as_table_converts_option_blocks():
"""A labelled, column-aligned block becomes a table; wrapped rows fold in."""
import build_manual
out = build_manual._as_table(
[
"Options:",
" -a/--aggressive Also removes node_modules, logs,",
" and IDE dirs",
" -d/--dry-run Print what would be removed",
"Pass neither to run interactively.",
]
)
assert out is not None, "a plain option table was rejected"
assert out.splitlines()[0] == "Options:", "the label line was dropped"
assert out.splitlines()[-1] == "Pass neither to run interactively.", (
"the trailing sentence was dropped"
)
assert (
"| `-a/--aggressive` | Also removes node_modules, logs, and IDE dirs |" in out
), "a wrapped description did not fold into the row above"
def test_as_table_escapes_pipes():
"""`|` splits table cells even inside a code span, so it must be escaped."""
import build_manual
out = build_manual._as_table(
[" -r/-R Recurse into it", " -e|-E Empty it"]
)
assert out is not None and r"`-e\|-E`" in out, f"pipe was not escaped:\n{out}"
def test_as_table_rejects_non_tables():
"""Returning None is always safe, so every ambiguous shape must return it."""
import build_manual
cases = {
"single row": [" -f/--force Force-delete unmerged branches too"],
"numbered list": [
" 1. git+cargo source build (fish shell itself)",
" 2. cargo (Rust tools — gets latest crate version)",
],
"misaligned rows": [
" -e/--empty Empty the trash",
" -S/--secure Permanently delete (single space, not a column)",
],
"synopsis continuation": [
" auto-pull add [PATH]",
" auto-pull status",
],
"unlabelled head": [
"Routes to the best tool by context.",
" --disk force duf",
" --dir force dust",
],
"live markdown in prose column": [
" add Register <PATH>'s git root",
" remove Unregister by basename",
],
}
for label, para in cases.items():
assert build_manual._as_table(para) is None, f"{label} was wrongly tabled"
def test_prettify_leaves_reference_tables_alone():
"""Column-aligned blocks are data, not shell, and must not be fenced."""
import build_manual
@@ -328,6 +498,7 @@ def main() -> int:
except AssertionError as e:
print(f" FAIL {t.__name__}: {e}", file=sys.stderr)
failed += 1
warn_public_functions_without_category()
print(f"\n{len(TESTS) - failed}/{len(TESTS)} passed")
return 1 if failed else 0
+15 -3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 12-ai-and-developer-tools
#
# SYNOPSIS
# agents-init [-a | --agents] [-p | --plugins] [-v | --verbose]
# [-q | --quiet] [-s | --silent] [-h | --help]
@@ -42,9 +45,18 @@
# version-managed from scripts/agents-tools/ and refreshed when their marker
# is stale.
#
# With no flags, runs both --agents and --plugins setup. At the end of
# every invocation, commits any uncommitted changes in the AGENTS/ sub-repo
# so that agent-made edits are captured automatically.
# Downstream tooling can read AGENTS/.version directly — a changed MINOR
# field signals a structure change.
#
# With no flags, runs both --agents and --plugins setup; --agents re-runs
# only the AGENTS.md / symlink step and --plugins only the plans/specs/
# devlogs wiring step. Managed paths are added to .gitignore. The sub-repo
# is pulled first when it has an upstream, and at the end of every
# invocation any uncommitted changes inside it are auto-committed so
# agent-made edits are captured automatically. Fully idempotent: a second
# run produces no output and no new commits.
#
# Called automatically by the claude and agy wrappers on every invocation.
#
# ARGUMENTS
# -a, --agents Set up AGENTS/ repo + AGENTS.md / CLAUDE.md symlinks only
+9 -1
View File
@@ -1,6 +1,12 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 12-ai-and-developer-tools
#
# DEPENDENCIES
# agents-init
#
# SYNOPSIS
# agy [ARGS...]
#
@@ -8,7 +14,9 @@
# Wrapper for the agy Antigravity AI CLI that ensures the AGENTS/
# sub-repository is initialized and any agent-made changes are committed
# before launch. Delegates all scaffold and commit logic to agents-init
# (full setup). All arguments are forwarded verbatim to the real agy binary.
# --quiet (full setup), which ensures AGENTS/ is scaffolded and CLAUDE.md
# is symlinked to AGENTS/AGENTS.md in the current project. All arguments
# are forwarded verbatim to the real agy binary.
#
# Opinionated component (C1): when disabled via __fish_config_op_aliases
# (or the __fish_config_opinionated master), the command is passed through
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 12-ai-and-developer-tools
#
# SYNOPSIS
# antigravity-ide [args...]
#
+7 -3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 04-git-and-version-control
#
# SYNOPSIS
# auto-pull [list]
# auto-pull add [PATH]
@@ -12,8 +15,9 @@
# background fast-forwarded when you enter them (see conf.d/auto-pull.fish
# and _auto_pull_sync). The fish-config repo is always covered as a baseline
# and does not need to be added. The registry is a plain text file, one
# absolute git-toplevel path per line, stored machine-locally in
# ~/.config/.user-dots/fish/auto-pull.list (never committed to the config).
# absolute git-toplevel path per line, stored machine-locally at
# $__fish_user_dots_path/auto-pull.list (defaults to
# ~/.config/.user-dots/fish/auto-pull.list) and never committed.
#
# Registry management works regardless of the C2 auto-execution guard; only
# the background sync itself is gated by __fish_config_op_autoexec.
@@ -22,7 +26,7 @@
# list Show registered repos (default when no subcommand given)
# add [PATH] Register PATH's git root; defaults to the current repo
# remove <NAME|PATH> Unregister by basename or exact path
# status Show whether auto-pull is enabled and the registry path
# status Show enabled/disabled state, repo count, and registry path
# -h, --help Show this help message
#
# RETURNS
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# SYNOPSIS
# bash [args...]
#
+4
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# SYNOPSIS
# bd-pull <owner/repo>
#
@@ -18,6 +21,7 @@
#
# EXAMPLE
# bd-pull myuser/myproject
# bd-pull rootiest/fish-config
function bd-pull --description 'Pull new Gitea issues into local Beads and link them'
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
+5 -1
View File
@@ -1,12 +1,16 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 08-terminal-management
#
# SYNOPSIS
# bkg <command> [args...]
#
# DESCRIPTION
# Launches a command in the background, fully detached from the terminal
# using nohup. All stdout and stderr output is discarded.
# using nohup. All stdout and stderr output is discarded. Simpler than
# detach; no --version flag.
#
# ARGUMENTS
# command The command to run detached
+22 -1
View File
@@ -1,4 +1,25 @@
# Switch to or create a git branch
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 04-git-and-version-control
#
# SYNOPSIS
# branch <branch_name>
#
# DESCRIPTION
# Switches to a local git branch, creating it if it does not already
# exist. Extra arguments are forwarded to git checkout.
#
# ARGUMENTS
# branch_name Branch to switch to or create
#
# RETURNS
# 0 Branch checked out or created
# 1 Not inside a git work tree
#
# EXAMPLE
# branch feature/new-ui
function branch --description 'Switch to or create a git branch'
if not git rev-parse --is-inside-work-tree >/dev/null 2>&1
echo "Not a git repo."
+8 -3
View File
@@ -1,19 +1,24 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# cat [args...]
#
# DESCRIPTION
# Enhanced cat replacement that uses bat for file display, runs ls when given
# a directory, falls back to raw cat for ANSI-colored log files, and finally
# falls back to standard cat if bat is not installed.
# Enhanced cat replacement. Wraps bat for files, giving syntax highlighting
# and line numbers; passes directories to ls; falls back to raw cat for
# ANSI-colored log files, and finally to /usr/bin/cat if bat is not
# installed.
#
# ARGUMENTS
# args... Files or directories to display
#
# EXAMPLE
# cat README.md
# cat ~/projects/myapp
function cat --wraps='bat' --description 'Use bat for files, ls for directories, and raw cat for ANSI logs'
# Opinionated guard (C1): fall back to bare command cat when disabled.
if not __fish_config_op_enabled __fish_config_op_aliases
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 02-navigation
#
# SYNOPSIS
# cdi [query]
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# SYNOPSIS
# cffetch [args...]
#
+4
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# SYNOPSIS
# cheat <topic> [args...]
#
@@ -14,6 +17,7 @@
#
# EXAMPLE
# cheat tar
# cheat git
function cheat --wraps='cheat' --description 'alias cheat=cheat -c'
if type -q cheat
command cheat -c $argv
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 06-dependency-management
#
# SYNOPSIS
# check_fish_deps
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 12-ai-and-developer-tools
#
# SYNOPSIS
# claude-docs
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 12-ai-and-developer-tools
#
# SYNOPSIS
# claude-pr
#
+9 -1
View File
@@ -1,13 +1,21 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 12-ai-and-developer-tools
#
# DEPENDENCIES
# agents-init
#
# SYNOPSIS
# claude [ARGS...]
#
# DESCRIPTION
# Wrapper for the claude CLI that ensures the AGENTS/ sub-repository is
# initialized and any agent-made changes are committed before launch.
# Delegates all scaffold and commit logic to agents-init (full setup).
# Delegates all scaffold and commit logic to agents-init --quiet (full
# setup), which ensures AGENTS/ is scaffolded and CLAUDE.md is symlinked
# to AGENTS/AGENTS.md in the current project.
# All arguments are forwarded verbatim to the real claude binary.
#
# Opinionated component (C1): when disabled via __fish_config_op_aliases
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 05-package-management
#
# SYNOPSIS
# cleanup
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 02-navigation
#
# SYNOPSIS
# clone [args...]
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 02-navigation
#
# SYNOPSIS
# clonet [args...]
#
+12 -5
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# SYNOPSIS
# config-help [section]
# config-help --html
@@ -14,11 +17,14 @@
# that matches the keyword. Lookup order: docs/fish-config.index (exact
# keyword aliases), then a normalized heading scan as fallback.
# When opened with ov a sticky navigation hint is shown at the top of the
# screen. Pass --html / -w to open the published documentation website in
# the default browser (deep links to a section aren't supported there —
# use the site's search box). Pass --man / -m to open the compiled man
# page; if a section keyword is given, the pager opens at the nearest
# match. Pass --help or -h for usage.
# screen. Section matching is case-insensitive. Pass --html / -w to open
# the published documentation website (https://fish-config-docs.pages.dev/)
# in the default browser via xdg-open — deep links to a section aren't
# supported there, so if a keyword is given a note points you to the site's
# search box instead. Pass --man / -m to open the compiled man page
# (docs/fish-config.1) via `man -l`; if a section keyword is given, the
# pager opens at the nearest match. Pass --help or -h for usage and the
# navigation key reference.
#
# ARGUMENTS
# section Optional keyword to jump to a matching section heading
@@ -39,6 +45,7 @@
# config-help --man
# config-help keys --man
# config-help --help
# config-help pkg --man
#
# NOTES
# The preferred invocation is `help config [...]` — this function is
+41 -7
View File
@@ -1,24 +1,58 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# SYNOPSIS
# config-settings [-h | --help]
#
# DESCRIPTION
# Opens an interactive full-screen TUI for managing fish config settings
# across four pages:
# across four pages, without having to type or remember variable names:
#
# Universal — opinionated-category toggles, persistent (set -U / set -Ue)
# Session — opinionated-category toggles, this shell only (set -g / set -eg)
# Sponge — sponge history-scrubbing settings (delay, codes, secrets …)
# Paths — scrollback log dir, log max, and user-dots path
# Universal — opinionated-category toggles (C1C6) + master, persistent (set -U)
# Session — the same toggles, current shell only (set -g)
# Sponge — sponge history-scrubbing settings: delay, successful exit
# codes, purge-only-on-exit, allow-previously-successful, and
# extra sensitive variable-name tokens
# Paths — scrollback log directory, scrollback max files, the user-dots
# path, and the user-dots convenience symlink toggle (Dots link)
#
# Toggle rows use ← / → (or h / l) to step OFF ← DEFAULT → ON.
# Value rows (Sponge, Paths) use Enter to edit inline; ← / h clears to default.
# Toggle rows use ← / → (or h / l) to step OFF ← DEFAULT → ON; DEFAULT erases
# the variable so the master switch / built-in default applies. Value rows
# (Sponge, Paths) use Enter to edit inline; ← / h clears to default. List rows
# (e.g. Extra secret, OK codes) accept values separated by commas and/or
# whitespace — "A, B", "A,B" and "A B" all yield the same two entries.
# Tab / Shift-Tab cycle forward / backward through pages.
# Changes apply immediately — no confirm step. Always available regardless of
# __fish_config_opinionated state.
#
# The Sponge and Paths pages always write universal variables — these are
# persistent, set-and-forget settings with no per-session scope. Editing a
# scrollback row updates both the __fish_scrollback_history_* source-of-truth
# variables and the exported SCROLLBACK_HISTORY_* mirrors, so the AUR/tmux/
# zellij log wrappers (which read the exported names) see the change in the
# running session.
#
# The panel adapts to the terminal width automatically, selecting from four
# layout tiers (with a 6-column buffer on each side before stepping up to the
# next tier) and horizontally centering the box. The panel redraws within
# ~0.3 s of a terminal resize with no keypress required.
#
# COLUMNS >= 9078-wide panel (most detail)
# COLUMNS >= 8674-wide panel
# COLUMNS >= 8270-wide panel
# COLUMNS < 8252-wide panel (default)
#
# Navigation:
# ↑ ↓ / k j Move cursor
# ← → / h l Toggle rows: OFF ← DEFAULT → ON
# ← / h Value rows: clear to default
# Enter Value rows: edit inline (Sponge / Paths pages)
# Tab / S-Tab Next / previous page
# q / Escape Exit
#
# ARGUMENTS
# -h, --help Print usage and exit
#
+6
View File
@@ -1,6 +1,12 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# DEPENDENCIES
# config-settings
#
# SYNOPSIS
# config-toggle [args...]
#
+4 -1
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# SYNOPSIS
# config-update [-h | --help] [-f | --force] [-n | --dry-run]
#
@@ -8,7 +11,7 @@
# Pulls the latest fish shell configuration from the upstream repository
# into ~/.config/fish. Git output is suppressed; status is reported
# through colored messages. After a successful pull the function prints a
# short summary of changed files.
# short summary of changed files; run `exec fish` to reload the shell.
#
# ARGUMENTS
# -h, --help Show this help message and exit
+4
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# copy <source> <dest>
#
@@ -14,6 +17,7 @@
#
# EXAMPLE
# copy ./mydir/ ~/backup
# copy ./mydir/ ~/backup # copies mydir INTO backup, not backup/mydir/
function copy
set count (count $argv)
if test "$count" = 2; and test -d "$argv[1]"
+5 -1
View File
@@ -1,12 +1,16 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 08-terminal-management
#
# SYNOPSIS
# detach [-h] [--version] <command> [args...]
#
# DESCRIPTION
# Runs a command in the background using nohup, fully detached from the
# terminal with all output discarded.
# terminal with stdout/stderr discarded. The command survives the current
# session.
#
# ARGUMENTS
# -h, --help Show help message
+4
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 13-media-and-utilities
#
# SYNOPSIS
# dng2avif [-h] [-i <file>] [-o <file>] [-q <n>] [-s <n>] [input.dng]
#
@@ -22,6 +25,7 @@
#
# EXAMPLE
# dng2avif photo.dng
# dng2avif -q 85 -s 5 -i shot.dng -o out.avif
function dng2avif --description 'Convert DNG raw to 10-bit HDR AVIF'
set -l options (fish_opt -s h -l help)
set -a options (fish_opt -s i -l input -r)
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# SYNOPSIS
# dockup [-h] [directory]
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 12-ai-and-developer-tools
#
# SYNOPSIS
# docker [subcommand] [args...]
#
+10 -6
View File
@@ -1,22 +1,26 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# du [--disk|--dir|--dua] [args...]
#
# DESCRIPTION
# Smart disk-usage wrapper that routes to duf (disk overview), dust (directory
# tree), or dua based on context or explicit flags. Falls back to system du
# when the preferred tool is not installed.
# Smart disk-usage dispatcher. Without flags, routes to the most appropriate
# tool by context; explicit flags force one. Falls back to system du when the
# preferred tool is not installed.
#
# ARGUMENTS
# --disk Force duf for disk-level overview
# --dir Force dust for directory-level breakdown
# --dua Force dua interactive mode
# --disk Force duf (disk-level free/used overview)
# --dir Force dust (per-directory tree breakdown)
# --dua Force dua (fast interactive space analyzer)
# args... Files/directories or flags forwarded to the selected tool
#
# EXAMPLE
# du ~/Downloads
# du --disk
function du --description 'Execute du'
# Opinionated guard (C1): fall back to bare command du when disabled.
if not __fish_config_op_enabled __fish_config_op_aliases
+4
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# dusize [dir]
#
@@ -13,6 +16,7 @@
#
# EXAMPLE
# dusize ~/Downloads
# dusize ~/Videos
function dusize --wraps='du' --description 'alias dusize=du'
du -sh (test -n "$argv[1]"; and echo $argv[1]; or echo .)
end
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 03-editors-and-viewers
#
# SYNOPSIS
# edit [-V|-t] [-e EDITOR] [-c] [-x TEXT] [-n] [-v|-s] [FILE...]
#
+25 -1
View File
@@ -1,4 +1,28 @@
# Edit and execute the last command (Bash-style fc)
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 03-editors-and-viewers
#
# SYNOPSIS
# fc [command_prefix]
#
# DESCRIPTION
# Edits the last shell command -- or the most recent one matching a
# prefix -- in $EDITOR, then executes the result. Bash-style fc
# behaviour. Falls back to vi when $EDITOR is unset, and aborts without
# executing if the buffer is left empty.
#
# ARGUMENTS
# command_prefix Search history for the newest command matching this
#
# RETURNS
# The edited command's exit status, or a message when history lookup
# found nothing.
#
# EXAMPLE
# fc
# fc git
function fc --description 'Edit and execute the last command (Bash-style fc)'
set -l tmpfile (mktemp /tmp/fish_fc.XXXXXX).fish
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# SYNOPSIS
# ffetch [args...]
#
+26 -2
View File
@@ -1,12 +1,33 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 06-dependency-management
#
# SYNOPSIS
# fish-deps [status|install|update|sync]
#
# DESCRIPTION
# Manages fish shell dependencies by dispatching to subcommand handlers.
# Defaults to status when no subcommand is given.
# Unified command for managing all tools this configuration depends on,
# dispatching to subcommand handlers. Defaults to status when no subcommand
# is given.
#
# Install method priority (highest to lowest):
# 1. git+cargo source build (fish shell itself)
# 2. cargo (Rust tools — gets latest crate version)
# 3. system PM (paru/apt/brew/etc.)
# 4. git clone (fzf)
# 5. curl installer (starship, fisher, uv)
#
# When multiple methods are available you are prompted to choose.
#
# Dependencies are grouped into three tiers:
#
# Required fish, fzf, zoxide
# Integrations wakatime, tailscale
# Recommended cargo, starship, uv, direnv, paru, yay, eza, lsd, bat,
# btop, dust, duf, prettyping, ov, ripgrep, lazygit,
# lazydocker, trash, kitty, wezterm, python3, yt-dlp
#
# ARGUMENTS
# status Report installed/missing deps (default)
@@ -20,6 +41,9 @@
#
# EXAMPLE
# fish-deps sync
# fish-deps
# fish-deps install
# fish-deps update
function fish-deps --description 'Manage fish shell dependencies'
set -l subcmd $argv[1]
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 06-dependency-management
#
# SYNOPSIS
# fzf-update
#
+10 -4
View File
@@ -1,13 +1,17 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 04-git-and-version-control
#
# SYNOPSIS
# gi [-h] [-b] [-p] [-s] [targets...]
# gi [-h] [-b] [-p] [-s] [-l] [targets...]
#
# DESCRIPTION
# Generates .gitignore content by querying the gitignore.io API. Appends
# results to the repository's .gitignore with MD5-based deduplication, or
# prints to stdout with -s. Supports boilerplate and interactive prompt modes.
# results to the repository's .gitignore with MD5-based deduplication
# patterns already present are not re-appended — or prints to stdout with
# -s. Supports generic boilerplate and interactive prompt modes.
#
# ARGUMENTS
# -h, --help Show help message
@@ -16,7 +20,7 @@
# -b, --boilerplate Append boilerplate from $GITIGNORE_BOILERPLATE
# -p, --prompt Prompt for patterns to append
# -s, --stdout Print API output to stdout instead of .gitignore
# targets Comma-separated list of language/tool names
# targets Comma- or space-separated list of language/tool names
#
# RETURNS
# 0 Patterns appended or printed
@@ -24,6 +28,8 @@
#
# EXAMPLE
# gi python,venv
# gi -b -p
# gi -s node > .gitignore
function gi --description 'Generate .gitignore files using the gitignore.io API'
argparse h/help d/description l/list b/boilerplate p/prompt s/stdout -- $argv
or return 1
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 10-network
#
# SYNOPSIS
# gip
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 10-network
#
# SYNOPSIS
# gip4
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 10-network
#
# SYNOPSIS
# gip6
#
+7 -3
View File
@@ -1,13 +1,16 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 04-git-and-version-control
#
# SYNOPSIS
# git-clean [-h] [-f]
#
# DESCRIPTION
# Fetches and prunes the remote, updates the current branch, and deletes
# local branches whose tracking remote has been deleted. Automatically moves
# to main if currently on an orphaned branch.
# Fetches and prunes the remote, fast-forwards the current branch, and
# deletes local branches whose tracking remote has been deleted. Switches to
# main/master automatically if the current branch is orphaned.
#
# ARGUMENTS
# -h, --help Show help message
@@ -19,6 +22,7 @@
#
# EXAMPLE
# git-clean --force
# git-clean
function git-clean --description 'Sync main, prune remotes, and delete orphaned branches'
set -l options h/help f/force
argparse $options -- $argv
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 04-git-and-version-control
#
# SYNOPSIS
# gitui [args...]
#
+23 -1
View File
@@ -1,4 +1,26 @@
# Fetch updates and show git status
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 04-git-and-version-control
#
# SYNOPSIS
# gitup [args...]
#
# DESCRIPTION
# Fetches updates from the remote and shows git status. Extra arguments
# are forwarded to git fetch.
#
# ARGUMENTS
# args... Forwarded verbatim to git fetch
#
# RETURNS
# 0 Fetch and status succeeded
# 1 Not inside a git work tree
#
# EXAMPLE
# gitup
# gitup --all
function gitup --description 'Fetch updates and show git status'
# Check if we are even in a git repository
if not git rev-parse --is-inside-work-tree >/dev/null 2>&1
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 04-git-and-version-control
#
# SYNOPSIS
# hist
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# SYNOPSIS
# joplin [args...]
#
+16 -9
View File
@@ -1,21 +1,28 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# SYNOPSIS
# kitty-logging [install | uninstall | status | dismiss] [-h]
#
# DESCRIPTION
# Manages the fish-config Kitty scrollback watcher. `install` copies the
# canonical watcher into the Kitty config dir and wires it into kitty.conf via
# a sentinel-marked managed block (commenting out any conflicting active
# watcher line to avoid double-capture). `uninstall` reverses it. `status`
# reports wiring, watcher version, and C5 logging state. `dismiss` silences the
# per-session setup reminder. Runtime capture remains gated by the C5
# .logging_disabled sentinel; install affects future Kitty instances only.
# Manages the fish-config Kitty scrollback watcher that powers C5 logging.
# `install` symlinks the canonical watcher into the Kitty config dir (so it
# always tracks the source) and wires it into kitty.conf via a
# sentinel-marked managed block, commenting out any conflicting active
# watcher line to avoid double-capture. `uninstall` reverses it. `status`
# reports wiring, installed watcher version, and C5 logging state. `dismiss`
# silences the per-session setup reminder.
#
# Runtime capture stays governed by the C5 .logging_disabled sentinel, so
# disabling __fish_config_op_logging makes the watcher inert without
# uninstalling. Install affects new Kitty windows only.
#
# ARGUMENTS
# install Copy the watcher and add the managed block to kitty.conf
# uninstall Remove the managed block and the installed watcher
# install Symlink the watcher and add the managed block to kitty.conf
# uninstall Remove the managed block and the watcher symlink
# status Report wiring, watcher version, and C5 logging state
# dismiss Stop the per-session reminder
# -h, --help Show this help
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# lD [args...]
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# SYNOPSIS
# ld
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 03-editors-and-viewers
#
# SYNOPSIS
# less [args...]
#
+5 -1
View File
@@ -1,13 +1,17 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 07-system-and-monitoring
#
# SYNOPSIS
# limine-edit
#
# DESCRIPTION
# Opens /boot/limine.conf in sudoedit, then re-enrolls the config hash,
# runs CachyOS boot hooks (limine-mkinitcpio), and re-signs all Secure Boot
# files tracked by sbctl.
# files tracked by sbctl. Combines the edit and sign steps into a single
# command.
#
# EXAMPLE
# limine-edit
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 07-system-and-monitoring
#
# SYNOPSIS
# lock
#
+15
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 11-pager-and-logging
#
# SYNOPSIS
# logs [-h] [-c <category>]
#
@@ -8,6 +11,16 @@
# Interactively browses terminal log files (scrollback, paru, yay) sorted
# newest-first using fzf. Supports viewing in $PAGER, editing, and deletion.
#
# Keybindings inside the fzf browser:
# Enter Open in $PAGER
# Ctrl+E Open in $EDITOR
# Ctrl+D Delete (with confirmation)
# ? Toggle keybind help overlay
#
# Paru and yay logs open in ov with syntax highlighting and sticky section
# headers. Scrollback logs open in ov with per-command sticky prompt headers
# based on OSC 133 markers.
#
# ARGUMENTS
# -h, --help Show help message
# -c, --category cat Filter to one category: scrollback, paru, or yay
@@ -18,6 +31,8 @@
#
# EXAMPLE
# logs -c paru
# logs
# logs -c scrollback
function logs --description 'Browse terminal log files interactively with fzf'
# Opinionated guard (C4): integrations disabled
if not __fish_config_op_enabled __fish_config_op_integrations
+5
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# ls [args...]
#
@@ -13,6 +16,8 @@
#
# EXAMPLE
# ls ~/projects
# ls
# ls -a ~/projects
function ls --description 'List all files'
# Opinionated guard (C1): fall back to bare command ls when disabled.
if not __fish_config_op_enabled __fish_config_op_aliases
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# lsr [args...]
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# lss [args...]
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# lstree [args...]
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# lt [args...]
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# ltr [args...]
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# lx [args...]
#
+4
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# mkcd [-s | --silent] <dir>
#
@@ -21,6 +24,7 @@
#
# EXAMPLE
# mkcd ~/projects/myapp
# mkcd ~/projects/newapp/src
function mkcd --description 'Create a directory (with parents) and cd into it'
set -l c_head (set_color --bold cyan)
set -l c_cmd (set_color --bold white)
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# mkdir [args...]
#
+8 -1
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# SYNOPSIS
# open-url [-s|--silent] [-v|--verbose] <url>
# open-url --help
@@ -11,7 +14,8 @@
# binary rather than deferring to xdg-open, whose MIME dispatch can hand
# local text/html files to non-browser apps (e.g. ebook readers).
#
# Silent by default: prints nothing on success (errors always go to stderr).
# Silent by default: prints nothing on success (errors always go to stderr);
# --silent / -s is accepted for explicitness.
#
# Resolution order:
# 1. $fish_help_browser (explicit override)
@@ -33,6 +37,9 @@
# EXAMPLE
# open-url https://git.rootiest.dev/rootiest/fish-config
# open-url -v https://fish-config-docs.pages.dev/
#
# 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'
argparse h/help s/silent v/verbose -- $argv
or return 1
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 09-clipboard
#
# SYNOPSIS
# p [args...]
#
+4
View File
@@ -1,12 +1,16 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 05-package-management
#
# SYNOPSIS
# parur
#
# DESCRIPTION
# Presents an fzf picker of all installed packages (via pacman -Qqs) with
# pacman -Qi previews, then removes the selected packages using paru or yay.
# Arch Linux only.
#
# RETURNS
# 0 Packages removed or none selected
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 09-clipboard
#
# SYNOPSIS
# paste [args...]
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 10-network
#
# SYNOPSIS
# ping [args...]
#
+11
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 05-package-management
#
# SYNOPSIS
# pkg [-h] [-i|-u] <package> [package...]
#
@@ -10,6 +13,14 @@
# In auto mode (no flag), detects whether each package is installed and
# toggles it — installing if absent, removing if present.
#
# The package-installed check uses the correct query for each manager:
#
# pacman/paru/yay pacman -Qi
# apt dpkg -s
# dnf/zypper/yum rpm -q
# brew brew list
# pkg pkg info
#
# ARGUMENTS
# -h, --help Show help message
# -i, --install Force install mode
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# poke <file> [file...]
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 07-system-and-monitoring
#
# SYNOPSIS
# ports
#
+14 -6
View File
@@ -1,16 +1,22 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 12-ai-and-developer-tools
#
# SYNOPSIS
# qc [prompt...]
#
# DESCRIPTION
# Quick-chat wrapper around aichat using the "cli" role. Resolves the
# aichat config directory (honoring $XDG_CONFIG_HOME), creates it if
# missing, and installs the bundled cli-agent role as a symlink at
# roles/cli.md on first use. Inherits aichat's own flags and tab
# completions (--wraps). The function is only defined when aichat is
# installed.
# Quick-chat wrapper around the aichat LLM CLI that defaults to the "cli"
# role — a system prompt tuned for concise, terminal-friendly output.
# Resolves the aichat config directory (honoring $XDG_CONFIG_HOME), creates
# it if missing, and on first use installs the bundled role by symlinking
# scripts/cli-agent.md to $XDG_CONFIG_HOME/aichat/roles/cli.md. Inherits
# every aichat flag and tab completion (--wraps aichat); passing --role/-r
# overrides the default role, so qc forwards to aichat unchanged. The
# function is only defined when aichat is installed. Run `qc --help` for
# aichat's full flag reference with the command name rewritten to qc.
#
# ARGUMENTS
# prompt... Prompt forwarded to aichat
@@ -21,6 +27,8 @@
#
# EXAMPLE
# qc "how do I list open ports on linux?"
# qc -m ollama:llama3 "explain this error"
# qc --role coder "refactor this function"
if type -q aichat
function qc --wraps aichat --description 'Quick-chat wrapper around aichat (cli role)'
if contains -- -h $argv; or contains -- --help $argv
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 10-network
#
# SYNOPSIS
# qr [text...]
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 03-editors-and-viewers
#
# SYNOPSIS
# rawfish [args...]
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# SYNOPSIS
# replay <commands>
#
+9
View File
@@ -1,6 +1,12 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 14-miscellaneous
#
# DEPENDENCIES
# open-url
#
# SYNOPSIS
# repo-open [-p|--print] [-r|--root]
# repo-open --help
@@ -39,6 +45,9 @@
# repo-open # open current branch (+ subdir) in browser
# repo-open --print # just print the URL
# repo-open --root # repo home page for the current branch
#
# 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'
argparse -X 0 h/help p/print r/root -- $argv
or return 1
+5
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# rg [args...]
#
@@ -14,6 +17,8 @@
#
# EXAMPLE
# rg "TODO" src/
# rg "fish_greeting" ~/.config/fish/
# rg -l "TODO" ~/projects/myapp
function rg --description 'alias rg=rg --hyperlink-format=kitty'
# Opinionated guard (C1): fall back to bare command rg when disabled.
if not __fish_config_op_enabled __fish_config_op_aliases
+7 -1
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# rm [-e [options] | -S | args...]
#
@@ -18,7 +21,7 @@
# ARGUMENTS
# (none) List current trash contents
# -e, --empty [opts] Empty the trash; opts forwarded to trash empty
# -S, --secure Permanently delete targets and run fstrim
# -S, --secure Permanently delete targets and run fstrim (irreversible)
# -r, -R, --recursive Forwarded to trash put alongside path arguments
# args... Files or paths to trash or remove
#
@@ -30,6 +33,9 @@
# rm file.txt
# rm -e
# rm -S sensitive_key.pem
#
# NOTES
# Falls back to /usr/bin/rm when trash is unavailable.
function rm --description 'Ultimate rm: trash, list, empty, and secure-erase'
# Opinionated guard (C1): fall back to bare command rm when disabled.
if not __fish_config_op_enabled __fish_config_op_aliases
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 07-system-and-monitoring
#
# SYNOPSIS
# sbver [--brief]
#
+3
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 07-system-and-monitoring
#
# SYNOPSIS
# screensleep
#
+4 -1
View File
@@ -1,6 +1,9 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 01-file-and-directory
#
# SYNOPSIS
# scrub [-a] [-d] [-h]
#
@@ -12,7 +15,7 @@
# IDE directories, and AI tool artifacts.
#
# ARGUMENTS
# -a, --aggressive Also purge node_modules, *.log, .idea, AI artifacts
# -a, --aggressive Also purge node_modules, *.log, .cache, .idea, AI artifacts
# -d, --dry-run Show targets without deleting
# -h, --help Show usage help
#
+4 -1
View File
@@ -1,12 +1,15 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 05-package-management
#
# SYNOPSIS
# search [args...]
#
# DESCRIPTION
# Delegates to paru or yay for interactive AUR package search and
# installation. Falls back to yay if paru is not installed.
# installation. Falls back to yay if paru is not installed. Arch Linux only.
#
# ARGUMENTS
# args... Arguments forwarded to paru or yay
+12 -3
View File
@@ -1,13 +1,17 @@
# Copyright (C) 2026 Rootiest
# SPDX-License-Identifier: AGPL-3.0-or-later
# CATEGORY
# 11-pager-and-logging
#
# SYNOPSIS
# smart_exit [-h] [-n]
#
# DESCRIPTION
# Closes the shell session, capturing and archiving the terminal scrollback
# log before exit (Kitty only). Automatically prunes junk and excess log
# files according to $SCROLLBACK_HISTORY_MAX_FILES.
# Closes the shell session. In Kitty, captures the terminal scrollback to a
# timestamped log file in $SCROLLBACK_HISTORY_DIR before exiting.
# Automatically prunes junk and the oldest logs when the count exceeds
# $SCROLLBACK_HISTORY_MAX_FILES.
#
# ARGUMENTS
# -h, --help Show help message
@@ -18,7 +22,12 @@
# 1 Argument parsing failed
#
# EXAMPLE
# smart_exit
# smart_exit --no-log
#
# NOTES
# The exit builtin is wired to smart_exit for interactive sessions. Typing
# `exit` or Ctrl+D behaves identically to calling smart_exit directly.
function smart_exit --description 'Capture colorized scrollback before exiting, with pruning and safe overrides'
# Opinionated guard (C3): exit plainly when overrides are disabled.
# This composes with Task #4's __fish_config_enable_logging, which will

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