From 11c7ceb29e762f6dd1d093d9fdb57e9612a92df0 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Wed, 7 Dec 2022 12:33:48 +0100 Subject: [PATCH] Extend math library --- Cargo.lock | 2 +- library/src/lib.rs | 12 +++ library/src/math/matrix.rs | 84 +++++++++++++++++ library/src/math/mod.rs | 186 +++++++++++++++++++++++++------------ library/src/math/style.rs | 161 ++++++++++++++++++++++++++++++++ library/src/math/tex.rs | 4 + src/model/eval.rs | 2 +- src/model/realize.rs | 4 + tests/ref/math/accents.png | Bin 0 -> 3077 bytes tests/ref/math/matrix.png | Bin 4854 -> 6079 bytes tests/ref/math/simple.png | Bin 6560 -> 8293 bytes tests/ref/math/style.png | Bin 0 -> 15288 bytes tests/typ/math/accents.typ | 28 ++++++ tests/typ/math/matrix.typ | 15 ++- tests/typ/math/simple.typ | 6 +- tests/typ/math/style.typ | 15 +++ 16 files changed, 451 insertions(+), 68 deletions(-) create mode 100644 library/src/math/matrix.rs create mode 100644 library/src/math/style.rs create mode 100644 tests/ref/math/accents.png create mode 100644 tests/ref/math/style.png create mode 100644 tests/typ/math/accents.typ create mode 100644 tests/typ/math/style.typ diff --git a/Cargo.lock b/Cargo.lock index 8fe3dba2..9de15487 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1027,7 +1027,7 @@ dependencies = [ [[package]] name = "symmie" version = "0.1.0" -source = "git+https://github.com/typst/symmie#8504bf7ec0d8996d160832c2724ba024ab6e988a" +source = "git+https://github.com/typst/symmie#6280fb20455cb63e6886ba5bb35b95a4b376da68" [[package]] name = "syn" diff --git a/library/src/lib.rs b/library/src/lib.rs index 29a6cc94..e41e7c0d 100644 --- a/library/src/lib.rs +++ b/library/src/lib.rs @@ -51,10 +51,22 @@ fn scope() -> Scope { // Math. std.def_node::("math"); std.def_node::("atom"); + std.def_node::("acc"); std.def_node::("frac"); + std.def_node::("binom"); std.def_node::("sqrt"); + std.def_node::("floor"); + std.def_node::("ceil"); std.def_node::("vec"); std.def_node::("cases"); + std.def_node::("serif"); + std.def_node::("sans"); + std.def_node::("bold"); + std.def_node::("ital"); + std.def_node::("cal"); + std.def_node::("frak"); + std.def_node::("mono"); + std.def_node::("bb"); // Layout. std.def_node::("page"); diff --git a/library/src/math/matrix.rs b/library/src/math/matrix.rs new file mode 100644 index 00000000..d835b348 --- /dev/null +++ b/library/src/math/matrix.rs @@ -0,0 +1,84 @@ +use super::*; + +/// A column vector in a mathematical formula. +#[derive(Debug, Hash)] +pub struct VecNode(Vec); + +#[node(Texify)] +impl VecNode { + /// The kind of delimiter. + pub const DELIM: Delimiter = Delimiter::Paren; + + fn construct(_: &Vm, args: &mut Args) -> SourceResult { + Ok(Self(args.all()?).pack()) + } +} + +impl Texify for VecNode { + fn texify(&self, t: &mut Texifier) -> SourceResult<()> { + let kind = match t.styles.get(Self::DELIM) { + Delimiter::Paren => "pmatrix", + Delimiter::Bracket => "bmatrix", + Delimiter::Brace => "Bmatrix", + Delimiter::Bar => "vmatrix", + }; + + t.push_str("\\begin{"); + t.push_str(kind); + t.push_str("}"); + + for component in &self.0 { + component.texify(t)?; + t.push_str("\\\\"); + } + t.push_str("\\end{"); + t.push_str(kind); + t.push_str("}"); + + Ok(()) + } +} + +/// A vector / matrix delimiter. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum Delimiter { + Paren, + Bracket, + Brace, + Bar, +} + +castable! { + Delimiter, + Expected: "type of bracket or bar", + Value::Str(s) => match s.as_str() { + "(" => Self::Paren, + "[" => Self::Bracket, + "{" => Self::Brace, + "|" => Self::Bar, + _ => Err("expected \"(\", \"[\", \"{\", or \"|\"")?, + }, +} + +/// A case distinction in a mathematical formula. +#[derive(Debug, Hash)] +pub struct CasesNode(Vec); + +#[node(Texify)] +impl CasesNode { + fn construct(_: &Vm, args: &mut Args) -> SourceResult { + Ok(Self(args.all()?).pack()) + } +} + +impl Texify for CasesNode { + fn texify(&self, t: &mut Texifier) -> SourceResult<()> { + t.push_str("\\begin{cases}"); + for component in &self.0 { + component.texify(t)?; + t.push_str("\\\\"); + } + t.push_str("\\end{cases}"); + Ok(()) + } +} diff --git a/library/src/math/mod.rs b/library/src/math/mod.rs index c613ea2a..4eb72e23 100644 --- a/library/src/math/mod.rs +++ b/library/src/math/mod.rs @@ -1,7 +1,12 @@ //! Mathematical formulas. +mod matrix; +mod style; mod tex; +pub use self::matrix::*; +pub use self::style::*; + use typst::model::{Guard, SequenceNode}; use unicode_segmentation::UnicodeSegmentation; @@ -272,6 +277,79 @@ impl Texify for AtomNode { } } +/// An accented node. +#[derive(Debug, Hash)] +pub struct AccNode { + /// The accent base. + pub base: Content, + /// The Unicode accent character. + pub accent: char, +} + +#[node(Texify)] +impl AccNode { + fn construct(_: &Vm, args: &mut Args) -> SourceResult { + let base = args.expect("base")?; + let Spanned { v, span } = args.expect::>("accent")?; + let accent = match extract(&v) { + Some(Ok(c)) => c, + Some(Err(msg)) => bail!(span, "{}", msg), + None => bail!(span, "not an accent"), + }; + Ok(Self { base, accent }.pack()) + } +} + +#[rustfmt::skip] +fn extract(content: &Content) -> Option> { + let MathNode { children, .. } = content.to::()?; + let [child] = children.as_slice() else { return None }; + let c = if let Some(atom) = child.to::() { + let mut chars = atom.0.chars(); + chars.next().filter(|_| chars.next().is_none())? + } else if let Some(symbol) = child.to::() { + match symmie::get(&symbol.0) { + Some(c) => c, + None => return Some(Err("unknown symbol")), + } + } else { + return None; + }; + + Some(Ok(match c { + '`' | '\u{300}' => '\u{300}', // Grave + '´' | '\u{301}' => '\u{301}', // Acute + '^' | '\u{302}' => '\u{302}', // Circumflex + '~' | '\u{223C}' | '\u{303}' => '\u{303}', // Tilde + '¯' | '\u{304}' => '\u{304}', // Macron + '‾' | '\u{305}' => '\u{305}', // Overline + '˘' | '\u{306}' => '\u{306}', // Breve + '.' | '\u{22C5}' | '\u{307}' => '\u{307}', // Dot + '¨' | '\u{308}' => '\u{308}', // Diaeresis + 'ˇ' | '\u{30C}' => '\u{30C}', // Caron + '→' | '\u{20D7}' => '\u{20D7}', // Arrow + _ => return None, + })) +} + +impl Texify for AccNode { + fn texify(&self, t: &mut Texifier) -> SourceResult<()> { + if let Some(sym) = unicode_math::SYMBOLS.iter().find(|sym| { + sym.codepoint == self.accent + && sym.atom_type == unicode_math::AtomType::Accent + }) { + t.push_str("\\"); + t.push_str(sym.name); + t.push_str("{"); + self.base.texify(t)?; + t.push_str("}"); + } else { + self.base.texify(t)?; + } + Ok(()) + } +} + /// A fraction in a mathematical formula. #[derive(Debug, Hash)] pub struct FracNode { @@ -301,6 +379,35 @@ impl Texify for FracNode { } } +/// A binomial in a mathematical formula. +#[derive(Debug, Hash)] +pub struct BinomNode { + /// The upper index. + pub upper: Content, + /// The lower index. + pub lower: Content, +} + +#[node(Texify)] +impl BinomNode { + fn construct(_: &Vm, args: &mut Args) -> SourceResult { + let upper = args.expect("upper index")?; + let lower = args.expect("lower index")?; + Ok(Self { upper, lower }.pack()) + } +} + +impl Texify for BinomNode { + fn texify(&self, t: &mut Texifier) -> SourceResult<()> { + t.push_str("\\binom{"); + self.upper.texify(t)?; + t.push_str("}{"); + self.lower.texify(t)?; + t.push_str("}"); + Ok(()) + } +} + /// A sub- and/or superscript in a mathematical formula. #[derive(Debug, Hash)] pub struct ScriptNode { @@ -348,7 +455,7 @@ impl Texify for AlignNode { } } -/// A square root. +/// A square root in a mathematical formula. #[derive(Debug, Hash)] pub struct SqrtNode(Content); @@ -362,91 +469,48 @@ impl SqrtNode { impl Texify for SqrtNode { fn texify(&self, t: &mut Texifier) -> SourceResult<()> { t.push_str("\\sqrt{"); - self.0.texify_unparen(t)?; + self.0.texify(t)?; t.push_str("}"); Ok(()) } } -/// A column vector. +/// A floored expression in a mathematical formula. #[derive(Debug, Hash)] -pub struct VecNode(Vec); +pub struct FloorNode(Content); #[node(Texify)] -impl VecNode { - /// The kind of delimiter. - pub const DELIM: Delimiter = Delimiter::Paren; - +impl FloorNode { fn construct(_: &Vm, args: &mut Args) -> SourceResult { - Ok(Self(args.all()?).pack()) + Ok(Self(args.expect("body")?).pack()) } } -impl Texify for VecNode { +impl Texify for FloorNode { fn texify(&self, t: &mut Texifier) -> SourceResult<()> { - let kind = match t.styles.get(Self::DELIM) { - Delimiter::Paren => "pmatrix", - Delimiter::Bracket => "bmatrix", - Delimiter::Brace => "Bmatrix", - Delimiter::Bar => "vmatrix", - }; - - t.push_str("\\begin{"); - t.push_str(kind); - t.push_str("}"); - - for component in &self.0 { - component.texify_unparen(t)?; - t.push_str("\\\\"); - } - t.push_str("\\end{"); - t.push_str(kind); - t.push_str("}"); - + t.push_str("\\left\\lfloor "); + self.0.texify(t)?; + t.push_str("\\right\\rfloor "); Ok(()) } } -/// A vector / matrix delimiter. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum Delimiter { - Paren, - Bracket, - Brace, - Bar, -} - -castable! { - Delimiter, - Expected: "type of bracket or bar", - Value::Str(s) => match s.as_str() { - "(" => Self::Paren, - "[" => Self::Bracket, - "{" => Self::Brace, - "|" => Self::Bar, - _ => Err("expected \"(\", \"[\", \"{\", or \"|\"")?, - }, -} - -/// A case distinction. +/// A ceiled expression in a mathematical formula. #[derive(Debug, Hash)] -pub struct CasesNode(Vec); +pub struct CeilNode(Content); #[node(Texify)] -impl CasesNode { +impl CeilNode { fn construct(_: &Vm, args: &mut Args) -> SourceResult { - Ok(Self(args.all()?).pack()) + Ok(Self(args.expect("body")?).pack()) } } -impl Texify for CasesNode { +impl Texify for CeilNode { fn texify(&self, t: &mut Texifier) -> SourceResult<()> { - t.push_str("\\begin{cases}"); - for component in &self.0 { - component.texify_unparen(t)?; - t.push_str("\\\\"); - } - t.push_str("\\end{cases}"); + t.push_str("\\left\\lceil "); + self.0.texify(t)?; + t.push_str("\\right\\rceil "); Ok(()) } } diff --git a/library/src/math/style.rs b/library/src/math/style.rs new file mode 100644 index 00000000..3db2e631 --- /dev/null +++ b/library/src/math/style.rs @@ -0,0 +1,161 @@ +use super::*; + +/// Serif (roman) font style. +#[derive(Debug, Hash)] +pub struct SerifNode(Content); + +#[node(Texify)] +impl SerifNode { + fn construct(_: &Vm, args: &mut Args) -> SourceResult { + Ok(Self(args.expect("body")?).pack()) + } +} + +impl Texify for SerifNode { + fn texify(&self, t: &mut Texifier) -> SourceResult<()> { + t.push_str("\\mathrm{"); + self.0.texify_unparen(t)?; + t.push_str("}"); + Ok(()) + } +} + +/// Sans-serif font style. +#[derive(Debug, Hash)] +pub struct SansNode(Content); + +#[node(Texify)] +impl SansNode { + fn construct(_: &Vm, args: &mut Args) -> SourceResult { + Ok(Self(args.expect("body")?).pack()) + } +} + +impl Texify for SansNode { + fn texify(&self, t: &mut Texifier) -> SourceResult<()> { + t.push_str("\\mathsf{"); + self.0.texify_unparen(t)?; + t.push_str("}"); + Ok(()) + } +} + +/// Bold font style. +#[derive(Debug, Hash)] +pub struct BoldNode(Content); + +#[node(Texify)] +impl BoldNode { + fn construct(_: &Vm, args: &mut Args) -> SourceResult { + Ok(Self(args.expect("body")?).pack()) + } +} + +impl Texify for BoldNode { + fn texify(&self, t: &mut Texifier) -> SourceResult<()> { + t.push_str("\\mathbf{"); + self.0.texify_unparen(t)?; + t.push_str("}"); + Ok(()) + } +} + +/// Italic font style. +#[derive(Debug, Hash)] +pub struct ItalNode(Content); + +#[node(Texify)] +impl ItalNode { + fn construct(_: &Vm, args: &mut Args) -> SourceResult { + Ok(Self(args.expect("body")?).pack()) + } +} + +impl Texify for ItalNode { + fn texify(&self, t: &mut Texifier) -> SourceResult<()> { + t.push_str("\\mathit{"); + self.0.texify_unparen(t)?; + t.push_str("}"); + Ok(()) + } +} + +/// Calligraphic font style. +#[derive(Debug, Hash)] +pub struct CalNode(Content); + +#[node(Texify)] +impl CalNode { + fn construct(_: &Vm, args: &mut Args) -> SourceResult { + Ok(Self(args.expect("body")?).pack()) + } +} + +impl Texify for CalNode { + fn texify(&self, t: &mut Texifier) -> SourceResult<()> { + t.push_str("\\mathcal{"); + self.0.texify_unparen(t)?; + t.push_str("}"); + Ok(()) + } +} + +/// Fraktur font style. +#[derive(Debug, Hash)] +pub struct FrakNode(Content); + +#[node(Texify)] +impl FrakNode { + fn construct(_: &Vm, args: &mut Args) -> SourceResult { + Ok(Self(args.expect("body")?).pack()) + } +} + +impl Texify for FrakNode { + fn texify(&self, t: &mut Texifier) -> SourceResult<()> { + t.push_str("\\mathfrak{"); + self.0.texify_unparen(t)?; + t.push_str("}"); + Ok(()) + } +} + +/// Monospace font style. +#[derive(Debug, Hash)] +pub struct MonoNode(Content); + +#[node(Texify)] +impl MonoNode { + fn construct(_: &Vm, args: &mut Args) -> SourceResult { + Ok(Self(args.expect("body")?).pack()) + } +} + +impl Texify for MonoNode { + fn texify(&self, t: &mut Texifier) -> SourceResult<()> { + t.push_str("\\mathtt{"); + self.0.texify_unparen(t)?; + t.push_str("}"); + Ok(()) + } +} + +/// Blackboard bold (double-struck) font style. +#[derive(Debug, Hash)] +pub struct BbNode(Content); + +#[node(Texify)] +impl BbNode { + fn construct(_: &Vm, args: &mut Args) -> SourceResult { + Ok(Self(args.expect("body")?).pack()) + } +} + +impl Texify for BbNode { + fn texify(&self, t: &mut Texifier) -> SourceResult<()> { + t.push_str("\\mathbb{"); + self.0.texify_unparen(t)?; + t.push_str("}"); + Ok(()) + } +} diff --git a/library/src/math/tex.rs b/library/src/math/tex.rs index e8917f30..f17134b7 100644 --- a/library/src/math/tex.rs +++ b/library/src/math/tex.rs @@ -125,6 +125,10 @@ impl Backend for FrameBackend { } fn rule(&mut self, pos: Cursor, width: f64, height: f64) { + if height == 0.0 { + return; + } + self.frame.push( self.transform(pos) + Point::with_y(Abs::pt(height) / 2.0), Element::Shape(Shape { diff --git a/src/model/eval.rs b/src/model/eval.rs index 204dfbd4..0ae8a0b1 100644 --- a/src/model/eval.rs +++ b/src/model/eval.rs @@ -434,7 +434,7 @@ impl Eval for ast::MathNode { Self::Expr(v) => { if let ast::Expr::Ident(ident) = v { if self.as_untyped().len() == ident.len() - && !vm.scopes.get(ident).is_ok() + && matches!(vm.scopes.get(ident), Ok(Value::Func(_)) | Err(_)) { let node = (vm.items.symbol)(ident.get().clone() + ":op".into()); return Ok(node.spanned(self.span())); diff --git a/src/model/realize.rs b/src/model/realize.rs index b4e38e30..862bc8b6 100644 --- a/src/model/realize.rs +++ b/src/model/realize.rs @@ -7,6 +7,10 @@ pub fn applicable(target: &Content, styles: StyleChain) -> bool { return true; } + if target.has::() && target.is_pristine() { + return true; + } + // Find out how many recipes there are. let mut n = styles.recipes().count(); diff --git a/tests/ref/math/accents.png b/tests/ref/math/accents.png new file mode 100644 index 0000000000000000000000000000000000000000..7e93d9b5e8ff3acc089308b45ca3af7bbddc75d4 GIT binary patch literal 3077 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 P&JR3OR97gIGY|O>wSQ-D literal 6560 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 diff --git a/tests/ref/math/style.png b/tests/ref/math/style.png new file mode 100644 index 0000000000000000000000000000000000000000..8dc11b3129b536c54f41d89a69a1a32fdebcc407 GIT binary patch literal 15288 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 $ + +$ acc(a, grave), + acc(a, acute), + acc(a, circum), + acc(a, tilde), + acc(a, macron), + acc(a, overline), + acc(a, breve), + acc(a, dot), + acc(a, dia), + acc(a, caron), + acc(a, arrow) $ diff --git a/tests/typ/math/matrix.typ b/tests/typ/math/matrix.typ index ec84778c..3d67800d 100644 --- a/tests/typ/math/matrix.typ +++ b/tests/typ/math/matrix.typ @@ -4,12 +4,11 @@ $ v = vec(1, 2+3, 4) $ --- -#set vec(delim: "|") -$ vec(1, 2) $ +$ binom(n, 1) = 1/2 n (n-1) $ --- -// Error: 17-20 expected "(", "[", "{", or "|" -#set vec(delim: "%") +#set vec(delim: "|") +$ vec(1, 2) $ --- $ f(x, y) := cases( @@ -18,3 +17,11 @@ $ f(x, y) := cases( 3 "if" x "is even", 4 "else", ) $ + +--- +// Error: 17-20 expected "(", "[", "{", or "|" +#set vec(delim: "%") + +--- +// Error: 9-12 missing argument: lower index +$ binom(x^2) $ diff --git a/tests/typ/math/simple.typ b/tests/typ/math/simple.typ index 55a853cf..1b63cbfc 100644 --- a/tests/typ/math/simple.typ +++ b/tests/typ/math/simple.typ @@ -11,9 +11,13 @@ $ a^2 + b^2 = c^2 $ Prove by induction: $ sum_(k=0)^n k = (n(n+1))/2 $ +--- +We know that: +$ floor(x/2) <= ceil(x/2) $ + --- // Test that blackboard style looks nice. -$ f: NN arrow RR $ +$ f: NN -> RR $ --- // Error: 1:3 expected dollar sign diff --git a/tests/typ/math/style.typ b/tests/typ/math/style.typ new file mode 100644 index 00000000..c9238a9a --- /dev/null +++ b/tests/typ/math/style.typ @@ -0,0 +1,15 @@ +#let part = $ a b A B $ +#let kinds = (serif, sans, cal, frak, mono, bb) +#let modifiers = (v => v, ital, bold, v => ital(bold(v))) + +#let cells = ([:triangle:nested:], [--], [`ital`], [`bold`], [both]) +#for k in kinds { + cells.push(raw(repr(k).trim(""))) + for m in modifiers { + cells.push($ #m(#k(part)) $) + } +} + +#set page(width: auto) +#set par(align: center) +#table(columns: 1 + modifiers.len(), ..cells)