mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Merge 0a812963e3bb3d798097aa3d88eb62c3c79e1d69 into 9b09146a6b5e936966ed7ee73bce9dd2df3810ae
This commit is contained in:
commit
6396eda37a
@ -220,7 +220,7 @@ fn layout_body(
|
|||||||
let mut x = Abs::zero();
|
let mut x = Abs::zero();
|
||||||
|
|
||||||
for (index, col) in cols.into_iter().enumerate() {
|
for (index, col) in cols.into_iter().enumerate() {
|
||||||
let AlignmentResult { points, width: rcol } = alignments(&col);
|
let AlignmentResult { points, width: rcol, .. } = alignments(&col, None);
|
||||||
|
|
||||||
let mut y = Abs::zero();
|
let mut y = Abs::zero();
|
||||||
|
|
||||||
|
@ -98,6 +98,12 @@ pub fn layout_equation_inline(
|
|||||||
Ok(items)
|
Ok(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct EquationSizings<'a> {
|
||||||
|
region_size_x: Abs,
|
||||||
|
gaps: &'a [GapSizing<Abs>],
|
||||||
|
padding: &'a [GapSizing<Abs>],
|
||||||
|
}
|
||||||
|
|
||||||
/// Layout a block-level equation (in a flow).
|
/// Layout a block-level equation (in a flow).
|
||||||
#[typst_macros::time(span = elem.span())]
|
#[typst_macros::time(span = elem.span())]
|
||||||
pub fn layout_equation_block(
|
pub fn layout_equation_block(
|
||||||
@ -118,9 +124,17 @@ pub fn layout_equation_block(
|
|||||||
let scale_style = style_for_script_scale(&ctx);
|
let scale_style = style_for_script_scale(&ctx);
|
||||||
let styles = styles.chain(&scale_style);
|
let styles = styles.chain(&scale_style);
|
||||||
|
|
||||||
|
let gaps = elem.column_gap(styles).resolve(styles);
|
||||||
|
let padding = elem.column_padding(styles).resolve(styles);
|
||||||
|
let sizings = EquationSizings {
|
||||||
|
region_size_x: regions.size.x,
|
||||||
|
gaps: gaps.0.as_slice(),
|
||||||
|
padding: padding.0.as_slice(),
|
||||||
|
};
|
||||||
|
|
||||||
let full_equation_builder = ctx
|
let full_equation_builder = ctx
|
||||||
.layout_into_run(&elem.body, styles)?
|
.layout_into_run(&elem.body, styles)?
|
||||||
.multiline_frame_builder(styles);
|
.multiline_frame_builder(styles, Some(sizings));
|
||||||
let width = full_equation_builder.size.x;
|
let width = full_equation_builder.size.x;
|
||||||
|
|
||||||
let equation_builders = if BlockElem::breakable_in(styles) {
|
let equation_builders = if BlockElem::breakable_in(styles) {
|
||||||
|
@ -6,7 +6,7 @@ use typst_library::math::{EquationElem, MathSize, MEDIUM, THICK, THIN};
|
|||||||
use typst_library::model::ParElem;
|
use typst_library::model::ParElem;
|
||||||
use unicode_math_class::MathClass;
|
use unicode_math_class::MathClass;
|
||||||
|
|
||||||
use super::{alignments, FrameFragment, MathFragment};
|
use super::{alignments, EquationSizings, FrameFragment, MathFragment};
|
||||||
|
|
||||||
const TIGHT_LEADING: Em = Em::new(0.25);
|
const TIGHT_LEADING: Em = Em::new(0.25);
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ impl MathRun {
|
|||||||
if !self.is_multiline() {
|
if !self.is_multiline() {
|
||||||
self.into_line_frame(&[], LeftRightAlternator::Right)
|
self.into_line_frame(&[], LeftRightAlternator::Right)
|
||||||
} else {
|
} else {
|
||||||
self.multiline_frame_builder(styles).build()
|
self.multiline_frame_builder(styles, None).build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,10 +189,15 @@ impl MathRun {
|
|||||||
/// Returns a builder that lays out the [`MathFragment`]s into a possibly
|
/// Returns a builder that lays out the [`MathFragment`]s into a possibly
|
||||||
/// multi-row [`Frame`]. The rows are aligned using the same set of alignment
|
/// multi-row [`Frame`]. The rows are aligned using the same set of alignment
|
||||||
/// points computed from them as a whole.
|
/// points computed from them as a whole.
|
||||||
pub fn multiline_frame_builder(self, styles: StyleChain) -> MathRunFrameBuilder {
|
pub fn multiline_frame_builder(
|
||||||
|
self,
|
||||||
|
styles: StyleChain,
|
||||||
|
sizings: Option<EquationSizings>,
|
||||||
|
) -> MathRunFrameBuilder {
|
||||||
let rows: Vec<_> = self.rows();
|
let rows: Vec<_> = self.rows();
|
||||||
let row_count = rows.len();
|
let row_count = rows.len();
|
||||||
let alignments = alignments(&rows);
|
|
||||||
|
let alignments = alignments(&rows, sizings);
|
||||||
|
|
||||||
let leading = if EquationElem::size_in(styles) >= MathSize::Text {
|
let leading = if EquationElem::size_in(styles) >= MathSize::Text {
|
||||||
ParElem::leading_in(styles)
|
ParElem::leading_in(styles)
|
||||||
@ -213,15 +218,17 @@ impl MathRun {
|
|||||||
size.y += leading;
|
size.y += leading;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut pos = Point::with_y(size.y);
|
let mut pos = Point::new(alignments.padding.0, size.y);
|
||||||
if alignments.points.is_empty() {
|
if alignments.points.is_empty() {
|
||||||
pos.x = align.position(alignments.width - sub.width());
|
pos.x += align.position(alignments.width - sub.width());
|
||||||
}
|
}
|
||||||
size.x.set_max(sub.width());
|
size.x.set_max(sub.width() + alignments.padding.0);
|
||||||
size.y += sub.height();
|
size.y += sub.height();
|
||||||
frames.push((sub, pos));
|
frames.push((sub, pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size.x += alignments.padding.1;
|
||||||
|
|
||||||
MathRunFrameBuilder { size, frames }
|
MathRunFrameBuilder { size, frames }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
use ttf_parser::math::MathValue;
|
use ttf_parser::math::MathValue;
|
||||||
use typst_library::foundations::{Style, StyleChain};
|
use typst_library::foundations::{Style, StyleChain};
|
||||||
use typst_library::layout::{Abs, Em, FixedAlignment, Frame, Point, Size, VAlignment};
|
use typst_library::layout::{
|
||||||
use typst_library::math::{EquationElem, MathSize};
|
Abs, Em, FixedAlignment, Fr, Frame, Point, Size, VAlignment,
|
||||||
|
};
|
||||||
|
use typst_library::math::{EquationElem, GapSizing, MathSize};
|
||||||
use typst_utils::LazyHash;
|
use typst_utils::LazyHash;
|
||||||
|
|
||||||
use super::{LeftRightAlternator, MathContext, MathFragment, MathRun};
|
use super::{EquationSizings, LeftRightAlternator, MathContext, MathFragment, MathRun};
|
||||||
|
|
||||||
macro_rules! scaled {
|
macro_rules! scaled {
|
||||||
($ctx:expr, $styles:expr, text: $text:ident, display: $display:ident $(,)?) => {
|
($ctx:expr, $styles:expr, text: $text:ident, display: $display:ident $(,)?) => {
|
||||||
@ -118,7 +120,7 @@ pub fn stack(
|
|||||||
baseline: usize,
|
baseline: usize,
|
||||||
alternator: LeftRightAlternator,
|
alternator: LeftRightAlternator,
|
||||||
) -> Frame {
|
) -> Frame {
|
||||||
let AlignmentResult { points, width } = alignments(&rows);
|
let AlignmentResult { points, width, .. } = alignments(&rows, None);
|
||||||
let rows: Vec<_> = rows
|
let rows: Vec<_> = rows
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|row| row.into_line_frame(&points, alternator))
|
.map(|row| row.into_line_frame(&points, alternator))
|
||||||
@ -148,8 +150,15 @@ pub fn stack(
|
|||||||
frame
|
frame
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine the positions of the alignment points, according to the input rows combined.
|
pub struct AlignmentResult {
|
||||||
pub fn alignments(rows: &[MathRun]) -> AlignmentResult {
|
pub points: Vec<Abs>,
|
||||||
|
pub width: Abs,
|
||||||
|
pub padding: (Abs, Abs),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determine the positions of the alignment points, according to the input
|
||||||
|
/// rows combined.
|
||||||
|
pub fn alignments(rows: &[MathRun], sizings: Option<EquationSizings>) -> AlignmentResult {
|
||||||
let mut widths = Vec::<Abs>::new();
|
let mut widths = Vec::<Abs>::new();
|
||||||
|
|
||||||
let mut pending_width = Abs::zero();
|
let mut pending_width = Abs::zero();
|
||||||
@ -179,18 +188,80 @@ pub fn alignments(rows: &[MathRun]) -> AlignmentResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if widths.is_empty() {
|
||||||
|
widths.push(pending_width);
|
||||||
|
let padding = add_gaps(&mut widths, sizings);
|
||||||
|
return AlignmentResult { width: pending_width, points: vec![], padding };
|
||||||
|
}
|
||||||
|
|
||||||
|
let padding = add_gaps(&mut widths, sizings);
|
||||||
let mut points = widths;
|
let mut points = widths;
|
||||||
for i in 1..points.len() {
|
for i in 1..points.len() {
|
||||||
let prev = points[i - 1];
|
let prev = points[i - 1];
|
||||||
points[i] += prev;
|
points[i] += prev;
|
||||||
}
|
}
|
||||||
AlignmentResult {
|
AlignmentResult {
|
||||||
width: points.last().copied().unwrap_or(pending_width),
|
width: points.last().copied().unwrap(),
|
||||||
points,
|
points,
|
||||||
|
padding,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AlignmentResult {
|
/// Inserts gaps between columns given by the alignments.
|
||||||
pub points: Vec<Abs>,
|
fn add_gaps(widths: &mut [Abs], sizings: Option<EquationSizings>) -> (Abs, Abs) {
|
||||||
pub width: Abs,
|
let Some(sizings) = sizings else {
|
||||||
|
return (Abs::zero(), Abs::zero());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Padding to be returned.
|
||||||
|
let mut padding = [Abs::zero(), Abs::zero()];
|
||||||
|
|
||||||
|
// Number of gaps between columns.
|
||||||
|
let len = widths.len();
|
||||||
|
let ngaps = len.div_ceil(2).saturating_sub(1);
|
||||||
|
|
||||||
|
// Discard excess gaps or repeat the last gap to match the number of gaps.
|
||||||
|
let mut gaps = sizings.gaps.to_vec();
|
||||||
|
gaps.truncate(ngaps);
|
||||||
|
if let Some(last_gap) = gaps.last().copied() {
|
||||||
|
gaps.extend(std::iter::repeat_n(last_gap, ngaps.saturating_sub(gaps.len())));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum of fractions of all fractional gaps.
|
||||||
|
let mut fr = Fr::zero();
|
||||||
|
|
||||||
|
// Resolve the size of all relative gaps and compute the sum of all
|
||||||
|
// fractional gaps.
|
||||||
|
let region_width = sizings.region_size_x;
|
||||||
|
for (i, gap) in gaps.iter().enumerate() {
|
||||||
|
match gap {
|
||||||
|
GapSizing::Rel(v) => widths[1 + i * 2] += v.relative_to(region_width),
|
||||||
|
GapSizing::Fr(v) => fr += *v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i, gap) in sizings.padding.iter().enumerate() {
|
||||||
|
match gap {
|
||||||
|
GapSizing::Rel(v) => padding[i] = v.relative_to(region_width),
|
||||||
|
GapSizing::Fr(v) => fr += *v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size that is not used by fixed-size gaps.
|
||||||
|
let remaining = region_width - (widths.iter().sum::<Abs>() + padding.iter().sum());
|
||||||
|
|
||||||
|
// Distribute remaining space to fractional gaps.
|
||||||
|
if !remaining.approx_empty() {
|
||||||
|
for (i, gap) in gaps.iter().enumerate() {
|
||||||
|
if let GapSizing::Fr(v) = gap {
|
||||||
|
widths[1 + i * 2] += v.share(fr, remaining);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i, gap) in sizings.padding.iter().enumerate() {
|
||||||
|
if let GapSizing::Fr(v) = gap {
|
||||||
|
padding[i] = v.share(fr, remaining);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(padding[0], padding[1])
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
use typst_utils::NonZeroExt;
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
use typst_utils::{NonZeroExt, Numeric};
|
||||||
use unicode_math_class::MathClass;
|
use unicode_math_class::MathClass;
|
||||||
|
|
||||||
use crate::diag::SourceResult;
|
use crate::diag::{bail, HintedStrResult, SourceResult};
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::foundations::{
|
use crate::foundations::{
|
||||||
elem, Content, NativeElement, Packed, Show, ShowSet, Smart, StyleChain, Styles,
|
cast, elem, Array, Content, NativeElement, Packed, Resolve, Show, ShowSet, Smart,
|
||||||
Synthesize,
|
StyleChain, Styles, Synthesize, Value,
|
||||||
};
|
};
|
||||||
use crate::introspection::{Count, Counter, CounterUpdate, Locatable};
|
use crate::introspection::{Count, Counter, CounterUpdate, Locatable};
|
||||||
use crate::layout::{
|
use crate::layout::{
|
||||||
AlignElem, Alignment, BlockElem, InlineElem, OuterHAlignment, SpecificAlignment,
|
Abs, AlignElem, Alignment, BlockElem, Fr, InlineElem, Length, OuterHAlignment, Rel,
|
||||||
VAlignment,
|
Spacing, SpecificAlignment, VAlignment,
|
||||||
};
|
};
|
||||||
use crate::math::{MathSize, MathVariant};
|
use crate::math::{MathSize, MathVariant};
|
||||||
use crate::model::{Numbering, Outlinable, ParLine, Refable, Supplement};
|
use crate::model::{Numbering, Outlinable, ParLine, Refable, Supplement};
|
||||||
@ -101,6 +102,23 @@ pub struct EquationElem {
|
|||||||
/// ```
|
/// ```
|
||||||
pub supplement: Smart<Option<Supplement>>,
|
pub supplement: Smart<Option<Supplement>>,
|
||||||
|
|
||||||
|
/// The gap between columns.
|
||||||
|
///
|
||||||
|
/// ```example
|
||||||
|
/// #set math.equation(column-gap: 3em)
|
||||||
|
/// $ 4 &= 4 & &"yes" \
|
||||||
|
/// 0 &= 0 & &"no" \
|
||||||
|
/// 1+1 &= 2 & &"maybe" $
|
||||||
|
/// ```
|
||||||
|
#[default(Fr::one().into())]
|
||||||
|
#[borrowed]
|
||||||
|
pub column_gap: GapSizings,
|
||||||
|
|
||||||
|
///
|
||||||
|
#[default(Fr::one().into())]
|
||||||
|
#[borrowed]
|
||||||
|
pub column_padding: PaddingSizings,
|
||||||
|
|
||||||
/// The contents of the equation.
|
/// The contents of the equation.
|
||||||
#[required]
|
#[required]
|
||||||
pub body: Content,
|
pub body: Content,
|
||||||
@ -248,3 +266,101 @@ impl Outlinable for Packed<EquationElem> {
|
|||||||
Content::empty()
|
Content::empty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gap sizing definitions.
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
|
pub struct GapSizings<T: Numeric = Length>(pub SmallVec<[GapSizing<T>; 1]>);
|
||||||
|
|
||||||
|
impl<T: Into<Spacing>> From<T> for GapSizings {
|
||||||
|
fn from(spacing: T) -> Self {
|
||||||
|
Self(smallvec![GapSizing::from(spacing)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Resolve for &GapSizings {
|
||||||
|
type Output = GapSizings<Abs>;
|
||||||
|
|
||||||
|
fn resolve(self, styles: StyleChain) -> Self::Output {
|
||||||
|
Self::Output {
|
||||||
|
0: self.0.iter().map(|v| v.resolve(styles)).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cast! {
|
||||||
|
GapSizings,
|
||||||
|
self => self.0.into_value(),
|
||||||
|
v: GapSizing => Self(smallvec![v]),
|
||||||
|
v: Array => Self(v.into_iter().map(Value::cast).collect::<HintedStrResult<_>>()?),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Padding sizing definitions.
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
|
pub struct PaddingSizings<T: Numeric = Length>(pub SmallVec<[GapSizing<T>; 2]>);
|
||||||
|
|
||||||
|
impl<T: Into<Spacing>> From<T> for PaddingSizings {
|
||||||
|
fn from(spacing: T) -> Self {
|
||||||
|
let spacing = spacing.into();
|
||||||
|
Self(smallvec![GapSizing::from(spacing), GapSizing::from(spacing)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Resolve for &PaddingSizings {
|
||||||
|
type Output = PaddingSizings<Abs>;
|
||||||
|
|
||||||
|
fn resolve(self, styles: StyleChain) -> Self::Output {
|
||||||
|
Self::Output {
|
||||||
|
0: self.0.iter().map(|v| v.resolve(styles)).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cast! {
|
||||||
|
PaddingSizings,
|
||||||
|
self => self.0.into_value(),
|
||||||
|
v: GapSizing => Self(smallvec![v, v]),
|
||||||
|
v: Array => match v.as_slice() {
|
||||||
|
[start, end] => Self(smallvec![start.clone().cast()?, end.clone().cast()?]),
|
||||||
|
_ => bail!("expected 2 sizings, found {}", v.len()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Defines how to size a gap along an axis.
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
|
pub enum GapSizing<T: Numeric = Length> {
|
||||||
|
/// A size specified in absolute terms and relative to the parent's size.
|
||||||
|
Rel(Rel<T>),
|
||||||
|
/// A size specified as a fraction of the remaining free space in the
|
||||||
|
/// parent.
|
||||||
|
Fr(Fr),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Resolve for GapSizing {
|
||||||
|
type Output = GapSizing<Abs>;
|
||||||
|
|
||||||
|
fn resolve(self, styles: StyleChain) -> Self::Output {
|
||||||
|
match self {
|
||||||
|
Self::Rel(rel) => Self::Output::Rel(rel.resolve(styles)),
|
||||||
|
Self::Fr(fr) => Self::Output::Fr(fr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Into<Spacing>> From<T> for GapSizing {
|
||||||
|
fn from(spacing: T) -> Self {
|
||||||
|
match spacing.into() {
|
||||||
|
Spacing::Rel(rel) => Self::Rel(rel),
|
||||||
|
Spacing::Fr(fr) => Self::Fr(fr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cast! {
|
||||||
|
GapSizing,
|
||||||
|
self => match self {
|
||||||
|
Self::Rel(rel) => rel.into_value(),
|
||||||
|
Self::Fr(fr) => fr.into_value(),
|
||||||
|
},
|
||||||
|
v: Rel<Length> => Self::Rel(v),
|
||||||
|
v: Fr => Self::Fr(v),
|
||||||
|
}
|
||||||
|
@ -78,6 +78,9 @@ alternating the alignment twice. `& &` and `&&` behave exactly the same way.
|
|||||||
Meanwhile, "multiply by 7" is right-aligned because just one `&` precedes it.
|
Meanwhile, "multiply by 7" is right-aligned because just one `&` precedes it.
|
||||||
Each alignment point simply alternates between right-aligned/left-aligned.
|
Each alignment point simply alternates between right-aligned/left-aligned.
|
||||||
|
|
||||||
|
By default, there is a gap of `1em` added between columns. You can modify this
|
||||||
|
with the [`column-gap`]($math.equation.column-gap) parameter.
|
||||||
|
|
||||||
```example
|
```example
|
||||||
$ (3x + y) / 7 &= 9 && "given" \
|
$ (3x + y) / 7 &= 9 && "given" \
|
||||||
3x + y &= 63 & "multiply by 7" \
|
3x + y &= 63 & "multiply by 7" \
|
||||||
|
BIN
tests/ref/math-align-columns.png
Normal file
BIN
tests/ref/math-align-columns.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
tests/ref/math-equation-align-column-gap.png
Normal file
BIN
tests/ref/math-equation-align-column-gap.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 489 B |
BIN
tests/ref/math-equation-align-columns-1.png
Normal file
BIN
tests/ref/math-equation-align-columns-1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
tests/ref/math-equation-align-columns-2.png
Normal file
BIN
tests/ref/math-equation-align-columns-2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 771 B |
BIN
tests/ref/math-multiline-line-spacing.png
Normal file
BIN
tests/ref/math-multiline-line-spacing.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 459 B |
@ -28,6 +28,7 @@ $
|
|||||||
|
|
||||||
--- math-align-toggle ---
|
--- math-align-toggle ---
|
||||||
// Test #460 equations.
|
// Test #460 equations.
|
||||||
|
#set math.equation(column-gap: 0em)
|
||||||
$
|
$
|
||||||
a &=b & quad c&=d \
|
a &=b & quad c&=d \
|
||||||
e &=f & g&=h
|
e &=f & g&=h
|
||||||
|
@ -205,6 +205,7 @@ $ sin(#1) $
|
|||||||
// attach, etc.)
|
// attach, etc.)
|
||||||
//
|
//
|
||||||
// This is not good, so this test should fail and be updated once it is fixed.
|
// 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 id(body) = body
|
||||||
#let bx(body) = box(body, stroke: blue+0.5pt, inset: (x:2pt, y:3pt))
|
#let bx(body) = box(body, stroke: blue+0.5pt, inset: (x:2pt, y:3pt))
|
||||||
#let eq(body) = math.equation(body)
|
#let eq(body) = math.equation(body)
|
||||||
|
@ -54,6 +54,32 @@ This is big: $sum_(i=0)^n$
|
|||||||
#eq(start)
|
#eq(start)
|
||||||
#eq(end)
|
#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 ---
|
--- math-equation-number-align ---
|
||||||
#set math.equation(numbering: "(1)")
|
#set math.equation(numbering: "(1)")
|
||||||
|
|
||||||
|
@ -17,6 +17,15 @@ $ x + 1 &= a^2 + b^2 \
|
|||||||
$ a + b &= 2 + 3 &= 5 \
|
$ a + b &= 2 + 3 &= 5 \
|
||||||
b &= c &= 3 $
|
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 ---
|
--- math-align-cases ---
|
||||||
// Test in case distinction.
|
// Test in case distinction.
|
||||||
$ f := cases(
|
$ f := cases(
|
||||||
@ -55,6 +64,12 @@ $
|
|||||||
$
|
$
|
||||||
Multiple trailing line breaks.
|
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 ---
|
--- math-linebreaking-after-binop-and-rel ---
|
||||||
// Basic breaking after binop, rel
|
// Basic breaking after binop, rel
|
||||||
#let hrule(x) = box(line(length: x))
|
#let hrule(x) = box(line(length: x))
|
||||||
@ -110,6 +125,7 @@ Nothing: $ $, just empty.
|
|||||||
--- math-pagebreaking ---
|
--- math-pagebreaking ---
|
||||||
// Test breaking of equations at page boundaries.
|
// Test breaking of equations at page boundaries.
|
||||||
#set page(height: 5em)
|
#set page(height: 5em)
|
||||||
|
#set math.equation(column-gap: 0em)
|
||||||
#show math.equation: set block(breakable: true)
|
#show math.equation: set block(breakable: true)
|
||||||
|
|
||||||
$ a &+ b + & c \
|
$ a &+ b + & c \
|
||||||
@ -121,7 +137,7 @@ $ a &+ b + & c \
|
|||||||
--- math-pagebreaking-numbered ---
|
--- math-pagebreaking-numbered ---
|
||||||
// Test breaking of equations with numbering.
|
// Test breaking of equations with numbering.
|
||||||
#set page(height: 5em)
|
#set page(height: 5em)
|
||||||
#set math.equation(numbering: "1")
|
#set math.equation(column-gap: 0em, numbering: "1")
|
||||||
#show math.equation: set block(breakable: true)
|
#show math.equation: set block(breakable: true)
|
||||||
|
|
||||||
$ a &+ b + & c \
|
$ a &+ b + & c \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user