diff --git a/Cargo.lock b/Cargo.lock index 781d749c63..186c520769 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -263,9 +263,9 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "railroad" -version = "0.3.3" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5b8e8a7c20c600f9b98cbf46b64e63d5c9e69deb98cee1ff264de9f1dda5d" +checksum = "813b53dbe6d583f1ac0c3fb394e0ce3b613530adff8265c274fcdfcd82cc6da5" dependencies = [ "unicode-width", ] diff --git a/tools/mdbook-spec/Cargo.toml b/tools/mdbook-spec/Cargo.toml index c71bd782a2..3a86ed03cf 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.2", default-features = false } +railroad = { version = "0.3.7", default-features = false } regex = "1.12.2" semver = "1.0.21" serde_json = "1.0.113" diff --git a/tools/mdbook-spec/src/grammar/render_railroad.rs b/tools/mdbook-spec/src/grammar/render_railroad.rs index f24d23523c..e5fa0bf312 100644 --- a/tools/mdbook-spec/src/grammar/render_railroad.rs +++ b/tools/mdbook-spec/src/grammar/render_railroad.rs @@ -9,6 +9,12 @@ use regex::Regex; use std::fmt::Write; use std::sync::LazyLock; +/// Maximum number of rows per column in a `ExpressionKind::Alt`/`ExpressionKind::Charset` +const CHOICE_MAX_ROWS_PER_COLUMN: usize = 5; +/// Maximum number of columns in a `ExpressionKind::Alt`/`ExpressionKind::Charset`. Above that, we give up and +/// use as many rows as necessary +const CHOICE_MAX_COLUMNS: usize = 4; + pub fn render_railroad( grammar: &Grammar, cx: &RenderCtx, @@ -92,7 +98,7 @@ fn render_expression(expr: &Expression, cx: &RenderCtx, stack: bool) -> Option>::new(choices)) + Box::new(bounded_multichoice(choices)) } ExpressionKind::Sequence(es) => { let es: Vec<_> = es.iter().collect(); @@ -290,7 +296,7 @@ fn render_expression(expr: &Expression, cx: &RenderCtx, stack: bool) -> Option return None, ExpressionKind::Charset(set) => { let ns: Vec<_> = set.iter().map(|c| render_characters(c, cx)).collect(); - Box::new(Choice::>::new(ns)) + Box::new(bounded_multichoice(ns)) } ExpressionKind::NegExpression(e) => { let n = render_expression(e, cx, stack)?; @@ -329,6 +335,20 @@ fn render_expression(expr: &Expression, cx: &RenderCtx, stack: bool) -> Option>) -> MultiChoice> { + let hard_max_columns = std::cmp::min( + CHOICE_MAX_COLUMNS, + inp.len().div_ceil(CHOICE_MAX_ROWS_PER_COLUMN), + ); + let soft_max_rows = inp.len().div_ceil(hard_max_columns); + let mut choices_iter = inp.into_iter(); + let groups = std::iter::from_fn(move || { + let group: Vec<_> = choices_iter.by_ref().take(soft_max_rows).collect(); + (!group.is_empty()).then_some(group) + }); + MultiChoice::new(groups.collect()) +} + fn render_characters(chars: &Characters, cx: &RenderCtx) -> Box { match chars { Characters::Named(s) => node_for_nt(cx, s),