OpenCAD Studio User Manual
#!/usr/bin/env python3
"""Build the static OpenCAD Studio HTML help system from help/manual.md."""
from __future__ import annotations
import argparse
import html
import json
import re
import subprocess
import sys
from dataclasses import dataclass
from html.parser import HTMLParser
from pathlib import Path
HELP = Path(__file__).resolve().parents[1]
SOURCE = HELP / "manual.md"
@dataclass(frozen=True)
class Page:
filename: str
title: str
summary: str
PAGES = (
Page("getting-started.html", "Getting Started", "Begin a drawing safely and learn how to use this manual."),
Page("files-drawings.html", "Files and Drawings", "Open, save, recover, and move drawings with their dependencies."),
Page("workspace-navigation.html", "Workspace and Navigation", "Work with spaces, views, selection, and object snaps."),
Page("create-edit-geometry.html", "Create and Edit Geometry", "Draw, modify, grip-edit, erase, and restore geometry."),
Page("layers-properties.html", "Layers and Properties", "Organize objects and control their inherited appearance."),
Page("blocks-references.html", "Blocks and References", "Create reusable content, arrays, attributes, and file references."),
Page("annotation-dimensions.html", "Annotation and Dimensions", "Add readable text, dimensions, leaders, and scaled annotation."),
Page("layouts-plotting.html", "Layouts and Plotting", "Prepare paper-space sheets and verify plotted output."),
Page("3d-modeling.html", "3D Modeling and Visualization", "Create and inspect solids, surfaces, materials, and visual styles."),
Page("parametric-constraints.html", "Parametric Constraints", "Capture geometric intent and diagnose solve or history issues."),
Page("commands-shortcuts.html", "Commands and Shortcuts", "Use prompts, autocomplete, aliases, and keyboard conventions."),
Page("automation-plugins.html", "Automation and Plugins", "Control drawings programmatically and extend the native app."),
Page("troubleshooting-recovery.html", "Troubleshooting and Recovery", "Diagnose file, geometry, rendering, and history problems."),
)
def slug(text: str) -> str:
value = re.sub(r"[^\w\s-]", "", text.lower(), flags=re.UNICODE)
value = re.sub(r"[\s_]+", "-", value)
return value.strip("-")
def split_chapters(markdown: str) -> dict[str, str]:
chapters: dict[str, list[str]] = {}
current: list[str] | None = None
for line in markdown.splitlines():
match = re.match(r"^## (.+)$", line)
if match:
title = match.group(1).strip()
if title in chapters:
raise RuntimeError(f"Duplicate chapter: {title}")
current = [line]
chapters[title] = current
elif current is not None:
current.append(line)
return {title: "\n".join(lines) for title, lines in chapters.items()}
def pandoc(markdown: str) -> str:
process = subprocess.run(
["pandoc", "--from=gfm", "--to=html5", "--wrap=none"],
input=markdown,
text=True,
capture_output=True,
check=True,
)
return process.stdout.strip()
def headings(markdown: str) -> list[tuple[str, str]]:
output: list[tuple[str, str]] = []
for line in markdown.splitlines():
match = re.match(r"^### (.+)$", line)
if match:
title = match.group(1).strip()
output.append((slug(title), title))
return output
def sidebar(current: Page | None, chapters: dict[str, str]) -> str:
parts = ['")
return "\n".join(parts)
def overview() -> str:
cards = "".join(
f'{html.escape(page.title)}'
f'{html.escape(page.summary)}'
for page in PAGES
)
return f"""
OpenCAD Studio User Manual Learn how to create and edit drawings, exchange DWG and DXF files, prepare layouts, model in 3D, use constraints, automate work, and recover from common problems.Find the workflow, command, or concept you need
OpenCAD Studio User Manual