summaryrefslogtreecommitdiff
path: root/library/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-12-07 11:28:52 +0100
committerLaurenz <laurmaedje@gmail.com>2022-12-07 11:30:17 +0100
commit5a0053c7291549bc0be3753a09d6dc0efb364da6 (patch)
tree02e304d1fe7f5816e1f911262e850b19e9e60253 /library/src
parentb2572f9d48a8f0efd30014302dcc271cd89fa91e (diff)
Vectors and cases
Diffstat (limited to 'library/src')
-rw-r--r--library/src/lib.rs2
-rw-r--r--library/src/math/mod.rs97
-rw-r--r--library/src/math/tex.rs20
3 files changed, 103 insertions, 16 deletions
diff --git a/library/src/lib.rs b/library/src/lib.rs
index af5c252b..29a6cc94 100644
--- a/library/src/lib.rs
+++ b/library/src/lib.rs
@@ -53,6 +53,8 @@ fn scope() -> Scope {
std.def_node::<math::AtomNode>("atom");
std.def_node::<math::FracNode>("frac");
std.def_node::<math::SqrtNode>("sqrt");
+ std.def_node::<math::VecNode>("vec");
+ std.def_node::<math::CasesNode>("cases");
// Layout.
std.def_node::<layout::PageNode>("page");
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![Glyph {
id: gid,
@@ -126,11 +126,11 @@ impl Backend for FrameBackend {
fn rule(&mut self, pos: Cursor, width: f64, height: f64) {
self.frame.push(
- self.transform(pos),
+ self.transform(pos) + Point::with_y(Abs::pt(height) / 2.0),
Element::Shape(Shape {
- geometry: Geometry::Rect(Size::new(Abs::pt(width), Abs::pt(height))),
- fill: Some(self.fill()),
- stroke: None,
+ geometry: Geometry::Line(Point::new(Abs::pt(width), Abs::zero())),
+ fill: None,
+ stroke: Some(Stroke { paint: self.paint(), thickness: Abs::pt(height) }),
}),
);
}