feat(docs): add CLASSIFICATION function-header field, rename history shadow

Rename the C1 history() shadow to pretty-history so it never collides
with the fish builtin -- every function expecting stock history
semantics (search, --max, merge, ...) would otherwise silently break.
hist.fish, which relied on the shadow's timestamp formatting, now
requests it explicitly via builtin history --show-time.

Add a CLASSIFICATION doc-header label so a function can declare its
interaction with C1-shadowed commands (uses-shadow/bypasses-shadow)
and general hazards (destructive, network, blocking-prompt) for
anyone deciding to disable an opinionated category or call the
function from automation. Wired into the manual/site build pipeline
(manualtools.py, build-manual.py) and the C1 shadow doc gets a new
"For function authors" bypass-mechanism reference table
(command/builtin/__original_help, and which shadows have no real
bypass target at all).
This commit is contained in:
2026-09-21 21:26:40 -04:00
parent 392e6593ac
commit aef686af86
5 changed files with 82 additions and 6 deletions
+6 -4
View File
@@ -97,11 +97,13 @@ if __fish_config_op_enabled (status basename) tricks-bang
end
end
# Fish command history override to show timestamps
# Shadowing the history command is opinionated (C1 aliasing); when disabled,
# the function is never defined and fish's stock history behavior applies.
# Timestamped history view. Named pretty-history (not history) so it never
# shadows the fish builtin -- every function in this config that expects
# stock `history` semantics (search, --max, merge, ...) would otherwise
# silently break, which has happened more than once. Opinionated (C1
# aliasing); when disabled, the function is never defined.
if __fish_config_op_enabled (status basename) aliases-tricks
function history
function pretty-history --description 'History with timestamps prepended to every entry'
builtin history --show-time='%F %T '
end
end
+25
View File
@@ -703,6 +703,29 @@ ENTRY_HEADS = {
}
def _classification_tags(raw: list[str]) -> list[str]:
"""Split a CLASSIFICATION body into its comma-separated tags.
A plain comma split (as `names()` uses for DEPENDENCIES) would break on
the commas inside `uses-shadow(rm, cp)`-style tags, so this only splits
on commas at paren depth 0.
"""
text = " ".join(raw)
tags: list[str] = []
depth = 0
start = 0
for i, ch in enumerate(text):
if ch == "(":
depth += 1
elif ch == ")":
depth = max(0, depth - 1)
elif ch == "," and depth == 0:
tags.append(text[start:i].strip())
start = i + 1
tags.append(text[start:].strip())
return [t for t in tags if t]
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.
@@ -739,6 +762,7 @@ def render_entry(fn: dict[str, list[str]], used_by: list[str], link=None) -> str
refs = []
for label, values in (
("Dependencies", names(fn.get("DEPENDENCIES", []))),
("Classification", _classification_tags(fn.get("CLASSIFICATION", []))),
("Used by", sorted(used_by)),
):
if values:
@@ -884,6 +908,7 @@ def render_entry_site(fn: dict[str, list[str]], used_by: list[str], link=None) -
refs = []
for label, values in (
("Dependencies", names(fn.get("DEPENDENCIES", []))),
("Classification", _classification_tags(fn.get("CLASSIFICATION", []))),
("Used by", sorted(used_by)),
):
if values:
@@ -19,7 +19,6 @@ all of these commands.
rg rg --hyperlink-format=kitty system rg
mkdir verbose path-tree display on creation mkdir -p silently
bash XDG bashrc + $SHELL reset on exit system bash
history timestamps prepended to every entry fish builtin history
cp / mv forced -i confirmation prompt cp / mv unmodified
wget forced --continue (resume downloads) system wget
grep/fgrep/egrep forced --color=auto system grep variants
@@ -31,6 +30,11 @@ all of these commands.
When C1 is disabled, `rm` uses bare `command rm` with no wrapper — files
are permanently deleted, not trashed. There is no intermediate safety net.
`history` itself is never shadowed — every function in this config that
reads history depends on its stock builtin semantics. `pretty-history`
(same `aliases-tricks` toggle) is a separate command that prints history
with a timestamp prepended to every entry.
## Sub-categories
`__fish_config_op_aliases` sub-divides into six sub-categories, each with
@@ -63,3 +67,47 @@ and the `help config` interception.
`claude` (AGENTS.md/CLAUDE.md auto-linking) and `edit` (multi-editor
launcher), plus `agy`.
## For function authors
Calling one of these names bare from inside your own function means the
override runs whenever C1 (or its sub-category) is on — which may not be
what your function wants: a shadow can change stdout (`cat`'s syntax
highlighting, `mkdir`'s tree display), prompt interactively where none is
expected (`cp`/`mv`'s forced `-i`), or reshape output structurally (`ls`'s
icons/columns, `rg`'s hyperlink markers). If your function's logic depends
on stock behavior, bypass the shadow deterministically, regardless of the
toggle state:
Shadow Bypass Why
─────────────────────────────────────────────────────────────────────────
ls, cat, rm, less, du, command <name> Real external
top, ping, ssh, rg, binaries — a
mkdir, bash, cp, mv, real system command
wget, grep/fgrep/egrep, exists to fall
dir/vdir, claude back to.
cd builtin cd The one true
fish builtin
in this table.
help config __original_help $argv `help` is neither
a builtin nor an
external binary
(embedded in the
fish binary
itself) — see
conf.d/help.fish
for why the
wrapper keeps its
own backup copy.
edit (nothing to bypass to) Purely our own
invention, no
stock command
exists. Call
$EDITOR/$VISUAL
yourself if you
want a plain
editor launch.
A function's own doc header records which of these it depends on: see the
`CLASSIFICATION` label (`uses-shadow(...)` / `bypasses-shadow(...)`) in
`AGENTS/functions/CLAUDE.md`.
+1
View File
@@ -64,6 +64,7 @@ SECTIONS = (
"CATEGORY",
"COMPONENT",
"DEPENDENCIES",
"CLASSIFICATION",
"SYNOPSIS",
"DESCRIPTION",
"ARGUMENTS",
+1 -1
View File
@@ -34,7 +34,7 @@ function hist --description 'Search fish history and put it in the prompt'
return 1
end
set -l selected (history | fzf --reverse --height 40% --with-nth 3..)
set -l selected (builtin history --show-time='%F %T ' | fzf --reverse --height 40% --with-nth 3..)
if test -n "$selected"
# Strip the timestamp for the final output