diff --git a/Cargo.lock b/Cargo.lock index 1c157a688..1472a2a01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "approx" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" +dependencies = [ + "num-traits", +] + [[package]] name = "arrayref" version = "0.3.6" @@ -83,6 +92,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bumpalo" +version = "3.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" + [[package]] name = "bytemuck" version = "1.7.3" @@ -135,6 +150,18 @@ dependencies = [ "matches", ] +[[package]] +name = "decorum" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "281759d3c8a14f5c3f0c49363be56810fcd7f910422f97f2db850c2920fde5cf" +dependencies = [ + "approx", + "num-traits", + "serde", + "serde_derive", +] + [[package]] name = "deflate" version = "0.8.6" @@ -214,6 +241,25 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "font" +version = "0.1.0" +source = "git+https://github.com/pdf-rs/font#f0ea791543140ccbe0d4fb20bac363ab66c53f68" +dependencies = [ + "decorum", + "indexmap", + "itertools", + "log", + "nom", + "pathfinder_color", + "pathfinder_content", + "pathfinder_geometry", + "pdf_encoding", + "rand 0.7.3", + "slotmap", + "tuple", +] + [[package]] name = "fxhash" version = "0.2.1" @@ -223,6 +269,19 @@ dependencies = [ "byteorder", ] +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + [[package]] name = "getrandom" version = "0.2.4" @@ -231,7 +290,7 @@ checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] @@ -280,6 +339,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.8" @@ -298,6 +366,15 @@ version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" +[[package]] +name = "js-sys" +version = "0.3.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "kurbo" version = "0.8.3" @@ -319,6 +396,19 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "lexical-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec 0.5.2", + "bitflags", + "cfg-if", + "ryu", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.118" @@ -339,8 +429,8 @@ name = "lipsum" version = "0.8.0" source = "git+https://github.com/reknih/lipsum#c97ce95ba01ed2cce1d1b0b230b6b78295b0720b" dependencies = [ - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", ] [[package]] @@ -410,6 +500,17 @@ dependencies = [ "adler", ] +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "lexical-core", + "memchr", + "version_check", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -489,6 +590,46 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "pathfinder_color" +version = "0.5.0" +source = "git+https://github.com/servo/pathfinder/#038a3476d803fd77a6e66a74117b5b8803a2cb49" +dependencies = [ + "pathfinder_simd", +] + +[[package]] +name = "pathfinder_content" +version = "0.5.0" +source = "git+https://github.com/servo/pathfinder/#038a3476d803fd77a6e66a74117b5b8803a2cb49" +dependencies = [ + "arrayvec 0.5.2", + "bitflags", + "image", + "log", + "pathfinder_color", + "pathfinder_geometry", + "pathfinder_simd", + "smallvec", +] + +[[package]] +name = "pathfinder_geometry" +version = "0.5.1" +source = "git+https://github.com/servo/pathfinder/#038a3476d803fd77a6e66a74117b5b8803a2cb49" +dependencies = [ + "log", + "pathfinder_simd", +] + +[[package]] +name = "pathfinder_simd" +version = "0.5.1" +source = "git+https://github.com/servo/pathfinder/#038a3476d803fd77a6e66a74117b5b8803a2cb49" +dependencies = [ + "rustc_version", +] + [[package]] name = "pdf-writer" version = "0.4.1" @@ -500,6 +641,24 @@ dependencies = [ "ryu", ] +[[package]] +name = "pdf_encoding" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7468173909bb32dbc74ca454c82dfdfe994ad1133ddf78d6c31715c9b88c40" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + [[package]] name = "pico-args" version = "0.4.2" @@ -576,13 +735,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "rand_core", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", ] [[package]] @@ -592,7 +774,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", ] [[package]] @@ -601,6 +792,15 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + [[package]] name = "rctree" version = "0.4.0" @@ -622,7 +822,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "getrandom", + "getrandom 0.2.4", "redox_syscall", ] @@ -659,6 +859,15 @@ dependencies = [ "usvg", ] +[[package]] +name = "rex" +version = "0.1.2" +source = "git+https://github.com/laurmaedje/ReX#b44e59bfa68cc4b0288bd2be80e093ed3b279af5" +dependencies = [ + "font", + "unicode-math", +] + [[package]] name = "rgb" version = "0.8.31" @@ -677,6 +886,15 @@ dependencies = [ "xmlparser", ] +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver", +] + [[package]] name = "rustybuzz" version = "0.4.0" @@ -729,6 +947,24 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "serde" version = "1.0.136" @@ -775,12 +1011,24 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e" +[[package]] +name = "slotmap" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bf34684c5767b87de9119790e92e9a1d60056be2ceeaf16a8e6ef13082aeab1" + [[package]] name = "smallvec" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "svg2pdf" version = "0.2.1" @@ -874,6 +1122,15 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ae2f58a822f08abdaf668897e96a5656fe72f5a9ce66422423e8849384872e6" +[[package]] +name = "tuple" +version = "0.5.1" +source = "git+https://github.com/s3bk/tuple/#fdf8b4400ffb10506c711018a3cb918412a3c8c1" +dependencies = [ + "num-traits", + "serde", +] + [[package]] name = "typed-arena" version = "2.0.1" @@ -904,6 +1161,7 @@ dependencies = [ "pixglyph", "regex", "resvg", + "rex", "roxmltree", "rustybuzz", "same-file", @@ -933,6 +1191,12 @@ dependencies = [ "syn", ] +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + [[package]] name = "unicode-bidi" version = "0.3.7" @@ -957,6 +1221,14 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07547e3ee45e28326cc23faac56d44f58f16ab23e413db526debce3b0bfd2742" +[[package]] +name = "unicode-math" +version = "0.1.0" +source = "git+https://github.com/s3bk/unicode-math/#8ab17ee2b125747876f48dfb579d58482bf876e5" +dependencies = [ + "regex", +] + [[package]] name = "unicode-script" version = "0.5.4" @@ -1006,6 +1278,12 @@ dependencies = [ "svgtypes", ] +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "walkdir" version = "2.3.2" @@ -1017,12 +1295,72 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +[[package]] +name = "wasm-bindgen" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 2bf6c58c7..585e85ee0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ usvg = { version = "0.20", default-features = false } # External implementation of user-facing features syntect = { version = "4.6", default-features = false, features = ["dump-load", "parsing", "regex-fancy", "assets"] } +rex = { git = "https://github.com/laurmaedje/ReX" } # PDF export miniz_oxide = "0.4" diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 790601373..12e2970ed 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -211,13 +211,13 @@ impl Eval for RawNode { } } -impl Eval for MathNode { +impl Eval for Spanned { type Output = Content; fn eval(&self, _: &mut Context, _: &mut Scopes) -> TypResult { Ok(Content::show(library::math::MathNode { - formula: self.formula.clone(), - display: self.display, + formula: self.clone().map(|math| math.formula), + display: self.v.display, })) } } diff --git a/src/library/math/mod.rs b/src/library/math/mod.rs index 5656890d6..ce41bd49a 100644 --- a/src/library/math/mod.rs +++ b/src/library/math/mod.rs @@ -1,14 +1,17 @@ //! Mathematical formulas. +mod rex; + use crate::library::layout::BlockSpacing; use crate::library::prelude::*; use crate::library::text::FontFamily; +use crate::syntax::Spanned; /// A mathematical formula. #[derive(Debug, Hash)] pub struct MathNode { /// The formula. - pub formula: EcoString, + pub formula: Spanned, /// Whether the formula is display-level. pub display: bool, } @@ -40,17 +43,23 @@ impl Show for MathNode { fn encode(&self, _: StyleChain) -> Dict { dict! { - "formula" => Value::Str(self.formula.clone()), + "formula" => Value::Str(self.formula.v.clone()), "display" => Value::Bool(self.display) } } - fn realize(&self, _: &mut Context, _: StyleChain) -> TypResult { - let mut realized = Content::Text(self.formula.trim().into()); - if self.display { - realized = Content::block(realized); - } - Ok(realized) + fn realize(&self, _: &mut Context, styles: StyleChain) -> TypResult { + let node = self::rex::RexNode { + tex: self.formula.clone(), + display: self.display, + family: styles.get(Self::FAMILY).clone(), + }; + + Ok(if self.display { + Content::block(node) + } else { + Content::inline(node) + }) } fn finalize( diff --git a/src/library/math/rex.rs b/src/library/math/rex.rs new file mode 100644 index 000000000..43e2c015c --- /dev/null +++ b/src/library/math/rex.rs @@ -0,0 +1,148 @@ +use rex::font::{FontContext, MathFont}; +use rex::layout::{LayoutSettings, Style}; +use rex::parser::color::RGBA; +use rex::render::{Backend, Cursor, Renderer}; +use rex::error::{Error, LayoutError}; + +use crate::font::FaceId; +use crate::library::prelude::*; +use crate::library::text::{variant, FontFamily, Lang, TextNode}; + +/// A layout node that renders with ReX. +#[derive(Debug, Hash)] +pub struct RexNode { + /// The TeX formula. + pub tex: Spanned, + /// Whether the formula is display-level. + pub display: bool, + /// The font family. + pub family: FontFamily, +} + +impl Layout for RexNode { + fn layout( + &self, + ctx: &mut Context, + _: &Regions, + styles: StyleChain, + ) -> TypResult>> { + // Load the font. + let face_id = match ctx.fonts.select(self.family.as_str(), variant(styles)) { + Some(id) => id, + None => return Ok(vec![]), + }; + + // Prepare the font. + let data = ctx.fonts.get(face_id).buffer(); + let font = match MathFont::parse(data) { + Ok(font) => font, + Err(_) => return Ok(vec![]), + }; + + // Layout the formula. + let ctx = FontContext::new(&font); + let em = styles.get(TextNode::SIZE); + let style = if self.display { Style::Display } else { Style::Text }; + let settings = LayoutSettings::new(&ctx, em.to_pt(), style); + let renderer = Renderer::new(); + let layout = renderer.layout(&self.tex.v, settings) + .map_err(|err| match err { + Error::Parse(err) => err.to_string(), + Error::Layout(LayoutError::Font(err)) => err.to_string(), + }) + .at(self.tex.span)?; + + // Determine the metrics. + let (x0, y0, x1, y1) = renderer.size(&layout); + let width = Length::pt(x1 - x0); + let height = Length::pt(y1 - y0); + let size = Size::new(width, height); + let baseline = Length::pt(y1); + + // Prepare a frame rendering backend. + let mut backend = FrameBackend { + frame: { + let mut frame = Frame::new(size); + frame.baseline = Some(baseline); + frame + }, + baseline, + face_id, + fill: styles.get(TextNode::FILL), + lang: styles.get(TextNode::LANG), + colors: vec![], + }; + + // Render into the frame. + renderer.render(&layout, &mut backend); + + Ok(vec![Arc::new(backend.frame)]) + } +} + +/// A ReX rendering backend that renders into a frame. +struct FrameBackend { + frame: Frame, + baseline: Length, + face_id: FaceId, + fill: Paint, + lang: Lang, + colors: Vec, +} + +impl FrameBackend { + /// The currently active fill paint. + fn fill(&self) -> Paint { + self.colors + .last() + .map(|&RGBA(r, g, b, a)| RgbaColor::new(r, g, b, a).into()) + .unwrap_or(self.fill) + } + + /// Convert a cursor to a point. + fn transform(&self, cursor: Cursor) -> Point { + Point::new(Length::pt(cursor.x), self.baseline + Length::pt(cursor.y)) + } +} + +impl Backend for FrameBackend { + fn symbol(&mut self, pos: Cursor, gid: u16, scale: f64, _: &MathFont) { + self.frame.push( + self.transform(pos), + Element::Text(Text { + face_id: self.face_id, + size: Length::pt(scale), + fill: self.fill(), + lang: self.lang, + glyphs: vec![Glyph { + id: gid, + x_advance: Em::new(0.0), + x_offset: Em::new(0.0), + c: ' ', + }], + }), + ); + } + + fn rule(&mut self, pos: Cursor, width: f64, height: f64) { + self.frame.push( + self.transform(pos), + Element::Shape(Shape { + geometry: Geometry::Rect(Size::new( + Length::pt(width), + Length::pt(height), + )), + fill: Some(self.fill()), + stroke: None, + }), + ); + } + + fn begin_color(&mut self, color: RGBA) { + self.colors.push(color); + } + + fn end_color(&mut self) { + self.colors.pop(); + } +} diff --git a/src/library/text/shaping.rs b/src/library/text/shaping.rs index 66a9f7c26..29973bc79 100644 --- a/src/library/text/shaping.rs +++ b/src/library/text/shaping.rs @@ -510,7 +510,7 @@ fn track_and_space(ctx: &mut ShapingContext) { } /// Resolve the font variant with `STRONG` and `EMPH` factored in. -fn variant(styles: StyleChain) -> FontVariant { +pub fn variant(styles: StyleChain) -> FontVariant { let mut variant = FontVariant::new( styles.get(TextNode::STYLE), styles.get(TextNode::WEIGHT), diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs index 95421213c..0f575f31a 100644 --- a/src/syntax/ast.rs +++ b/src/syntax/ast.rs @@ -5,7 +5,7 @@ use std::num::NonZeroUsize; use std::ops::Deref; -use super::{Green, GreenData, NodeKind, RedNode, RedRef, Span}; +use super::{Green, GreenData, NodeKind, RedNode, RedRef, Span, Spanned}; use crate::geom::{AngleUnit, LengthUnit}; use crate::util::EcoString; @@ -77,7 +77,7 @@ impl Markup { NodeKind::Strong => node.cast().map(MarkupNode::Strong), NodeKind::Emph => node.cast().map(MarkupNode::Emph), NodeKind::Raw(raw) => Some(MarkupNode::Raw(raw.as_ref().clone())), - NodeKind::Math(math) => Some(MarkupNode::Math(math.as_ref().clone())), + NodeKind::Math(math) => Some(MarkupNode::Math(Spanned::new(math.as_ref().clone(), node.span()))), NodeKind::Heading => node.cast().map(MarkupNode::Heading), NodeKind::List => node.cast().map(MarkupNode::List), NodeKind::Enum => node.cast().map(MarkupNode::Enum), @@ -106,7 +106,7 @@ pub enum MarkupNode { /// A raw block with optional syntax highlighting: `` `...` ``. Raw(RawNode), /// A math formula: `$a^2 = b^2 + c^2$`. - Math(MathNode), + Math(Spanned), /// A section heading: `= Introduction`. Heading(HeadingNode), /// An item in an unordered list: `- ...`. diff --git a/tests/ref/math/basic.png b/tests/ref/math/basic.png index 381e92c46..42723bc51 100644 Binary files a/tests/ref/math/basic.png and b/tests/ref/math/basic.png differ diff --git a/tests/ref/text/par.png b/tests/ref/text/par.png index 6ee4aa9cf..189084489 100644 Binary files a/tests/ref/text/par.png and b/tests/ref/text/par.png differ diff --git a/tests/typ/math/basic.typ b/tests/typ/math/basic.typ index cad01d107..33246261d 100644 --- a/tests/typ/math/basic.typ +++ b/tests/typ/math/basic.typ @@ -7,6 +7,14 @@ The sum of $a$ and $b$ is $a + b$. We will show that: $[ a^2 + b^2 = c^2 ]$ +--- +Prove by induction: +$[ \sum_{k=0}^n k = \frac{n(n+1)}{2} ]$ + +--- +// Error: 1-10 expected '}' found EOF +$\sqrt{x$ + --- // Error: 2:1 expected closing bracket and dollar sign $[a