diff --git a/.github/wiki/README.md b/.github/wiki/README.md index 6588bec4..06c53b87 100644 --- a/.github/wiki/README.md +++ b/.github/wiki/README.md @@ -18,6 +18,12 @@ touches `man/**` or this tooling. - `extras/.md` — optional hand-maintained appendix (screenshots, showcase snippets that have no man equivalent), appended verbatim after the generated body. +The generator also keeps `_Sidebar.md` in sync: any `Module:-*` page in the mapping +that is not yet linked in the sidebar is inserted alphabetically into the `Modules:` +list. Existing sidebar entries (custom labels, nested sub-entries, hand-written +non-module links) are never modified — so a new module auto-appears in navigation +without disturbing the curated structure. + ## What it touches Only the pages listed in `mapping.json` are (re)written. Every other wiki page diff --git a/.github/wiki/generate.py b/.github/wiki/generate.py index 7e84e0d9..f915bec1 100755 --- a/.github/wiki/generate.py +++ b/.github/wiki/generate.py @@ -90,6 +90,54 @@ def build_page(man_dir, sources, page, extras_dir): return "\n".join(parts).rstrip() + "\n" +ENTRY_RE = re.compile(r"^ - \[([^\]]+)\]\(\./Module:-") +LINK_RE = re.compile(r"\]\(\./(Module:-[^)]+)\)") + + +def sync_sidebar(out_dir, mapping): + """Non-destructively add any mapped Module page missing from _Sidebar.md. + + Only inserts links for pages absent from the sidebar; existing entries + (custom labels, nested sub-entries, hand-written non-module links) are + never modified. Insertion is alphabetical within the top-level module list. + """ + path = os.path.join(out_dir, "_Sidebar.md") + if not os.path.exists(path): + print(" no _Sidebar.md; skipping sidebar sync") + return + lines = open(path).read().splitlines() + linked = set(LINK_RE.findall("\n".join(lines))) + missing = sorted((p for p in mapping + if p.startswith("Module:-") and p not in linked), + key=str.lower) + if not missing: + print(" sidebar up to date") + return + + def entries(): + return [i for i, l in enumerate(lines) if ENTRY_RE.match(l)] + + if not entries(): + print(" could not locate Modules section; skipping sidebar sync") + return + for page in missing: + label = page[len("Module:-"):].replace("-", " ") + new_line = f" - [{label}](./{page})" + pos = None + for i in entries(): + if ENTRY_RE.match(lines[i]).group(1).lower() > label.lower(): + pos = i + break + if pos is None: # after the last module entry and its sub-entries + j = entries()[-1] + 1 + while j < len(lines) and lines[j].startswith(" "): + j += 1 + pos = j + lines.insert(pos, new_line) + print(f" sidebar += {label}") + open(path, "w").write("\n".join(lines) + "\n") + + def main(): ap = argparse.ArgumentParser() ap.add_argument("--man-dir", default="man") @@ -130,6 +178,7 @@ def main(): out = os.path.join(args.out_dir, page + ".md") open(out, "w").write(build_page(args.man_dir, sources, page, extras_dir)) print(f" wrote {page}.md ({', '.join(sources)})") + sync_sidebar(args.out_dir, mapping) return 0