From 444c8682ce1db796210064f2fdb892b0c45b5edf Mon Sep 17 00:00:00 2001 From: Ana Gelez Date: Tue, 2 Apr 2024 14:16:00 +0200 Subject: [PATCH] Never shrink lines in raw blocks (#3796) --- crates/typst/src/layout/inline/mod.rs | 15 ++++++++----- crates/typst/src/model/par.rs | 9 ++++++++ crates/typst/src/text/raw.rs | 7 ++++-- tests/ref/layout/code-indent-shrink.png | Bin 0 -> 8232 bytes tests/typ/layout/code-indent-shrink.typ | 28 ++++++++++++++++++++++++ 5 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 tests/ref/layout/code-indent-shrink.png create mode 100644 tests/typ/layout/code-indent-shrink.typ diff --git a/crates/typst/src/layout/inline/mod.rs b/crates/typst/src/layout/inline/mod.rs index d79dcba49..9928cb822 100644 --- a/crates/typst/src/layout/inline/mod.rs +++ b/crates/typst/src/layout/inline/mod.rs @@ -73,7 +73,8 @@ pub(crate) fn layout_inline( let lines = linebreak(&engine, &p, region.x - p.hang); // Stack the lines into one frame per region. - finalize(&mut engine, &p, &lines, region, expand) + let shrink = ParElem::shrink_in(styles); + finalize(&mut engine, &p, &lines, region, expand, shrink) } let fragment = cached( @@ -1191,6 +1192,7 @@ fn finalize( lines: &[Line], region: Size, expand: bool, + shrink: bool, ) -> SourceResult { // Determine the paragraph's width: Full width of the region if we // should expand or there's fractional spacing, fit-to-width otherwise. @@ -1207,7 +1209,7 @@ fn finalize( // Stack the lines into one frame per region. let mut frames: Vec = lines .iter() - .map(|line| commit(engine, p, line, width, region.y)) + .map(|line| commit(engine, p, line, width, region.y, shrink)) .collect::>()?; // Prevent orphans. @@ -1243,6 +1245,7 @@ fn commit( line: &Line, width: Abs, full: Abs, + shrink: bool, ) -> SourceResult { let mut remaining = width - line.width - p.hang; let mut offset = Abs::zero(); @@ -1289,12 +1292,12 @@ fn commit( let mut justification_ratio = 0.0; let mut extra_justification = Abs::zero(); - let shrink = line.shrinkability(); + let shrinkability = line.shrinkability(); let stretch = line.stretchability(); - if remaining < Abs::zero() && shrink > Abs::zero() { + if remaining < Abs::zero() && shrinkability > Abs::zero() && shrink { // Attempt to reduce the length of the line, using shrinkability. - justification_ratio = (remaining / shrink).max(-1.0); - remaining = (remaining + shrink).min(Abs::zero()); + justification_ratio = (remaining / shrinkability).max(-1.0); + remaining = (remaining + shrinkability).min(Abs::zero()); } else if line.justify && fr.is_zero() { // Attempt to increase the length of the line, using stretchability. if stretch > Abs::zero() { diff --git a/crates/typst/src/model/par.rs b/crates/typst/src/model/par.rs index cc4a1fcb7..f8a833aca 100644 --- a/crates/typst/src/model/par.rs +++ b/crates/typst/src/model/par.rs @@ -96,6 +96,15 @@ pub struct ParElem { #[resolve] pub hanging_indent: Length, + /// Indicates wheter an overflowing line should be shrunk. + /// + /// This property is set to `false` on raw blocks, because shrinking a line + /// could visually break the indentation. + #[ghost] + #[internal] + #[default(true)] + pub shrink: bool, + /// The contents of the paragraph. #[external] #[required] diff --git a/crates/typst/src/text/raw.rs b/crates/typst/src/text/raw.rs index 2d590d2a9..f0105363f 100644 --- a/crates/typst/src/text/raw.rs +++ b/crates/typst/src/text/raw.rs @@ -16,7 +16,7 @@ use crate::foundations::{ PlainText, Show, ShowSet, Smart, StyleChain, Styles, Synthesize, Value, }; use crate::layout::{BlockElem, Em, HAlignment}; -use crate::model::Figurable; +use crate::model::{Figurable, ParElem}; use crate::syntax::{split_newlines, LinkedNode, Span, Spanned}; use crate::text::{ FontFamily, FontList, Hyphenate, Lang, LinebreakElem, LocalName, Region, @@ -440,13 +440,16 @@ impl Show for Packed { } impl ShowSet for Packed { - fn show_set(&self, _: StyleChain) -> Styles { + fn show_set(&self, styles: StyleChain) -> Styles { let mut out = Styles::new(); out.set(TextElem::set_overhang(false)); out.set(TextElem::set_hyphenate(Hyphenate(Smart::Custom(false)))); out.set(TextElem::set_size(TextSize(Em::new(0.8).into()))); out.set(TextElem::set_font(FontList(vec![FontFamily::new("DejaVu Sans Mono")]))); out.set(SmartQuoteElem::set_enabled(false)); + if self.block(styles) { + out.set(ParElem::set_shrink(false)); + } out } } diff --git a/tests/ref/layout/code-indent-shrink.png b/tests/ref/layout/code-indent-shrink.png new file mode 100644 index 0000000000000000000000000000000000000000..26f6ec404f5e8073c96cbc379da0eea0c520fc2d GIT binary patch literal 8232 zcma)>WmFu&mVjrFfxrZpA=n@xIKvR!HMmQF0E0`g;O-2TAPFQuaDux8mm#=A7(##$ zT!Om>Sl-+Hu|M9vw|%Nl)v4QctNK>=z2EJQ(Nur&81D%l004Nbq$sBi006NbP9QGE zLl1G0>OKHKf1o5Mt?M(lJ7cDzV@`uQ;yx!iCphN@-8RQ*iL`7n!b{?&-!g7EkQ*lP zG8%!xi5|7!hJ6Jwgx*RIrj2oUM*DbVW!9}uHoG^t2mB6|U>!o^k4J*h2T_Z??sQ}8 z2mVVLz=!Gn=g1)!2qBGt04xB}Kqx5WKQ@FGcya5oIMl&VkOhF32s1hqA_eXNSU^EU zn7kp7Xkd@jzZ5-4|3#5~ZCTxir$Rd!d9tSr)4kzijK}WR3d`M|Ie5_Xf=aez&#!qW zH#6H#m2zQvn>VIQPc-jqc4tf|B%TxWqKvg`Vs0rBz?(4#DNkxk+AR}P8G_W~XsjEm z2ioZGR`=tjP`cEMzRABZ2`ptjhfAIscOrLsXV)+2`LD)ylFJMtaAM>bQ+xY zNvbSNZT2Ih)Po&+HT}=zNxiN0Oa%(#rd=dY_vys%e$mlB16c@VoOL1!an{ZUAg9mT zk2zmdrvI!J5c-nQ{-xhfUm}q0#VS7K+}_^^JMESLwct~?qZPf|qq6lz`?C%4*FL&F ziNosw5@rIQ$&J4)yF!UzYC1lvtZ_DeQiVQ;*JKe{FP_F0fBi-G=Fg2()=r%0w1T$qM{$5im1 z64|?2SG$m1w0oU7Juiy@AgdvNm2~b{|4v+lnzZiCdJ%Q6O!5)4XPhV(XtSq$|5M*- z6$=i3a~Y(wwt%@e{rX|ZA*9$iM@a-Z zs#?+wVX@*rug>5xYh-!n4IiDDr|6Nw_a+v2r@-`SSnEWJOAZZ@z{G^fA-kqMjL5ha zPb2943eeR4-%c32Cic8YV|oxUJAuz=u@M`-2VE+$p|w8885F-fKK0cbmi(TZG4-%( z6GcwiB`X)q?Fqc2?PsHiLrc1jg#sbmY#<5ATw3Nip7cf0oT{FL4IP6i@BW+}KZ)!r z{jzW49wMVw@CtpE44!8f^reCqTRF9VDBqu@&QU*1mDw%)wKvQ9{)~d3@W*5g-z|&S zfrk8k2@7}Xx|?vCs(x7tZUnCa^O$j!NKsg0e4P{b{`a5!BTL=&U3g$r$dWf0Ar%6I z5Fr2{EJz3t2zqGz+k(6g>8dTSpf7To_o8`$l~?M}xoALUeZmZb8W761oAQw1At+{)@paj~7Jr`~I)=X`vtXMTnvPoF-;#>P%gc}yiW)(__3;Lr^c78hUm z^-Go9me-`}Q)OjkZ7p0+&(Oxm*m!4WM_wxe45i1|nw-=s9pd5UKEDc3jT*JdH@ofY z>pMC+`udgsBY_1dF$#VtrokZX>G_peiIcWpsqul4Zr^P8KW|FfD1Tx$S#cXy*}d)M9Ur*d<1zkQQwoUc$56%pB**YIaHv+iA+vWGxs!9lrGD~oISJ+@AXL!cPByvoY>P2YjTPDE2%*U>#^ zx6@7KRr)9EK8qU7wAaie<|1o8yKU>gbncH6*1VsHok%KMW7fv0`;&XVco_{cUQu9I z0TU2toA|@i9yW%lk;3bpfxvy@sQUVnOli{+-!AZeiPXuy>a2owir7Hc=obm|Cqa># zCU1B3!`&tYo+-_VNzNk z)i$lB!NS_Gq1tAMUnml1jjl8Bo?p&uC68Llq~y$27GDE{isfxUH>ibad2i$jHd(rJ;=|g=6bjmBd!E}Fbg{B7YK1L*_3U9O8b4}A3f*0Px8bEF?H*D zRHu<}(DoHby5JX>a*S?3bYTz>#OLHd+1S{Yj+|2QLf(lZY+knc9Q|Ww)69Px$(1hn zEiu4oG5v7|_`CmlHVzJecf2J-;sDf$y}C-`Y^sn|#fQ;WBYc4QTNI@V?h{|L1wD8( zTU%Q=Ty|mq)#@M#=!0BUXA2gk<1d}1&H)TkE-}$a_Eq_?urO4gHUa_F$8Po7!>~bq zeLWNZPwONaOV=4Jo{tOP?cd@U*&<6+T>1>M`rMyGVUmgIR03vZB~v^A8tI`0GHgd4 zpzQ>7g}RbE)2IFsDXnjH)Ich>IvHS`4QmY3LcQ$4>_S39fQ0L{wYA-YgMPHA)7&F)PY!tLb zYic5+aM_7^p80BSDCC4cxkFu9elFR{ZE4DqP{j?FdfB{zc|b`=_Y?D*&+mZSpvzLA zMU$JTcxth}1DCH9z4+{(Skn0A_4)U0o_8n9Eh77yl!Pa}di5%KVN)!_sNF~P-ks&c;2#e+%>>Au z9w&v4o+q6}VhTg{_W$QoJSQurO)>dn7J{D%bKKbC4#C*l8*8vG+` z_&-w*8^`~Ztc0X334u_v%>Ow}`EPx&XkB)4Fo>4m1^1^Z4b}X~XgNmHs+rA`Kldh# zNt$H6&W)djtu0{M;Mly>QJb>qC+`%_v_hp&7B#Of2jkNsw5cQCh}Eg$Qx}j?4Jnv2 zQ0c$trHEyf6&KTBayszsPb!#SCg7>L<)7%i1$HcEDGrU&Ogi+Z>$v^IH; zZ?_%zj-6yI-%E}Y5qH@sC?HKoM#smaA|g`L(kdz{{)h-lN(S56DN+xXm6es2vb(#V zl$UdQ!sFuN?CtFn5)ve@ogbq7-QC^p(b5u14rIyLeQ_a}v$;V-Lz8T_Q&GXi!BI9g zrY>%@yT9M}>-@Yyy-unkKi^VY`~AmbyhsfA+WLA4X>ny`Lw)`8#Bc{kN2`RQq9PVJ z#4Ody#btcm*WX`KOzba}o2Tb=RqMgtUhj{wvG__-7iZ^=j*j|Ijn&ntG`sl1An;WB z=g+gNS69t3;Jz22Uouu!%omiDloz%G-QBC#*G30cu!#@lsvy}Ly~kEfO--<*F4n=r z<739WtCp4rIDWY2l7B9knvRabPIJb~+dD=94-YRrJzbGx%?hz~cINqjdTnhPIT$+@ zr)z6p9^!0ub)v-Y@IMg_2L}faHZn0Wd5B&zj+U1B?d_Q{r#w77{(gSS%F2EH{nJUy zi!M6{2b(9myN+&d@4?1$aBpw#{QUfaf&#fK#;tyC{~pRgayNpAWO;e{2m3#O;RE~q z`0?Y*@b&=eTUJ(<(9^M4HhOw`x3u|ra2`*p zY%)1Hc}i+3>oZK0nxZ1$=~C8`grK0oTLLiH$Ip)u@bZBNot&Jerlw*9wRLoeEn|tw z%F8|6+>Vcq%u8x&YR=Biy1Ke>H7m50kPl!2$8v3}uV?**R-QLy)rc;Fv0JohvpmAZ`FV~m zm?LUSXKrIQw)2v^11u#JO{qbP%lC=Edq;;6I-p*TFrvM zeI{A^{qxyOwXv?8pAcxi2@_Jn=lSPR67UB=_)^yH<)1%Fe(7UM6@Nl#t?u&Pew@hH zvg$n6a&u%2wKzs3-quk&P*YRa*4_id&n7lgsVcGYW8N18V|EV?#uRn;?6bmzuu1Gq z2U*neYUHitx!)w7oSclQ;urA?3Kq4DPIGf}lR=u9CBGf!x3;!cjv$y&iDoUppJ+6C zF--cB9VCke1MH<(UIIV`GQ5xpAqaz_l$U&(DH!?d1r0rYoEC3#QGO--!SRiJHhUKi zj5*-yf}I!2cnWk2%B3jFQ|v=R7{H2x?2?sQ3|pNFiv;)rZz7+KrZ^WYst!Tz(k65l zjHF-*TPh2$q;)lqPx3__9-1miM75b}{nHc)) zWQmf@csuBY+1abh%gg1Dc&V5n4=$N3hzYNYYdlQx-4hXr*yKp7ukLb@V`0MM{id0n zZE$YeqhOx|tjd zszrAy$jigS5G7_Ui(0YZ3S(1Kfj>Wfe3bbRh74Xad?XKR1nzkmfA4KjbXBg#8+@b{ zF*7rhhgS^IF&Rsu?h;2{^C#7PH5&c$p28&HK|~o#nxM2OLW(vsGh<79AjKjf=)k3G z#QR_ebKx%Sz1OxKk7L3@yzK>^yj$CilprZnb4*!y`SPXaNbxs4CS@LqD(M_W71D~g z)?+S?KW1i@LupK2SG6oSKSE0GF7P_Td5N%>Bn+0MJWdtS^{?<4CZ|x3o2KuTnBM7c zXvmP&_8yxOJE2-d8*CjDGTSaJ1~~T?k7Ok8KYuv;IXm%qjL5lhehCkgM)-}W&fhb? z^*C`Xzog0(KD5HSo$DSU2bMP`=dN3HDJi<9R2_P@u0bu8t*V;GKuSGSr0nzcok8UC zZ~wE3{wMl@1bCOzkP$Su*_gu>+Do55)BjL+6Rm`?rs`^Arr>c;x7 zh2;|U&5H+ld2_kXiUm|>z(ork7NGDtRlJQp^b3QslsJZp+BxDH`)sUkYH4nBPr(4Y zyBf0OvM+%oV3&xKD@R%vv+3F*x1!;7MyJDP+V&Y(-Sb`hVVR&-5%sW4J|Wx>#a|3b zz|x5b+%POzB4$V!w2KJq5fZ8h!;%hT!2N%Sy3K&kD4(RBuDgW9f{LDgPjNa495Z9U1D7sUv_p`f>*ldrkc9$tkSZ5x;JLQjkm&{GU zvXJNA+vV`+XaLol4Ks=RE?r$tPI3sm@zR`puCV=#T)Ir;ZO3lC>kFmDfEi3(9j|Dt zM_rz5_1oS#f6Q(ga!(+HpuLZ6l^!kG=il)mu`^BdeS zp6HIOl#`AVGW5%@bu?CoZK+W8dbRSayaW_)KR<#tESZwcez`QVLJ&Dg)s7O|&-+Bq z?^O~_vYnB}w0cZ*8_!hd@Uw*=N|~0Rp39^<-k(-lduylnR2}Mi$^CuU6F+|QUii%! zCx6+CC?!aC3%DF0a%6~4nxCq6&+pZ5@?DmcxcllYDEx+5izwv6o!B@X{}Q(YJIZP> zcBgt3bYd@qmqId$7_Pshf+~GG! zmkH4}AT6%$n6;f>nf+S%Nh|WM zK|h3zT(iH0Sf$w7xd?3167?FLRXS+^1wV5s&?O9{V1ux-&YNX1xa;ZcwHa$32~anX zwo810->mj02#SX{f5*7x=xUW^Hw~j7DkUr|uA$j+eF~OhL3f8MFri=!1~8O@x8XVY ze(G;l=qcyIl&^_)#4R%d;kE))ad^4So-X})*3m!VcyjE;K|*c4o~{4SjUHV?OFvBm zO$p*@E`Nc(Y4~1Y?a*Xo{fH~$!bS6MXnGU_Fp9A=tB{hzwq3t=o>i$n$N;*3$fJ$wp@cOcp08D8(a z$2aB{>vdz4$?1x+jb@msrJfB!Y&oRhH|Oc&`p+n)e@C1yISun#JGGERUp8gR!iT&%j6^Nf@%wA6 z+L&P=!a4$P`hItUKt~~zB9B`xofTAcnaJ57FKf3)8FZsoTaH%rUr+3Kt%_XwVjGQ} zSc+pxGPv9gBkb6DRw$dBRU^)AyHJ~U0tu~LbIa=3*_E5DL65-jN**kbt^wmmrX!J_ zW3&OQGV`GjY66yNLgtf_+J6aBZ2bGDLmnomc63MM$2lK6b; zg9yPI8XDqLSl0p&aNVprL+JESism&POfl0XoS`#U^YIjmL)AR{q_b=45Qz*+&HiJU z>rFNg{8WQ6#|%$S#-Tif zB(V0{rb}l7!o65dEb|@^zWaUE#4?AnWdWNZ9)7B5#Ej5){I?y$tE#DZ6q&6TWIMXB z2?6fU>ZrGVNrujz^5iP$FMQkH-$9gdR^Q$zc0LX8nBgfwyW0g5v)UJmSTHmwUq@dH zpj@d$@dy(SPc}6GmER4lnBWxS7T=laVvA^W4Fsn(G@c8KWK*7Ryr@pVZ5{0lb7fl#Ng%Z{r<{K)#pJ zFx8!!;|Kf<^q^ho_+jDOjllI`b({8DqAdv3rNEX6B*eNP<4Z}X*$u+z!8eo$p9;qO zVxX&_4P2^SLBwnotEFxC)MwI6m)_j?M^VMUKEDUMsJJ6<11#^y52w3O8JOY4HnDJ6 zfG3RgF);ko8=d6PWtDL0j0%!G5r)u{J0Pr(8?*Zk#}5tzgFl3tBT~U&%x)_L1j2&Z xje?~;bPoQzDjV2s1y56b_}2C>s$l6mOk>M6f#$z@#sBypuOzQ7S1E%C`!B(sQda-~ literal 0 HcmV?d00001 diff --git a/tests/typ/layout/code-indent-shrink.typ b/tests/typ/layout/code-indent-shrink.typ new file mode 100644 index 000000000..1527e061c --- /dev/null +++ b/tests/typ/layout/code-indent-shrink.typ @@ -0,0 +1,28 @@ +// Spaces in raw blocks should not be shrunk +// as it would mess up the indentation of code +// https://github.com/typst/typst/issues/3191 + +--- +#set par(justify: true) + +#show raw.where(block: true): block.with( + fill: luma(240), + inset: 10pt, +) + +#block( + width: 60%, + ```py + for x in xs: + print("x=",x) + ``` +) + +--- +// In normal paragraphs, spaces should still be shrunk. +// The first line here serves as a reference, while the second +// uses non-breaking spaces to create an overflowing line +// (which should shrink). +~~~~No shrinking here + +~~~~The~spaces~on~this~line~shrink \ No newline at end of file