From 240f238eee4d6dfce7e3c4cabb9315ad052ca230 Mon Sep 17 00:00:00 2001 From: PgBiel <9021226+PgBiel@users.noreply.github.com> Date: Sun, 23 Feb 2025 08:26:14 -0300 Subject: [PATCH 01/12] Fix HTML export of table with gutter (#5920) --- .../typst-library/src/layout/grid/resolve.rs | 21 +++++++++++---- crates/typst-library/src/model/table.rs | 2 +- tests/ref/html/col-gutter-table.html | 26 ++++++++++++++++++ tests/ref/html/col-row-gutter-table.html | 26 ++++++++++++++++++ tests/ref/html/row-gutter-table.html | 26 ++++++++++++++++++ tests/suite/layout/grid/html.typ | 27 +++++++++++++++++++ 6 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 tests/ref/html/col-gutter-table.html create mode 100644 tests/ref/html/col-row-gutter-table.html create mode 100644 tests/ref/html/row-gutter-table.html diff --git a/crates/typst-library/src/layout/grid/resolve.rs b/crates/typst-library/src/layout/grid/resolve.rs index f6df57a37..762f94ed0 100644 --- a/crates/typst-library/src/layout/grid/resolve.rs +++ b/crates/typst-library/src/layout/grid/resolve.rs @@ -1526,11 +1526,7 @@ impl<'a> CellGrid<'a> { self.entry(x, y).map(|entry| match entry { Entry::Cell(_) => Axes::new(x, y), Entry::Merged { parent } => { - let c = if self.has_gutter { - 1 + self.cols.len() / 2 - } else { - self.cols.len() - }; + let c = self.non_gutter_column_count(); let factor = if self.has_gutter { 2 } else { 1 }; Axes::new(factor * (*parent % c), factor * (*parent / c)) } @@ -1602,6 +1598,21 @@ impl<'a> CellGrid<'a> { cell.rowspan.get() } } + + #[inline] + pub fn non_gutter_column_count(&self) -> usize { + if self.has_gutter { + // Calculation: With gutters, we have + // 'cols = 2 * (non-gutter cols) - 1', since there is a gutter + // column between each regular column. Therefore, + // 'floor(cols / 2)' will be equal to + // 'floor(non-gutter cols - 1/2) = non-gutter-cols - 1', + // so 'non-gutter cols = 1 + floor(cols / 2)'. + 1 + self.cols.len() / 2 + } else { + self.cols.len() + } + } } /// Given a cell's requested x and y, the vector with the resolved cell diff --git a/crates/typst-library/src/model/table.rs b/crates/typst-library/src/model/table.rs index 82c1cc08b..6f4461bd4 100644 --- a/crates/typst-library/src/model/table.rs +++ b/crates/typst-library/src/model/table.rs @@ -282,7 +282,7 @@ fn show_cell_html(tag: HtmlTag, cell: &Cell, styles: StyleChain) -> Content { fn show_cellgrid_html(grid: CellGrid, styles: StyleChain) -> Content { let elem = |tag, body| HtmlElem::new(tag).with_body(Some(body)).pack(); - let mut rows: Vec<_> = grid.entries.chunks(grid.cols.len()).collect(); + let mut rows: Vec<_> = grid.entries.chunks(grid.non_gutter_column_count()).collect(); let tr = |tag, row: &[Entry]| { let row = row diff --git a/tests/ref/html/col-gutter-table.html b/tests/ref/html/col-gutter-table.html new file mode 100644 index 000000000..54170f534 --- /dev/null +++ b/tests/ref/html/col-gutter-table.html @@ -0,0 +1,26 @@ + + +
+ + + + +a | +b | +c | +
d | +e | +f | +
g | +h | +i | +
a | +b | +c | +
d | +e | +f | +
g | +h | +i | +
a | +b | +c | +
d | +e | +f | +
g | +h | +i | +
`WTlj^q^j90_-6|9VsCxd2|; zUqLMefUB{5=^We(5v+XDbxrti=$Q|NP4qgv=z#7b%>EFIx39L&jj4965Zq=~%O znQ~wQ$jQ8i1>9C erqF~!Q)miJDD+>X{{?rUzwPilq4)p* N002ovPDHLkV1m<1w@d&4 diff --git a/tests/ref/issue-math-realize-scripting.png b/tests/ref/issue-math-realize-scripting.png index ee2d4cdf7a64d95e4bd8fffe538a89de1bde1ae4..7d721ed776199bd6611d1178bb7582c1dd6fe7c8 100644 GIT binary patch delta 2596 zcmV+<3fuLv6s;7HB!BctL_t(|+U?nCP?L8a!0~;*@Al2^zS-TGc4k{^Ywe*uwXLnL zReOyhR#t6Y6_09NY(2RIBBBV0T9C_fNVpAPI7LJO1pz6Sa$g1r5ps}_`@4?8k)Tu3 zO;)y@eBb7o`ONd5$?yN0 `#M0_6x|m#97<*4L(LR9q`9?^68B3>`)T&W11^0s12ct@* zpC0BpiZd=B8GpvLt16ryD-*+wG^gAIy3z>o#*m&ojJewayL3>V;f^H%maZpVF);s9 zrFpZ!16U1!O>o<+D^aKJ!((&!amAetb;IuF_xk}1OL|$|ulrJ@ElL11=?4nrWj;b{ z_{srZA8%NN+gNRFE3n>ncyuXOzq=1JpIm &nv>$J{c$LELGc%L(sQF;Uo=_6!kn}F>)K=eMgSfi^}ZX986dtqRtZn4 zFV?ZMy7@A;6=`%V%w-+6)Y|F1kDc&u5jKh=T4n^k*(7mu9IVt$4+ dNA-9D)AFe$yJ VG28>i82tpPe->lWOct3#MS}4r$n6mn$Bt>eB zvww>-w2L=x09 =S}%SU?kTkr?2k2 z900XUc2Fi$0?EO=W4!SVE@L{K0r>ittv-8rxcVH;irIauP6wF0rRtPT@J1>*SwQw^ zLa2y0 %}43}dtOR0RVOR4!1+=VN`;%SaUzg*H`g2Y9q)c50@9lUJuFZs-o(R=qJ&yr$Cg zTlsEJj(;x%nq6I8ON`0l!uWW!JE7RUPFXT4*xh6eU(Lxm)+tT?!GNVr01(#Tn12Bh zXkuy&JgJ6k$Ij}33)t2VI2NYf#??peypNsmZwA)fN{zcV{4`;6Phq&v-fwmt6N*ml z-L}UwD6>)bRA5Q*9SxH*_LkTD5?C5L!jw#X0MudK-~iUuW1Xzu7C7 T79g`@!-TkOheoS;HM9i z07yUrU|y9AfLbx}!0^I$00ux}+ahp&i(u8w`*6up_WF6QP!N|A2 JkqG{~)hF7|s0UCT)=9v- z%nWd5h|)^{%M6KeKx-1(0095Xqbto1PJpgB05_>gWCN`KgQ;&J1zTC(XndBG{dgs` z&mHSigJEMrVsvivYswTe;C};n0=VGP1qgIl-f+7#HZTY9e)zxF~NfY2h@#taShG zxFgj82?c(YAwlw>Q1X0=fHr@B|N5WOs*-O5k~$zC;PQo60WJbPEkJj2X|xRVML@X{ zs226ne!<}bB(gXne@15YP jv zluXy@(Ixa10 #k!3;=OVYR4VmY!ev0(R6gk?16hjN!kKMnfE}o86bXh4Nc Rj`N)XIR<^00)NbhD$2R&hvqH`)LjU;?4CR zH1dMk`i(!(-`P|jaYg Y* z%eqf{wqxm^jvbjkJXS7GN*&}_xUB%&N>Df!=8^(i>aB6!$4=M@J7FjM>wvX011nRa zLuUjYYE-y54sKR3T?J_ZdhY^+G}#5qFZS}V(PS{63 -4mpS7A@U7flShH;Zz7u!9r~0i1^YC`i zY*R|!Hr2m0Zhh2SHQ@(Rit`fBV#x)2VVOuI>ZC{9-(LzIa4W9~sU}z4jHROhpevB& zX{oGcqJKS(oz>~xOwGWPx>D^}m}nEWG?s{iVci(EG~!$YoUjvi!cO@A7S=Xo2-dIl z71oYDJ-8=2EYRC4GOtmozFidK>vbgbZ1Yor4Lp|KPPj3y4H!L%b)q_~>W#%ZakYJL zee%$PpBN7*O95a!5CCpuMt1^m*a(0uyf7aCyng|pCM~YbE;!W(uj7pOm@H1*u2BGb z!35C1Jre+l0W$z4?kx`=klO_VAJ=FiPwn!k2k?@f0!TYprd|thY|IPbR>B@!4FKMH ze}JOUbKUFhgp*_FGoDH{0aO&=4bZV(Qgjs12Ow+)I+LS}O91+#2vPx^o)yH{2j37; z3x6&{g8)8Ikq7V(4qgY6Z=?4ESUYt6fb_u$(03MK3B5IT!EJABa1;7ezBZTu44nZE z0p|6CFB<`Gu)Lvr-`10b4^99)0agyDVi!DARaK>wU00ME0Er4{2ky3}YyxNnWC}oA zrm6;15}?Zrj8y$kCRc#SOFAR7+R);>ogJL86L!Kg2>%D!l$`cC8)=*X0000 l}yWi>co85N0+-A%x{7uYXNVRse)Gb8#iSn?ON6Q2OBP z>3lvI1Sk>+777H3z=vJN#l+ Wcd?>_ndAo{$g1)HD{!IRl%9SH zW@xE71;kUeuune|`!{}{a=*H;*7nZ;fRz9+HW{2cJu`l8SMVqG3&JnXto_PMv1*6q zi`@x&5P!Y;$}1OiCxp4a2`ImYvd@~NiE{tXTJ7QV!ZW^29r3}V0FRE^=ca20NDxm{ z&eQ6RckQeeRp3}LX4k@07;vOEvHL!D!@ot?ER4Q8CGf4*2Wwmhs|=Ha>CH$1NG^07 zHr&+m6Pe-x(Ez{$k%cF^Ie G65Kx(a8}W&k}WX?I^a+%E9C} z9ccTb& 1ottIuw1s}JAjp51l3$pBaaq}q&)@YV$i zbAbYRazs9FDF7;BW0%Lq<^XRGYd;~fn1AVd0N7}847UD>!3A8|$?|)=Otv52r8h1> zHwJ`M-%cz#jb@sWx??~zwR4q<+1MZT5-tczBU)>>13cO?#kxu0G|#M*^<5F$>Nms) zSJwJ{quAxg(Y@(_$ji&C+?*!7oRoxqCzNezQkBaEyISqx>cYY!VrkkBCTwpE0DqCq zt{EU<7ADrr(`qho?W`Wi!?AwAwJ>)aTzwSo``8WtcHsW_-G=7u`S$YAGV4p&ceO=h69&rRt`CTReV{^rP z$Kz=aU-(E2=e;Wc;EL^IUmpzsm48+MIJxJx-2-F3K1v5*UU; Sv;*+t zd=&r^i$wxpT~P#pX3+M)@VpKHx=dEFV~fD~&4LxT9>V2|*%$1$Oi4mU7+`#WZ#3s4 zkNVvN2=0ynXbh<#2%w @>Jt}iHUg-> zGdzHRt5$&1LsVV?SYk>^0NPT~hXRCD$UnD^p8%2sfHhJ}z5}rF_m CeP{+iqtK(sSC6Lp{=raExXW+I_ zg2J%1A0YL81r)wy1%Lz|YsY=yOe>fJ&~ pUD^Ow;=?H;$TkprtWeAT+PM4RB@rPsP)~+UqPJ?=*|W0I+|^X}G+Wg5p4!(}yS& zNV49U-@?mQ`!}9%yua~Ibd};g0N_i5vvAMfro9+$3>D^VKYwY}Z-ncMu4{vIg0~y& z;ndvdEmylv`E>vQ|8nif4CIN5cv{-Su7%q#;aJH^*TP&;;z&IW?)%scyJ0u%hJPKf zerjM {z(Xxc57)sWC6je2Q$SBYKzOTDu;OA5*pjD#^+XgveB@IW`p|O7Wg(m~ z!`YfbXJFN_wtuBpuyxb` KgQ%zh__y<4CkqFosr)`Ka!A^FU>rVJOhNu$d)VMz;Mr?>@tU`F z^O_yNYKzk__ck;9CM<~MdK@4VCY-#}{jCt7Ix1>eRDaYtAS{`Mmg@&u(*^)OQm0|* zG3(vDZ7{cz`cpujvU*zyvs3^^wK_np)&X-y)XP=TMa&ojfNvDe!n!5CKF9m_QvXh~ zb$C1Iwy7SxYq|64nEg?2)kW>kC@W4m0|0p7EG)~<&ll4z?CYxpZ@69Did0u56afI= z1AyU@tbbTfZ9TSjyLMJ*bulp$PphilwJ>oO97&Uci(!KXM;di60&dt1yJ0u{i-q;g z*@AVegVGx{&kpX6iwq0!k11|ZY44Su4e~z}aYpn^U=vSdbP~RHvL2A1z`pz@?COcf zK4HCc@Xc)P{5r zbCr%8&H%0(tQGb_90I===fQHP3cBkNi!vq{ HPt2 z=6}m4CIEj+5J1t{v)${Qgk!TAu!iRWP+mol1?XQjEIba3g^}9`^e3J(E(YjKB3usi z?|*F|$vL>9oLX2u(hU#*O}PMz+1mglO0Wb1c#c*F^o^eYLni?i(ca<|+&q2hKQeqS z&S^;l`r?3t0PF6)Y5@X(<0k {?%T-?yJ0sxh46m>q8^<9AAJvS00000 LNkvXXu0mjf*}K?_ diff --git a/tests/ref/math-accent-align.png b/tests/ref/math-accent-align.png index 84e8dc8ccda955a6b747d1462610b51219f43f43..efc66ec3faf784dcc17fcb8d3fbcb7a58c151773 100644 GIT binary patch delta 600 zcmV-e0;m1v1n~rrB!4(bL_t(|+U?ihOH*MS$8rBN$w3kfBPv$eMcov2VL?y{MM8Gd z57tG+P#LwUIa5}x)1Z##bk5AS;bf#!r!0#&JL+oI**ZJt6W_~c-3eb0>hr#O_};vD z9u8kP4RELi2}@YQ65cUb>$&>GV*>U>jQR%P-C18S!VZ7Ng@1IO4#^ox1Mso6P;xWF z)B#ihSiJ%23r(7!o@a+U7MiOeIutdk0wCwcnPql(Tuls_5bElDzUahPZ6D16PQZo1 zDY-x-yvt$Ra0piK?60S;1Rf6Gt^qLqP!@pf{ngoic6h|RqP_-T`5sdl0MU;4#$9HZ zI%tB*%~L<=*ne#QNU*~LS`#7wthaBdJk47066|o-i$JdiF@N-{+*}ft@HXI$?hn(B zz$jG>N8s4#oC-00c-~-##}}^$+D*Xn-lNj=_$R8K1Up>Dkxhu*>c=6I9WGjp$UwO9 zsg*5vmK{FXb1pOkA*IjXs<6YbQ2T#m%grU>T?`lW@_&+*L0vXKocq2$_csAC^V%MM z>R )hCJgvkbG!Rw7{BUK< mETOK_Z@IZ7EMW=nVE+J61?9wOxq%M=0000 @y^($#u_1zm+% zU4*?s7G`a@&AB-$v&h;&a;CDE7F1JbTFoVF%9^cBx3hD;@m!wW6+9kf&-Wkra9;R5 z@U&o2Eeck!f)%`FaK7KsdrSi(@=o* R>~LN6 zq%jrs`p-wyfGAkO{|tXvT$!r8q@e}*aG_Gmv5YybPk%m4ZA1S }i{HEd 0uQ^@uw>x;^K>s?!o;_IoS)CbKf?i6j{pu)Hwcu$%!1JYD@< J);T3K0RVa;6*B+; delta 53 zcmX@kbew6z2hrCT?4_2y>JfK%bbHQ$Ri`Dy>}_k?CbKf?iKI9dFkf_)7H0qgPgg&e IbxsLQ0CcJp7XSbN diff --git a/tests/ref/math-accent-dotless.png b/tests/ref/math-accent-dotless.png index 81eb4fa2bd7b48cba24fa3e1c8d6beda09bb6506..389ceb634aad124cc19196123c8ea188a72a0633 100644 GIT binary patch delta 1002 zcmV CXn9AOw3HbC%@)O|M?u=yLe9RO2H|3+iKUIDXjeaBY#OPp@e5UJcz1 2iXlDm zA-RGw>lT-6aDPQ+rU#X9caat;a~ o`z$u4bE=^-+Nsx>^#}PaW7~pC^5tMD}(lY;D7d!kM2=(2TCgkMhb!Qj!O}a z2H@(cc;N`l?XGb?JO_dO$D+kU0)M>-9WPx|3DdhuuN~(9W=; _$ox znC}j#fGO#e89pWxerIQRGc%kB6MNad9ennP8hGEDw-LBnO{*JLGqLn z5d-eF3A~mIP @NM8OpCICa$<)^=1*hN?`~t!M Y0Al&n0a`kXD*ylh07*qoM6N<$g5P%2D*ylh delta 1004 zcmV pnSbg;BivD_N6K0T_;x!|MRqw-ah_GybnFYHL&Y-nmojC2*{5Wi&jGA_ z`Lb4c>d1g>JVVCz2}q4)NJZVfvcY%VNNoZ$d^8v7z <3a&m=q@cuH_(-~R?Le-F|~6~J^2$x~2djYBil z0Mr`*R;oh3O+k2Q=(;XBjQ&@dr6Y^LeCaI{K)g7=I0V30Q&UrfwN5(a=`RLAHIzIA zp!AB&!a*CbIy!2o)c_M?U2)&qF~)!HUWDYZy?^RDQg#^NyKP9f-`@|?Pq|(|a(*0_ z?Ro>rd+ohW0QPQ0%2WZyUO%7#HuoQwjik#2G5~2CNI%rgfTZ7X4x}8Uj&M#n0E1~r z=>qfh4h=A8+hhjz$*jJ$IULPeO@xWP=-3E8xkn4UeaTk`T&$qc1B+SMde-1N9|GSo z1AkCf0o<4oI9LVH_ZrR?1RggE>}dq@^EJTncL*E Od 4!2`44 z_rQD 2(|yP9dwM`@0K7w D~l&E{xDzw0#8>zmvv4FO#o$i9smFU delta 69 zcmbQkG>2(|yBc@TM`@0K7w z|+;wWt~$(698sT9m@a! diff --git a/tests/ref/math-accent-sym-call.png b/tests/ref/math-accent-sym-call.png index 0837a86c9e861a960cbca4d157ea7e719b54cd0f..609197f3c3da71d9f4b4efa72b92bcc64311b935 100644 GIT binary patch delta 908 zcmV;719SYI2cid%B!6j1L_t(|+U?cdPg`XG$MMC##Ka44jLDMua>Iqg7~_IVhFRvK zbB3sM5rUh8xj`l{7fet$L4t{Mq@fFRFaaAFAVpxPY|t|3RyMKix{j`ID?0^B*VFSg zd7hI>7Bwc%7B1G$&G{wg;`=;T&n7m=6Pq?jKD@!< 3 F@gD2)<+#AwBM2 zK=9&K3u`u{m%$W!>&GlWrz1WFz-qO#4M87W^dQtmE7iicQwY&rw~-9%r)dD@8!=rA zU`j@i!ZU_axPNk}yaRx)J#$qE_x7BO0iYdhmZxg8pXf&DZLpNeLmjyEp-T9|$CP>i zD7%{7g0wS^(B|;e05CiF%?I+n&olG|0I|NV=TyQK{S-z3*v`dwkqVLg$9v8LQ2xEA zBn)tIKSzGO3t->7QV>=MpX(cV&B{kN;j{32x7eKol7BmZnkgVs8K=w#1%Wd~JvTmq z#KAvaY`<&mfVv-?&z?~TGkeFQarH7Vp}{~1vcEI~0SBaF!5Tc1ppS=d+|O8nJG1cx z;C8j;h>P`We#@@W$a3FsVVX(>lzsfs}P%3S3804rkVnP!w|!TNFbw3``jm!b yNf&iZ%x&=Tn zf?=@?0uZ=dxJJ?Z2*L{W2LN+dSECjl+Z^C*1fdF{VpQ7-fYbK^6i3b@S$31tQi598 zb!w`3aS*8=fVF2Btpi~7rz6hg&DX{e241~SJ5u*{UAHNPs~b4FpMaM10iy nIiXDzy5op9!~y=;KG!+2{|svnaMwk i`EWj*4?kAnzW^mukOPEx)hPe~002ovP6b4+LSTZ{g0Nix delta 904 zcmV;319$wQ2c8FzB!6W|L_t(|+U?cdPg7?A$8od2WXUdevn(-jFE?CFmSveCCbAf3 zHs?aNIWq{;S)4)~;0#OHrh^fd%t< C+g0$zm z z7@PCBL+)wE^rpA2%fUaXT zBLD>5Zuc7M?i*f>V2b-01IQq2Bm#ke@wmf uMLV}k%JSGb!IR_rq_gsMoHTKIMvA+qZ>lA(RE3cz$7NK-mU z$uLrA+)xUa^?#PO0?@H%vK(P?&&enNiGvODRCSIMHiQec)?#_610$cPgfD(Zu@``n zYuPPGJ7WmVPH!au6FuL5Ebsd=y TLPjAAPp$~7dI|(Fr0DqM(AY2xs#0Po$nF9Nb&mn&B zpI2M%XsuBFv-`y}3SlPZy$P;e1%?vP9fa(q20(X0IvS|NI}Dl2p&NJCG+=%rHbcw- zcsvo68%w`~)C;_QI1LOZAkeP$(PtoKognGgk(9%0{~y7Kxrok*AsNQ{R|;Vzxo|H0 zNZ~ldd4CWCj3*UtuC8(-m8ZBzU(Lx@Sl4bKO-?I^Nv?tPm%+V4*TK}UY1{lrmJ^y5 zQww|k#?+lfn74tH868Sv3I~I;Nu Dd56)1@f{e@ifKGY{6kt<~{- z8-im;+lA*GN@06rGo~$RgwzO<)l=IsdTt4!A%8>3H%RpcMU5zh{dqcH9l8ZTA%bDG z_5h$?&0nElx*uVQngd|&iVD=igPV2Eh7rmUECY$H0JwdxKw @5GXEJR{;fh+0?nh4~eZYXhBrNR2((~t{ z4u9C^IxqUpt{5J`m6zc3AQ>+(^x86~MwP<8eW#m_f7is=M}Q@@v=z{7Kh!0LivgSt zM@M^l;SFH#vHGLC3_=CKJ5}|E-$Nz5&SgF%b3J^c9!~y?Fa}cmCX)HqG@kn{=EAvf eF8ox5{{vrCkOUezRbl`D002ovPDHLkU;%=IT%-#C diff --git a/tests/ref/math-spacing-decorated.png b/tests/ref/math-spacing-decorated.png index b8846ff0595667a56f7004ac4b0fcc5925670200..2f3c704e5d981ce119ac1e903e154c4a186e1553 100644 GIT binary patch delta 2364 zcmV-C3B&f$62}sdB!3P`L_t(|+U?kRP*jHj$MO8xnRKRqb^1s9kG;}%T06~Tnsla( zSBy0=Mbb1zLv`X63}WKMXpDkJkwYRNFp3}oivn^lheV7L2rN-RP7xPjxe-{7U9Pw1 zx4yT>yq&>hvw<0=;q&MI^__S9-rJ{Gte#pbTPj;BTPpiulz)x!?Q~}5q&FdQHD#Ee zvew`5t%jCsn9IP*T4V+{d=LnF?>rph)0Cc oq6JEPiv|#lUBD(MX8<{EYVtN5lD|YUm6dNRQx#@fxP7%S3fc>< zjYwr}hbq(V0Dr$O&lcP)oAfds&Bw*ZdHNkLW$)EjTtddUVJb%a!5R_vSg3ET2{61l zk Z81aSQZ@5^zVh&^?zbP>li*NsccspD}bNEvT66q zj#e2~-@%0spJvOC+1>qE)W}5Vv9iYMIA%xIY5=koO!kRoS%I{8S))n?AglrJ23wh0 zDqAtdGgkM?+7i Jl1lJK+xy~5hf zyYrwgD}OE+bbcS+`%gsKnlh*f48J-LPg 1l?LJAYb>jp{@{w7=xn3|z>=?yF-{-fow* z>To`34+bgB)PB^8>!Oc0T5)ac@WLT%7@J4!wnd*Q>xPSwv*plUWd=yd)7_q`p9TIg zG%@RLnSaguY1oV;#&!c|4z~oml;xhui9_yS ^u^c@H?*v} z4S(Gc*A7W#k5+}XdV}>RiYqa0mMIUiM=dS-i7o5imlpkX{lI$pqL2Ow{g`~wtF{w( z8z;k#WT0uaGTAJaosA}C+29slLh`ysEMr$4tHAPOE59 I>J`C~!zBN7NHI6x++hTjvV?diPK 9ClNpKrG7@8>1sA>A!ATrCu$jCM%zxZF zR&2O4M1Dr6$_MBx6u|iK;Y3I0qs~E~suXw2Bu3^*-H}d2_`NJ_}NRr!(2+1zF@UqS9Ie2a~i751q48)F-QSIsS3-6)$btbfjEMbxDcO#>K< zvT!LIF1|I6Tzy_+iUEg00g0igtQ(p?%jLSFh?|E)eb2#IepDA|B2vB%FUmaA1l?z2 z^xuCsAK|%=Mj1P>AdB92*`^uK7z>pJ#sw*x>9U#NiCXG$NL^gt=w x#@z#1nq(9$3(_pn-^LJW)`Q z@L+z+n$99u`9)YU->eOhdcp4il>(8zo^K^I&HyMwFC<0<592i3G{c-Mt=jKcR*`l< zk6lQ@X@IUjV`srdRzQ>*o3UrLh>Q>Ghmg^}(uB;z E)Z}k2 z+lwy_d)NW+$OoID6kHgX!C?&!w~;&KQr4pA!Y z< rw$cZnBa3L}g@J)nJc&a$usHcn!9 zKT;xKvySSmFdG^9>E_7DHmG?S(LlUJ2j|c5_6WfEn14vKvjE8SEz}^E1*R~*-1yqP z-N2XqY*N8=fK;}>PRx~9egQwT%vE+mrCU>m-E6l6yY2W_%FkxQVI~`qIa@NjvJ9{! zCOme0( {U zZe->nFMs3m%}f(A!$~ {tcR{`N)9kxyFp zhFAKOV$%{7^0nu?DYW9La1HFn;ZjYaYO%Zp>5}s^8gR(2+{?U{g|{+K9vJ4g?1Nc6 zqK{eVH%G716g;wLfy=akLx=Ii10TiIf|eP=4>fD>MEu?OnguOGFyfK(J$n}E7mBHD ieCexhscfmtef$qL_H7;wJ~U|n0000 `F^D?b3Hkx$iwHk*`q=H?_I*yl{fJA3m zbivGicgu#d%6fs`NRb*S^)DVoFn%7J{QN zW8v22q8RA7 z^5v*l)^?~W^M5w*>xw+Rn`K%b ove;PO9tV2EMQY$R%ROH(MuZ1# z2oG<9_U92iN)(MlRuFr-ankQh1Iqjqw-L(16PfwF{(nu4P|!M#pHeK_)y4|or?70s zy|Sa#hSj%m;m7BB(lfiWA4@wDv2s?{S{-M0WUUGyPlmQ%D9a6|#m5>`rUxP$@olt~ zwTopdrg_HdURhgGR=`)TpR>H&IHYC7eJz_rqCY+>un>pHQ3Nxwr&f*p@hQASG~I_(Ce0D znKd&b^;Lcd4Nh %7Q8XN*r3U+C4057{&4mHhLxVT7PRRo|$17siSq+D31+5$4ddtz fh4V^#Fid8q?m#Q9i#~DJii_qh9~>e_uzA#BTlCrT9=LE?R{ W`HF5 z)UD|T9q{+zNu9f8fwdoGVl$c?-vgXF+!F3mR&Xjm0jYykpGJanow^X5D9Y>+$|eJ5 zE`P*-w7zB4E$E5<@{m~eXjNpZFIayf%ZPKcOmUDs?c$;z+w#f>;-bH)8C)k_^szso z8J8}4^>%`9;bhp63N)=&q?(1YGqI#C8`{E4h~88QW$dbF6 29ewH{Eq@MO z*l6zqv-d(u47Z0V% bRlSO6!d}l4}2SH1*j+$6b9Y^IC!BS zv23G~>W!0|(=G#HBRo4KmaSmwA29Gdnq_X3ovChrxd6bFn 9GU>s>mNlJ0s_N^A5~R{Yk9Xsu4MF>&e*=^<1e!*kNZ&LIpolo1 z91}i*ldgG|IaylOKd`Ja^MD4s6G f)d-B8cYlVFP`}oMMCWqfU_{2f z>4? N}zE1rr{!EPKb)+Q^L%3aW8YGHN*4tdpkS
l14iwG6!x skDTk>vqYazOyv{ar#f$$x6FO~2MvI2Ak9&t&Hw-a07*qoM6N<$f*P!yYybcN From 3744c99b07f97a954a8468bef5fdb08c5c7914d7 Mon Sep 17 00:00:00 2001 From: Malo <57839069+MDLC01@users.noreply.github.com> Date: Mon, 24 Feb 2025 17:15:17 +0100 Subject: [PATCH 07/12] Override the default math class of some characters (#5949) --- crates/typst-utils/src/lib.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/crates/typst-utils/src/lib.rs b/crates/typst-utils/src/lib.rs index 34d6a9432..b346a8096 100644 --- a/crates/typst-utils/src/lib.rs +++ b/crates/typst-utils/src/lib.rs @@ -360,6 +360,21 @@ pub fn default_math_class(c: char) -> Option { // https://github.com/typst/typst/pull/5714 '\u{22A5}' => Some(MathClass::Normal), + // Used as a binary connector in linear logic, where it is referred to + // as "par". + // https://github.com/typst/typst/issues/5764 + 'â…‹' => Some(MathClass::Binary), + + // Those overrides should become the default in the next revision of + // MathClass.txt. + // https://github.com/typst/typst/issues/5764#issuecomment-2632435247 + '⎰' | '⟅' => Some(MathClass::Opening), + '⎱' | '⟆' => Some(MathClass::Closing), + + // Both ∨ and ⟑ are classified as Binary. + // https://github.com/typst/typst/issues/5764 + '⟇' => Some(MathClass::Binary), + c => unicode_math_class::class(c), } } From 36d83c8c092e7984eaa03dbecc1083f49da13129 Mon Sep 17 00:00:00 2001 From: Sharzy Date: Tue, 25 Feb 2025 00:35:13 +0800 Subject: [PATCH 08/12] HTML export: fix elem counting on classify_output (#5910) Co-authored-by: Laurenz --- crates/typst-html/src/lib.rs | 6 +++--- tests/ref/html/html-elem-alone-context.html | 2 ++ tests/suite/html/elem.typ | 7 +++++++ 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 tests/ref/html/html-elem-alone-context.html create mode 100644 tests/suite/html/elem.typ diff --git a/crates/typst-html/src/lib.rs b/crates/typst-html/src/lib.rs index 25d0cd5d8..236a32544 100644 --- a/crates/typst-html/src/lib.rs +++ b/crates/typst-html/src/lib.rs @@ -307,18 +307,18 @@ fn head_element(info: &DocumentInfo) -> HtmlElement { /// Determine which kind of output the user generated. fn classify_output(mut output: Vec ) -> SourceResult { - let len = output.len(); + let count = output.iter().filter(|node| !matches!(node, HtmlNode::Tag(_))).count(); for node in &mut output { let HtmlNode::Element(elem) = node else { continue }; let tag = elem.tag; let mut take = || std::mem::replace(elem, HtmlElement::new(tag::html)); - match (tag, len) { + match (tag, count) { (tag::html, 1) => return Ok(OutputKind::Html(take())), (tag::body, 1) => return Ok(OutputKind::Body(take())), (tag::html | tag::body, _) => bail!( elem.span, "`{}` element must be the only element in the document", - elem.tag + elem.tag, ), _ => {} } diff --git a/tests/ref/html/html-elem-alone-context.html b/tests/ref/html/html-elem-alone-context.html new file mode 100644 index 000000000..69e9da411 --- /dev/null +++ b/tests/ref/html/html-elem-alone-context.html @@ -0,0 +1,2 @@ + + diff --git a/tests/suite/html/elem.typ b/tests/suite/html/elem.typ new file mode 100644 index 000000000..81ab94577 --- /dev/null +++ b/tests/suite/html/elem.typ @@ -0,0 +1,7 @@ +--- html-elem-alone-context html --- +#context html.elem("html") + +--- html-elem-not-alone html --- +// Error: 2-19 `` element must be the only element in the document +#html.elem("html") +Text From 225e845021b9cfb37e6dc719c8bc85ccdc1ff69f Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 25 Feb 2025 12:31:15 +0100 Subject: [PATCH 09/12] Fix introspection of HTML root sibling metadata (#5953) --- crates/typst-html/src/lib.rs | 2 +- .../src/introspection/introspector.rs | 18 +++++++++--------- tests/ref/html/html-elem-metadata.html | 2 ++ tests/suite/html/elem.typ | 8 ++++++++ 4 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 tests/ref/html/html-elem-metadata.html diff --git a/crates/typst-html/src/lib.rs b/crates/typst-html/src/lib.rs index 236a32544..aa769976e 100644 --- a/crates/typst-html/src/lib.rs +++ b/crates/typst-html/src/lib.rs @@ -83,8 +83,8 @@ fn html_document_impl( )?; let output = handle_list(&mut engine, &mut locator, children.iter().copied())?; + let introspector = Introspector::html(&output); let root = root_element(output, &info)?; - let introspector = Introspector::html(&root); Ok(HtmlDocument { info, root, introspector }) } diff --git a/crates/typst-library/src/introspection/introspector.rs b/crates/typst-library/src/introspection/introspector.rs index 8cbaea891..9751dfcb8 100644 --- a/crates/typst-library/src/introspection/introspector.rs +++ b/crates/typst-library/src/introspection/introspector.rs @@ -10,7 +10,7 @@ use typst_utils::NonZeroExt; use crate::diag::{bail, StrResult}; use crate::foundations::{Content, Label, Repr, Selector}; -use crate::html::{HtmlElement, HtmlNode}; +use crate::html::HtmlNode; use crate::introspection::{Location, Tag}; use crate::layout::{Frame, FrameItem, Page, Point, Position, Transform}; use crate::model::Numbering; @@ -55,8 +55,8 @@ impl Introspector { /// Creates an introspector for HTML. #[typst_macros::time(name = "introspect html")] - pub fn html(root: &HtmlElement) -> Self { - IntrospectorBuilder::new().build_html(root) + pub fn html(output: &[HtmlNode]) -> Self { + IntrospectorBuilder::new().build_html(output) } /// Iterates over all locatable elements. @@ -392,9 +392,9 @@ impl IntrospectorBuilder { } /// Build an introspector for an HTML document. - fn build_html(mut self, root: &HtmlElement) -> Introspector { + fn build_html(mut self, output: &[HtmlNode]) -> Introspector { let mut elems = Vec::new(); - self.discover_in_html(&mut elems, root); + self.discover_in_html(&mut elems, output); self.finalize(elems) } @@ -434,16 +434,16 @@ impl IntrospectorBuilder { } /// Processes the tags in the HTML element. - fn discover_in_html(&mut self, sink: &mut Vec , elem: &HtmlElement) { - for child in &elem.children { - match child { + fn discover_in_html(&mut self, sink: &mut Vec , nodes: &[HtmlNode]) { + for node in nodes { + match node { HtmlNode::Tag(tag) => self.discover_in_tag( sink, tag, Position { page: NonZeroUsize::ONE, point: Point::zero() }, ), HtmlNode::Text(_, _) => {} - HtmlNode::Element(elem) => self.discover_in_html(sink, elem), + HtmlNode::Element(elem) => self.discover_in_html(sink, &elem.children), HtmlNode::Frame(frame) => self.discover_in_frame( sink, frame, diff --git a/tests/ref/html/html-elem-metadata.html b/tests/ref/html/html-elem-metadata.html new file mode 100644 index 000000000..c37a7d2ef --- /dev/null +++ b/tests/ref/html/html-elem-metadata.html @@ -0,0 +1,2 @@ + +Hi diff --git a/tests/suite/html/elem.typ b/tests/suite/html/elem.typ index 81ab94577..b416fdf94 100644 --- a/tests/suite/html/elem.typ +++ b/tests/suite/html/elem.typ @@ -5,3 +5,11 @@ // Error: 2-19 `` element must be the only element in the document #html.elem("html") Text + +--- html-elem-metadata html --- +#html.elem("html", context { + let val = query( ).first().value + test(val, "Hi") + val +}) +#metadata("Hi") From acd3a5b7a5999d22fbf2da488744d564b2f3638e Mon Sep 17 00:00:00 2001 From: aodenis <45949528+aodenis@users.noreply.github.com> Date: Tue, 25 Feb 2025 13:41:54 +0100 Subject: [PATCH 10/12] Fix high CPU usage due to inotify watch triggering itself (#5905) Co-authored-by: Laurenz --- crates/typst-cli/src/watch.rs | 57 +++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/crates/typst-cli/src/watch.rs b/crates/typst-cli/src/watch.rs index 91132fc30..cc727f0fc 100644 --- a/crates/typst-cli/src/watch.rs +++ b/crates/typst-cli/src/watch.rs @@ -204,6 +204,10 @@ impl Watcher { let event = event .map_err(|err| eco_format!("failed to watch dependencies ({err})"))?; + if !is_relevant_event_kind(&event.kind) { + continue; + } + // Workaround for notify-rs' implicit unwatch on remove/rename // (triggered by some editors when saving files) with the // inotify backend. By keeping track of the potentially @@ -224,7 +228,17 @@ impl Watcher { } } - relevant |= self.is_event_relevant(&event); + // Don't recompile because the output file changed. + // FIXME: This doesn't work properly for multifile image export. + if event + .paths + .iter() + .all(|path| is_same_file(path, &self.output).unwrap_or(false)) + { + continue; + } + + relevant = true; } // If we found a relevant event or if any of the missing files now @@ -234,32 +248,23 @@ impl Watcher { } } } +} - /// Whether a watch event is relevant for compilation. - fn is_event_relevant(&self, event: ¬ify::Event) -> bool { - // Never recompile because the output file changed. - if event - .paths - .iter() - .all(|path| is_same_file(path, &self.output).unwrap_or(false)) - { - return false; - } - - match &event.kind { - notify::EventKind::Any => true, - notify::EventKind::Access(_) => false, - notify::EventKind::Create(_) => true, - notify::EventKind::Modify(kind) => match kind { - notify::event::ModifyKind::Any => true, - notify::event::ModifyKind::Data(_) => true, - notify::event::ModifyKind::Metadata(_) => false, - notify::event::ModifyKind::Name(_) => true, - notify::event::ModifyKind::Other => false, - }, - notify::EventKind::Remove(_) => true, - notify::EventKind::Other => false, - } +/// Whether a kind of watch event is relevant for compilation. +fn is_relevant_event_kind(kind: ¬ify::EventKind) -> bool { + match kind { + notify::EventKind::Any => true, + notify::EventKind::Access(_) => false, + notify::EventKind::Create(_) => true, + notify::EventKind::Modify(kind) => match kind { + notify::event::ModifyKind::Any => true, + notify::event::ModifyKind::Data(_) => true, + notify::event::ModifyKind::Metadata(_) => false, + notify::event::ModifyKind::Name(_) => true, + notify::event::ModifyKind::Other => false, + }, + notify::EventKind::Remove(_) => true, + notify::EventKind::Other => false, } } From f31c9716240eb5c81ae225455c069089088015bc Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 25 Feb 2025 13:47:41 +0100 Subject: [PATCH 11/12] Deduplicate watcher update call (#5955) --- crates/typst-cli/src/watch.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/crates/typst-cli/src/watch.rs b/crates/typst-cli/src/watch.rs index cc727f0fc..0813d8ffd 100644 --- a/crates/typst-cli/src/watch.rs +++ b/crates/typst-cli/src/watch.rs @@ -55,11 +55,11 @@ pub fn watch(timer: &mut Timer, command: &WatchCommand) -> StrResult<()> { // Perform initial compilation. timer.record(&mut world, |world| compile_once(world, &mut config))??; - // Watch all dependencies of the initial compilation. - watcher.update(world.dependencies())?; - // Recompile whenever something relevant happens. loop { + // Watch all dependencies of the most recent compilation. + watcher.update(world.dependencies())?; + // Wait until anything relevant happens. watcher.wait()?; @@ -71,9 +71,6 @@ pub fn watch(timer: &mut Timer, command: &WatchCommand) -> StrResult<()> { // Evict the cache. comemo::evict(10); - - // Adjust the file watching. - watcher.update(world.dependencies())?; } } From bad343748b834cdc155c5fe76cd944e74f4665cf Mon Sep 17 00:00:00 2001 From: Laurenz Date: Tue, 25 Feb 2025 14:00:22 +0100 Subject: [PATCH 12/12] Fix paper name in page setup guide (#5956) --- docs/guides/page-setup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/page-setup.md b/docs/guides/page-setup.md index c93a778e2..36ed0fa23 100644 --- a/docs/guides/page-setup.md +++ b/docs/guides/page-setup.md @@ -56,7 +56,7 @@ requirements with examples. Typst's default page size is A4 paper. Depending on your region and your use case, you will want to change this. You can do this by using the [`{page}`]($page) set rule and passing it a string argument to use a common page -size. Options include the complete ISO 216 series (e.g. `"iso-a4"`, `"iso-c2"`), +size. Options include the complete ISO 216 series (e.g. `"a4"` and `"iso-c2"`), customary US formats like `"us-legal"` or `"us-letter"`, and more. Check out the reference for the [page's paper argument]($page.paper) to learn about all available options.