summaryrefslogtreecommitdiff
path: root/graph/render_docs.py
diff options
context:
space:
mode:
authorDibyendu Majumdar <mobile@majumdar.org.uk>2023-08-19 08:52:57 -0700
committerDibyendu Majumdar <mobile@majumdar.org.uk>2026-10-04 13:30:41 -0700
commit787a37d6b1753bb7c6abd36cba293737ad6b9a0a (patch)
treed26601274ec93203ca8df7bd2e71cf8b52d12d9b /graph/render_docs.py
downloadSimple-787a37d6b1753bb7c6abd36cba293737ad6b9a0a.tar.gz
Simple-787a37d6b1753bb7c6abd36cba293737ad6b9a0a.zip
Chapter 1: Introduction
Co-authored-by: Cliff Click <cliffc@acm.org> Co-authored-by: Thalia Archibald <thalia@archibald.dev> Co-authored-by: hadha <helsgithub15@gmail.com> Co-authored-by: XmiliaH <45106915+XmiliaH@users.noreply.github.com> Co-authored-by: Tamás Hadházy <85063808+Hels15@users.noreply.github.com>
Diffstat (limited to 'graph/render_docs.py')
-rw-r--r--graph/render_docs.py71
1 files changed, 71 insertions, 0 deletions
diff --git a/graph/render_docs.py b/graph/render_docs.py
new file mode 100644
index 00000000..a0c5ec26
--- /dev/null
+++ b/graph/render_docs.py
@@ -0,0 +1,71 @@
+"""Render documentation snapshots with the same layout and SVG export as make view.
+
+Requires Python Playwright and an installed browser; not needed to build chapters.
+Example: python graph/render_docs.py --browser msedge chapter01/docs/01-graph.json
+"""
+import argparse
+from functools import partial
+from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
+import json
+from pathlib import Path
+from threading import Thread
+from playwright.sync_api import sync_playwright
+
+
+class QuietHandler(SimpleHTTPRequestHandler):
+ def log_message(self, *args):
+ pass
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('--browser', default='chromium', choices=['chromium', 'msedge', 'chrome', 'firefox'])
+ parser.add_argument('snapshots', nargs='+', type=Path)
+ args = parser.parse_args()
+ web = Path(__file__).resolve().parent / 'web'
+ server = ThreadingHTTPServer(('127.0.0.1', 0), partial(QuietHandler, directory=str(web)))
+ Thread(target=server.serve_forever, daemon=True).start()
+ try:
+ with sync_playwright() as pw:
+ engine = pw.firefox if args.browser == 'firefox' else pw.chromium
+ options = {'channel': args.browser} if args.browser in ('msedge', 'chrome') else {}
+ browser = engine.launch(headless=True, **options)
+ page = browser.new_page(reduced_motion='reduce')
+ # No connection to a compiler or to the user's live viewer session.
+ page.route_web_socket('**', lambda ws: ws.on_message(lambda message: None))
+ page.goto(f'http://127.0.0.1:{server.server_port}/index.html')
+ page.wait_for_function('rendererReady')
+ page.evaluate('''() => {
+ layout = new GraphLayout();
+ document.getElementById("assocs").checked = true;
+ document.getElementById("near").checked = false;
+ }''')
+ for source in args.snapshots:
+ snap = json.loads(source.read_text(encoding='utf-8'))
+ page.evaluate('''async snap => {
+ const evt = {kind: "PHASE", phase: "Documentation", near: [], temps: []};
+ const scene = await layout.run(snap, evt);
+ renderer.show(snap, scene, evt);
+ renderer.select(0);
+ }''', snap)
+ # Capture the normal export's Blob without bulk browser downloads.
+ svg = page.evaluate('''async () => {
+ const create = URL.createObjectURL, click = HTMLAnchorElement.prototype.click;
+ let blob;
+ URL.createObjectURL = value => { blob = value; return create(value); };
+ HTMLAnchorElement.prototype.click = () => {};
+ try { renderer.save(1); }
+ finally { URL.createObjectURL = create; HTMLAnchorElement.prototype.click = click; }
+ return await blob.text();
+ }''')
+ target = source.with_suffix('.svg')
+ target.write_text(svg + '\n', encoding='utf-8', newline='\n')
+ print(target)
+ browser.close()
+ finally:
+ server.shutdown()
+ server.server_close()
+
+
+if __name__ == '__main__':
+ main()