diff --git a/crates/mermaid_render/src/render.rs b/crates/mermaid_render/src/render.rs index b32a36cbfa..5db7ca8753 100644 --- a/crates/mermaid_render/src/render.rs +++ b/crates/mermaid_render/src/render.rs @@ -122,7 +122,12 @@ fn to_merman_config(theme: &MermaidTheme) -> merman::MermaidConfig { "theme": "base", "darkMode": theme.dark_mode, "fontFamily": theme.font_family, + // resvg can't rasterize HTML `` labels, and the + // fallback that replaces them loses soft wrapping, so emit native SVG + // text labels. Nodes read the top-level key; edges read `flowchart`. + "htmlLabels": false, "flowchart": { + "htmlLabels": false, "padding": 16, }, "themeVariables": theme_vars, @@ -144,10 +149,6 @@ mod tests { !html_label_svg.contains("` lines rather + /// than the resvg-safe pipeline's single-line `` fallback, + /// which overflows the node box (see the `htmlLabels` comment in + /// [`to_merman_config`]). If the fallback marker reappears after a merman + /// upgrade, the config has stopped disabling HTML labels. + #[test] + fn long_labels_render_as_wrapped_svg_text() { + let source = "flowchart TD\n \ + A[\"Pass 2: search transcript with annotation blocks excised, \ + map offsets back to buffer space\"] --> \ + |ambiguous or zero| B[\"Error describing where matches were found\"]"; + let svg = render_mermaid(source, &MermaidTheme::default()).expect("render failed"); + + assert!( + !svg.contains(r#"data-merman-foreignobject="fallback""#), + "labels went through the foreignObject fallback, which loses soft wrapping: {svg}" + ); + let wrapped_line_count = svg.matches("text-outer-tspan").count(); + assert!( + wrapped_line_count > 3, + "expected long labels to wrap onto multiple tspan lines, got {wrapped_line_count}: {svg}" + ); + } } diff --git a/crates/mermaid_render/tests/check_invalid_attrs.rs b/crates/mermaid_render/tests/check_invalid_attrs.rs index e4d49384bf..93093d899d 100644 --- a/crates/mermaid_render/tests/check_invalid_attrs.rs +++ b/crates/mermaid_render/tests/check_invalid_attrs.rs @@ -268,25 +268,7 @@ fn generics_not_double_escaped() { } #[test] -fn backslash_n_converted_to_line_break() { - let theme = rgb_theme(); - let source = r#"graph TD - L7["Layer 7\nHTTP, FTP"] - L6["Layer 6\nEncryption"] - L7 --> L6"#; - let svg = mermaid_render::render_to_svg(source, &theme).expect("render failed"); - assert!( - !svg.contains(r"\n"), - "Literal \\n should not appear in SVG output" - ); - assert!( - svg.contains(">Layer 7<") && svg.contains(">HTTP, FTP<"), - "Label lines should be split into separate elements" - ); -} - -#[test] -fn class_diagram_fallback_text_uses_accent_classes() { +fn class_diagram_label_text_uses_accent_classes() { let theme = rgb_theme(); let source = r#"classDiagram class Animal { @@ -303,32 +285,19 @@ fn class_diagram_fallback_text_uses_accent_classes() { use quick_xml::events::Event; let mut reader = quick_xml::Reader::from_str(&svg); - let mut in_fallback = false; let mut accent_classes: Vec = Vec::new(); loop { match reader.read_event() { Ok(Event::Eof) => break, - Ok(Event::Start(e)) => { - if e.name().as_ref() == b"g" { - if let Ok(Some(attr)) = e.try_get_attribute("data-merman-foreignobject") { - if attr.value.as_ref() == b"fallback" { - in_fallback = true; + Ok(Event::Start(e)) if e.name().as_ref() == b"text" => { + if let Ok(Some(class_attr)) = e.try_get_attribute("class") { + let class = class_attr.unescape_value().unwrap_or_default().to_string(); + for token in class.split_whitespace() { + if token.starts_with("zed-accent-") { + accent_classes.push(token.to_string()); } } } - if in_fallback && e.name().as_ref() == b"text" { - if let Ok(Some(class_attr)) = e.try_get_attribute("class") { - let class = class_attr.unescape_value().unwrap_or_default().to_string(); - for token in class.split_whitespace() { - if token.starts_with("zed-accent-") { - accent_classes.push(token.to_string()); - } - } - } - } - } - Ok(Event::End(e)) if e.name().as_ref() == b"g" => { - in_fallback = false; } _ => {} } @@ -336,7 +305,7 @@ fn class_diagram_fallback_text_uses_accent_classes() { assert!( !accent_classes.is_empty(), - "expected zed-accent-N classes on text elements in fallback groups", + "expected zed-accent-N classes on label text elements", ); }