Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_austenite/src/bin/diagram_demo.rs

4.3 KiB, 28 runs

created by r1870400018:36159, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//! `diagram_demo` -- draws the compile-loop flowchart and sets it in a real document.
2//!
3//! Builds the flowchart from the diagram DSL section of the Austenite language document -- Source
4//! through Parse, a Types-OK? decision, Lay out and Write Pearl, with a Report-error box off the
5//! decision and an orthogonal "fix" edge back to the parser -- wraps it as a captioned figure, and
6//! authors a one-page document around it: a heading, a sentence of prose, then the figure. The whole
7//! is run through the two-pass driver, decorated with a folio, and written as SVG pages and a PDF, so
8//! the flowchart's boxes, routed edges and shaped labels land on a typeset page.
9//!
10//! Usage: `diagram_demo [OUTPUT_DIR]` (default `diagram-out`).
11
12use oxedyne_fe2o3_austenite::{
13 diagram::{
14 layout::Route,
15 shape::{
16 Port,
17 Shape,
18 },
19 Diagram,
20 DiagramStyle,
21 Endpoint,
22 },
23 doc::{
24 self,
25 Block,
26 },
27 theme::Theme,
28 driver::{
29 self,
30 Config,
31 },
32 emit::Emitter,
33 font::FontMetrics,
34 ir::{
35 Graphic,
36 Sp,
37 },
38 page::PageGeometry,
39};
40
41use oxedyne_fe2o3_core::prelude::*;
42use oxedyne_fe2o3_font::{
43 face::Role,
44 set::FontSet,
45 shape::Dir,
46};
47
48use std::sync::Arc;
49
50fn main() -> Outcome<()> {
51 let args: Vec<String> = std::env::args().collect();
52 let out_dir = match args.get(1) {
53 Some(s) => s.clone(),
54 None => "diagram-out".to_string(),
55 };
56
57 let fonts = Arc::new(res!(oxedyne_fe2o3_austenite::fonts::libertinus()));
58 let geom = PageGeometry::a4();
59 let style = Theme::default();
60
61 let graphic = res!(compile_loop(fonts.clone()));
62 println!(
63 "diagram_demo: flowchart is {:.1} x {:.1} pt.",
64 graphic.dims.width.to_pt(), graphic.dims.height.to_pt());
65
66 let blocks = vec![
67 Block::heading(1, "A Flowchart Set on the Page"),
68 Block::paragraph(
69 "The figure below is drawn in Austenite's diagram sub-language: its boxes and edges are the \
70 same outline paths the body text is, and its labels are shaped in the document's own font. \
71 It shows the engine's own compile loop, the parser fed again whenever the type check fails."),
72 Block::figure(graphic, Some("The compile loop".to_string()), None),
73 ];
74
75 let (document, heads) = res!(doc::author(fonts.clone(), geom, &style, &oxedyne_fe2o3_austenite::fonts::FaceResolver::default(), &blocks, None, None));
76
77 let metrics = FontMetrics::new(fonts.clone(), Role::Body, Dir::Ltr, style.text.body_size);
78 let mut out = res!(driver::run(&document, &metrics, Config::default()));
79 res!(doc::decorate(&mut out.pages, &out.ledger, &heads, &fonts, &style, geom, "", None));
80
81 res!(std::fs::create_dir_all(&out_dir));
82 let emitter = Emitter::Svg;
83 for page in &out.pages {
84 let svg = res!(emitter.render(page));
85 let path = fmt!("{}/page-{:03}.{}", out_dir, page.number, emitter.extension());
86 res!(std::fs::write(&path, svg));
87 }
88
89 let pdf = res!(oxedyne_fe2o3_austenite::emit::pdf::render_document(&out.pages));
90 res!(std::fs::write(fmt!("{}/document.pdf", out_dir), pdf));
91
92 println!(
93 "diagram_demo: composed {} page(s) in {} pass(es); wrote SVG page(s) and document.pdf to {}/",
94 out.pages.len(), out.passes, out_dir);
95 Ok(())
96}
97
98/// The compile-loop flowchart, exactly the graph the language document's DSL example draws.
99fn compile_loop(fonts: Arc<FontSet>) -> Outcome<Graphic> {
100 let down = Sp::from_pt(30.0);
101 let down_lo = Sp::from_pt(34.0); // a touch more room beneath the diamond
102 let across = Sp::from_pt(70.0);
103
104 let mut d = Diagram::new();
105 d.node_at("src", "Source", Sp::ZERO, Sp::ZERO, Shape::Stadium)
106 .node_below("parse", "Parse", "src", down, Shape::Box)
107 .node_below("check", "Types OK?", "parse", down, Shape::Diamond)
108 .node_below("layout", "Lay out", "check", down_lo, Shape::Box)
109 .node_below("pearl", "Write Pearl", "layout", down, Shape::Stadium)
110 .node_right("err", "Report error", "check", across, Shape::Box);
111
112 d.edge(Endpoint::node("src"), Endpoint::node("parse"), None, Route::Straight)
113 .edge(Endpoint::node("parse"), Endpoint::node("check"), None, Route::Straight)
114 .edge(Endpoint::port("check", Port::South), Endpoint::node("layout"), Some("yes"), Route::Straight)
115 .edge(Endpoint::port("check", Port::East), Endpoint::port("err", Port::West), Some("no"), Route::Straight)
116 .edge(Endpoint::port("err", Port::North), Endpoint::port("parse", Port::East), Some("fix"), Route::Orthogonal)
117 .edge(Endpoint::node("layout"), Endpoint::node("pearl"), None, Route::Straight);
118
119 d.build(fonts, &DiagramStyle::default())
120}