Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions great_docs/_build_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def estimate_build_time(
========= =========== ============================================
griffe 3.2 s/item Import + introspection (~1.3 s) **plus**
source-link resolution (~1.9 s) per
`_object_types.json` entry.
documented object.
quarto 0.5 s/page Markdown-only page render average
code cell 3.0 s/cell Jupyter kernel startup amortised per cell
post-rend 0.3 s/page HTML transforms (BeautifulSoup)
Expand All @@ -209,8 +209,9 @@ def estimate_build_time(
Parameters
----------
n_api_items
Total entries in `_object_types.json` (classes + methods +
functions + attributes — **not** just top-level exports).
Number of documented objects, counted as entries in the previous
build's `objects.inv` (classes, methods, functions and attributes,
**not** just top-level exports).
n_total_pages
Total `.qmd` / `.md` pages Quarto will render (reference +
user guide + sections + changelog + homepage + CLI).
Expand Down
25 changes: 19 additions & 6 deletions great_docs/assets/great-docs.scss
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ $font-family-monospace: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "
// Selectors for similar groups of elements that are created by the renderer
$docstring-sections: ":is(.doc-parameters, .doc-other-parameters, .doc-type-parameters, .doc-returns, .doc-yields, .doc-receives, .doc-raises, .doc-warns, .doc-attributes, .doc-parameter-attributes, .doc-init-parameters, .doc-see-also, .doc-examples)";
$doc-object-names: "span.doc-object-name:is(.doc-class-name, .doc-method-name, .doc-module-name, .doc-function-name, .doc-alias-name, .doc-attribute-name, .doc-type-name, .doc-typevar)";
$member-groups: "section:is(.doc-attributes, .doc-classes, .doc-type-aliases, .doc-methods, .doc-functions):not(.doc-pages)";

// Reference pages and the index links in their sidebars. Sidebar links include
// the path from the site root, so index links end in `/index.html`, and the
Expand Down Expand Up @@ -470,12 +471,24 @@ section:has(> h2.doc-notes, > h3.doc-notes) {
text-decoration: none;
}

// docstring spacing and indentation
section.doc-attributes > section.doc-attribute,
section.doc-methods > section.doc-method {
@extend .ps-4;
border-left: 0.025rem solid $gray-500;
backgroud-color: cyan;
// Rules between the members of a group: solid after the summary table,
// dotted between members. Drawn as a block before the member's heading so
// that the margins collapse as they would around an `<hr>`. The responsive
// tables script may wrap the summary table in `.gd-table-responsive`.
#{$member-groups} {
> :is(table, .gd-table-responsive) + section::before,
> section + section::before {
content: "";
display: block;
margin: 1.5rem 0 1rem 0;
border-top: 2px solid #c5c8cd;
opacity: 0.25;
}

> section + section::before {
border-top-style: dotted;
border-top-color: #b0b4ba;
}
}

// docstring section parameters
Expand Down
84 changes: 1 addition & 83 deletions great_docs/assets/post-render.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import annotations

import glob
import json
import os
import re
import sys
Expand Down Expand Up @@ -33,28 +32,6 @@ def _configure_stdio_for_unicode() -> None:
from pygments.formatters import HtmlFormatter
from pygments.lexers import PythonLexer

# Load object type metadata for accurate classification
# Keys are object names (e.g., "parser.ParserError"), values are type strings
# ("class", "namedtuple", "typeddict", "protocol", "abc", "exception", "function", "method", "constant", "enum", "type_alias", "other")
object_types = {}
object_types_path = "_object_types.json"
if os.path.exists(object_types_path):
print(f"Loading object types from {object_types_path}")
with open(object_types_path, "r", encoding="utf-8") as f:
object_types = json.load(f)
print(f"Loaded {len(object_types)} object type entries")
else:
print("No object types file found, falling back to heuristic classification")

# Load constant value metadata for displaying values on constant reference pages.
# Keys are constant names, values are dicts with optional "value" and "annotation".
constant_values: dict[str, dict[str, str]] = {}
constant_values_path = "_constant_values.json"
if os.path.exists(constant_values_path):
with open(constant_values_path, "r", encoding="utf-8") as f:
constant_values = json.load(f)
print(f"Loaded {len(constant_values)} constant value entries")

# Pygments class to Quarto class mapping
# Quarto uses different class names than Pygments default
PYGMENTS_TO_QUARTO_CLASS = {
Expand Down Expand Up @@ -226,73 +203,14 @@ def enhance_sig_name(m):
for html_file in html_files:
print(f"Processing: {html_file}")

# Extract the item name from the filename (e.g., "GreatDocs.html" -> "GreatDocs")
item_name_from_file = os.path.basename(html_file).replace(".html", "")

with open(html_file, "r", encoding="utf-8") as file:
content = file.read()

# Re-highlight the signature with Pygments for better syntax coloring
content = highlight_signature_with_pygments(content)

# Convert back to lines for line-by-line processing
content = content.splitlines(keepends=True)

content_str = "".join(content)

# Inject constant value/annotation into constant reference pages.
# Replaces the bare ``<p><code>NAME</code></p>`` that the renderer emits with a
# styled display showing the type annotation and assigned value.
obj_type_for_value = object_types.get(item_name_from_file)
if obj_type_for_value == "constant" and item_name_from_file in constant_values:
meta = constant_values[item_name_from_file]
annotation = meta.get("annotation", "")
value = meta.get("value", "")

# Build the display string: NAME: type = value
parts = [f"<code>{item_name_from_file}</code>"]
if annotation:
parts.append(f'<code style="color: #6b7280;">: {annotation}</code>')
if value:
parts.append(f'<code style="color: #6b7280;"> = {value}</code>')
replacement_html = "<p>" + "".join(parts) + "</p>"

# Replace the original bare name paragraph
bare_name_html = f"<p><code>{item_name_from_file}</code></p>"
if bare_name_html in content_str:
content_str = content_str.replace(bare_name_html, replacement_html, 1)

content = content_str.splitlines(keepends=True)

# Add separator lines between class details and individual members,
# and between individual member sections.
# - Thin solid line after the Methods/Attributes summary table (before first member section)
# - Dotted line between each individual member section
for i, line in enumerate(content):
# Individual members render as `level3` sections.
if "<section id=" in line and 'class="level3"' in line:
# Check if the previous non-blank line ends a table (</table> in </section>)
# or closes another member section
for j in range(i - 1, max(0, i - 5), -1):
prev = content[j].strip()
if not prev:
continue
if "</table>" in prev:
# First member section after a summary table — solid line
content[i] = (
'<hr style="border: none; border-top: 2px solid #c5c8cd; margin: 1.5rem 0 1rem 0;">\n'
+ content[i]
)
elif "</section>" in prev:
# Between member sections — dotted line
content[i] = (
'<hr style="border: none; border-top: 2px dotted #b0b4ba; margin: 1.5rem 0 1rem 0;">\n'
+ content[i]
)
break

with open(html_file, "w", encoding="utf-8") as file:
file.writelines(content)
file.write(content)


print("Finished processing all files")
Expand Down
Loading
Loading