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:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user