Add delim-size parameter to mat, vec, and cases

Takes either a function or a relative length, just like with `lr`,
`stretch`, and `accent` which was changed in the previous two commits.
The short fall was changed in the first commit, so no test updates here.
The default is now much clearer to the user: `x => x * 1.1 - 0.1em`.
This commit is contained in:
mkorje 2025-04-27 21:04:39 +10:00
parent 92d06fbd9a
commit b30a38046c
No known key found for this signature in database
11 changed files with 98 additions and 27 deletions

View File

@ -1,14 +1,13 @@
use typst_library::diag::SourceResult;
use typst_library::foundations::{Content, Packed, Resolve, StyleChain, SymbolElem};
use typst_library::layout::{Em, Frame, FrameItem, Point, Size};
use typst_library::math::{BinomElem, FracElem};
use typst_library::math::{BinomElem, FracElem, DELIM_SHORT_FALL};
use typst_library::text::TextElem;
use typst_library::visualize::{FixedStroke, Geometry};
use typst_syntax::Span;
use super::{
style_for_denominator, style_for_numerator, FrameFragment, GlyphFragment,
MathContext, DELIM_SHORT_FALL,
style_for_denominator, style_for_numerator, FrameFragment, GlyphFragment, MathContext,
};
const FRAC_AROUND: Em = Em::new(0.1);
@ -49,7 +48,7 @@ fn layout_frac_like(
binom: bool,
span: Span,
) -> SourceResult<()> {
let short_fall = DELIM_SHORT_FALL.resolve(styles);
let short_fall = DELIM_SHORT_FALL.abs().resolve(styles);
let axis = scaled!(ctx, styles, axis_height);
let thickness = scaled!(ctx, styles, fraction_rule_thickness);
let shift_up = scaled!(

View File

@ -1,19 +1,20 @@
use typst_library::diag::{bail, warning, SourceResult};
use typst_library::foundations::{Content, Packed, Resolve, StyleChain};
use typst_library::layout::{
Abs, Axes, Em, FixedAlignment, Frame, FrameItem, Point, Ratio, Rel, Size,
Abs, Axes, Em, FixedAlignment, Frame, FrameItem, Point, Rel, Size,
};
use typst_library::math::{
Augment, AugmentOffsets, CasesElem, MatElem, StretchSize, VecElem,
};
use typst_library::math::{Augment, AugmentOffsets, CasesElem, MatElem, VecElem};
use typst_library::text::TextElem;
use typst_library::visualize::{FillRule, FixedStroke, Geometry, LineCap, Shape};
use typst_syntax::Span;
use super::{
alignments, delimiter_alignment, style_for_denominator, AlignmentResult,
FrameFragment, GlyphFragment, LeftRightAlternator, MathContext, DELIM_SHORT_FALL,
FrameFragment, GlyphFragment, LeftRightAlternator, MathContext,
};
const VERTICAL_PADDING: Ratio = Ratio::new(0.1);
const DEFAULT_STROKE_THICKNESS: Em = Em::new(0.05);
/// Lays out a [`VecElem`].
@ -39,7 +40,15 @@ pub fn layout_vec(
)?;
let delim = elem.delim(styles);
layout_delimiters(ctx, styles, frame, delim.open(), delim.close(), span)
layout_delimiters(
ctx,
styles,
frame,
elem.delim_size(styles),
delim.open(),
delim.close(),
span,
)
}
/// Lays out a [`CasesElem`].
@ -67,7 +76,7 @@ pub fn layout_cases(
let delim = elem.delim(styles);
let (open, close) =
if elem.reverse(styles) { (None, delim.close()) } else { (delim.open(), None) };
layout_delimiters(ctx, styles, frame, open, close, span)
layout_delimiters(ctx, styles, frame, elem.delim_size(styles), open, close, span)
}
/// Lays out a [`MatElem`].
@ -125,7 +134,15 @@ pub fn layout_mat(
)?;
let delim = elem.delim(styles);
layout_delimiters(ctx, styles, frame, delim.open(), delim.close(), span)
layout_delimiters(
ctx,
styles,
frame,
elem.delim_size(styles),
delim.open(),
delim.close(),
span,
)
}
/// Layout the inner contents of a matrix, vector, or cases.
@ -302,19 +319,23 @@ fn layout_delimiters(
ctx: &mut MathContext,
styles: StyleChain,
mut frame: Frame,
size: StretchSize,
left: Option<char>,
right: Option<char>,
span: Span,
) -> SourceResult<()> {
let short_fall = DELIM_SHORT_FALL.resolve(styles);
let axis = scaled!(ctx, styles, axis_height);
let height = frame.height();
let target = height + VERTICAL_PADDING.of(height);
frame.set_baseline(height / 2.0 + axis);
let target = size.resolve(ctx.engine, styles, height)?;
if let Some(left) = left {
let mut left = GlyphFragment::new(ctx, styles, left, span)
.stretch_vertical(ctx, target, short_fall);
let mut left = GlyphFragment::new(ctx, styles, left, span).stretch_vertical(
ctx,
target,
Abs::zero(),
);
left.align_on_axis(ctx, delimiter_alignment(left.c));
ctx.push(left);
}
@ -322,8 +343,11 @@ fn layout_delimiters(
ctx.push(FrameFragment::new(styles, frame));
if let Some(right) = right {
let mut right = GlyphFragment::new(ctx, styles, right, span)
.stretch_vertical(ctx, target, short_fall);
let mut right = GlyphFragment::new(ctx, styles, right, span).stretch_vertical(
ctx,
target,
Abs::zero(),
);
right.align_on_axis(ctx, delimiter_alignment(right.c));
ctx.push(right);
}

View File

@ -1,6 +1,6 @@
use ttf_parser::math::MathValue;
use typst_library::foundations::{Style, StyleChain};
use typst_library::layout::{Abs, Em, FixedAlignment, Frame, Point, Size, VAlignment};
use typst_library::layout::{Abs, FixedAlignment, Frame, Point, Size, VAlignment};
use typst_library::math::{EquationElem, MathSize};
use typst_utils::LazyHash;
@ -28,9 +28,6 @@ macro_rules! percent {
};
}
/// How much less high scaled delimiters can be than what they wrap.
pub const DELIM_SHORT_FALL: Em = Em::new(0.1);
/// Converts some unit to an absolute length with the current font & font size.
pub trait Scaled {
fn scaled(self, ctx: &MathContext, font_size: Abs) -> Abs;

View File

@ -2,7 +2,7 @@ use crate::foundations::{elem, func, Content, NativeElement, NativeFunc, SymbolE
use crate::layout::{Em, Length, Ratio, Rel};
use crate::math::{Mathy, StretchSize};
const DELIM_SHORT_FALL: Em = Em::new(-0.1);
pub const DELIM_SHORT_FALL: Em = Em::new(-0.1);
#[func(name = "x => x - 0.1em")]
pub const fn default_lr_size(base: Length) -> Rel {

View File

@ -5,15 +5,27 @@ use unicode_math_class::MathClass;
use crate::diag::{bail, At, HintedStrResult, StrResult};
use crate::foundations::{
array, cast, dict, elem, Array, Content, Dict, Fold, NoneValue, Resolve, Smart,
StyleChain, Symbol, Value,
array, cast, dict, elem, func, Array, Content, Dict, Fold, NativeFunc, NoneValue,
Resolve, Smart, StyleChain, Symbol, Value,
};
use crate::layout::{Abs, Em, HAlignment, Length, Rel};
use crate::math::Mathy;
use crate::layout::{Abs, Em, HAlignment, Length, Ratio, Rel};
use crate::math::{Mathy, StretchSize, DELIM_SHORT_FALL};
use crate::visualize::Stroke;
const DEFAULT_ROW_GAP: Em = Em::new(0.2);
const DEFAULT_COL_GAP: Em = Em::new(0.5);
const VERTICAL_PADDING: Ratio = Ratio::new(1.1);
#[func(name = "x => x * 1.1 - 0.1em")]
const fn default_mat_size(base: Length) -> Rel {
Rel {
rel: Ratio::zero(),
abs: Length {
abs: Abs::raw(base.abs.to_raw() * VERTICAL_PADDING.get()),
em: DELIM_SHORT_FALL,
},
}
}
/// A column vector.
///
@ -40,6 +52,13 @@ pub struct VecElem {
#[default(DelimiterPair::PAREN)]
pub delim: DelimiterPair,
/// The size of the delimiters, relative to the elements' total height.
///
/// See the [stretch documentation]($math.stretch.size) for more
/// information on sizes.
#[default(<default_mat_size>::data().into())]
pub delim_size: StretchSize,
/// The horizontal alignment that each element should have.
///
/// ```example
@ -101,6 +120,13 @@ pub struct MatElem {
#[default(DelimiterPair::PAREN)]
pub delim: DelimiterPair,
/// The size of the delimiters, relative to the cells' total height.
///
/// See the [stretch documentation]($math.stretch.size) for more
/// information on sizes.
#[default(<default_mat_size>::data().into())]
pub delim_size: StretchSize,
/// The horizontal alignment that each cell should have.
///
/// ```example
@ -244,6 +270,13 @@ pub struct CasesElem {
#[default(DelimiterPair::BRACE)]
pub delim: DelimiterPair,
/// The size of the delimiters, relative to the branches' total height.
///
/// See the [stretch documentation]($math.stretch.size) for more
/// information on sizes.
#[default(<default_mat_size>::data().into())]
pub delim_size: StretchSize,
/// Whether the direction of cases should be reversed.
///
/// ```example

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -16,6 +16,12 @@ $ x = cases(1, 2) $
#set math.cases(delim: sym.angle.l)
$ cases(a, b, c) $
--- math-cases-delim-size ---
// Test setting delimiter size.
$ cases(reverse: #true, 1, 2, 3) cases(delim-size: #100%, 1, 2, 3) $
#set math.cases(delim-size: x => calc.max(x - 5pt, x * 0.901))
$ cases(1, 2) cases(1, 2, 3, 4) $
--- math-cases-linebreaks ---
// Warning: 40-49 linebreaks are ignored in branches
// Hint: 40-49 use commas instead to separate each line

View File

@ -54,6 +54,12 @@ $ a + mat(delim: #none, 1, 2; 3, 4) + b $
$ mat(1, 2; 3, 4; delim: "[") $,
)
--- math-mat-delim-size ---
// Test setting delimiter size.
$ mat(c; c; c) mat(delim-size: #100%, c; c; c) $
#set math.mat(delim-size: x => calc.max(x - 5pt, x * 0.901))
$ mat(delim: "[", f; f; f; f) mat(delim: ||, x; x; x; x) $
--- math-mat-spread ---
// Test argument spreading in matrix.
$ mat(..#range(1, 5).chunks(2))
@ -263,7 +269,7 @@ $ mat(a; b; c) mat(a \ b \ c) $
--- math-mat-vec-cases-unity ---
// Test that matrices, vectors, and cases are all laid out the same.
$ mat(z_(n_p); a^2)
vec(z_(n_p), a^2)
vec(z_(n_p), a^2)
cases(reverse: #true, delim: \(, z_(n_p), a^2)
cases(delim: \(, z_(n_p), a^2) $

View File

@ -50,6 +50,12 @@ $ vec(1, 2) $
// Error: 22-33 invalid delimiter: "%"
#set math.vec(delim: (none, "%"))
--- math-vec-delim-size ---
// Test setting delimiter size.
$ vec(1, 2, 3) vec(delim-size: #100%, 1, 2, 3) $
#set math.vec(delim-size: x => calc.max(x - 5pt, x * 0.901))
$ vec(delim: "{", 1, 2, 3) vec(delim: "[", 1, 2, 3) $
--- math-vec-linebreaks ---
// Warning: 20-29 linebreaks are ignored in elements
// Hint: 20-29 use commas instead to separate each line