Skip to content

Commit 739c572

Browse files
authored
Merge pull request #3 from phaseLineStudios/feature/betterIndex
Feature - Better index
2 parents 006a7d2 + f8e05ad commit 739c572

File tree

2 files changed

+142
-17
lines changed

2 files changed

+142
-17
lines changed

gdscript_to_docs/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
__all__ = ["__version__"]
2-
__version__ = "0.1.4"
2+
__version__ = "0.1.5"

gdscript_to_docs/writer.py

Lines changed: 141 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from __future__ import annotations
22
from pathlib import Path
3-
from typing import Dict, List, Tuple
3+
from typing import Dict, List, Tuple, Optional
4+
from datetime import datetime
45
from .models import ScriptDoc
56
from .parser import parse_gd_script
67
from .render import render_script_markdown, render_function_markdown
78
from .indexer import build_index_for_docs, compute_reference_links_for_function
8-
from .utils import slug, rel_href
9+
from .utils import slug, rel_href, split_brief_details
910

1011
def write_docs(
1112
src: Path,
@@ -107,17 +108,141 @@ def write_docs(
107108
path.write_text(md, encoding="utf-8")
108109

109110
if make_index and not single_file:
110-
index_lines = ["# Index", ""]
111-
for d, _, path in rendered:
112-
rel = path.relative_to(out)
113-
index_lines.append(f"- [{d.class_name or d.path.stem}]({rel.as_posix()})")
114-
if split_functions:
115-
class_basename = d.class_name or d.path.stem
116-
func_root = rel.parent / class_basename / "functions"
117-
real_func_root = out / func_root
118-
if real_func_root.exists():
119-
for m in [m for m in d.members if m.kind == "func"]:
120-
f = real_func_root / f"{slug(m.name)}.md"
121-
if f.exists():
122-
index_lines.append(f" - [{m.name}]({(rel.parent / class_basename / 'functions' / f.name).as_posix()})")
123-
(out / "INDEX.md").write_text("\n".join(index_lines) + "\n", encoding="utf-8")
111+
write_index(out=out, rendered=rendered, split_functions=split_functions)
112+
113+
def write_index(
114+
out: Path,
115+
rendered: list[tuple["ScriptDoc", str, Path]],
116+
split_functions: bool,
117+
) -> None:
118+
"""
119+
Write a structured index under ``out/_index/``.
120+
Args:
121+
out: Output directory where docs were written.
122+
rendered: List of tuples (ScriptDoc, rendered_markdown, class_md_path).
123+
split_functions: Whether function pages were split out.
124+
"""
125+
index_dir = out / "_index"
126+
index_dir.mkdir(parents=True, exist_ok=True)
127+
128+
class_rows = []
129+
for d, _, class_md_path in rendered:
130+
title = d.class_name or d.path.stem
131+
rel_class_md = class_md_path.relative_to(out)
132+
parent_rel_dir = rel_class_md.parent
133+
extends = d.extends or ""
134+
counts = {
135+
"func": sum(1 for m in d.members if m.kind == "func"),
136+
"var": sum(1 for m in d.members if m.kind == "var"),
137+
"const":sum(1 for m in d.members if m.kind == "const"),
138+
"signal":sum(1 for m in d.members if m.kind == "signal"),
139+
"enum": sum(1 for m in d.members if m.kind == "enum"),
140+
}
141+
class_rows.append((title, rel_class_md, parent_rel_dir, extends, counts))
142+
143+
by_folder_lines = ["# Classes by Folder", ""]
144+
from collections import defaultdict
145+
classes_by_folder: dict[str, list[tuple[str, Path, str, dict]]] = defaultdict(list)
146+
for title, rel_md, parent_dir, extends, counts in class_rows:
147+
classes_by_folder[parent_dir.as_posix()].append((title, rel_md, extends, counts))
148+
for folder in sorted(classes_by_folder.keys(), key=lambda s: (s.count("/"), s)):
149+
depth = 0 if folder == "." else folder.count("/") + (0 if not folder else 1)
150+
header_prefix = "#" * max(2, min(6, depth + 2))
151+
folder_label = folder if folder and folder != "." else "(root)"
152+
by_folder_lines.append(f"{header_prefix} {folder_label}")
153+
by_folder_lines.append("")
154+
for title, rel_md, extends, counts in sorted(classes_by_folder[folder], key=lambda r: r[0].lower()):
155+
href = rel_href(rel_md, start_rel=Path("_index")) # file lives at _index/by-folder.md
156+
summary = f"{counts['func']} funcs · {counts['var']} vars · {counts['signal']} signals · {counts['const']} consts · {counts['enum']} enums"
157+
ext = f" — *inherits* `{extends}`" if extends else ""
158+
by_folder_lines.append(f"- [{title}]({href}) — {summary}{ext}")
159+
by_folder_lines.append("")
160+
161+
(index_dir / "by-folder.md").write_text("\n".join(by_folder_lines).rstrip() + "\n", encoding="utf-8")
162+
163+
classes_lines = ["# Classes A–Z", ""]
164+
buckets: dict[str, list[tuple[str, Path, str, dict]]] = defaultdict(list)
165+
for title, rel_md, _, extends, counts in class_rows:
166+
first = title[0].upper() if title else "#"
167+
if not ("A" <= first <= "Z"):
168+
first = "#"
169+
buckets[first].append((title, rel_md, extends, counts))
170+
171+
letters = [c for c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ"] + ["#"]
172+
classes_lines.append("**Jump to:** " + " · ".join(f"[{L}](#{L.lower()})" for L in letters))
173+
classes_lines.append("")
174+
175+
for L in letters:
176+
if L not in buckets:
177+
continue
178+
classes_lines.append(f"## {L}")
179+
classes_lines.append("")
180+
for title, rel_md, extends, counts in sorted(buckets[L], key=lambda r: r[0].lower()):
181+
href = rel_href(rel_md, start_rel=Path("_index"))
182+
summary = f"{counts['func']} funcs · {counts['var']} vars · {counts['signal']} signals"
183+
ext = f" — *inherits* `{extends}`" if extends else ""
184+
classes_lines.append(f"- [{title}]({href}) — {summary}{ext}")
185+
classes_lines.append("")
186+
187+
(index_dir / "classes.md").write_text("\n".join(classes_lines).rstrip() + "\n", encoding="utf-8")
188+
189+
if split_functions:
190+
funcs_lines = ["# Functions A–Z", ""]
191+
fn_buckets: dict[str, list[tuple[str, str, Path, Optional[str]]]] = defaultdict(list)
192+
for d, _, class_md_path in rendered:
193+
class_title = d.class_name or d.path.stem
194+
class_rel = class_md_path.relative_to(out)
195+
functions_dir = class_rel.parent / class_title / "functions"
196+
for m in (mm for mm in d.members if mm.kind == "func"):
197+
fpath = functions_dir / f"{slug(m.name)}.md"
198+
real_path = out / fpath
199+
if not real_path.exists():
200+
continue
201+
first = (m.name[0].upper() if m.name else "#")
202+
if not ("A" <= first <= "Z"):
203+
first = "#"
204+
brief = None
205+
if m.doc and m.doc.markdown:
206+
b, _ = split_brief_details(m.doc.markdown)
207+
brief = b or None
208+
fn_buckets[first].append((class_title, m.name, fpath, brief))
209+
210+
funcs_lines.append("**Jump to:** " + " · ".join(f"[{L}](#{L.lower()})" for L in letters))
211+
funcs_lines.append("")
212+
213+
for L in letters:
214+
if L not in fn_buckets:
215+
continue
216+
funcs_lines.append(f"## {L}")
217+
funcs_lines.append("")
218+
for class_title, fname, rel_fn_md, brief in sorted(fn_buckets[L], key=lambda r: (r[1].lower(), r[0].lower())):
219+
href = rel_href(rel_fn_md, start_rel=Path("_index"))
220+
title = f"{class_title}::{fname}"
221+
line = f"- [{title}]({href})"
222+
if brief:
223+
line += f" — {brief}"
224+
funcs_lines.append(line)
225+
funcs_lines.append("")
226+
(index_dir / "functions.md").write_text("\n".join(funcs_lines).rstrip() + "\n", encoding="utf-8")
227+
228+
now = datetime.now().strftime("%Y-%m-%d %H:%M")
229+
main = [
230+
"# Game API Reference",
231+
"",
232+
f"*Generated on:* {now}",
233+
"",
234+
"### Navigation",
235+
"",
236+
"- **By Folder:** [_index/by-folder.md](_index/by-folder.md)",
237+
"- **Classes A–Z:** [_index/classes.md](_index/classes.md)",
238+
]
239+
if split_functions:
240+
main.append("- **Functions A–Z:** [_index/functions.md](_index/functions.md)")
241+
main += [
242+
"",
243+
"### Tips",
244+
"",
245+
"- Use your viewer’s search (e.g. GitHub’s file search or browser **Ctrl/⌘+F**).",
246+
"- Each class page has a summary and detailed sections (functions, signals, etc.).",
247+
]
248+
(out / "INDEX.md").write_text("\n".join(main).rstrip() + "\n", encoding="utf-8")

0 commit comments

Comments
 (0)