diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-12-07 11:28:52 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-12-07 11:30:17 +0100 |
| commit | 5a0053c7291549bc0be3753a09d6dc0efb364da6 (patch) | |
| tree | 02e304d1fe7f5816e1f911262e850b19e9e60253 /library/src/math | |
| parent | b2572f9d48a8f0efd30014302dcc271cd89fa91e (diff) | |
Vectors and cases
Diffstat (limited to 'library/src/math')
| -rw-r--r-- | library/src/math/mod.rs | 97 | ||||
| -rw-r--r-- | library/src/math/tex.rs | 20 |
2 files changed, 101 insertions, 16 deletions
diff --git a/library/src/math/mod.rs b/library/src/math/mod.rs index 1e8145cc..c613ea2a 100644 --- a/library/src/math/mod.rs +++ b/library/src/math/mod.rs @@ -54,7 +54,7 @@ impl Layout for MathNode { styles: StyleChain, _: &Regions, ) -> SourceResult<Fragment> { - let mut t = Texifier::new(); + let mut t = Texifier::new(styles); self.texify(&mut t)?; layout_tex(vt, &t.finish(), self.display, styles) } @@ -71,7 +71,7 @@ trait Texify { /// Texify the node, but trim parentheses.. fn texify_unparen(&self, t: &mut Texifier) -> SourceResult<()> { let s = { - let mut sub = Texifier::new(); + let mut sub = Texifier::new(t.styles); self.texify(&mut sub)?; sub.finish() }; @@ -88,19 +88,21 @@ trait Texify { } /// Builds the TeX representation of the formula. -struct Texifier { +struct Texifier<'a> { tex: EcoString, support: bool, space: bool, + styles: StyleChain<'a>, } -impl Texifier { +impl<'a> Texifier<'a> { /// Create a new texifier. - fn new() -> Self { + fn new(styles: StyleChain<'a>) -> Self { Self { tex: EcoString::new(), support: false, space: false, + styles, } } @@ -346,7 +348,7 @@ impl Texify for AlignNode { } } -/// A square root node. +/// A square root. #[derive(Debug, Hash)] pub struct SqrtNode(Content); @@ -365,3 +367,86 @@ impl Texify for SqrtNode { Ok(()) } } + +/// A column vector. +#[derive(Debug, Hash)] +pub struct VecNode(Vec<Content>); + +#[node(Texify)] +impl VecNode { + /// The kind of delimiter. + pub const DELIM: Delimiter = Delimiter::Paren; + + fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> { + 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_unparen(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. +#[derive(Debug, Hash)] +pub struct CasesNode(Vec<Content>); + +#[node(Texify)] +impl CasesNode { + fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> { + 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_unparen(t)?; + t.push_str("\\\\"); + } + t.push_str("\\end{cases}"); + Ok(()) + } +} diff --git a/library/src/math/tex.rs b/library/src/math/tex.rs index da07f1d6..e8917f30 100644 --- a/library/src/math/tex.rs +++ b/library/src/math/tex.rs @@ -69,7 +69,7 @@ pub fn layout_tex( }, baseline: top, font: font.clone(), - fill: styles.get(TextNode::FILL), + paint: styles.get(TextNode::FILL), lang: styles.get(TextNode::LANG), colors: vec![], }; @@ -85,18 +85,18 @@ struct FrameBackend { frame: Frame, baseline: Abs, font: Font, - fill: Paint, + paint: Paint, lang: Lang, colors: Vec<RGBA>, } impl FrameBackend { - /// The currently active fill paint. - fn fill(&self) -> Paint { + /// The currently active paint. + fn paint(&self) -> Paint { self.colors .last() .map(|&RGBA(r, g, b, a)| RgbaColor::new(r, g, b, a).into()) - .unwrap_or(self.fill) + .unwrap_or(self.paint) } /// Convert a cursor to a point. @@ -112,7 +112,7 @@ impl Backend for FrameBackend { Element::Text(Text { font: self.font.clone(), size: Abs::pt(scale), - fill: self.fill(), + fill: self.paint(), lang: self.lang, glyphs: vec