From 2c48c8d7a10c89fe15c0e29083ab3f3b39585423 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Sun, 22 Jan 2023 13:31:16 +0100 Subject: [PATCH] Multi-line alignment with `&` --- library/src/math/align.rs | 60 +++++++++++++++++++++++++++++++++++++++ library/src/math/mod.rs | 1 + 2 files changed, 61 insertions(+) create mode 100644 library/src/math/align.rs diff --git a/library/src/math/align.rs b/library/src/math/align.rs new file mode 100644 index 000000000..82b461e9d --- /dev/null +++ b/library/src/math/align.rs @@ -0,0 +1,60 @@ +use super::*; + +/// # Alignment Point +/// A math alignment point: `&`, `&&`. +/// +/// ## Parameters +/// - index: usize (positional, required) +/// The alignment point's index. +/// +/// ## Category +/// math +#[func] +#[capable(LayoutMath)] +#[derive(Debug, Hash)] +pub struct AlignPointNode; + +#[node] +impl AlignPointNode {} + +impl LayoutMath for AlignPointNode { + fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> { + ctx.push(MathFragment::Align); + Ok(()) + } +} + +/// Determine the position of the alignment points. +pub(super) fn alignments(rows: &[MathRow]) -> Vec { + let count = rows + .iter() + .map(|row| { + row.0 + .iter() + .filter(|fragment| matches!(fragment, MathFragment::Align)) + .count() + }) + .max() + .unwrap_or(0); + + let mut points = vec![Abs::zero(); count]; + for current in 0..count { + for row in rows { + let mut x = Abs::zero(); + let mut i = 0; + for fragment in &row.0 { + if matches!(fragment, MathFragment::Align) { + if i < current { + x = points[i]; + } else if i == current { + points[i].set_max(x); + } + i += 1; + } + x += fragment.width(); + } + } + } + + points +} diff --git a/library/src/math/mod.rs b/library/src/math/mod.rs index de954fbf5..35e005d09 100644 --- a/library/src/math/mod.rs +++ b/library/src/math/mod.rs @@ -3,6 +3,7 @@ #[macro_use] mod ctx; mod accent; +mod align; mod atom; mod frac; mod group;