mirror of
https://github.com/typst/typst
synced 2025-06-28 08:12:53 +08:00
Fix nested attachments when the base in math.attach
has attachments (#4832)
This commit is contained in:
parent
77b6c8481f
commit
0b31f6039f
@ -52,20 +52,22 @@ pub struct AttachElem {
|
||||
impl LayoutMath for Packed<AttachElem> {
|
||||
#[typst_macros::time(name = "math.attach", span = self.span())]
|
||||
fn layout_math(&self, ctx: &mut MathContext, styles: StyleChain) -> SourceResult<()> {
|
||||
let base = ctx.layout_into_fragment(self.base(), styles)?;
|
||||
let new_elem = merge_base(self);
|
||||
let elem = new_elem.as_ref().unwrap_or(self);
|
||||
|
||||
let base = ctx.layout_into_fragment(elem.base(), styles)?;
|
||||
let sup_style = style_for_superscript(styles);
|
||||
let sup_style_chain = styles.chain(&sup_style);
|
||||
let tl = self.tl(sup_style_chain);
|
||||
let tr = self.tr(sup_style_chain);
|
||||
let tl = elem.tl(sup_style_chain);
|
||||
let tr = elem.tr(sup_style_chain);
|
||||
let primed = tr.as_ref().is_some_and(|content| content.is::<PrimesElem>());
|
||||
let t = self.t(sup_style_chain);
|
||||
let t = elem.t(sup_style_chain);
|
||||
|
||||
let sub_style = style_for_subscript(styles);
|
||||
let sub_style_chain = styles.chain(&sub_style);
|
||||
let bl = self.bl(sub_style_chain);
|
||||
let br = self.br(sub_style_chain);
|
||||
let b = self.b(sub_style_chain);
|
||||
let bl = elem.bl(sub_style_chain);
|
||||
let br = elem.br(sub_style_chain);
|
||||
let b = elem.b(sub_style_chain);
|
||||
|
||||
let limits = base.limits().active(styles);
|
||||
let (t, tr) = match (t, tr) {
|
||||
@ -248,6 +250,43 @@ impl Limits {
|
||||
}
|
||||
}
|
||||
|
||||
/// If an AttachElem's base is also an AttachElem, merge attachments into the
|
||||
/// base AttachElem where possible.
|
||||
fn merge_base(elem: &Packed<AttachElem>) -> Option<Packed<AttachElem>> {
|
||||
// Extract from an EquationElem.
|
||||
let mut base = elem.base();
|
||||
if let Some(equation) = base.to_packed::<EquationElem>() {
|
||||
base = equation.body();
|
||||
}
|
||||
|
||||
// Move attachments from elem into base where possible.
|
||||
if let Some(base) = base.to_packed::<AttachElem>() {
|
||||
let mut elem = elem.clone();
|
||||
let mut base = base.clone();
|
||||
|
||||
macro_rules! merge {
|
||||
($content:ident) => {
|
||||
if base.$content.is_none() && elem.$content.is_some() {
|
||||
base.$content = elem.$content.clone();
|
||||
elem.$content = None;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
merge!(t);
|
||||
merge!(b);
|
||||
merge!(tl);
|
||||
merge!(tr);
|
||||
merge!(bl);
|
||||
merge!(br);
|
||||
|
||||
elem.base = base.pack();
|
||||
return Some(elem);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
macro_rules! measure {
|
||||
($e: ident, $attr: ident) => {
|
||||
$e.as_ref().map(|e| e.$attr()).unwrap_or_default()
|
||||
|
BIN
tests/ref/math-attach-nested-base.png
Normal file
BIN
tests/ref/math-attach-nested-base.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
@ -69,7 +69,7 @@ $ sqrt(a_(1/2)^zeta), sqrt(a_alpha^(1/2)), sqrt(a_(1/2)^(3/4)) \
|
||||
sqrt(attach(a, tl: 1/2, bl: 3/4, tr: 1/2, br: 3/4)) $
|
||||
|
||||
--- math-attach-descender-collision ---
|
||||
// Test for no collisions between descenders/ascenders and attachments
|
||||
// Test for no collisions between descenders/ascenders and attachments.
|
||||
|
||||
$ sup_(x in P_i) quad inf_(x in P_i) $
|
||||
$ op("fff",limits: #true)^(y) quad op("yyy", limits:#true)_(f) $
|
||||
@ -112,7 +112,7 @@ $ attach(A, t: #context oops) $
|
||||
$iota_a^b$
|
||||
|
||||
--- math-attach-default-placement ---
|
||||
// Test default of limit attachments on relations at all sizes
|
||||
// Test default of limit attachments on relations at all sizes.
|
||||
#set page(width: auto)
|
||||
$ a =^"def" b quad a lt.eq_"really" b quad a arrow.r.long.squiggly^"slowly" b $
|
||||
$a =^"def" b quad a lt.eq_"really" b quad a arrow.r.long.squiggly^"slowly" b$
|
||||
@ -120,11 +120,22 @@ $a =^"def" b quad a lt.eq_"really" b quad a arrow.r.long.squiggly^"slowly" b$
|
||||
$a scripts(=)^"def" b quad a scripts(lt.eq)_"really" b quad a scripts(arrow.r.long.squiggly)^"slowly" b$
|
||||
|
||||
--- math-attach-integral ---
|
||||
// Test default of scripts attachments on integrals at display size
|
||||
// Test default of scripts attachments on integrals at display size.
|
||||
$ integral.sect_a^b quad \u{2a1b}_a^b quad limits(\u{2a1b})_a^b $
|
||||
$integral.sect_a^b quad \u{2a1b}_a^b quad limits(\u{2a1b})_a^b$
|
||||
|
||||
--- math-attach-large-operator ---
|
||||
// Test default of limit attachments on large operators at display size only
|
||||
// Test default of limit attachments on large operators at display size only.
|
||||
$ tack.t.big_0^1 quad \u{02A0A}_0^1 quad join_0^1 $
|
||||
$tack.t.big_0^1 quad \u{02A0A}_0^1 quad join_0^1$
|
||||
|
||||
--- math-attach-nested-base ---
|
||||
// Test attachments when the base has attachments.
|
||||
$ attach(a^b, b: c) quad
|
||||
attach(attach(attach(attach(attach(attach(sum, tl: 1), t: 2), tr: 3), br: 4), b: 5), bl: 6) $
|
||||
|
||||
#let a0 = math.attach(math.alpha, b: [0])
|
||||
#let a1 = $alpha^1$
|
||||
|
||||
$ a0 + a1 + a0_2 \
|
||||
a1_2 + a0^2 + a1^2 $
|
||||
|
Loading…
x
Reference in New Issue
Block a user