diff --git a/Cargo.lock b/Cargo.lock index 186c520769..6f5b8e5e45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -263,9 +263,9 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "railroad" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "813b53dbe6d583f1ac0c3fb394e0ce3b613530adff8265c274fcdfcd82cc6da5" +checksum = "7286d8b4d9fc00078819e06ff24cefa276f39461ff53b74d63d24736be27192f" dependencies = [ "unicode-width", ] diff --git a/theme/reference.css b/theme/reference.css index ab4f9e5675..fa48768881 100644 --- a/theme/reference.css +++ b/theme/reference.css @@ -1,15 +1,6 @@ /* Custom CSS for the Rust Specification. */ /* Per-theme variables. */ -:root { - --railroad-background-color: hsl(30, 20%, 95%); - --railroad-background-image: - linear-gradient(to right, rgba(30, 30, 30, .05) 1px, transparent 1px), - linear-gradient(to bottom, rgba(30, 30, 30, .05) 1px, transparent 1px); - --railroad-path-stroke: black; - --railroad-rect-stroke: black; - --railroad-rect-fill: hsl(-290, 70%, 90%); -} .light { --alert-note-color: #0969da; --alert-warning-color: #9a6700; @@ -45,14 +36,6 @@ .coal, .navy, .ayu { --grammar-comment-color: lch(from var(--quote-bg) calc(l + 50) 0 0); --inline-code-color: var(--grammar-comment-color); - --railroad-background-color: hsl(230, 10%, 20%); - --railroad-background-image: - linear-gradient(to right, rgba(150, 150, 150, .05) 1px, transparent 1px), - linear-gradient(to bottom, rgba(150, 150, 150, .05) 1px, transparent 1px); - --railroad-path-stroke: hsl(200, 10%, 60%); - --railroad-text-fill: hsl(230, 30%, 80%); - --railroad-rect-stroke: hsl(200, 10%, 50%); - --railroad-rect-fill: hsl(230, 20%, 20%); } /* @@ -686,55 +669,25 @@ main > .rule { display: none; } -svg.railroad { - background-color: var(--railroad-background-color); - background-size: 15px 15px; - background-image: var(--railroad-background-image); -} - -svg.railroad rect.railroad_canvas { - stroke-width: 0px; - fill: none; -} - -svg.railroad path { - stroke-width: 3px; - stroke: var(--railroad-path-stroke); - fill: none; -} - -svg.railroad .debug { - stroke-width: 1px; - stroke: red; -} - -svg.railroad text { - font: 14px monospace; - text-anchor: middle; - fill: var(--railroad-text-fill); -} - -svg.railroad .nonterminal text { - font-weight: bold; -} - -svg.railroad text.comment { - font: italic 12px monospace; -} +/* +The theme-specific railroad backgrounds intentionally match mdBook's page +backgrounds. Offset only their lightness here so embedded diagrams remain +visually distinct while retaining each theme's hue and saturation. The Light +railroad theme already provides this contrast itself. -svg.railroad rect { - stroke-width: 3px; - stroke: var(--railroad-rect-stroke); - fill: var(--railroad-rect-fill); +Including `html` makes these selectors more specific than the stylesheets +embedded by mdbook-spec. +*/ +html.rust svg.railroad { + background-color: hsl(from var(--bg) h s calc(l - 5)); } - -svg.railroad g.labeledbox>rect { - stroke-width: 1px; - stroke: grey; - stroke-dasharray: 5px; - fill: rgba(90, 90, 150, .1); +html.coal svg.railroad, +html.navy svg.railroad, +html.ayu svg.railroad { + background-color: hsl(from var(--bg) h s calc(l + 5)); } +/* Styling specific to the Reference's negative-lookahead railroad node. */ svg.railroad g.exceptbox > rect { fill:rgba(245, 160, 125, .1); } diff --git a/tools/mdbook-spec/Cargo.toml b/tools/mdbook-spec/Cargo.toml index 3a86ed03cf..68b9aefabe 100644 --- a/tools/mdbook-spec/Cargo.toml +++ b/tools/mdbook-spec/Cargo.toml @@ -16,7 +16,7 @@ mdbook-markdown = "0.5.1" mdbook-preprocessor = "0.5.1" once_cell = "1.19.0" pathdiff = "0.2.1" -railroad = { version = "0.3.7", default-features = false } +railroad = { version = "0.3.9", default-features = false } regex = "1.12.2" semver = "1.0.21" serde_json = "1.0.113" diff --git a/tools/mdbook-spec/src/grammar.rs b/tools/mdbook-spec/src/grammar.rs index 8aa98d3608..de51f825dc 100644 --- a/tools/mdbook-spec/src/grammar.rs +++ b/tools/mdbook-spec/src/grammar.rs @@ -72,7 +72,16 @@ pub fn insert_grammar(grammar: &Grammar, chapter: &Chapter, diag: &mut Diagnosti .unwrap(); } } - content + + // Inject the stylesheets for railroad diagrams if necessary + if content.contains("class=\"railroad\"") { + format!( + "\n\n{content}", + render_railroad::themed_stylesheets() + ) + } else { + content + } } /// Converts link reference definitions that point to a grammar rule diff --git a/tools/mdbook-spec/src/grammar/render_railroad.rs b/tools/mdbook-spec/src/grammar/render_railroad.rs index e5fa0bf312..9f4c3c5398 100644 --- a/tools/mdbook-spec/src/grammar/render_railroad.rs +++ b/tools/mdbook-spec/src/grammar/render_railroad.rs @@ -15,6 +15,30 @@ const CHOICE_MAX_ROWS_PER_COLUMN: usize = 5; /// use as many rows as necessary const CHOICE_MAX_COLUMNS: usize = 4; +/// Returns the railroad stylesheets, scoped to their corresponding mdBook themes. +/// +/// mdBook selects a theme by placing its lowercase name on the root element. Scoping +/// each railroad stylesheet to that class lets the diagrams follow theme changes at +/// runtime without duplicating the styles in every SVG. +pub(super) fn themed_stylesheets() -> String { + const THEMES: [(&str, Stylesheet); 5] = [ + ("light", Stylesheet::Light), + ("rust", Stylesheet::Rust), + ("coal", Stylesheet::Coal), + ("navy", Stylesheet::Navy), + ("ayu", Stylesheet::Ayu), + ]; + + let mut css = String::new(); + for (theme, stylesheet) in THEMES { + let selector = format!(".{theme} svg.railroad"); + // Re-scope the selectors in each stylesheet, so they are scoped only to the selected theme + let scoped = stylesheet.stylesheet().replace("svg.railroad", &selector); + writeln!(css, "/* mdBook {theme} theme. */\n{scoped}").unwrap(); + } + css +} + pub fn render_railroad( grammar: &Grammar, cx: &RenderCtx, @@ -448,6 +472,23 @@ mod tests { }) } + #[test] + fn railroad_stylesheets_are_scoped_to_mdbook_themes() { + let css = themed_stylesheets(); + + for theme in ["light", "rust", "coal", "navy", "ayu"] { + assert!( + css.contains(&format!(".{theme} svg.railroad {{")), + "missing stylesheet for the {theme} theme" + ); + } + assert!( + css.lines() + .all(|line| !line.trim_start().starts_with("svg.railroad")), + "railroad styles must not leak into the other mdBook themes" + ); + } + // -- RepeatRange tests -- #[test]