From 8234fcdeb201c524deaf4bbf557e093495f5a5e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Mon, 12 Oct 2026 11:15:52 -0400 Subject: [PATCH] typography and documents: an exported formula frames its outlined text; rendered modes have no source selection --- src/documents/document/place.rs | 4 ++++ src/documents/document/tests/place.rs | 12 ++++++++---- src/typography/math.rs | 17 ++++++++++++----- src/typography/math/tests.rs | 18 ++++++++++++++++++ 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/documents/document/place.rs b/src/documents/document/place.rs index 4ba8935..3cdb5ad 100644 --- a/src/documents/document/place.rs +++ b/src/documents/document/place.rs @@ -31,6 +31,10 @@ impl MarkdownDocument { /// The selected Markdown: the source's, or the open block's. pub fn selected(&self, cx: &App) -> String { let Some(open) = &self.open else { + // Rendered modes show no source selection. + if !matches!(self.mode, MarkdownMode::Source | MarkdownMode::Split) { + return String::new(); + } let editor = self.editor.read(cx); return editor.text()[editor.primary().range()].to_string(); }; diff --git a/src/documents/document/tests/place.rs b/src/documents/document/tests/place.rs index cdbddc8..965f39d 100644 --- a/src/documents/document/tests/place.rs +++ b/src/documents/document/tests/place.rs @@ -211,10 +211,14 @@ fn the_selection_reads_in_source_and_in_an_open_block(cx: &mut TestAppContext) { document.read_with(cx, |document, cx| document.selected(cx)), "One" ); - document.update_in(cx, |document, window, cx| { - document.set_mode(MarkdownMode::Visual, window, cx) - }); - frames(cx); + for mode in [MarkdownMode::Preview, MarkdownMode::Visual] { + document.update_in(cx, |document, window, cx| { + document.set_mode(mode, window, cx) + }); + frames(cx); + let selected = document.read_with(cx, |document, cx| document.selected(cx)); + assert_eq!(selected, "", "{mode:?} shows no source selection"); + } super::type_in(&document, Some(1), None, cx); document.update(cx, |document, cx| { let open = document.open.as_ref().expect("a block is open"); diff --git a/src/typography/math.rs b/src/typography/math.rs index f3db1e0..87bf6ed 100644 --- a/src/typography/math.rs +++ b/src/typography/math.rs @@ -125,13 +125,20 @@ pub fn formula_svg(source: &str, display: bool) -> Result { font: 1600, scale: 100, }; + let (svg, width, height) = laid(&formula)?; // RaTeX writes text where it has no outline. - let (svg, _) = svg(&formula)?; - crate::documents::flatten(&svg).map_err(MathError::said) + let outlined = crate::documents::flatten(&svg).map_err(MathError::said)?; + framed(&outlined, width, height).map(|(svg, _)| svg) } /// The formula as outlined SVG holding all ink; its size. fn svg(formula: &Formula) -> Result<(String, Size), MathError> { + let (svg, width, height) = laid(formula)?; + framed(&svg, width, height) +} + +/// RaTeX's SVG and the layout box's width and height. +fn laid(formula: &Formula) -> Result<(String, f32, f32), MathError> { let ast = parsed(&formula.source)?; let [r, g, b, a] = formula .rgba @@ -144,7 +151,7 @@ fn svg(formula: &Formula) -> Result<(String, Size), MathError> { }) .with_color(Color::new(r, g, b, a)); let font = f64::from(formula.font) / 100.0; - let laid = guarded(|| { + let typeset = guarded(|| { let list = to_display_list(&layout(&ast, &options)); let svg = render_to_svg( &list, @@ -158,8 +165,8 @@ fn svg(formula: &Formula) -> Result<(String, Size), MathError> { ); (list.width * font, (list.height + list.depth) * font, svg) })?; - let (width, height, svg) = laid; - framed(&svg, width as f32, height as f32) + let (width, height, svg) = typeset; + Ok((svg, width as f32, height as f32)) } /// Runs RaTeX's layout; a panic becomes an error. diff --git a/src/typography/math/tests.rs b/src/typography/math/tests.rs index e408244..b874a29 100644 --- a/src/typography/math/tests.rs +++ b/src/typography/math/tests.rs @@ -193,3 +193,21 @@ fn an_exported_formula_outlines_its_text_or_says_why() { let why = formula_svg("\\text{\u{F0000}}", false).expect_err("no font"); assert!(why.to_string().contains("font"), "{why}"); } + +#[test] +fn an_exported_formula_frames_its_outlined_text() { + // Wide or tall faces from the system, where fonts have them. + for source in [r"\text{ν•œκΈ€}", r"\text{π“€€} + x"] { + let Ok(svg) = formula_svg(source, false) else { + continue; + }; + let tree = + usvg::Tree::from_data(svg.as_bytes(), &usvg::Options::default()).expect("parses"); + let (ink, shape) = (tree.root().abs_stroke_bounding_box(), tree.size()); + let inside = ink.left() >= -0.01 + && ink.top() >= -0.01 + && ink.right() <= shape.width() + 0.01 + && ink.bottom() <= shape.height() + 0.01; + assert!(inside, "{source}: {ink:?} in {shape:?}"); + } +}