diff --git a/crates/typst-layout/src/math/mat.rs b/crates/typst-layout/src/math/mat.rs index d678f8658..1056735a7 100644 --- a/crates/typst-layout/src/math/mat.rs +++ b/crates/typst-layout/src/math/mat.rs @@ -220,7 +220,7 @@ fn layout_body( let mut x = Abs::zero(); for (index, col) in cols.into_iter().enumerate() { - let AlignmentResult { points, width: rcol } = alignments(&col); + let AlignmentResult { points, width: rcol } = alignments(&col, Abs::zero()); let mut y = Abs::zero(); diff --git a/crates/typst-layout/src/math/run.rs b/crates/typst-layout/src/math/run.rs index ae64368d6..faee3797a 100644 --- a/crates/typst-layout/src/math/run.rs +++ b/crates/typst-layout/src/math/run.rs @@ -192,7 +192,9 @@ impl MathRun { pub fn multiline_frame_builder(self, styles: StyleChain) -> MathRunFrameBuilder { let rows: Vec<_> = self.rows(); let row_count = rows.len(); - let alignments = alignments(&rows); + + let column_gap = EquationElem::column_gap_in(styles).resolve(styles); + let alignments = alignments(&rows, column_gap); let leading = if EquationElem::size_in(styles) >= MathSize::Text { ParElem::leading_in(styles) diff --git a/crates/typst-layout/src/math/shared.rs b/crates/typst-layout/src/math/shared.rs index 600c130d4..8b471376b 100644 --- a/crates/typst-layout/src/math/shared.rs +++ b/crates/typst-layout/src/math/shared.rs @@ -118,7 +118,7 @@ pub fn stack( baseline: usize, alternator: LeftRightAlternator, ) -> Frame { - let AlignmentResult { points, width } = alignments(&rows); + let AlignmentResult { points, width } = alignments(&rows, Abs::zero()); let rows: Vec<_> = rows .into_iter() .map(|row| row.into_line_frame(&points, alternator)) @@ -149,7 +149,7 @@ pub fn stack( } /// Determine the positions of the alignment points, according to the input rows combined. -pub fn alignments(rows: &[MathRun]) -> AlignmentResult { +pub fn alignments(rows: &[MathRun], gap: Abs) -> AlignmentResult { let mut widths = Vec::::new(); let mut pending_width = Abs::zero(); @@ -159,6 +159,9 @@ pub fn alignments(rows: &[MathRun]) -> AlignmentResult { for fragment in row.iter() { if matches!(fragment, MathFragment::Align) { + if alignment_index > 0 && alignment_index % 2 == 0 { + width += gap; + } if alignment_index < widths.len() { widths[alignment_index].set_max(width); } else { diff --git a/crates/typst-library/src/math/equation.rs b/crates/typst-library/src/math/equation.rs index 32be216a4..8195ded2f 100644 --- a/crates/typst-library/src/math/equation.rs +++ b/crates/typst-library/src/math/equation.rs @@ -11,13 +11,15 @@ use crate::foundations::{ }; use crate::introspection::{Count, Counter, CounterUpdate, Locatable}; use crate::layout::{ - AlignElem, Alignment, BlockElem, InlineElem, OuterHAlignment, SpecificAlignment, - VAlignment, + AlignElem, Alignment, BlockElem, Em, InlineElem, Length, OuterHAlignment, + SpecificAlignment, VAlignment, }; use crate::math::{MathSize, MathVariant}; use crate::model::{Numbering, Outlinable, ParLine, Refable, Supplement}; use crate::text::{FontFamily, FontList, FontWeight, LocalName, TextElem}; +const DEFAULT_COL_GAP: Em = Em::new(1.5); + /// A mathematical equation. /// /// Can be displayed inline with text or as a separate block. An equation @@ -101,6 +103,17 @@ pub struct EquationElem { /// ``` pub supplement: Smart>, + /// The gap between columns. + /// + /// ```example + /// #set math.equation(column-gap: 3em) + /// $ 4 &= 4 & &"yes" \ + /// 0 &= 0 & &"no" \ + /// 1+1 &= 2 & &"maybe" $ + /// ``` + #[default(DEFAULT_COL_GAP.into())] + pub column_gap: Length, + /// The contents of the equation. #[required] pub body: Content, @@ -185,6 +198,7 @@ impl Show for Packed { impl ShowSet for Packed { fn show_set(&self, styles: StyleChain) -> Styles { let mut out = Styles::new(); + out.set(EquationElem::set_column_gap(self.column_gap(styles))); if self.block(styles) { out.set(AlignElem::set_alignment(Alignment::CENTER)); out.set(BlockElem::set_breakable(false)); diff --git a/tests/ref/math-align-columns.png b/tests/ref/math-align-columns.png new file mode 100644 index 000000000..8420ae315 Binary files /dev/null and b/tests/ref/math-align-columns.png differ diff --git a/tests/ref/math-equation-align-column-gap.png b/tests/ref/math-equation-align-column-gap.png new file mode 100644 index 000000000..696793129 Binary files /dev/null and b/tests/ref/math-equation-align-column-gap.png differ diff --git a/tests/ref/math-equation-align-columns-1.png b/tests/ref/math-equation-align-columns-1.png new file mode 100644 index 000000000..c5320ed23 Binary files /dev/null and b/tests/ref/math-equation-align-columns-1.png differ diff --git a/tests/ref/math-equation-align-columns-2.png b/tests/ref/math-equation-align-columns-2.png new file mode 100644 index 000000000..edf986285 Binary files /dev/null and b/tests/ref/math-equation-align-columns-2.png differ diff --git a/tests/ref/math-multiline-line-spacing.png b/tests/ref/math-multiline-line-spacing.png new file mode 100644 index 000000000..468e92f2b Binary files /dev/null and b/tests/ref/math-multiline-line-spacing.png differ diff --git a/tests/suite/math/alignment.typ b/tests/suite/math/alignment.typ index 941c20556..521886cc9 100644 --- a/tests/suite/math/alignment.typ +++ b/tests/suite/math/alignment.typ @@ -28,6 +28,7 @@ $ --- math-align-toggle --- // Test #460 equations. +#set math.equation(column-gap: 0em) $ a &=b & quad c&=d \ e &=f & g&=h diff --git a/tests/suite/math/call.typ b/tests/suite/math/call.typ index 5caacfac6..116168a11 100644 --- a/tests/suite/math/call.typ +++ b/tests/suite/math/call.typ @@ -205,6 +205,7 @@ $ sin(#1) $ // attach, etc.) // // This is not good, so this test should fail and be updated once it is fixed. +#set math.equation(column-gap: 0em) #let id(body) = body #let bx(body) = box(body, stroke: blue+0.5pt, inset: (x:2pt, y:3pt)) #let eq(body) = math.equation(body) diff --git a/tests/suite/math/equation.typ b/tests/suite/math/equation.typ index 148a49d02..c379e5287 100644 --- a/tests/suite/math/equation.typ +++ b/tests/suite/math/equation.typ @@ -54,6 +54,32 @@ This is big: $sum_(i=0)^n$ #eq(start) #eq(end) +--- math-equation-align-columns-1 --- +// Test columns in equations. +#set page(width: auto) +$ sum a &<= & sum b &<= & &sum c \ + log sum a &<= & log sum b &<= & log &sum c $ + +#math.equation(block: true, column-gap: 0em, $ + sum a &<= & sum b &<= & &sum c \ + log sum a &<= & log sum b &<= & log &sum c +$) + +--- math-equation-align-columns-2 --- +// Test columns in equations. +#set page(width: auto) +#set math.equation(column-gap: 1em) +#block(stroke: black + 1pt, $ + && x & = y && & a & = b + c && && && \ + && -4 + 5x & = -2 && & a b & = c b && && && +$) + +--- math-equation-align-column-gap --- +// Test column-gap in equations. +#set math.equation(column-gap: 4em) +$ a &=b & c&=d \ + e &=f & g&=h $ + --- math-equation-number-align --- #set math.equation(numbering: "(1)") diff --git a/tests/suite/math/multiline.typ b/tests/suite/math/multiline.typ index 34e66b99c..ea5157219 100644 --- a/tests/suite/math/multiline.typ +++ b/tests/suite/math/multiline.typ @@ -17,6 +17,15 @@ $ x + 1 &= a^2 + b^2 \ $ a + b &= 2 + 3 &= 5 \ b &= c &= 3 $ +--- math-align-columns --- +// Test columns created with alignment points. +$ A &= B &= C \ + D &= E &= F $ +$ A &= B B B B &= C \ + D &= E &= F $ +$ A &= B & &= C \ + D &= E & &= F $ + --- math-align-cases --- // Test in case distinction. $ f := cases( @@ -55,6 +64,12 @@ $ $ Multiple trailing line breaks. +--- math-multiline-line-spacing --- +// Test modifying spacing between lines. +#set par(leading: 2em) +$ a &=b & c&=d \ + e &=f & g&=h $ + --- math-linebreaking-after-binop-and-rel --- // Basic breaking after binop, rel #let hrule(x) = box(line(length: x)) @@ -110,6 +125,7 @@ Nothing: $ $, just empty. --- math-pagebreaking --- // Test breaking of equations at page boundaries. #set page(height: 5em) +#set math.equation(column-gap: 0em) #show math.equation: set block(breakable: true) $ a &+ b + & c \ @@ -121,7 +137,7 @@ $ a &+ b + & c \ --- math-pagebreaking-numbered --- // Test breaking of equations with numbering. #set page(height: 5em) -#set math.equation(numbering: "1") +#set math.equation(column-gap: 0em, numbering: "1") #show math.equation: set block(breakable: true) $ a &+ b + & c \