From d1c7d08893ef293e74ac0763005e1dd3f46e6495 Mon Sep 17 00:00:00 2001 From: Leedehai <18319900+Leedehai@users.noreply.github.com> Date: Mon, 8 Jul 2024 15:32:58 -0400 Subject: [PATCH] Primes should not further raise next superscript's position (#4492) Co-authored-by: Ian Wrzesinski <133046678+wrzian@users.noreply.github.com> --- crates/typst-syntax/src/parser.rs | 7 +-- crates/typst/src/eval/math.rs | 6 ++- crates/typst/src/math/attach.rs | 50 ++++++++++++++------- tests/ref/math-primes-complex.png | Bin 1274 -> 1652 bytes tests/ref/math-primes-with-superscript.png | Bin 0 -> 956 bytes tests/suite/math/primes.typ | 15 ++++++- 6 files changed, 53 insertions(+), 25 deletions(-) create mode 100644 tests/ref/math-primes-with-superscript.png diff --git a/crates/typst-syntax/src/parser.rs b/crates/typst-syntax/src/parser.rs index 7e7eeea5f..ff01bacfd 100644 --- a/crates/typst-syntax/src/parser.rs +++ b/crates/typst-syntax/src/parser.rs @@ -393,11 +393,6 @@ fn math_expr_prec(p: &mut Parser, min_prec: usize, stop: SyntaxKind) { continue; } - // Separate primes and superscripts to different attachments. - if primed && p.current() == SyntaxKind::Hat { - p.wrap(m, SyntaxKind::MathAttach); - } - let Some((kind, stop, assoc, mut prec)) = math_op(p.current()) else { // No attachments, so we need to wrap primes as attachment. if primed { @@ -429,7 +424,7 @@ fn math_expr_prec(p: &mut Parser, min_prec: usize, stop: SyntaxKind) { math_expr_prec(p, prec, stop); math_unparen(p, m2); - if p.eat_if(SyntaxKind::Underscore) || (!primed && p.eat_if(SyntaxKind::Hat)) { + if p.eat_if(SyntaxKind::Underscore) || p.eat_if(SyntaxKind::Hat) { let m3 = p.marker(); math_expr_prec(p, prec, SyntaxKind::End); math_unparen(p, m3); diff --git a/crates/typst/src/eval/math.rs b/crates/typst/src/eval/math.rs index 0e5e0eef0..548c935dc 100644 --- a/crates/typst/src/eval/math.rs +++ b/crates/typst/src/eval/math.rs @@ -54,7 +54,11 @@ impl Eval for ast::MathAttach<'_> { if let Some(expr) = self.top() { elem.push_t(Some(expr.eval_display(vm)?)); - } else if let Some(primes) = self.primes() { + } + + // Always attach primes in scripts style (not limits style), + // i.e. at the top-right corner. + if let Some(primes) = self.primes() { elem.push_tr(Some(primes.eval(vm)?)); } diff --git a/crates/typst/src/math/attach.rs b/crates/typst/src/math/attach.rs index 7cc03bbab..8d85f8c41 100644 --- a/crates/typst/src/math/attach.rs +++ b/crates/typst/src/math/attach.rs @@ -52,31 +52,47 @@ pub struct AttachElem { impl LayoutMath for Packed { #[typst_macros::time(name = "math.attach", span = self.span())] fn layout_math(&self, ctx: &mut MathContext, styles: StyleChain) -> SourceResult<()> { - type GetAttachment = fn(&AttachElem, styles: StyleChain) -> Option; - - let layout_attachment = - |ctx: &mut MathContext, styles: StyleChain, getter: GetAttachment| { - getter(self, styles) - .map(|elem| ctx.layout_into_fragment(&elem, styles)) - .transpose() - }; - let base = ctx.layout_into_fragment(self.base(), styles)?; let sup_style = style_for_superscript(styles); - let tl = layout_attachment(ctx, styles.chain(&sup_style), AttachElem::tl)?; - let tr = layout_attachment(ctx, styles.chain(&sup_style), AttachElem::tr)?; - let t = layout_attachment(ctx, styles.chain(&sup_style), AttachElem::t)?; + let sup_style_chain = styles.chain(&sup_style); + let tl = self.tl(sup_style_chain); + let tr = self.tr(sup_style_chain); + let primed = tr.as_ref().is_some_and(|content| content.is::()); + let t = self.t(sup_style_chain); let sub_style = style_for_subscript(styles); - let bl = layout_attachment(ctx, styles.chain(&sub_style), AttachElem::bl)?; - let br = layout_attachment(ctx, styles.chain(&sub_style), AttachElem::br)?; - let b = layout_attachment(ctx, styles.chain(&sub_style), AttachElem::b)?; + 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 limits = base.limits().active(styles); - let (t, tr) = if limits || tr.is_some() { (t, tr) } else { (None, t) }; + let (t, tr) = match (t, tr) { + (Some(t), Some(tr)) if primed && !limits => (None, Some(tr + t)), + (Some(t), None) if !limits => (None, Some(t)), + (t, tr) => (t, tr), + }; let (b, br) = if limits || br.is_some() { (b, br) } else { (None, b) }; - layout_attachments(ctx, styles, base, [tl, t, tr, bl, b, br]) + + macro_rules! layout { + ($content:ident, $style_chain:ident) => { + $content + .map(|elem| ctx.layout_into_fragment(&elem, $style_chain)) + .transpose() + }; + } + + let fragments = [ + layout!(tl, sup_style_chain)?, + layout!(t, sup_style_chain)?, + layout!(tr, sup_style_chain)?, + layout!(bl, sub_style_chain)?, + layout!(b, sub_style_chain)?, + layout!(br, sub_style_chain)?, + ]; + + layout_attachments(ctx, styles, base, fragments) } } diff --git a/tests/ref/math-primes-complex.png b/tests/ref/math-primes-complex.png index 5f5558eb214d68ffe35bf8455ffc4ea857c4540d..0e85d08d36563c74ed8a41070bdcc02f6289c71b 100644 GIT binary patch delta 1648 zcmV-$29Npr3G@t*7k_sM00000?OEH~000I%Nkl81gl?;nRauj5iJ&V`}=hC|DPw&$P=k> zD*T|5nl99Y zkG62Uwvnj!uAL@EMP02IrGmz@K$odsRrnnY#RQ3%%pz7_4ndUezOD9g@)(AlOIGgG z4O)=+jf1O!_kYaogt_!%?&;!*o|q-BLUWg@aB%a|TNeNpmXL^B<_?yj;M=s4sb|^x z)g`LJA0FbhS*8MnUEaseAppjaoGjuM2NQyF$<|r<4i({jCe{t{+A?8>^=pG2W4PWx zlGP(@7-Ex`u$-2)J2uU;n5`n*Szi6;dbZqj0si$s|9^>^^b5Q`B-UB6r2)6joqy#r zuio?ktAC6v$rz$)Sw)xt0RCvOVOO_O``9j z!3ellKsHf)uM}{2L3aD&x>jJt9a(bzb`7e-LT!l{J19HgLdjQKMhtKH0e|WskP1Iq zIG|B@;(wq<;bJFowkIL%>+Rd4+2!!koXFaJgnrd z;l>Q)x+_4I#rFF|`28L#^;f1*7ybt@dZEcS<$qKR;D+&CYY=4D+jL{ZIAyIwefYs< zw)H?vxafKXVIHew35jd%`)JGBr=TXB0ei3TVn{qD;5jM}fT?i{VWVdx*O2s{iC9$= z{u})LzHMU{nV_>s0|kEwz-(8wC{qC9i=i4bjA-ExQm$bmn+(r~OE~*OuWuB;JkbK zx53y*tf4Ygg`W)(75wcr;*7NVFv7Lc5+4zBO&*#=b>W|)H2KsFG3rkatOqz#Qh!NA z@7~3q1FFLAUl5}@10~^^P~U%uw{F&*25wd1$#ujyG>y{qpE%YyL7ZRn>Cp*O+rNfX zguAyOY5yMpH6|kRJApl>&4trMRaFD|?Qi9Gw1!Hrst6kkkOWHsx+?(iz7KHE1mM7l zf};w+&MMgRf&?Bhyc#HKMKT=(tbcFX9gc;5-P2NXg0C@2nElAut%jS&9xZ&mAP) z*FyjoVBKm2GTHHv1cqhzI)9f+W>5;ArEoa4EvCY$a4MXbu%J4kGi4BLP9 z{7Y+o|H~gf`2$xH!_LmAL2V8KAxL_-(O5WcxRm^G#~JE`!z4d!Pv1NeuxJn-VLls@ uA9igTuI7k_3500000CDRJ!000ERNkl21lfdF(k4_Vf5VC;2{{|H=P14S$79i-+Uk|EX4?aC5OD z;nSLYVjXr8Wymve=^N*G%)_f4L|QXeX5L{&TKG;$1OM)EE|JWoST*%l31QvOj3;0q z#GG4B1jlKe!AqFI{0oDUf2UM4rfu{R^0B*@2nmiRA}sRtA~if#2(&es30X%E;U-sO zCYP8RXGrcxR5T8KKaI|=8#Ruh7JH|Y0R-l`eR>1OyK zPaSq&?yA1;UeunAAh!c(t<$SXK7X!x0>qqJ-PA!sO(8&r5zt<1YbCMjVxwE)sqQS& zst{B&C7G`PZw&$NbEy7ne-JWBBVdj2 zFsSiHwWTJv@0wd$I0fLLhub>*QlZ1haQzOWk$-?+bt|tDA;Ys5q=gf~yRKoGHhchN z^{WVRx`@OB+48K5-DHvPLW~f%+mSY$uYGaP|naJiam6_ibm1 z4S#ralrUra0X(a%WCH!g2<#&uJv>>A=%Tuy1EA1Fm_J4VTG!^??gMT(0ZtVhMxd1z z=AH?`NXcP0`Fn%}{A@{Co1``CT-`ym?&gnP=@ zccMg?;R$zq=Zc5_V>pRu-a9c5*VWR#D}PXP`njNDcdWx#F6?(_xe%q#%FN8%^TWL9 zCQ@9n4zD!ABmA6iUq;Y!)Yd?(!|#t1(lgVHzz8u9ze%`b3*4pVu?!zCLS(!NkY)jJW)uL_+kayh zzS5FnC!}C*Qc}{g4`;k;jrBLSpEJa-#dtU#j)!FqSIQN(>qC0s=32SJ`suS&e=E-3 zn)LcBHn!R13X}1|S^Qi_4$+8gVHUhLKtLVH7#@COu2-2;UH9T}0o|!`hJQ={Q*irw+2WU)WeoSfGdpPE zbF>KDvOBDL`NJa_1FHtJ4DyGyYfSgZL;f&lJ}dN0DiAJaYzxRAw(KZB?}#t-@o+pG d4?kz&zW_}cx|`89^XmWr002ovPDHLkV1i`PYT5t* diff --git a/tests/ref/math-primes-with-superscript.png b/tests/ref/math-primes-with-superscript.png new file mode 100644 index 0000000000000000000000000000000000000000..88a892b9772223f3b18a8468ec09666ccc2c2ee9 GIT binary patch literal 956 zcmV;t14I0YP)`EWjb-@`xkTK;7x?LwDAKrw%!D}x_J?2JVvl4W?mOSXt2)aX%2DC!qH8Dc0- zjk#2W?7}}>1Oi_NQMCGizel*;oty?bIA_ryN+= zi(;`2;Q0i>Dv0htAsqnN?LshI>4w`!$S!d8fFN?drmenas|2)I~a!yF{q zac7B?feFA-U}1Rn1UQGr?|I_HO<=|h(BFZ~I|XznYmL{CO3U8_5Ql-~&jDtP5Q2SW zFaHH_L%Ay91xTuW<8AI0{%Rx8kN`Mv10dYIEj2k_TOq~z6e!`P+?u-XBp zYjW9R!zC6@BHI=s>6uyjC(vGc^I_HwA=~dDlkF`qAv2!=fq0hT=^~n<$X-efp%xRe zl`_&+pAe5PA$ui;%2NTm6OspFLN+lllvB8&`dieD#ojL{M5Cwr7$$!wduC9Zs@jF+ z${wMUqV-(D&&E*;ydHy~0ga-tuvP(LsfgNpH)E7ey$_)ZatL=l?LZ|`_o|DPHaBXQ z9=Fl+2V(nt5EaKpGvl`AFyZ5~@f^aoPtiDZ8EI?zcGTu}fgj!}-V#7jCCAuP4t3-S|qcxG-!u_?&s2%