Two small fixes. - `OptionsFrame.xml`: the comment on the missing Use UI Scale checkbox said benilla has no `useUiScale`. It is registered at "0" and never read, which is why the UI scale always applies. - `scripts/doc-links.py`: `--help` and `-h` print the usage in the module doc instead of running the full `cargo doc` pass. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
102 lines
3.6 KiB
Python
Executable File
102 lines
3.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Fail on a doc link whose target is declared nowhere in the workspace.
|
|
|
|
It reads rustdoc's unresolved-link warnings and fails on a `crate::`, `super::`, `self::` or
|
|
`Self::` path whose leaf name is declared nowhere: the item is gone. Every other warning is a
|
|
convention here, not rot (a private module named through its parent, another crate's module
|
|
named with `crate::`, a bare name for an unimported bevy type).
|
|
|
|
scripts/doc-links.py # the gate: exit 1 on any dead-target link
|
|
scripts/doc-links.py --report # + the benign counts
|
|
|
|
The leaf test is a loose declaration grep: a name declared anywhere counts, since what it catches
|
|
is a deleted item, not a misspelled path.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
def run_rustdoc() -> str:
|
|
out = subprocess.run(
|
|
["cargo", "doc", "--workspace", "--no-deps", "--document-private-items"],
|
|
cwd=ROOT,
|
|
capture_output=True,
|
|
text=True,
|
|
)
|
|
return out.stderr + out.stdout
|
|
|
|
|
|
def declared_names() -> set[str]:
|
|
"""Every name the workspace declares, in one scan: a grep per link is too slow for a gate."""
|
|
names: set[str] = set()
|
|
# `fn` gets its own pattern: in one alternation, `const fn foo` captures "fn" and never
|
|
# indexes `foo`.
|
|
pats = [
|
|
re.compile(r"\bfn\s+([A-Za-z_][A-Za-z0-9_]*)"),
|
|
re.compile(r"\b(?:struct|enum|trait|type|const|static|union|mod)\s+([A-Za-z_][A-Za-z0-9_]*)"),
|
|
re.compile(r"\bmacro_rules!\s+([A-Za-z_][A-Za-z0-9_]*)"),
|
|
]
|
|
for rs in (ROOT / "crates").rglob("*.rs"):
|
|
try:
|
|
text = rs.read_text(encoding="utf-8", errors="replace")
|
|
except OSError:
|
|
continue
|
|
for pat in pats:
|
|
names.update(pat.findall(text))
|
|
names.discard("fn")
|
|
return names
|
|
|
|
|
|
def main() -> int:
|
|
if any(a in ("-h", "--help") for a in sys.argv[1:]):
|
|
print(__doc__.strip())
|
|
return 0
|
|
report = "--report" in sys.argv
|
|
text = run_rustdoc()
|
|
found = re.findall(r"warning: unresolved link to `([^`]+)`\n\s*--> ([^\s:]+):(\d+)", text)
|
|
|
|
names = declared_names()
|
|
dead, benign = [], 0
|
|
for target, path, line in found:
|
|
# Only a `crate::`/`super::`/`self::`/`Self::` path asserts a local item; a bare name may
|
|
# be a bevy type not imported for linking (`SystemParam`), which is not rot.
|
|
if not re.match(r"^(crate|super|self|Self)::", target):
|
|
benign += 1
|
|
continue
|
|
leaf = target.split("::")[-1].split("(")[0].strip()
|
|
if not leaf or not re.match(r"^[A-Za-z_][A-Za-z0-9_]*$", leaf):
|
|
benign += 1
|
|
continue
|
|
if leaf in names:
|
|
benign += 1
|
|
else:
|
|
dead.append((target, path, line))
|
|
|
|
if report:
|
|
print(f"doc-links: {len(found)} unresolved-link warnings")
|
|
print(f"doc-links: {benign} name something that still exists (see this file's header)")
|
|
|
|
if not dead:
|
|
print(f"doc-links ok: no doc link points at a deleted item ({len(found)} benign)")
|
|
return 0
|
|
|
|
print(f"doc-links FAILED: {len(dead)} doc link(s) point at something that no longer exists:\n")
|
|
for target, path, line in dead:
|
|
print(f" {path}:{line}\n [`{target}`]")
|
|
print(
|
|
"\nEach names an item declared nowhere in the workspace. Repoint it at whatever replaced\n"
|
|
"the thing, or drop the brackets — a dangling link promises navigation that is not there."
|
|
)
|
|
return 1
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|