From fb3a2155911fe5687ba4f890b682d75a07754ecb Mon Sep 17 00:00:00 2001 From: albert Date: Fri, 4 Sep 2026 21:29:37 -0700 Subject: [PATCH 01/37] Bump version to 0.3.5 --- lib/src/app/app_metadata.dart | 2 +- linux/io.busystack.busymark.metainfo.xml | 1 + pubspec.yaml | 2 +- snap/snapcraft.yaml | 2 +- test/src/visualization_packaging_audit_test.dart | 10 +++++----- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/src/app/app_metadata.dart b/lib/src/app/app_metadata.dart index cf7c681b..ca81e724 100644 --- a/lib/src/app/app_metadata.dart +++ b/lib/src/app/app_metadata.dart @@ -1 +1 @@ -const busyMarkAppVersion = '0.3.4'; +const busyMarkAppVersion = '0.3.5'; diff --git a/linux/io.busystack.busymark.metainfo.xml b/linux/io.busystack.busymark.metainfo.xml index 95d6e057..f69c6ca8 100644 --- a/linux/io.busystack.busymark.metainfo.xml +++ b/linux/io.busystack.busymark.metainfo.xml @@ -87,6 +87,7 @@ https://github.com/busystack/busymark/issues + diff --git a/pubspec.yaml b/pubspec.yaml index 024e53e7..05923db1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: busymark description: Local-first Markdown and Writerside-compatible documentation editor. publish_to: 'none' -version: 0.3.4 +version: 0.3.5 environment: sdk: ^3.12.1 diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index a32f800b..dd320f4d 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,6 +1,6 @@ name: busymark title: BusyMark -version: "0.3.4" +version: "0.3.5" summary: Markdown and Writerside documentation editor # Snap Store listing translations are managed outside this Flutter package. # Update store metadata when approved translated listing text is supplied. diff --git a/test/src/visualization_packaging_audit_test.dart b/test/src/visualization_packaging_audit_test.dart index 58b47737..4e5463f0 100644 --- a/test/src/visualization_packaging_audit_test.dart +++ b/test/src/visualization_packaging_audit_test.dart @@ -11,10 +11,10 @@ void main() { 'linux/io.busystack.busymark.metainfo.xml', ).readAsStringSync(); - expect(pubspec, contains(RegExp(r'^version: 0\.3\.4$', multiLine: true))); + expect(pubspec, contains(RegExp(r'^version: 0\.3\.5$', multiLine: true))); expect( snapcraft, - contains(RegExp(r'^version: "0\.3\.4"$', multiLine: true)), + contains(RegExp(r'^version: "0\.3\.5"$', multiLine: true)), ); expect(snapcraft, contains(RegExp(r'^grade: stable$', multiLine: true))); expect( @@ -39,9 +39,9 @@ void main() { ), ), ); - expect(metainfo, contains(' Date: Fri, 4 Sep 2026 21:47:11 -0700 Subject: [PATCH 02/37] Refresh README feature screenshots --- README.md | 6 +++--- docs/screenshots/busymark-editor-view.png | Bin 136722 -> 76830 bytes .../busymark-keyboard-shortcuts.png | Bin 83228 -> 75561 bytes docs/screenshots/busymark-preview-view.png | Bin 325070 -> 70915 bytes docs/screenshots/busymark-split-view.png | Bin 364651 -> 123323 bytes docs/screenshots/busymark-welcome.png | Bin 0 -> 32705 bytes .../visualization_packaging_audit_test.dart | 18 ++++++++++++++++++ 7 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 docs/screenshots/busymark-welcome.png diff --git a/README.md b/README.md index b1e72fc4..2abe8a5f 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ projects.

- Split view with a Writerside project tree, Markdown editor, and rendered preview. + Split view with Markdown source, outline navigation, and locally rendered diagrams.

## Features @@ -51,14 +51,14 @@ projects. BusyMark editor view
- Editor view with formatting tools and document outline navigation. + Editor view with formatting tools, outline navigation, and offline diagrams. BusyMark reading view
- Reading view for rendered Markdown documentation. + Reading view with locally rendered Mermaid and PlantUML content. BusyMark keyboard shortcuts dialog diff --git a/docs/screenshots/busymark-editor-view.png b/docs/screenshots/busymark-editor-view.png index d8042059bbcad9da80063368efdefb0603abfd0e..784064ca9cdeadf6323ff1d2e26271b48e9bec18 100644 GIT binary patch literal 76830 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 literal 136722 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

+7kh0ulsR;`q!sY;-aL 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

fI5okVbd6KBBw?f)7Ik+`MvQD^*v{ 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%0D_RsW(*U$hvo_X{x^5t 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 PYyvkkjFo9Q+B5!NQX;wR diff --git a/docs/screenshots/busymark-keyboard-shortcuts.png b/docs/screenshots/busymark-keyboard-shortcuts.png index ffeed2f19e405b456fbd15a41928dd7ecc760b5c..ae5fcbe5a862b7c86de3875ff349f37e819cddd1 100644 GIT binary patch literal 75561 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 MPOJW-Z0!4g0Fm0l%>V!Z literal 83228 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 z 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 MROv|aVZE#W7d<|a`v3p{ diff --git a/docs/screenshots/busymark-preview-view.png b/docs/screenshots/busymark-preview-view.png index 0e82e3c834e0b2071f7561dfd95561de71f13851..7bf6e1f1f50f0d7bdf606fb774f156704ecba932 100644 GIT binary patch literal 70915 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

h)1UoFGZX$GAg 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�J)@ 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

_P*$viU2r~?d@$RAb4r!fw#vMZ?U?2 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�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%0APW+E0c-qgGks$u8k@$h{%S@1HDk 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

HSukQX^WNS>bNDD;gBtb8!sqZud0{1q~ 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

U!2}%mfp2qy-K*HQf zRxfq9l_JQkkuh7iNozwa?hgL@Y1$rQ6DA#`l@v@)Agy_=4k%-qMl%B((7Zb&-dV| z&fo!JH#CPtHrXPkpYRK2rt4Kptu_o1@=2c;k))S(p?X%Hj+hrDfW?zfu(zFYku^xS ztb&|&Ng_51*^L`ZO70$iXJv0ZEfeHNy{t|BRJS=`GJ!F_J4(kK)}Xxou|ZVjZW{+e zLb_u+T>pKr6sUlR-B915?OU-N6Wu*?ePplB9aV-Mga~@0DNKE{Id@<5fzy)TzI42! zop&G{=f2m2uGizPiyn-C4-j~}uZxkj({aF>3&^A=1g?eUM)>VoSi9LVd!xGR)n|=} z?{PQj5)zPQl{@(enHG#<@!Lk>S-UBf7DRS}0H&Nj+j4PvIg8MTrZ_RR`kK?|9nLZw?J(Y1@GZ_I7wMJlH_UhSSw*=Zi27*c2uVK|}-}-Sl=#-ZMWO$#Io-FU}_)>lvsBhFOVfHp+ zqFmTa@uLnnul?jJ97towL%$M~$OoM%#Y|EzN)(qH$)E&N6TWWe2mMYfnxu1n0vhfh zf8`CZ9Ak8wrMhj2YYY(>z1i8tUs)Tv%odZ1G#+jXdf}h%NdE%1CqO92^|EC$+qD<7 z(%T#zi+bI4G|e>3rX^`sHFT2ujr2`C4gU_^qO3*ONvM*$6Ny=Vo7+C9A%G-{|9md9 z*@4J;!n@my3?X-FQ9+>rHmm43ZnpcvfEzrx`G(cJS%0OUdmM#g>rkJg6GBkG5;^XZgZgnpSYOe$~=AEKzcRF2k z)_l-67+Sl-Uu92o*wtr?dbR#~<3RXdLZrsK+tSxPM-WUfsp4Gkb-5#W_6D)XMMFmG zU_3{92GF?Ig5C#2y&(MM&``Qwtm?(GlAP$)BM7)@07Cp1T=N2dZ_9!Fg)mMm3Ej$S zd)Rw(E&6?ufd}Un@{y21v$Ffu+SC-_-l{v9dmoN&zJAW+zXe04B6I&E-VgRZMM>aN zqT_Qd%VmE*FKXtl5hQ)UhaZPC(ji#SdZh(ho2}=z*$aYOUIBxjvte0Y92$pe$O7`;#3TF{joa zr+NHbLdRG~oRmstwll4aXNBE`Nj#okLoMQrduxabXr6d5QSy7S;11bhDSmBpcAiu- zk|<5e?HA>-VGXDJFS~lj6*5lC6@-g`-oNH+KcCztmiU6+{=Q^kC(2D=>?7$AH0u*R zd&%unF+rBtkF0 zjcEIJ99Quaau(kcFzP?_vlv^6sDzEoZj@%~hcfw(;j~NI+DavIy1rR883r#U8n7kP zT7;5>P^wLnCacKW5AQPD(hv6}*&HaMQLoc^h|W@wC)`YztW}P8aW9~^pzP@UT?HM?$QZb%L~8c{qB1PZTV9af(952wsvv?sq!N7t#Qt_3*5I(4nT6h zBkStevb9pijJ)@fc~ozvvz!61PhD?BKVl!2J8l>B+yh%6t9&0x{k?LNAYHxi zK{SadpdU5gEQYwYC5a7udYe;t4CC9pP$paG7lk(kc?17;VNCA56B7(jg{gbxghv6l zfrwbQE?=gGbasfGo#$aa9SxVrx4l!w(7)NRR!78hSY|@DcEk0w!ghdZE=v;P^Cr3} z+dFG}ca&n)T9!801xk<5FP}7ww$lCgAGh!uPNC?zBdH$3yhO>AR>QCd6ux~$%*H*UJLcFszVUA}iEeBD zlWXG^+qW+F%k5-rV-Ej_~KPV5Cnbv;}YzwO{5} z9;X{q(F`IenXNC{Tcq;Q=&LK0+BZX4@qOWk69SbN0Jvxsk=pFVrMP0c znv_mU)aWK3uWU3PK`1N};#YaPsErg79{dIYXzyG`(}cwR$-9ZpCmDG`hQTxZx-_pCy& zrhi{fvWK4@@STV$&&Y5WlVwdy7_uFS`#kbythJ54mf2yD8~-kRCY&K4r$Cq)u8~zK9w4-_DOOI_szn_(MvwAJaWu9HnSL zsn!T?fFmB+e$&f!?%SNd8CS-5TdwN}9iO58T@B>Rd|LoWR;_4jLXNAD#2Mh2CXjNL zZrpvJ3-U&M+05#U@4T&YI!wE`)sI|Aw0Fb+g&$9V9{KOnRo!&a!$IiIbUKFT2o|NYa@IbutpB9V>&8L+T9?NIO-_dx656>#V^()_y+*Ccs zR>>}Dv2n|_`zB?VSDp!d+PjJu$Z%-|81zB|(W)A><~!8X=ARlSMb{j~3;kn67!+_8 z0~r!f^^=>Rt^KIdYky;y>H8`Ywk&@L0!k~BVjS{nLg|tYrBS)|e&Qo#V&Xc{|=(o~lh@1w~BJE{sr>(|l9MRePwQCB6g%0L3m_QkED>k#Ubj3u~*V;#v zuq8OzGX2lKloR5L!u-^?qHopM(1NPGyvRcjgMLa-sgpjo(YE~>3%h#`f} z(xKtN{b$}~9ho`Qt=Ks1hUMCo4i1A-f`bron3|bKV~+i%(CqcAU^|hriDv8OPPo7K z)dDO7aiJ&Po4EhDziCYfU8hef_=YHH4dWQd)~KfxN%snfXhBlICT|mHZU>gS&iTGY_1M{-53Hmm<_y^0v#xr3QHWBkv*ls zBYh3yuDS@?5tXXbR`=Y;&bfdU*n-BGdP1`E7U{p;y2Jh*5#%27E6lDEQajFeyaj8`3{G_|718LB2d#(8Ua+r3v+i1+yEI(M|CES04$9wQ%ZTx?Wy`TFC`yo%j7zulFYx z{gaQCQu)?@c6Oh-anNr?WrqfvCP)uCWh-H}CP;Cj5EA`=4-9@89!! znt9il1Ej~_&yENGzAh3!rP5>uts~#Bl{j9IEAclL|3mqIt$X2F3m28?gZ@TO>X3x5 zfWRvNM%U&e$+*Qk6V+G$%Qwj7sdJ$I(4dF~`PZ?C^55Zaznv~y2Ij${@*=9@CV28$ zNQ8=raiV;(Ob%Qks+Y+@MOQiuE&((#XSM{I7N|{XS|5s)AZ8<8rsgK&H7Dq-8vu`` zeu&@F?2H%l(w?H>Fy*-Fr{e0qEIR~>FF(5?+$u3CzsZ=aL)q@E#CqA zK?GMVVS-<8m(+vkf^&}_$F0dvo9W^)X9k!UtWk_J(yp9J27Z^SlWG=|GzE3ArhS8; z^ZW@!SsVhA9AC?Hr_(MX|}Ch=bY=QzOkHSW=nI+`{XpB z&#yXGl#k_FcIWDWwz9t0o?jM+?*t7nip$)T_!{VdL)sjV0=d6AyJbnz*gfpAr_z=4 zw2a-H^x#q2uK)4p_PIo1lY$OR6}z2U*tOV5ntzUAJSDms{#LHETER|>sB5CLbK*0@ zj7<*)e}8I0-rp?yEGhWj#CS!^KX!218D^72>&I&Gdd1+Tu|+eWx+LU?D3uo};P zANnV$0wTm*y2z<0PmoC>U=O$3+}0nmyU**Ucm;?~Pg}zt!W<|*?>|jyz`(%#TP|#I z%sc2TlxGV&S%a?@1|`>K)+TNWZVzDhy72LNQ&=@^()rFRJmKu8x(%LV2IQ(dw|^*A z4ae=5%uh@Z7#?x@aL896Smw1noM+vZqipTB=Snqn zY6_AE8#LdE!%)C?M`JnE=zLBnDYtnvyaq*Kc`cpH@cPObkwD}a8VeGz5=t1yF)4s; z9sX4*!Q&N9Cg7o<*4NjVNxMaw^ee~q>gwr+xhxM#wXYjpZ~)uvpP8o6L_Zjq)}~AH zB~aqi!jR8vd4d##fRnoR5LO;br1qCXK`yl`cV+ZP?Mz%*MS>vvJnm<+?m{nR7IDBem+iip_X5ym@1`a5{_O_d35uLpLh*lwyM#G7UXwLeln`};9R@GjMy2*pO zd9rC7yX*!fo|0YdEr_bR9qjDV)LF0jY>HXvO&EII#(#ipHK2EHEz9`UlNWHT2`13g z=CLPzDRz{-38&W0R?rlZ&moWU-;30~hD}KAv7`92MT96#Oqdvn8=-T+2)H_dO>`)h z)z9|J$q6VA1lgN%^OAZ(-z7BS{?KsSF+iy!{E)BfCjsP|iGE8u$vrt8CaqSqviy)Z zaM?6==f&sz*U|99w^eCrqS&Dxf_L#G@`qQV9F!=JNV6it+HTZC&w`ebJG0|UzlG1! zrd2k3$>PkO#DxfmKzWM5dYV3jE=34Sb*4@RVO@QiQ@TYqO;(Ex8URhC{Os+jJS7oM zdk%bHv&q`2fAs70Jg`NUZ@kxvk^s2jE+*xJf9%}3W_LoW5q%5gn!UdOPTq%27SwiG zcxv{l9S`ibudpp^0ny|?;@DGouz|HV-j7#%Vb46Ch^MWw!{Bg(er=M>aPFh};mw;TsL&K{J|B7Eb4856NmZN`WfT$1{*VVuSE zTv0Kz5cam^Geu0@qFI}l>}yd^hU_MjRTwd$Gkz1Ih}P&_2IgEhE~0n8vueU*3L>M; z-drXQ+CCv|QS z;lKK~V42yNO(p^K@ZzHt3oR=dt1OEmi4bLj?e&To9ni#16$>S zf&?)==I?%7;df$EaZ!n%hhAVau2*Jwn$NcW#t~y3wuCeR`HJI<)aqXbvTLLD_JS-0 zD=+`d`w#Wy^Y}U+JrOO9cILJ%S0C=l;N#u(-T+W&e9R4}7g#o}1KSV9Ji_SMV!QCi+g!E)ML6T6c&yB+wRpUGwaL2OXepo2IGs_;ovPGB9R3GwnjF4tv(Dx^a{A^fLBOJa#^ zLP|mF?$o1rk+5%_e$0Ma9T$K0e|#I315%b6>$z@!*3v83BEzRKD;Qc zs9puk@7w+rTZa*$@0LD(O{TeGq+=H%!RWMY&6cW5OZ@r>jtoZ1(m27S>s4W1YCR&y zqAthB_r(kQSlaK59A5z?X*)#myQ1{Jdl1Kf>$Oly>%`zTxBE-+>}$}Ei}I(rr($eT zeo_4FDq^A(nn=grFVl1P#n`D^sY>ciFnLja;RDrJ#Z9u8h-R5P_99DY(r>nHdEi?4XoY_e>$ z&|~0}LEal?s)!*w+l5Udm^~G95nI%bw%Ee@=(#YP0Gu6F^DeVm%VzG$bh0_Rze)ye zwdKeXpnJbWl9;!>Ne=l-{Gt9%YHbRvj#5tvu zp*9PiW&ODHT0X)yT2z1NE9d+fN^z5OP{Jt%oY|EG#JU=cIU@FC+D^S^OZ@>uL=l>? z71|SQw8bswI~G%QW)wV{UMRL6HimX@CTl;kd{IMK&0nya(g;;54|;r_#=Z20vE!E7{$f-fsw#0d^sst2A}1CNaIzc)k# za&{I_cU{jpNw?V_Yq64SdUYYM6Ybpg`1A= z2~lb3&6RJO0Ce@BDNO^4DOz^JguVe*EAjEPqBGK3<_>q<+Srr+I*(ks3+ljHeoJs{ zUU>c1Fuk$hZ)D2L<4Zna`IcFA0KeN-n``;m-BJPUWzcAw%vX5$uqOnAfhA7l{_Xfi>GMu!y6`#CRwY?Yr8$uGxBdMP^D(Y zxjM3yRfyH|hzHNe?p_g?H^@?{$wJ!@?DGFf7{;s3+BkWtX>%~CTQv=7UqB_$;nk$0EV2(i^C!xcgy1}-Insi11?5KF zxhu0Ai`O#ee83Y_g;iYobKq>(;}A+=!F1dJz?>OTEL`>Xa07ViKCu& zOs~fu}W>{;8Y5M38o8!H^pn3J@XG^x0mB$W-PPlQfs12vttoYiNgkBcDma0 zY!IVNaNiTOZ6o%Gu?lD~j_&(5fT(*gd=q9`A+m>DJv9_4&H39CymEi$#6yaTf zg^uR|b9R;X%J?MPstT(>bew}>ceAdzJ$TjPU%DL(v&Fm^BFC^tm7Oj#blH}-E z4a4&B!n|Yy>q~8oi!lDvd)vj5WwOTD>XA}=f1eMnuy;s{kqeC!cJ_>WpVZ{%x`q;hhcLz#Az?a_PCJfCwzcJsD_t!h-Q1XzeHd~{q~AAqbqAhR>>=hq0~SH zS88IzcfNgX#!j;*hYL=khR&=e2t-S$pL39>{VYlaO}XD|%iCWYx&VzF9eQx+5=NtP#^otT~X(7gFGQ+)QvHeG*5s_uGo!`SxRILpG*rxo!tOjcRj1n zz%b)qG_g;N*TLUtB3+I}qWOeqF{uh0l;tl&aEDV})@FLhNAny%?9rb@GdFVoshhyY z!!(eW#{4QM@TfVyLc)72Zb;!dlvRx zTh=%<6g2H-(yzFSz%0)G5l{hJgJ_G@czF^c;_qM_9z46K{P!P8@qDZ~*IF8RVZdu9(!=WmbQQF*eynJn+K~e?3Gdc-IL#)c&`C zK{t+p2c7(?%~2P07Xf0y2X%;6DvP1&dHRzf6&uj7gS>iTPTB;eG#PCt6OY7Pk4rOM zq(!HN1Ee|dQlK$kc7dUBAEvTy8jD7vDz78f7FksB1>BD^NeC?#1jgJvicX=Lq^Gn* zs!!PNlnQdy=ya39E?IlUN1!0-C!aRKU9^5=aUFKCok_Z-@54Pvr~6GobA0#&_;SqI zA12?gsxuo}NAp(kv(CKoTQ2k2fCZz~0y(+igR-gXu4C-brAZ&=7Jn^)0bu$FfOm*` zD@btMCL&G&Qf!gcs@R-*g^;luBD%Hp#ItSLE#a3k+-VCfjK8V`J7FE;lEOQu>WBd( z4}b4&DcN`7dbE;{(zI|ut5#bP0{MXEnhb;q5@{I|BlxpDgv$8Rl%N=4*gMVx+d@h$ zO^dywr0Ln&_)22Cq{R#3F?6|(J~!rUywS19`7AO9k@`QhQqWaax&&T1vd)X-l?HvlTSG0Op8PrSKpi)) zHQPttTg&EW`;LL)*Pj)`na*L~XoZ0uwW*79*lIahQ(yZlo+J5p&4sxP2lkP!e=ry0 zH>Bb>^Quzi6p|r*>IX-8zqi*FX?x{KYuX`9Jki2FWuW8Lr(uN-<@hg`rg3dmgqZ(_ zt+$GbgA2BGp>Ycq+zIaPPJ%lGcMZXzad(&CF2UX1-GW1KcXw^%cK*H3x#Ny;UwLXq zSFc*DYR+#$M*#O|FolWB+qyy~c0Yn^SEkTM!=|s65)^t{QN37_nGHhPxi_OLR0qP( zzav|(MkxA#n%!oh6nmf)bgH(_9#pV4b>~CRP^%^0F3{a-p|d|CGqHo?TG3Wa;l1=$h7^j#<-A9im+iU6A z{oK5vY5hw_#Zn-u5pz3fVP4RGkMg-I5bf)&vQn+qI~Wog@K{pn3-bDZ3c(unD7=M< zGWSq=z(7PB4wabZ^vcKtaj^I*Gry!TsDys;zr^uzBocagvy!v)BrguO#OG))lH(k%2u+)=z=#b#VDp4#?XoQ#eKH(+vcn0wZ0a%_Z9aPP3o7HHPXsv@k%70Z{Ffr(j1PRS_V3}fDwgmHR?u4slfzJKq1 zl3*_mRj$JB`=bt%y2F*m$HxL>7%*i_M!Ay?<_6woQ}ALb-mSnWj-2>$l=hDfi&{fyy`<>i3z_nRE`q{{&b6uA3#tU=w!l(^HGS zmwD{AYsW6pzirNTby@qTFAL!LJP^IZd$@xc?NrXhlTS!>Bq8KMRw^aXG7XC%#Nbl}Oj3qQY3Kl2+zk-Ml2 zw=bWlfx<1JZ1XR(tuQl|5T?7rpHlEgvqH(DTXF&kA%$_{;`u7SY?v)iTqOK925(-v z59-`HAQ~DVrdxWNfQ`BQe@7}2P7`1?+e&xZ05}}?Zp>kHq@F}00oV@TGl zPeL>zCu+j4`7(Y0DoOw(9RJ+IMHA6x`>3jRnw#M#p;xaI?V679(rFK{-reHp;#ZuA ztrI!}R|~8NjJuR52;xVY0052XwQ4m>gpOcNgoKY>wG}`$zI$|6o^EVc9N+6>n9=aq z;CIN=>jbs1Q;@u7;fPlN6NX7K$C(j#FI!Y+UlDO;hsBc}7{o9Yd3%j}g5|${hC23u zEV`sbezb0>Ti+`L?Ih}#6RN%JDx@+{=5IG(enlHZ>AQ2BXge%V(m=MGL`ZfSH@95m&?l9<}RcvhHpm%jC?QY z%jA0|<@l?gz@hYY0mMKb;2J-a-cwpg83WkTiuyWJED!PS*NqAW_zVaC`$zfYMVY z5ARknYGsnZ_UHV?i@m5*}AzEP0M zYrFVG!?YRnPuU1MY^T?tAL4(3$P$HQK0{7|eR39NUvwfmOH&W{ae77_ zS(9a$_1f-;z1Js&K-M<6zIG2{#+p67pFzBWV13WG|0$Wz$J4WE7TMuap(+1_$E4s& zk}M+hmFhWYW?_Exic8SVGr zIu@osj1l4ze@hXm`f5qNGf33u2mKJW#t0GdHVOk6+?i0brIs?GHl*nJ;w8gMD*%z8 zEiU_G?mi5NHR}8yw-G*s`#C;yssw)M zlCI<*H)@5JzOlJP0K+AEV-hw+0jI@rP1DD_(J;AIIKFqLDp`owjiUhH2>jHUByNGDc zWoD2WyfCA><^oAyiz*|ns_ZoINkX%519MKXde)}9%Fc>MNvSUESkD*JSRnMbifsmg z0`QS2EyplNUSnhd0kK6Mpbqzbyb3r(90!rOdw1<0n#uE8I5Fv6;p$MR5PUY{5r0%mWkRm!TH@X6R zrQWy%a$B}7u#;HHeReu|Mhpr*DI)#dWK)~#uqOc61zM?;l0JFWkUx*IWr3<2<81a5 z4)Spd0$Adl89niGI5(|a=a*7`*hpFa>bM-H+_JO%KCu%YNSWbz?Z0jUL~?4ZvrhY+ z^G_ASaCVZ2>}5<4+i}%*LC9^RJYN|NJWc!$&Ap=A-uLg+C z?Os-fvue^g=^rUrEVzp*t|1T8-er{20Bo#T*1BPCvnwwJwv-eb85%c^!kJ`P!9sRg zJ&kh<+EXDdXI8B;Zm0x~v!T^>(^_2{8q#R@PZdPXBRXelewt~xi(S81yNi?>6s8Z; zTUmFFElK40tT2-|t=Ep~IC4tQ>Y`@O39c6nd`ZSNvclXlM5G|YOB0W~@j}EEQNnE> zwlc}P2j7kw|3pq;cq~HGeIJ4~*;Cy4Cer|_YyjfzQD~$J3*Gd7( z3^(c985+Au<*}@n@0xrAHZn@C$l|+J{o#K!vNhx3Hu@>Bx!O?2VXF|J(;Wy-a!?MfwFqT+vhT=B5RFyGQH%*nv0*x-z1jRIp zf3hl)YM=Y^Mz5^>YdJJ3FA4$OPLIZ-`q`|}`2!_6vHjD7-ydKV@0{9hFcQvBJ`RIT zM4q(SXMa?$+-JKgo$^$Hmwzq@VK8`%V? z48qspiZoYmu^&&U^1g2e+})+L11WkgX&aAIzVE7wjp9{jwHh=DlK&qk^Kn;PEQU*x zP%O-|hH=3Qlv>uC6_HCpm{O@O1D%MPM*bmO?y$xp*-YY>uSaD~gbLX-dG!~D5U^6q z{;IJ>f>W-6vwAqYgNQe2$kx?)g49}{E?~@dnrvo!6XaBz^_+>?0C8&&41*>@u%Ou= ztDOGjiy!cBNZ9$V@5T+T_ap9>pTbG4X^0cW>Z3BJ>A})kL0Xhu4kiUCcBm0L?qspW zQ%20<-QTeF~Gf#KlFu`VJmX<)H>)6TR$l8!59nz=~;mfQo0xWTw8u zbxae(g)p1{&qBH@xgm)ma;8h86l!_IP9o@2_^)?IRlo@=!A%}KJX3M_QHOaBM?4a4 zO-aDU&RzjPew7VP!5;{*)fa!s@-2HyWl=ay)Ox$L#-q(FBcg6nI%;eU*w8$hJCez9 zqFr?fll$woPe)>7H6HZrr2+blIAU%v)>7@n+hGz3(fhfq&Sr&+G%YR%j{*kx^VI+A zYy&!)J#PK(Nd)rT1xg~Pa3jMyr;#FuB5!nCz-W!0Sfg(5-VqanQJhBwl~d0A^W1y+ zbyUDuxE$OY&aOEK<$TKDuhn1GJ?aQx_B+CSw@_yMv`DH=9a@Ho)Tz2dg zA3u{mXL$U;pK1I=`5if{<}iiFLvLP*UrW9KGU2{KN6pBdfy#F6gHIL31WRyDC(TVM2pfI#ZmjG-~1hwgb& zf{n{`;$LT-yyR%7JKGM7Pn26^i82(%RKP;M2wV{VSpMH9mtYOdLbkScC%}-`xs8kBFUeR*{8*Muv4pg2Y#yyn=CB@~=pk0M`lO+aV+ z!7_L?gS(csK}1z$^~@n2zGF#I&${>40!E!B=s*vNf_}`>N*z*w0_wiDsbuLu@1Z3gaz0>^Gbne;No#X9C0~ms+G$UnZtrOA;QC1*Mm@0Rud7S(L(ppF$0dxDiOdi}>hW7c zJTDOlU-UPGW*Q94m_AzDfD+jp&i5^+KT&xkJ;uS_Ys|Q3U+nr=3f1^hGn!nU1@o&p zAq6U#bfB_bn|VB&_N3qZ zrASl`fzLg#D{o>Qu~N?<*6W+!E$K)>(_m5OhsXeiO$ahNF$P377_hA!@t#!e^^Jr& z%;fn2EW%zD)aPEXU8f5W>^cznx+McgwVpxS3f@QCEjejRfU`c5Tbm;kX5qks(UE<} zxi0gnQz2T7xR#ha2?>e4$o$`=NhhbLb7uc68~^+I06$psC`i5|CkllZ+FVL7Iq=Cu zTRBjS+BwKhO5AHF&8!s(Xl%_s9Z}#fh@KHSOAURvabbiIJ%nbqv}y4%%h`fdkF?v@r4oB~8s(<__g|A73TrCy zn>Hv3;p2?SQe+!)XH6NT@*30(8r&Z(!#rmS@|!5L42yT>KrN;zGmMrY=o9s^HikAp zYqs2o?Z{Kmg*rfVL-FW)>0f1xxba8f?-$*r)kxGx&`tOWY%z_w8=HT#qto$;3nDNl zgUPsjra|$jmX;0YoR`IOK(`+?TFxZ5f#jBaC1g1bM==%M(ucUc1;&LAM@ zMjCW{FBIxg5A&T3?gDQvw$MvJ^K5w%$>#($BZu`kWv9n{Akkb5j;p95!07o`TyJ|0^jl_n;gv{oc)g<@Tl%1;^v(K zD|v^AUy38VIhN;c^e#P8l2hg&p9iRg(4CTmDJQI`NCg(1b1qP+J~Xe! z%9M!KFlYG28H_aUftpoOrj}k@%mebhfKFhl0&Vg&0c7UA-WTlv+r{yfp&63pB2txA zF8oiHhE*0rp{w7dhDZre#BN|nR}j2WyAj?Qf<1xeCp;cG9ffL7K{WnKb2Jl~>{a?l(SDam>)bWiWns;IQrsr|+2ny;N8 z@8c*#z`Q45IQ?wu`yvnfg7esW9v}-34QsB!RpXKUqW)e+e%PTxlRd`N-Igv(ZL8d0 zY361RB6?l$AVhCfm#@Tulz5D7fZF`P#NGdxVuCbzI|PLYad9)M#l3T=HKvt zn*lq$9Nw6|RPZnTXJTzA7DV|+-@d+_ckKqPn@=761ONA*9h9a0eak0#D~VbDxBKt{ zr%s6dZ{xH4*aLB%(Rkz1^9x5d%~Rr5zrlvKyV;J4Xu?i}*vHl+z@~Q!=8$i7yoH?J zJ%)#e3+5V@s8EJRfBA%Qft}gfAv+~|{4x)``jrLVsKXl8z4DtwQ1m;cDxG^M%#rpN zVng#3sv-nSWy9j9&6;-E#_b>Hb5bxqK-@P{7hYbrcI9c49d0y88cbSdpITXVb+~p$ zcr<>hwvC^oeK_88Sz+1YA#QG5(+6>kae-qIsp2rv4!};Cn-_i+S_aauD##^&MpjYE#ftUill$eE~s$7nVmAkX}B6-&64>M}LKp-PVQ;6A)(V=`~BJ+{> z*ouZwD6R^qY-qo6fsLV=%CI3XH`xSzv690i7D9J6Z8=+>7S}BG6BKYQcbGb10ilW= zfq+#jh6G~7TPwXNa1x~AWHsH8+Ae`i(ch{-2`sszy0t+cVo#+phYL}I%0`eI zzj5c+1{$h&NtOL)jpFQIRhvn_XwnQiBoEoGIi!+Zc=k6pR4DoPjpGs#4O;2n;tRYT zD-I)2XZleK9!sz2I5v@68!m&u#s^JCR12ONHCFFTv)#iS->&zJOKFQaFuKh5?Qy=& z;eld*lyRFLbFBC@W0W+vev%LApQ{MVdKPPJKN#V(eg=Fl`FMf7K11&j)Gx37FW|aX z)~osFx8REfmnYCPY*V!3yxOfc7;X*x{M3JhVPkz8qqmns&^t>fF=#Ku?L&vQXX1=*o7(J{Gm zOxtT!=(?F!W!JJ&Uw@HWV2d)00CAp{ zzuV&OgBl-Q2hkw@vq$YPMW7vW9x*e>OTgdx=Iv zZ8&@CTI`x(V<;>gpe#lMu&Q#D%O;@LxMLMg#)in6z7H#9oS)b6^iN2PYKW8nlAyq; zS7$`qnOrm+mBCu&FIt3CcnJcXiSjN~3_1LCt9OzqpIdm8qlZXKXtTzI$~-Em9N~pl zwqP(HTWaOKhwUvYbW)wmC0Cr=)Ow#fH(c?o5YKh$BJlAf>3HyA)Qeq){cJUogeMO( zr5p3U%Eh#6@A*f_l(ePq$LUe8&#%B+hym2kd7Ev{ryLdLWo}r3(pzWuBLx?43y<9& z-W_1C$uQV!=lKSO7GW#NmjFHm395~+PzPhd4md6549lZ(^-7iL5#|sbyG|^Fm)Vqy z>-QjN2Kr9$+=CM@`|@$)u}kA)=}Kk>oD!8WWg)}c{|laU`8Hl*iiLvq^W3CX-$yQ- zpp@)o>jpB!PZZpA>9fL7N3i%-uUc1QksK*(?4mzbO<#)@*g6=<~8M->ZcYk%yCBlj|jPJxwpz4u? z%w`CMiF!?cM7B^9l+cL$DupVU1nvu&H(;M^oqS;8!2>%(2 zEV1-*gMW{MbU~yfLbbm#-_^)$mAru(=@B}ev6>ZnyahJ_@eaSB>t>_rp?j~5p2Qa6 z#*(8WH#2*S`3&wS8SP;^4!p=~8iZJ}1#7%b=gJ{wu)g8d@sVT=Br%rFAg_*0Oq?6lr@W`J$D;!_5(AMCXX8!v9W*G|uk%G#L<`5d3 z8>~=Oa>gwmyirzQds?#e#-j>xAl%31zJ8G$?)@anVJweUX{$p>6ajGv8Af{uB&+-C zWw)d7N5zpU`m)*wj1N7w;X|K2uN26FeF&l!*e0$v1Gv*r6*fOC zy-wKqiZghVQ|Lr% zuS`1KK7wGV#5)rAIxsE}q+kQ%)o}W70b_-6s6y zpDH2Kb;I2QJrEAvbbC{SDwF41@GH~J@)AhO2-Wi@xkP%qnc)#;i&3j@k}_2 z4%|We7Db<%gclwV4cKpb?OCDIqR=tIkwE-BB6;$y;9Dg2vBz!S;$ru^bEl#B%&6kX zh)q6wfWK{K^KuwY&e8PVV1-iVC93aJ|I^x`Q1g`YAt-oNs&gB~uE(|OHcK#h>c%Ao zlexkn$2jMhzPdxD*@){u+0nnV|87*We=~UIM3J@Io^t54J8&0e*B-0WG!kYga}PH~ zSD93fX+-Kr63(4&K{&OIXN%W1e0FP5iO3Ark>(@3Z?tN3O+s^5X6RvcYR}FDr`Pah z9}kp+nbwyCEVq7s^o+9rMixX{c_Jr#00okoMJAlQ!ju`?51cS;jePR)27i1I4I+=R zirbeQ37HKJ9aj!7c*rNK;Ec+u9`%~hO$2V??uXE)0iw;`!P}`Jeg$8DvB|6JQkBFa zK`gy>7gY&6PAIE+8|kMqv-Kj=PCVqjG(-G{B01`W5%>nihQ{r$%ac}PCM~{3tYM+Y zumvV6a|6eJfzeL!Jqg*OvRftRt5OzqR9hkYmjG=&Av)&KaW=h0Wsyt_2y3{jncEp) zKst#iypmE?jG;Aye+}_?tJyk2U90@HCQB2(?H&@3{BOY=aRpL~H8vYaI%mbhU#mkp zvsCck>X~U|Pu_A%ON7mQ{+vLkUEE}<x9H4@=A12*PvF??~SGT^Cyf%|^ZFoFp^aWA9%Ov(K?U3YXsN$U_Sr-{h88 zwaM81cZ^b;G_Bgs`9xSJ)H?3Vz_>Cv{QD(VUfFK<1+OFrLR|Vhw&yerw`_+HGM)lv}ji({*lju0G|Iuq(P=EX{0U=Zq_4Xj4n6f@Jd8X+pQh*RK%Z$+! z6cRu>K+_gUlsISVoD7J(>BO|-f&R|A65e2xqNdJI!eCfzJiCLB9CNDkt`WC?nU1JIt%#!=F{E>IiJz_VrL!0 ziO4(MZ4vB3Ct$WJj{qT?$b{j$J&jl^cqarv7Ywfaq?zawFB``uh)Qtu@?k*tFE)_6uYUihpTLxI@Lz za%f_l!9%xh0%Aw>V$rShG0q-4-AO?61`QMF$qZ0nzEq}>;2OMCiJiS~7o{QhU zBwU=ZPYGZiW_wok(FD-Hi`qGB-`2MN@bc2tF;xmOM%Lj^H5Mip8&)!UevmWPLE`&r z0M7IRZy?%+^!uz^MSG-cork%*uA>ijtrvRrhbu3eyMM3x2{MT<5lo^FIvhfN9;O4j zU|`ozUG+j_!u=j+?$(8*8D<3T)_+G>uc~~D1>5iccgi4HuWN?^Rmg1Q^DfM)_7>xp zTFFEBEmi9r&Q?0jcX97P{_L5Mj~pSu7~rVzGovRVmKo8yfupePCzg_y10Mc32{iL2 zRPawgp)pkR@9XAE!>tScMh?%s-7QEHlP5DpRGFI0exwE; zYQs7>V4VmCi1^iHw1%-+yMJ!qB3>G0l>z{2HCEIpK>GD zb`o1!znkG4p79cP3GFrn)}E$0pI(bd@-I@SQ%)uR?iA(mqmvL1e%pLOGH%|0l@!r7 zal>tde3qtp-j0PVSGP>($@+ChjsK82-*CnAS;4~}#Kr`{oyV;+J~{`Og{Q4|WXSqF zO-u2KIx*7CPIriHlNxP0Fk=#tkc&mRw~%R5BL9LMuU?+KWlltQ=ugZr$H0iWaZC-r zSW|YkP;hxrXYx5c@C%yyfH~a7cTSab{X~u#$4t24aX|a7{R&Rs> zY{`$Y&dPIu2j9&I60#|(S`&T=D}$Eb4|3Z$bp}7*pd5Uq3T3$IyT2OufL91hfeMC$6E;DW4L{`8Q{h+rSP zDhYQK^}iI!boC%(AQF>iO%KJFF_I~7nBgnd=Z)uA`W503A^ z1jkNoo#+~`>}?kuUHje!NT|yHdo|&RbTg}XFu5}&j(l!SF}@u*&GRNfWk>&QmI63r z;QGi0LUZV~A37l;N8|~fZ%I?jA6b>f1k2Qs?5i3eyKc}Ht?_#KL&)0A9A7aBV^8+r z*ca=*o>!>XYBRwbFxy)s^mKOXd9%Zg(GIM@#Qi05en;o{ZYA)36^H(mLVYzqU<;*% zrH;^Y!ywrs4Tz~&tcpQyvm;iED~genC*~b=pQw6c7#&i#5`ma zv@fbO7nS!4p6y#&9{tL{wL-`4z7pQJUty z3oe`w5OjIbWB9g?B_2B=1Eq!H%VWfM`XZH39}+sw_)80lKNtI29ep+H>rkye zeH{+Su9T~Y9ggQ?zAixc{`<6!31nT`p^)qQ>39;RWRTC9WPa-Fw2R2$kQrNhxi?S$ zr-o~utS09Kx=j{u?S)|3(8@mP zGKO27B-Lf}ryAt_4Z_7^uq(|>o~Zf12J!j$NAfOKZT+1CgRLh$+x7Pn9@niJ%)Dug zQPmEWX;xzqVJ;cLV>E5g?ew$Z3 zMfp%TqcEE-Yrai>v0Gd|%)U7WsC zb}JFoHVQ`Db>p>MI>YIsJPL%@GY%83^GU_khfW9^&?l5RS6`p>)~_Nli%5!Odtmga zg{9!BmFA7@`Kuse_LwSZce|3A=1_1Wi$BZFqAbIE0QI-1u1-g@c&fco=+xn6MUU%Y z=bjFhGMGeR8PaZk>X2ob4el3<40z}*rUr#I@3ejCFd=724L{$#Z?vsCjksmc|Xl|r0sNe7Y^-I}?J`TGCcM-!| zY@x^dr;aF9g0#otd#e64pC9Eqjsd`G;-_Zw+RrU2Ia+VsqAE`in$YbWf?T$@FbAQ3 zcK1gH#0g}>UQdR*+^C1}gF_8AQ-DGF*b~P*(dgG(O%+39y1X~3pFzLF?Qh|x z6M8Sbr_+Tj5Q(bDQd?N(`##+Xu*U9iGHZe*{|yT&-VH0oR*A{3YNf>?KjcYi6HHNT zfTMw=9!@X30SbmNO`62;!uI!jhM)(P7N~xUn=mYf(sO0`UGi+9aehDIG$fFx^0Ft&xpB=XW&PHFuw)(k) zzub1D^Aspnsx{U66_e8y6B}DUwp}8J*+g}Co1zUgCSv8LZ^K+dYZWH6msO~7JF#V*m%=qd81bobYT@{)Ugez@SkMwvPP zL2qh&70Y*e^l-;vLFhvsIAB7IbZBJ&!(}(?oeufUflpz7sp7Qqav&dC-@`G}x>5&D z){h7z{c>&C{*(=@$@YabKFlmPn*r|6tV<3T9U>S4u^KI>6*?8{_se(Lv7600RqIe< zstmaL{W&4I)fuWL#cT~a)rTD+El+KDVRar+)LfBsQ4ZLx;6}Ih8c~*o`h4BsL~{441ZE(sKOOjQi75RR~Mk&90{{XO{t%B9iLB(8)g=N4gbz|DS&3V zY&n&9eOt707>;hv6`(blS7zCSV>=kfnZWeZo^CZVi>3YG+R_xQDU4=X;2qt_CG4I) z{sD8bVvefHE2Pl1EpMN5FSmP)LxTarF9*n!d@ctv*Fu0A1XmKSsDj zofGjCNCHTS=0Gq$MRA_OFy})t09oP3ok2^V-f%grQY?@2T|J+KL{mbSP{V{3abB-G zo9d5!UoWN_rm8WT%X+$H{_r24;w7G-yEj~I`6Gd*xd-RX)migVUSXyEzUhBRqWIk@mvF}5`7aM@SQ%6^seR~FLa|}>pc)H~TEUJ}?YS?rCWiG?8rTr0% z$FZotSaWS5W|%l^=?07ZXAV1#zA?|%(DgZ0afA6NOvQjD@9=FIhE@wdwf~6*IPOZ} z9F!kUaBZtRA~*5Gdsi4v5~J^nhOn<0Q1gU`{ZxJRx9qB59SH)1NFhkOgHn8xF^3-5H^@ktz{^g(47g&aeqwQ``2S7O`ul$4RO7`t0Ao zA!URX$Y9h6{zJkq4Qlty0T%os`Faae4Fc@RQ;9weus|S zoP2~GGO4{o`aH_LCR*iWFk{FvvQfDdBsGtZC{oTwrTZ9OOP-9x@H!%F+kfq9-OGx~ z57kS(oC;~9dT`MqnxY~r)Eur>Ure=>r~~p$RHuOHsJm%N*kEi4R8< zLWS^I4pH{N*$DJt<92Vg5mw9zaODXLjW=?`2xxONlwL!+)_6~ zx7iIXXn-tNJPArnBu#D~2AN-5;j)!8t2x~(HaaGyp_;0h728X)j$`AN!THpY0U`dG z=m+hR0y)*G;#b=)lYaMyfMF9J?f>_wtNHK;>Km2*Eh>j1u{KEILe`5|bpW9u)n_u0 zLQFwlOBmM!4Ec-wUanqB5ZB8GZF?rTOc%0nMJFU~?S>}dx~mI8?N7805!4|kX3;GR zCgV_gdU)J*X>{Erd5}&*S+(gM?hH|6?$))&0EyRpK{8NFbg<$ccE+wJe^8cnY=F!WP=VqJC&9ibLhP4Lvmh)7cK^jr2WnE z=E58LFJAC4*e}5tOzp4~ld0nGPhV05GPRvnwF9$`F=GBlW0^HCPDMQztgFrhXdW)sq%-dTVCWTOA516@xcb=^dT$*UB@Ta7@_ZZ zhuh>RcqbS&ts}4P9JFgzG8xXn>rEo91+`Vn>V(T`%@_P+@P`gPD~(pp8+gVeCST6K zNyC*ui0k-p3rUvH|59l-*PzB`J{ko0rvWXwps}%Uv^ZR%jr!MhY8`)tVyagv9a+8* zc>wat>`g@nA2`&t5lF2F7PB5s8{{`9A;jq9zA*4#dMzDhBYBRhJhj7aRqK}4Byb*J zgX+fFIx8K|R+cTty4}0as{bCeqbHciokq>&!HkGL^XGk6wBv3=bl81Km`XUsPbHyV zBUe&o{_UrcY|g%}2eD^gTeK?yU%G$CL{v=~6_spX6t&xEK^(f{Y=u?CIub^ClufV1 zU}P20Ob~Kc5*;Tfgee-F7>hq%4>MLbwO7!i)+e!>-VnE^OV%;H1!s2WQty@J&4csM zWYoY{cJ(Xgw5yAlA$v3MQ=1jc)_3TO*<(#S{NWX6*X<{h?QMp+V}!(GjDy!F(Nm^sl@$qLAVm@A>Og7)O27hqtDKI=rD|%?NR=7viq>z7fWdjBgPw-f=8YxSLFVt5o?l zC8^Tw^t^7R+tzr%rMP(bE|tU?I$W8YqiW|eKJ{0}`b4p{t`6b95iM?*{gISXwQe{e zA>seV69EgtDtX}RVu~=E#ifG~h-_dO^m$0M{0V}nfp0j7Hb1QFG;s8U4A7F}lySvL zjUg-;j^-9sVu%wRPCiOe#(L14K5R*kgB2!wI!9Zn{dPuuE7iZrlbW~cViPMT=TN>0 zzH+Mu!MUIq9d1pFo}>G0j!MuqeI5q-5c5Zp3`*UHY7=|&&@fHk@Y=N!qzLq>_o;(Nmm@!qT`NVEK1C&#;Sv(} z9$m!|@;@3r&wg9^!p1lq23jSegol3E6I79GXoU22aU@gDSwH zLiw8w@W7CN6Vh`AFrb2`87W_fv7U}EGoYvYHwo0hyt*9|+fTXIaYJdZK@3&>clt4% zkYs56)UMaEZ-dVX0mdL)PMaAX7t9iD@P&WzL)=n%H0um$JZ(1a@*AiS=?I@8i;9&u zl=927d9KUSbDQ{W`{!eA>S_l>R6QwHeKU$$442JZ8SCcUGZ}{;+@1e8#fdb4FZZmgBuz4 z-J|8Gugp;E7!rP67Arl(r2pwJGJ(dg1Z~Mx5|~fGp1D5(%3Boocl@z}%8ciQE7Mzf85c|BJuY2*+@YZ^Mk+&|KvRI=I*gX@mQBtZ zYZZ?t)`jaBB1}51m|UyWK7BemH-59tN@3x{+NINZ)=F%B@1=Nats?&)bWc(q)y8sQlZq$E}W!LMNo>%KW28A)VuY=;i<27ymo*wZf?{vd(QZTdl*z z{t){^-X2Uz8u$vYz@SZk8=lpIVn-P%SZbok7%#g;5#8(y;bS3U6m*?uJWL0gIJ<rOZ0u&00+Kz5b zwsa8*yNB=k>sCLB|6ePl*T+j=VMAlFtRQWGyrJg;SgnS=J$l&hv+LVyP&>;5z0KVp zw8V{>-I234zb&A}F*%_rCoE1CG}4l`yK+0jW~-8uQ=8tygKA;|0KwqjTx`56pp0nM zc|+gN#j>CNF(kvo3Sl2iaA2&j;`fhK&&3z^Od3UioaBTFX628O8*6E5JS z7#Q5Q(ViE$(!$FK+?(^5`wG;8d=N8(SENgt-uQiTkt}(0jBI?1V{C6veX-F1lVl9z z4X{9ZCY)unLusD@hH*g?$KTdzSR{p?D14#0c3l{(wAD{j{7{aC>AJUh0#624lLJ0R z=>7J`w{ATpm^PjO?VZA}2=6cVSIc$Bh0IVf29+`D)s$)xThsNXQ3ONL;P{0OxdJ(w z_~RtnOQJvMkNk6zbK;HKiO)2@)l2huw7%72eI`JLUWWmagsaT|e`NLGQpH9$XVB|FTNf16bbh_o ztlhx{!Y^@*PX2fpp>VqiP(pq;P2>Ai;pLGHohR( z9iX@WA+B=*xHHX;$|_U@ga$^cQZ>+6Gou%kD2@rCso{h|s;(KVNf7E>%9$)^Q4Z_~ z$wWtk(JO@J(lSaO7-Gy%u1{r$wu!7)RwlRYz02eZ9J|TpHWbR>*-?ecoYU^jc zI6%PDL3-0Ue1)vBzH9SC+!|*Ml(oRTef!oPk+tq}^mr(p==1A^>6MzCVWx#gKb>i! znHD0YS!*51i=sDdN6s7a-xX)7^OrTJsD#VJxz>X#7nHvC1MMe<W&}s}F$;#w+P&qk6u`n!X1W2Wk+tcYGt+5R zZW@O}$3R}TZ4)*Zz{w45Yn)NqSnGBk8E`-TM~Zvx-g`lUpAML(jE|W1S>^VHljo;( zP-Vg&n0T%S=4h~gCU=?=@8Pb|+145+5Z>Q(n)+mBwyhX8C9l@Unn={+TB<<&WVWpZ z`^RmlZD6Qey7v%UkrY&1?5F=TO8vh0r`n zk^_Cm3}O1U$u881)PbGX*vL&xsQHPRw1R9e#xTK;v6szy<8XfA80-P?oOL8| zHAQw;HriE(%w%9jogF~As$(Hr6+2qiY(`mSt}@Z!3wH1QhQJ5q4d)NygNL|X*7tkc zJY8{0+`n|uB`wgs%Jo!f&asvE50h@~MsN9y67}h4MBr4HLs8pVW~rWd+RH}Vz8-a) zgS{a&vCpyl5BllztR5zfF76(mcqX=EXb;b}S{qN8!ElFq2LI?|H2^JSCvfqEZ$Pe$ zXE z8|xhtqt)g{58zgHP-Rmb8AamlvgiS_(}mQ^$s<|L)mONwEz6O{|>JaN|GUK0O4U%Zmi>bbOJUkO-3q>lS7y{Uo7nZPgN#I zJ|Y+%opMi()YdxuQ_A)=F6xDn`9lKDFJ$2mx%AdU(_sw}4s3>B=Xs&&(1t~Wdul+E~FzB#uw`%_}9E~`DZhvSqRJG%*nbzrr z+OrJ)3!v;FED*vz3j-sBuFGH*dtEzA`o*p6RrWtu$fUnEVGaf5*Ti{o6 zjnI2Isov@=nC_^x)&BPXuyv0Aaencij%_qn8{0M-qe)}ip4e{EIO)V{(x9Yb|>2p(AHe8U2aiPVB5d=oeK;f zrf)O?&+tAbflV6G{JnM$O)9KxF*3eibZo-p*EtMxlu6tIV#$MA81l2E?lKHf9cjpQr96 z0-39ru3VHO=1qx?194Nc=!Z-h(Agkg&(0^Ns(Ym->?8}?kh@!6miMR6k40Ie(N`DE z^Dh1k3r1vCZrUS)EnK_!VEVky{)_NmB+l{$V%U0^B~x~fW;>n0qSA7%CG20D zmA$*_{fT!iMWFI8HzPmUe7bxW$8u!9J=~c<9EJ&f)n7(GW#<7b@Dp~Kajgmyqy9gV zz4UJi5=FW-`L)fb!@R=VVdN)y5V4GLd0LKuX=`@ z;SHn6G7k_^3iNv?0)N zi5C+@i8_HD29Mw_Y$>@Qb5(g`JQg{AZy`ym3Kj(5BCRN2KXAo#gqu0**2#3bdlTf^ z#6~pu^7rR2rN*unB$X0lT@Sb$kLbU;i9-BLim*I>+>xC13R+pfvtH|q+Sm1ET7M;o zHP;+?<$H;Ma~+8lac3_)1DI3ixQIzCD{)n1rgn4GTw4TQ#uOr_(*aD`6ozhsZ9HhV z#|@OVzu!;6(fex~H%+x2p-Bx(Dv(GG4OP<2F=v5Vy!l+#V)-B{x*!SO89r7Z!;dw@ z+yXEX(H%mM#SKtHQz5zqU@oLOC0W;}ZWgAnDmfXNqzs1}O{cC9tU6A=oi8c&(+Dwd zIbjDR;6Ap=zqMO~l=P~$IKLBGpr{V>x*UfF9yi@rQ8s}CW3+p#oZrV57x2t!J8xX7 zYTa2c7_n3C<`*DiTgdeZ;03CSeyYu{LxWz)f^X(%y2*%ET@5DqiS9YFVMS!b(6P6- zpA_-vNy^>i52&>Y`29<{ICw(0Vj)x2)9_fFss{J@6y%B|lD2QbOxcUZwaT=@*xXI0 z_HBmehz6=HSF-?)*2uuk0&Vr6w&(jy4_$HqGc#)kRvqjmz%TaG|L2Jpj1BZdM>*@! z?6`MRU}fAF{uI>Zb(j-jXa|B_h$-*gng5CF)DZROTIA_ixgPLPm!u@AJJot66HhLY zO!zL@ON2Z0L~n=h)4ZnHpGPZlkoPZ!E_3q+1`^Zx1!}WL)R(BuRR23Ok>pG3&x~Bv zUT`o=S8;2i(}N8Sfkx=%N@l6`aKZ+$0x%MR-W`6MM1T=#~LpNqY>Xc#H1Fd zV{M~gkL}lrlH-~h%B2R9?YiG$*g6|M`>Tv>EXFOhZvGso&4CO6;B8w< zLhC8(wz@LjZ1HcNk@~0gIo*geOA5mYhB__%sv~?kl-=e!Dy6P}IL~^(66p4E*SK>l z%*yvDWG!ee!J0`cu#adHrn9KX9R6OHy&cTLJntT6_tYh+3oSV-8D;};Y7G^v)r!zz zFWg}>kn^X>8F?ALJejL=(bsAW;$kMuU4K)Q5y-b(dB*!)E>r{&!`#ay zvD?&MI_2xgRBzD=A+Vu`E6C>);sd)@qmbd+4N)V`9rnA-uzCf7;oPl^Gj$kk zKq9CVRd>Mbrs5k)9Io@}O6#pq8m$5I@R~yM{C27$M~P4#vmy(^$~MT1gAa8QQNN-W| zqqwQht(4dtHGUt@MK3ZB13}HjjO4J5hFW6Q*h~@X3Lxy8GlV&1HY-uT>Fq78 ztaD%<4)wWT0fLAHee?O&>}rn^+pil5@K@s~D$-Dp9+XY#`aiJ>z3PzftG z!k-*T2dX{J`WkSB9(U<(;ywJzNdFr94@;>Ani39}N77Av?ZyQJ z5=(x*--7S$*ug{+nXX|uaRuvY@p)5>HsvC^JUk|+L%Z1F&Qe*42AhbDH)c)JeRUe< zrK&xw0Z{?(Zk)nF#5nd|IWJ0ktMeK}&c$_nIz=ed(MPvb916UC;9 z!^a9`i`Ul}E)9XZ2Wyw_EiDPYhpj4p+sH;a04x(b0#nGB2o4@=NcA0^-@#Wl^yJ3lYs{~4hHv`)ZOEOw1DtvnhnSJ+Ht zuxE*D+|7{x5NutRsqV9GSVf&hz(|!GM>D9uHC&$IT9skN)ay_4{+>dk;tU70QQ6({tR` zAf(xbd3S?8TSj;rQF&_fIF|3cZk83V`hA(MDD!vcrt=_)=VLD!czjMg)Q|<9ZF}b# z8-m&S7Bd|ORH_B}O4LMBNwZ{(P8MM0=B%(iwNq24(UqvdV0J9HX1!VGdnc0|Aq#Fr z$AVkY5bf6j0SH=Qp>Q(m#$Cq5m`s5Duluh9CIR7o3-tE??5@f`}z z*{ZL(4chAf$4x^nAG_p`W@M19SQa^91%6dc=?-mO;SqzmD78=!VVD$55ap`2M`2&7 z15!qkQZvU)ey>GteEmvpiS+Z(&3N&$K(Ml6)WUGM`$?NouM-*;vcT41C2AK20Bl8G zs{4({GclQ0dSQI$i6Z0V{y3hNOf z3G=sAZIs=)ug@tUy6vf(J5NcrS1#^N)F)J1F`P}sfo&^<`Klv}(|Qp%b0WP{K&mEg z|3r;2maZu}-%k8Af`syR#3Z9(Lp$_nH)&aAS3}Q%J=^s=m4v$Fl#srxbkud8g6^N# z)ax^ktFX-zcU$V1DfGIbUHTb?uylk(`H(s#xKe+K5Kru`L6n zp-*ffY!~<5L)i;u=mCZ< zS$s->SJZ&S`+;rxFAfK&JOPg_R3V-!Jlao5<1lS79R3qEVFdoCEOUCf8r%g_9Zn3^ zeZWyr8X%)~aJ}7ve|$fsMhB04c45e8743>{U>Xk;o6DK#m$Pw~gTXaQV za4C$sP%K3KB2y(iBYFAVjoY~9%H!57Cm7u5p1y>4rX6-+y!ER`hdzenO%bS?`&!c437tgkA+??cFfAcDM811CbX0VO@4#~8#<+pp1 zfJWAa8NrG`CN+7Gfb)7wIX)9s&GQiQ%iodBJymDb*gpfTl?;{JTsPh;a|t}W?6J;4 zzHZuYqSAykv5UsleR^t!!~j&>X&!?xa6P1<3ZCcgP(?AuCdHqT|BYQ`C zgqliYB>8z?QvBP|-~(g82DD3X{h?T}w}g*kxKU!oaZ?#G_5dQEcA-M@bCNLh zQAbBb3lxpeC039<_ zSLVoXoK=P_ZfmvaHQD&sVyCN>ZawxAhn)m(wLxCQ>O z0x3{;R=DJhX~bT3s3s;!&7sc$W;468owFI>5TMJPKS{AgekrDwdPfna%N$9h9b|X90ML87tmE`A3jMnwC zUxRI#JXwPma z6KzfnWJX_wi>N+X+TH%n;DVylzqEwl9@FsAg39@k*B+0#M0YtvIA}p2aKC3)i(TAz zid3wXUEYod%XnaFJ@)fqd(4|=0qK^Jsp|4{Y5kI3*Ew-9V)w=1mI`TT(46S}k#x0g zkh?*YbCXM{m$mAL`En9=l2*qNzF9fp-(9GPQ$`+cB}wXLftq$>b{|29l2ykVVBdW# z^3-|CG;>7#GNli<_sYX`Bnashs|MB79KKXpD|%aZqWfe!U>m;ud?h7Gbn(u;S0vU_ zojGv;rmuhJfOmQ3`Y;t(I~ye9DRZQea)($Gqmah0pD9{PQv{1`AemzMm7IR@uNGte zcRJIn7g&6vl4180Hp)S=e5fpY$fjiglzx_Wff=X)E!tMw_ZQW5jWCRl0fa_##jqsd zsB$aJIx^76$Ot32YtBr8 zs3O1e2Fgkip7xOXVxTT8xLNr=34(txi7u!VQPCa!a4bA%o#Ih=1{b_C&{qP$4!Nz0 z){B{tM~#nmq7~3WD*k3@Dnj^{BFh$d`TIB zZ#!~nf}Q~PG81$@JvR*sDK(}!C1IreF^0*65n{Y503|})g24$SpI8jaH0La#GGVwr z09qOE77|ZjlV?EOAx7@CmwXDdy4LX5TOuBZK5(;s>A)2s`Ivd1>{T&?+xqx|Yf&#B zBSa{RR(#3rbb-rI0&n$Wrw~ea6FK=7w~{Y;-wB3pU4hv}7-7M(QU#{5PLzP(GilF- zJngdjMwvcP8+myY|Fx;X?l9=v;qi$nWlYI4e} zSgc<(C|xahZIC1b_e!0>hzaGv>^$g?Zfnbf1;a(ongi+C#agpki7jDTZa zq^A>;eZ8djthYnMWQP_2z;{sJwHrr_fPNQ1%jJDX4D@_=IC3AC~nDTv@Yu zQq03BzT9ITZLBd-({IL1pG?9!38R?S8|Gg)bmtYOzN9c&U{V&HabZUe#=}@O`=TA& zeUE?HK_Sc^?8_coA+E8Vo&RSA4(D(F1p79lnYMKXT6ba#q-h5O zd3jV;i0RRgrJKH8`IYz$R)c6qt`yF+&9C)@@uz;li!TQ zeYmJF>jL&6JE@0~nSpN3Q5cpbBql(DZBC^tfq8>3?G} z*#7ZYQ%-y)Xe=2Eqe5Qy+wMim{S4Uebpgz3&VBQ+`qQKOL=P_cM>WJMCEJj~ef^0K zd>z7MwLJquahjX(@`NTTHkz|;qPVZ{sY))!ew)4d#oDT&hDS5HswT@H9s|t@XusBB zYqp4?&?YwBd^9Cs#z}F-F09J%=yF)3!(KD@Qp%6b7yA~)Kb8WCURBgHuCi>Wfu8Nv z<6(HBUgzJw@BrT;0O!)jN&@b|w1BTXKd?S@Z z=uSHNsLzh(Aub{OLi4~3$LzV1%wdh$d4N;Cr)yz(%KFNRD?V-s-g5araYP!$Rk@rl zl+Ow)@ye2m=Zblbgx|mzoGmWXld@Xnkn$mHKR_);{N9ZoE#h^25o!y|O>S)Go6+Ll zTwN`N|FkCD(z(Qv?3C>N(7IXvD)jUQ<0Q!XWo_T~(O0~u(s!Q$$qzsA^6jCs^J!gV zc9$cveWt11(Q8x}rx*(jJGy#J7zY%K^@v4`)raYO^_g5MW&OjyN;L}Z<@(@GVQqZ- zzyspE2>L77n#Y6PwN758OmwKN zw1KP^u-_S=d(?8^-))eT`7hVs7|?SA_4^1Vj@dp)c1!P+F6ov1#!v*Ot8R@26kIxI#^~rfKDUa}w)43KS-bUpaJ?VMX|~*rK%drJ)=#~aaW}b?^ooAR!=jF3Q+|z=Y3%6Hb~)c>56N6a>>r! zD9BmzCas5(T3c4kvvW-qtHv>YM_wT+wifw(lkYG`OPiapH{bl8jtOwEo7GHmm3VBr zip{7ppVfyFrxB%JnVzROgw`ft2nu2w*I0ZVN;s!#TFBT<1wE=cjDwEi>jlF~)4uCX z*t;BEoQlcuPCq{4b31B9%xrzyGhZgT*3uOY$sALpUmBb_`$g{vPF`r8JPF@ax90|Tc6yjP9H4Jy2 zit#8o`sfBrQwCreVYY;Rwi7rmNV*j+%!|OVr)DD$;}MTKes;y0!Jx<55Zb|vQ;}Ib zF+!Gl^!gA`4N=U2!x0pWLAxIe7PnAECWZqKHn-gvo|Db+_G9q@wJLI409$?!QR%)c$W)j2huP!2T;@JxQ}UP>Gw;l=vyF7E6=Gi^03 z(pI6@jP+2DaMMg0x|Ej$93)elO+XYnMk#6%x#YP2H>HpRf1vzE(wlErL`w&_SCuF3FSQLM`q^Ex05Tw@z!bq`aqTRx&bWK& z=;S%~@m9_HRZ9ebI_~ed*@X#qpK5ygxHA^iCxbwbvd|uxWqvm=Ea1RPjZ;evgo?a` zgB&~maH_M~!10@#d7IhlQe2%_V=mR|Ts;g;Rwv5SQ<>yV)p=~EvD2zPt#T}^3R`%> zFy+Ns2ZDe{wCT5pNZt}l8vaa7UNQ8Usi5L^!H}vhLUso9*%vB$v|(I( z51q0(^<=Y}D}bZ5jb&bBK|_&F?+OS_6UERC%%B2;=!AE+gbio2u^qUo>#J1z%);^W zE%)l1635`;v4S@=;p2MH7zGg*m;^8K5T4qk&?S2$mpcm0AbzIdv_ud5 ze)A7?Fy?}#1rt$Ef|Y%C*A+L&h}Qyyl~w)XBNP8A>Jk_$_hw(<(D7uEB_DMv!z;DL zLF7z=@aKWL<-TdGgbC&G4QG3=AJ4EX;3q<=r&txP)&ylN#rjXcQT6u>qZ6m*9mR-U zaLa+?ta6Dt7|+0KIw&_4{vtvg0fz-;ww}0WeEA2c_j|-)d)~4yDR>FZaN#;lz;SP6 zY`GL3;&)-)Zwb~Q79B3KYQJ-|u%k;m-V=b~a%jz!p%PO5f|0ip2A`+w=$@6@VOHOs zL;M6+Z)Ml&UEv*C4s4=Fo;bVFd~mUNb%@le-22#=yOIJOQv%DF^3`9C7tVPtrD&K1 zojZE|-s>Ti6m$*Z=pyvPa&zIF9l!O~*#wz=$p^ban(pc>tC+U)4V#P&vTYH4=?giE zNBW(C^q`7L+)Ehium*Rg9Lp`#+2!Nwy({R^u=Cu(FUA^T3oV-`{d8JU&W%y^`;dBu zE3pCJ-Ho(skO$4Zt10Irg9DW^{1~(ym_?&UX97w2n1}anQZc6Hi@6n871xqobi=3U zBzJ`;oU2QFp(=gnql zHU_^dnGgB?hlsnhF!6kLFue1mOphR})K zGeTj?dKYpJ+5OL*^~!p_0ql8yKL*U+PzVgIT9uGe9m=jt1V@k=C@RHaOn4F0S zWR^A+^uFf&+C`$#ug5M3*ou4xjEE>8wd&ir+%UspM)*IgMR%0H_HDPtgz}h1zi9i* z!_$nylr)!t`*mLI{i^)2{eYF6^R1@Z2cm8yk;hOZ#)uf4W0hG6vS$@N@8drwa5h55 z9hG+tj%)PrXoU%n6V)Sn27mw506tv{?7Y8rz88t;_9xz6*2*t#%z@v-J7$VYmU~KA zo15#2)8S<~tQ%+yw}0I(?EkY}PmP@*4cYdrx|2R#8oPbe!!;Nd#y2?zms{ez#!Tn* zWmC@VdQ*ECc0k^lcyPxjs~JsX)q}J-y;wdi7QLNm9FbkAPB-u(k3sxUh>JS!ZxilB zXnR*6xtG>qcDsgjid>)Dd@`^cx&sJoKmU?x#cz#XMHiG1and9m1!y|mfXRgSNh?3~ zF6bRsLG{3p*slb$J*bALln2bt$sjI3|0Kk_`+j2^RSFWhe-6Wqdr?N&c$A)_kuLHR z*8h>gQ#RO=vk`oiU<~UgJ1VAJ6H7(H1&Bc-$4)|aZU6Mu7SWEGij6%xba(J7Bg1y7 z3Vg}VYn=det?lE@W`&sXP<%}MW8P7y*Q~{iEW=x(?%x)sVe?8i%ZL?^0?Qp@P zraz?U9`uza*ZE|h)&wl66MW2&IwPgaJ3&)I;;9*%vy~f@=G{5VH%@|6<#QT zwTs)LNJYyX>ww81@}y4*CAtM44CFkl@p-E*o+qS5i!+&J)(!k;O* zsp>8$TEBwa*JRnoE(brEtt9@4@Ul2?)uv+uG1mI%axO!`;OqS;bI+E7PDnUFVDC_} z%X!!{}itD7N+cwH87T?eNRHmK3qoqv-~8P?r=))0!M z#4pf|nhK<05X3Y~qtIs)G&auR5}rsB2HMy7#?XuiMpFFnz4~dm#yGf(ND7k0on0K%sxGS%~Z54g2A2+zM9kMBnG-tfVYdSbL`P~9T_K_#BDr%Ds1Z~sANJ?Cj z8HSgm)gf>BdDKJV%IC+Xn{OtC1PXdO9eLzs`sn$|$xL=m8CEKDb-SBjAyEeSyMFSz zpMB#^dVEO1YtvdF12)xq(2VZ&{*+^MJ$$_RjmHvNO*IPG!JnF6rRSGLlzKS$x-Z3U z0Aq&R*D*4Ae7_sxs?0;<(>+lbn)7ee9n!d&4c+|^iFaALkt@)qWsqywMMO$^03hV; z<;#{KygeHu(BHfxCHIz9v=n7=av1(9fZjKK0>_-(Zrx(PD?E6&@4v7jZd?JLxZX?G zJ_$-j0VqoeOxUEm_)-o@85=EY4UMLfE@-zi(zAuNI|;KUzTOt(M7z9l8@uc_P2wt3 z+{C9KERP)N0q!Rx-nG&D7estrSDMWbrVRaGpE77v9TYZd zRt7&(oDBCZlQys2GBU6MChE&741V19$(hSpmz>_hjV6F5JY*xjp@L&QQ|MfqF?*59 zR2sgpOWvN~0-o;7V9Hhfz`5>6GBM8spb!=XD?Gj9msbn#sI`y=h5y(mepm+!HvT3F ziCGEgW>$%ZJT?2JYGJU_h;>==-qogLhNxJ;!> zitL4H8U-Oum2v60S$KEM!<0|?@x3@8=N3Cc{kFT0q1wvah28B{k1&tq2Qg0TPa*Lk zwtA|%k?+UAq|I_QTTVfssleC*XjB2U7&X;At3liu;0SALt8Oo>7NN|Qcw2^;~UwmI42SvUX2ubl6*^2Xbvh=7Bv~)kcDroX# zfdp0ZN;BfHtJvxy@NDii+j4u%t5Qf=7OMI(+Yu#lhb}({%iYiHh2a_$r_ohss)e7a*&Ocwx#3sF})7PMIXZt27GU89z~@x z%Nd@TJts(o+1LuTj!ca?cwe=ElWaSik}YgcJn=aRV2D`G_@Xk;#rEq9>1SH1x(u}7 zYezmvN)`hbUwl&T)q7~1hZJPyCehhRubHj~Yem-_hgF2aW_<;~`-x`f-yAXV%Vpj& zU9Q=-vr3B_uOHyM@kKo!r-^$$cw22X$g*R(hzRl1^4x@|VWj`)e3wfBSn4?HW}5DK{|2d1MI8C$EMNZ5}+%9tKI`$+R-YGLi~6gUvQ3sZ5b3_vh4scGUB zt;1LYt6AVK9U2*?fDiv35}P=iVX!q=8s-L^Ed8KF811FYbfgWJ2b{Hox|f-QOswbh zlJqW|UJ;vc`otvc=Wyvxg&g-DmN+kIGn>enx@@6V8{!bQ?0fICuw^XFi4(n&ry?^h zh$X##{}5*mdAl!gSe03xzdLh~&u7XI*Qb^bhki;n&y2qg=$F&)GF9(3rluLxQ`gwx z#s6ixW6~V%+W~!(!lWT1s0FB^;82eB8^DxMaXBYCv~Fb#SbiaeEk(@>&LnEU*ut*s z%Bc8Gpi9~rt;nt-Ymg*wL%<9DOO>C8z+P9y8Rf^>$?@Wqj3x5Q7jc#<1Of8wrWp#}?V3DKzYP?Z3?bQcR4J&r%ALf+K9&^Qv+vRFK&Gb`i`$ zP#x$#{@!QJ1mC5!#eTxGKxIZW9I>KM&`4Ph2HiXCq6ufUZi&i2AaHoGj@ON=z__%{ z1mp%L?QaUwAy9nouik>>&iXkUNh9%cStX5&K0zlAl}#JI({fE2Oq24mvxk4ips;IH zhS!fB$Lj1wJzht`m~a@;d3eT?&7`%Bp z1Ielk{tRy8o&U?qmJY#=LZ43m)@}g?Sg$STC+EgoX!5@;qyNf@sd7V9o2L_2!jKmo z_-Xm#Gd|cWT$)J(#mNuqU36*HdSWGFdre>MaYxE@%x*g?r8xrZ2zPt!S0gHGAnfUi z5oUF?Ey<=1T@~efFb5`q1Rh8VYp_jb=!QDOV4l_vB81M2)2Wr59T2^BArAq&N>`4; z42oJ5SmN6y4rZi{7zQF2&T+E=*b5V|Sl1?BSWMW{z?30;B+l6eOgPuhUH7ZL@JcG; zte+O?DX;T(!sy^g%kYXJ{Gs1;sq3Vh(6x_K_~$W39tX*4f2J0WxTKtS@!rnL9!B%I zS-xALGdV_#9}U_XA%cuw$eA~nWB#Cf^Dp@QlNg_Ijv91$$;eDpyXAm!=r}TKMo2Nk zM>7+^vg*5Wnt`gp;#-Pg-+nrBj`k2jVnL%6>vncp-%hI@21Io#B zkW?1Ubm#omb!=_I#R*dwr05Raj(fjf_9fv{6aDEC68`vbSVtmpt@TbbL`jgMhsidg z<>%>zAiWN9Cl1^|#nmQAXw6*2if$n&`}9i`E8&S(&Rx8z!@C{I$!^d5;JaU9Yw1hj zIg32`tqGznJYf!|+pr)B>Wft#y-*N&JYki-zgtpuo-( zIGq}nQxzhDUiSz$;bM_ckw* z36WFIEcgl$f@1slf)-X>VdS<9#$RqkNo?}+^J+D*3T>K?dYDaGrKWa+)N5~Xn|ZF& zNZJ}1vK*GDfiSx8eGdpkNcUq?-&>`zBdYL8)>q(%Ev@Z?Q@w>NHY^P`m zOf&gCwF{Mojx$6lg5`iuwPuxJr~ zRW6yx7xgi4MBV9&{0iO=D6KAc;!a!tqO~8a)?F!2tI!CLC}=ui(7v+5X7SHM?WR7Z5MFguRDxnrIndNzOfW|Nr zKEP?G#D^DXW_3eyaSgx(yJXs|4k)OP+N?ANt0$Oy9Q-}b%QHbnKb?L+s`y}UA9nPy zru#*fEA-^%wOc#h3;@4?YmPpPi(W1u1hQOKK%M# z`@ekrqCo>4l18mO_~ZXl{ro0Xe26^mo%ijjF`55WdKw!Uq8+x|6EVnmB1@&%*s`3L zfCx$E)wnXemQ%oa8Sw0B%;IBI?X;lKo>b)X_9p0FmA(4%O6%+x?jqQXuk|DhtZOGB zIfgeaeqmxVd~cMWxMDvPh8!gB)OnZ1+bYg1#MGD=MdodjVUB$}kD#^Jt&DT+FcGWl zc{)aV+YNQzgLTj#MxNIq`g=1WZF=>(y?@xx z(0!k^4w6A@SaacmlMb)8+P^wFx{#_MXJyI~WB;`<wu z?d$c=Xv@>-7Kbb^F(zvdF~wI=!J@-kcReuAjV z>-KY5yuHoonH2kKSgZl0)%A;55s4|0gQ#;2Y0vLBG{Avk58w8( zr0kYS^Jk22TMoVRPl%8dkhblrU$x0;D2gpD<1wbv>ZOf`sXeclmzj~Jf@&2s7J*O* zYQxKg0}_8Ota^CYQ?th)b4(L^jAz_@3kw$S*8I(WGft(grl~a2t^egqBcfinRsOC$ z$<%1bBD$GyM^7EC`h;bbMUUV!8UmYnAxDXGm1u07eDH(a`={LAvQ|1E(R-qX<`b6cs zJuJV{ynn0{opNbT*Y~jH&lb%K5rG@$UvvS0nrI+-oCAwLx*8yp1j%F--JfUr&wvK0 zAii!nB@sAOyF{ofY~=q0iXbAsN@j z`1)s@HfZd6kvtAR*a6#suj{WoWUdHikseGv!SEvT3l!m5xV6Zr$Xmn-tIp@2+z~_h zFNP}zW5|5yh=WvNWZR6gWW0F;?qI+bis_Tk3=&$h2QyxIme8EBw0?NU-F@#Z9AG!W z(crlVh|dHnH#TLrTy4)?-I9h7s^)KOCDll^rvi41sm_LdAh4XOleqz4?zEF-np&51 zf^mj1HTWPi#730V#!zG6#y4==&QHw8Lp`+NPkF`Cjt89f-NsQ?mdafx)xsOM1 zOpw*d35P;(g|PH&-!e^NY(LHl(I@W#240J~!PLyye^&Cw5&>xQuza@&fr1rBxkV>d z%XJlwdR^%Pg%Gp$$^>}iASJ9&KDOwEq|2||#)n1<5Jl)I$2Os$eJB@Fj5VScTT4?p~cf~^s6FdBk z0>%jI^A7VdTXtYY;I^b76-Y&4ao&dC+b^t)@efbQF{#|2C{dMJ7QslPi*{;!J6lNu5ruyp(2R3E!4NDP(357u|}*RJrIdxA*C7FERY01y6jtp zs)|UIx13e9X%nBb7>>pZiU%J6s@!T567ZJDUy*|>E;#^SBOJu|VYM&x=zgIPC#4iD zx7Hn)Za9&Y4ie!{4zR6d58NTwwzNH&!_&lR7?);DO4uA}c#bMXkSIf!a4#LF7ykIy z=7Xgx_mhqpdn?n12XW$g=o%`QA` z>}QZZyBRWYDsL~d_!7Q##*_u5Kw?b${P+dN?41tC0G2@H%%NkT@9C0ApA8PGYJ_uF zq2tOoYo#j}Va@jTZlT^6o61rv|9+4L2(TY#2~8~-#=jVPw;z>% z5%^A)H&RF)3?l&?MY0A5%r3pBt6SL(_9I7+V}q;#RhiiwLLQEBToU0r!BVl*^K0Yy zrEgGKX%WU{_degV1TGyDqCH%e>9m|LLRbwSbqx?;NHWzIyT&71=+yoxL6U?C#`>*| zvUwlYJB?tkytA!SbJlHbSA>TJ0q~RzuT}U&CV3t>2(3IF#(oa8<&L{5!Htu;u2>hd z$7@Z|bae<1Ge|GkaCBjz{q8JQl6}3cc2K2a@m; zak#=C_BziIZ(QguqA(N^_2*u)x7_1&(248-Nw^^pES554!>fkzbNmfTh#gY_I9@OS zei%8oB%3owP^J0I0)%Q240QXuf>dDQ)qI8&)$wC%Dj$|}?!0%fbCzEGY?P~-9i)pT zy6bWO1Al&SaKVq>&-}onK+{|T-JU9!;J_r&kUU3}No3>0?z2iS^8JhQ2NFN?6M*vq ztIjLmiYi_{%?-XCi@(+d!}i9fte?%u+2On1>{{e&e}t@OW)b-v38258!T~<*z5OC# zQ@CXo^*<(zUVlRmSI=*6%oEWU|8pj|)cjVs8(T=2Jv!UgvuQn(R~-gNAm4R}_H>Mn zMt^&RTg=&|f*+Lrp3`0n5x?6~b6;X}K?=vV%FaQ9#^FlrPHeH!Ws!txpBPZPOi84~ zy~pY>Wn2XvOBc(e+mQNa`jXRiK48*MU8wv@hHyAh_8)H+0T)i2=DOPJeDlLzP14as z!Io`WRZ)3J&#vj>3o|3(aF2PEN0LJ~eN>(+J1LJ-@>Zk}S*hEuB&8FQZrcTXa#-i& zeN!j;THCJckLsZ>f9KiLp=`bwd$DJEL(wqk2yaLhe9ra!ODDLbMzgn3!gwF8XkzRL zeF)Hx8~Pnqtcm1gYm4bv)?FUssxlGNONWybm zjcuDdwrv}`v2EK)qj&ed@AZG5`H&A;JIPvEb6qoY&T$?;LFBr5HnrPKWo8AO79%s6 zrJf%Bj=X~SKB2?~2(H*mk*#e3camyv_B~cy=A{v^=3R)D7Rm*E>rEAGXN}(aWZ9Yc z(a~-!s9i}VY<&ESSma9|2v$pd$t=m(ztzQ%ybwb6x#V#)FW-_GzM5=6i!}rb3980 zg{~sYJqI9oeIxqr5#wV%z6Ae8<~enFh0r+6aur6R@`vsR9*#}v?-)4vrx^eE*}}3& zYsd;bDEkgB7zvt^_Masr9hcg36)cA>NO5)2+S^9;&^%fD?6wNNh}C?*Ru}z|t31dl zBoH#hf(ft{Eq2q;qlrTpxsfI?dnIULslq&cz#C6yLxXt20nt>s4%{)0ZN+|EUR+sm z_eknioGx$~Xl5(=B@vT_4AOoyP(gnsUw%7702RGT1zN%dJERskGvyei@{btQs6PCQ z&pRLlFFxI*%I@l!eyR*t(-VoCDVBik)HBqSv&60e!Z_;cx1?BUr|TOa>8&U+Jlm1f zF#N`5edo3~%CV&qlz&xbexw$*%CDeo%1y~J!>hbPz%E*1cQ%hvbAx!*LIl~*vLEQ>e&u}OV}f5FTzsD5e? zY022R{xSOG(2HGYNcZBLUOm5^_>jU$;DUmW3t}4ohP%qq6Ya$bc7{) zdYhrRl$|x(^xgUW?}(D!7et<_%KtMi8|4rhPo{ADC*`OLs=Cua<_3-}a!hIG+_*er zEjh(0_0OQo!GW0^55DneWC)pho{R|RNAkH1>R!0x2yj`pAn9K7p*PQ1<<>|6)5z<3qqS1~YczI#SS<^*iS!zw&p2a%`jrz%kB=tH5bLL1_^7BB zTmA;Z;F~nZki@==n&Qea)L=SYn=Sm_D^hWwR?!>?(TN_DZ{>DQbR*Fnpit7~pk(-RQ0a zhUW*CZJ-($+OYSbfdV>O@zA?5!#8J!Rvckr{HhNZZnETihEusekgzBCA+Pvf501l% zFR$Ad&kXfPwsD1zyQHJOJ)gq9;-S-g1C^~+G--roiz573!GA%3QQx|pYqp>wzUjop zIoyu(BH7WWzmy)Dlc%)8aNHUV~vX*YQIBBkR>(Og}Z47oR?Q|%kx2&d1%6s6O;lQ zXDodM8JmqX6~E(X)fvjngvyAh`&=F>8d?a#lkDKZh?68%AktAZCM-!BK@i-*tI0x8 z%?ZSOtF^j~<)M5RVCXqvf0Vq1s`nZgTBYT6;%&L(!Qn6c!~{n z`140w_@?~cD54)VT_r+X`{kb^o|opV<8ed+Ik-+aDy5X1U=yV5buVzG1x=`KD$fz9 z7%FHSL@${bvV|n$jx-Ss&TwZ6(rvC7e@%pq_$0p>iUeDvz2xt2hF8M#jO`VC{_;hn zUfabr+x~%O+YYkKT)lFS8}z9=2Y1(|YjJYvY{og1cP{?=E|8`JvkrV>Cn`na$=UGTauK!RZ(cg)2vCPVh{`dDQ%hGS)2~M4D}ZTL|B)l4-(bCmC#X_5AF=?Z8nss7dv|Rh ztPdmX9iPRJZ=_>9)38k5!z=xi@}v_b0e2RV7B{2wRvGRhYW=cMHJ)HM1rKP;PATtb zuR(_Hc<_+uD=z+HH6@c+UA@gK%?LYC+U>);TW?c$0Q`D!7Dzr4M!v_NeSaOHBNRO| z%QIZA#dzm)BrF_B84m8Xzn}WEmS#_Pw1Aa0{BLzusqH!(z*ES6vJHXOMSp+MUe2O@ z^9c9(BuJ@#cD{~-=?P4J{OZR_Y*L7N+i~2~U>X5PY&lYAc|+3P!PhtsD0{570<)(w z&DOExsfy$R#QqxaQz9&Aw@BZ%B38v`Gx_fv6sem(-%nH=&RX!?deztUyl8p`f#boR z8Tud}{u$;XD7p>tb-l-Ofv$^Cp4C3aFY)UO=#xbMT|F-^*bat~FH%S6t@tjn7_|!p z`JPfW1@0a~>zOLvD^3oe54~W4?LvMr&+i<1SqEoQ;?ZSY5U1nI+R_$rN*mnpr}$32 z($Jb4lt;hX-Cz}ES@@U`9@&wOLNR*y37Xzagcg|Rd#gY|b4#XQGunKRgDc@t%YVpgdH$g{ zcBhD45R`XTk2q#bvR}VFkd})ww7xM?^PJUOO#jAyxI^4hH6+Y!-B<5^H2wzXal4Vr zv(9QOH;Ef7^@tITw?qj}gFd1SBvmQbG=!wkeg`8gc`L z&4uSOU;WJ6`G9Y-mXGj-@DcX#;*Vt?Qv&M=*&L8fuFg>#86rnkhtD1F2!h$fbnJuRd~jV zDXa*#Y+0pP&^>`~k8tybS5{|rZX8GXp7C}S{oQ4`)ACZ?Jw6o!tryC5m*|q!Uzot2Y+p7=Bo#O{(YfY{3NZlMTrS{`-c2r!);`IZ^S6Y zTqvLZH=8XkCgW$`CW)4}O0Ev~`10KoeL%fQ`=-&dn>aRBO*P3Jqto&q!%k=NlzW5a z)1j5iNgKttU+H(Hz4vFoFT~`D44S=YC*6<9cd&-z@o_`QYa>kioWZeX;Z0;XB~H)Z zk1eJYA8;*soiMAZzsi3Qnx)B;!x*ZxPd1KZhcRKj(iU#m4j$%&%?ke}tN$%68`0E9 zmNkwv#cNCH^IS~5+i-BE{AejXq~ZqXK&W}U$=O+V<;TnVp7hFZs*^BEWt=8(MS%4C zdDK&Uc`aS?u~F1z`}V!0TjHbeO!<&~_#+cS+PEHN%o6fl)%4FAJ&C6qJ64SVZhU?0 z)S zKYAf*!Ui`5j{%O;O+SSM`~j*f%4#MZk!-P?EevbPl1+Uo7ZD+ZoPs?I`F^&8rN$92 zyuXXI(NVlcgAo9U-@(V&Kp~vv^N?K6T&}yI7%r2j8QK&jZCHkiq#gC@D^t z@9m=S9R8gUl+4G`xJiTs75HUlx)7hnpV69M?FXw!Jgl1W;2-Pc#(OC;fK7UJe z93EdRk|O9aHM#IHbNPZx4SLB+{N~Up?>S_T69x**>_z-^VDlg7&;%{iQjv^O!P?_* zF#wKO={T{BA$XKcm|*Y(z(e`6Rx6*Qp{QIlO4UA%u{wttNaBFgeOozOgV^FINsh%J z9rin5f`hrAN+IVIj0wI*YeCUPe2UHtyzMZw_2NYX_YpZUq*M&-(c@YmFY6r|rY4Ww z2#wI&M08r~*2*eX?q{s8-iLvZ7;sYP>ojyqJF!l0jmFxE(CatXq9k+JJK6!aJ$8(WPvVea;p z6`~KqFqr@mWJd+j5>!q$amx5!S{x$%zfqwDV$t8>{^cW6se-Vy&%w`+t4~W7k&fz~ z4-fA*P$UN|sP#Vf{BF4+=iT}Z)RQ(l^3sXowGCM{BJ@}nYq&QYz3O}RpWe>NwT`X# z%SESu?dyAonRdfAEgK>KlohR@Z!dXRAB-nIgD^WkPOHVA?|&cuCQg<7%lkGS2tj_m zANA@-&(3`c20nvY?Swa|ZPyrE)&s7*j`&xf5}> zG7{2p^UZ^Xfj6iAL%GI9!ep{qq6bwqxI80xqzM8?UZzT&cItpLDKy z8HpDTUFCmVDGK7V{$`DdFj(5$VW;8vxt$D9&@^og+e#$xfmsl0<*z z1bsN9D2!fqcNH3hF4>Rg-6zAJnIpsM%>l z5b0`$TA&j*wp$&l?GAO4_hMq6yAE>%8|X=28sO?L!PA-a3PMYcE{TmO|H5U zIC77&lQ1dh)<_TL>P&rTvlj62Mxml=EX|k`x?4`U?D!VG?A33vj1``D&dmu|Mz^Mq zPQs16192Tnk_tO4Do0ICSnA@gKUccV~Zz1~IsM2w?8y6mKA^ zK5WYCko~nX^K6H$%_}?iUyt_ys2fF8;M@>pZscWkC=#2VgOWnvAW8KefyQOwhla%p zzo#b1nPIT-3daS?9J~f8nDjp7Q{i%+Kz|aPI?EX?8#GUM^{zayH}8wNX}$I@K&?5! zDWyHA6~?qjm|6d52Nadxr&1ITPc`7c^}CtT5sEc>C-%0|O}imILe1^W7-#)f=0ES!L)w4(NPaQ5&QUAQ$} zOpLBpmdm;L*zDf5=B!H^I3fW6hKw@pQ2_%pNg;IY;^~ou4m+pocPHWGcj|%o$YX^Z zUFn<*KiOx>wIQN7o&z=BG7PvBnZ9^qA+~9h&tl(xtrnuXBLh0fxvEJ?F}4)rxjqfV zghBXuf;16)qJ?!^bz@H-NL26^A=y53)(g}0l=r<5y9;NiVH@%DW_1+oCIzop^;L**7@F%jV)(E?T z0Hhu*)r@D@^n|qe*oDbU>zb1Jnbivi1`OilVuZKB3jW-XU=ls2yn`99Z$7DgjZo1x z+wM1Lh;c?db|!f~G;#=dt7z}luQUYr-h0(1t30pui_p4KMxuW`LDJM`0@PafOK5xM zRxnK`L|t6tqt@hW*QY~Rh?b2GP{ z!ZQEw50;5~a2Ql*wS4mI%+3j?L+Qof-Ngs~kwJbyIks{z)qxPG>BC!SHE4ZA|6tWI zQuWc(8 zW4I%#|3D*RH4;%*7W(|1%b}C#eBO=3+(pH?ML7Xk4~&BSp^{}&82Ug<=<%Y}7Ye2$ z?w%Lqk2~Q{)z2=MGj$hUGzy;=puwW>roc*GWIRb6)2QoAm3u!tb>oLONQQQnTI^a! z5i_Z@3CDY~45)CEOz}(1M^7UCPLTO8h20IbB-cE3yVU!(~$ z18rXW2AA$AK(K56|2CAT)$=pAkf=&GWR!%;NFTxsYEu7!+&v`T&d zk9~I5AMcRk(M>$NM!oa%a9rNILupR{l%G4ePb0M64ue5{KTe50>dXjQ-j3OEI{s2a z)Q(rB)^WIxmG3#6wqfsLZ*>vuiF*d29^OoVibwyRDEm#*W+s*!Z5_chg zbxC5UkVmq5BT4`w6NdEY!+i7|iW~_x&RX0>RGYTzpJ>)AR40FtS7tP?G4aX-8R|Xh zAw3K>2i>N8Sk-!f>Sr?|G`L5)90GRtJu(j7`EYN)KEp;kzRtHtBlES3<76AWKhAx6 zonSWyku0D@kbYDS98$+=stvE?Y>cN zHSxwVz|lf=QLlOt6*CQ+RuTT^!C5|nU_p$3axuXcE9H@mp~=p=9Ee7ZRU zAM`V9R6x#fLb*gH5amU*O!7D6I*GsmIkj*wpJ6ztp2`1hM4jh#2)S_QF&D-q% z-vh!MPI6rjWEy}Zx&~vU%%p|cy@pE67mo*vw`a%5Bj1REMOReoI6&b8u8RNTDm`}b z#H2xLw!wx*0Fx5L{3C@cpW+rs^HiRg1Qu^QPhZ_?)N@vderumN18)E?Abt(ZVfbzK z;zpCLY5#gue*ueb@U*(rtv+|e`|Y1=`bjJGUx_t&p-T%2yG>Vt8RmA^yrM-ncK{i; z-kbNSgoykXT>e_2DtEp#=8H^O@ZKY(c~DDJILqXUvJ2j{}}_;NE<$p`onTLSF+y zvE$l}pd}ZU7hHNsTMhr7_v8z>Qy|TlcQwo!1?zn3aDI3_7?8%2$djP`l!^1_q^3Ol zndSo!&E*3AWO#oI8QkH#MU%T)c&jz=K|0ZC<=EE?=Xw6KSF7{ua_3kp1n2!Q`wq9W zZA^@Lj+8GOO>C-Z2eTJyr*nt|kRkT9cx(r+2GW=XNu?o^iWVTe@W9X#Br+l)5F$+% zqJ!{C6&uqN0b5wVmR5Z$D5VD;AaLfqs3*Sqv3((0m#*Ox1 z{@`jv%y}ImR<7opwkJO=j~X&YnBRr?b%vKcrv!KO&FjJfH(b(L7JeygQy>@+wN~wk`>14JL_#P%1eYOypp#2R=;UQXf-r@`qxW`Tws{yqg zGBQ?2_P=|_eaA6M?ZaWTVo1?J7I*tYZ>MAntjlJ7DV#Uv&s%05fQ@ik_hVCyg}b2a5qu`R zfY$8P>;Fmsh`U=VVli3#zne*pK$ffP5ypLhyu2@(anY5b;mBEB6u>WkB#szGN*Br@ z8DiX%E1#`%frm8Rxhp5hjBf|6jKgt-AmN50g;^^M6xO%gWrpE7T&(m}T8oyOqm+t@ zrBT&yGoTxTiN^s|L6ht!NBp!CUzmZVY=$19z7_k-Z~q$Vs4hZF`8roJ??N+(%0*t!kQGmqy_s! zt3-S>(ZStOkJG>1YN-!sIwM!I-F-809V@)qE4tOoOVj~n$Va_iU3_wLeA12#Wy~ww zM>RB^anq;p_8uhUjA`XI w?KVjtNh9M80%n%tvxo7@MbC+0>>csH1_{=1Vf2KoZ z*wYaLeN$g<)YJa%_-nmxOC?`Im}RXp1)ezFTwZO<0CK`%aK8&eXF=eci(JpxFQr4p z>k)gxB?p~@Q-n>;bw*~_re^%&8dI~H$JG0GI3ohPe%+;Bfyv05`g)}Gpd*fhXJu?! zY?55fJ_8nRpGvAb4HOXdW+*!fZ+qm#9DD~f=r?EqukKar+%0m}0()Vob;c!lIlrmt zhWT(=8oz_?7urL!q5X+4RYI5--Mdn;R-$Sr79_?p(KZwGdjxDU&6+;;3@;WNyr{?# zbI;K$HYWP)J)?8-_R#~pE??KYbOD1-13G0G9fEa($I`J=alfJ-spi0Pp|;XoE(gd+ zpNde-Z`R@YfD;FL@BJGYi8!qTj>M0gd}+_YK}Dt)c@hlhW>e#?4({xMk;h>ss|PPf zIa}?qV6_?w2)LbdOer06nB%i{Fz`*0Yhyy$v7YODwVqG5>-Gc4JQ#HXOhN6T`CXn* zyZ3X7!pC=C8ZR&u5%~G}&Ab^$!bI*xQ9R=Kj92y=^qk|_M#JAl{x_SWcT*kP?_Doe z7a%BM5s3LTua(Yzksc9B#HCbxz%LAQF&w+m=7Vah<#3l!L3P|mAKO%z*k3UfO<6!Y zJ-}70G&4oX? zgxpm2OpHG(Xzd$V@_I|juFYlQFue=LGVI1P;dh|aabZhp-YIb}RZ!j3E0&-l7WZ9{ zSF+1L6kv^2FS$obmrh5@lxUM7m^@kEOl5a~b#fZHPK#Q-FGpkVso>1*NFM{l;5FLn z(8RDnkGDOYJ7o-iBh+$0m;g%|R82a53LsVH2cz)PM?X?|f=x8A4#;XKg85XX$zW(r78yQP z86ykW<^d%Pa8P1HI9`)=KKD9030HP5u~1&{|QVPsGAT1 z{!^ZL#q1-Kozhb1ldyYCq39IA={2@1loC8uZUvcuIn9seRTUS0T{BGCV#^M|pTI$@ zI--rT*}}Zl+8r1Z-QnnQzxvhpQ0AaNc6p8PZ{|^(Gt3-19Zu!=h6-;Q{GCmm-*DRr z#y)i=E?*u9k4siiN*PDx3b8nXMcc?+7pi^*ovsT~lu<9cKi{u%?wUi52Uz!0JBnme zn^jK#dDJXy=;D|`Ld8}HLSQvHwZ-b&ty1(BB_R2V^PRge7J3*Lm z2kC6TvmnCzoT^$Oo2#r=k zQ8T7{@9%V%1v3`PecCbRmNhqFAZxKkYV_Pp4aT;!E2JJ`96Hz!+GOR+soV-VYztLj z2d;^@+dPt393J=|vZR9-yo~_Nmg?GxvTqzTvo>6TD*GgVhMsgtCgLwfUN=KQA~&N& zQtVe;-9VeQi5;3F&!E7M-64DZJMCw=v&S_OJiQ3{IoWz;JM;7w+KyjSV=VFOOO79U zvYxdc_d`6ktzjdZ98gju$Mb3m>b&9k=k$gK8fMxpZ7K;oGAOQ% z@&cp<$}G10rKVfaGK-fe_43o@LILE8xUGnfP7h7G9VFX)bMZ4DiH6ULx*}yMtLXDw z%Zl?0-ZKeS{>w~;ERY^_lqOD;d+nyZ%4B(a<$^r8kNd5^Yz5SlJ=?ViGE0ePxFD)k zHAM7M+#@Vm&|4Vcd@Y^y%Lg8l=C%dS&^Wq5iEJIN1DGrk7yR1|uqD=ZPHs5afRc_H zPr)~T|6Wx1IkaAGQ8gFv%pKjj5p#AN;>qY{`JY#6?OX*gGI%7kaT+AY&+{0=)Fl`R z=-S25d=11ETdaz}2mBSo;Fc`57H1nOGza_eWJgKhQ-QW1mRcTko+^PV5p`b_p%byo z|L~Fv4QKi8zY8^s!hn`_$4IJzDM_R$(lFy)?yQjW_33;e{gr-M1%aH-MLE1)P~LsA%1a2E4+k7|88m@w&bMEwEq6F*^UMm4uyPyQ(Z|- ztc{~)bPk$?wy#$MtUc{h3u~dzxf@Apjy1Z8t+rY7KY&W35|ELgis_TN@Z49>$71~@ zgC?Oeol7R=^0qqN8~BudpD%;|uRPQ6%$;_GibTA-H9ZgvsEQ*!+gXo=vRwEKcl2h& zGSLrKdFS%?ENIoCRLx379Kvl&19CX`^C%uGr7MNMBcZb<%|Upd&ZyUj2J~oG8Rp{U zp+S%g`GhlY*X%>TnL_6uKry&4bH)w#$3x^d0_(2w*3_i2P^Z=Apq$Lw=e1?$p_#`2 z!mo;9>&fUjB13y5?PT^Te{0!TIf6(PfQ$zAfIk5ZevD*c7xv7N9-}7+UA^?Co1L-k z$V2jqu{n{hX>7}KTXO8sxN&$B>R~|7>i<>|R#AXb)XEVL?Oh8H>8}LUXvTjjqmc}= z{=E8=76nh3;G+0Qzft8am8B_KrbCx3lBcO$VyZ|L(|O)w#$uxhZ$pw{?PR7=qU%*U zS}&Wi{AG)W9zJ#MyML*nrt0?Fe%kbmrq#TOetvOF;U@L#4|)VbM&Mn-waJ%y2%M8& zQ4;icyBKpEF3tGco#Ss3CPH|adyO_hl6%El)Un7Zm;67l!?or8={6F;*%vSDnu=vg zb~-`nmDL~owJ|mjx7RH;3-9|#&k!1V0Vk1{p?;b$lXJPu<&R!A$7x*ntjN9*-w0hQ zEScp}qNNBJ`4xxIA>55280gb5YI#|cF`og*vj>F1sp}LF`X;|eo5$bAuQ1(xev{=p zO|_kjQlREVwxHhg2J;@eRO;jkBIQJ+o46D31Lpo;;p7tdwX&%~P)l%LHTyQn`$Ha< z+zxgYG+B|mCaC&n-YtCJ8O6O#4gPDHw(an--si?w_P%K`n@sJh zYm%+NHS3JC=7u2e=0W#%Efgv~Q?qu{|7|a-$l`v!W(0wSzBk#W>!2uDZ41N+^h9(G zO&OX_l}uyy2vgDbm+sf8UvF^ToJ6e0etHLVN~*g^B;8s8g|k?+kY z$YTw%pc_fbKnJvW%lc>Ax)ptKS3r8O#1%*EaM*3?*zSN27VE4fiXXwb9{2$Kgm>G1 z<7A1bmeA@xgNMUVN;4;0;V|80K>6jtLz=PX)5)59m|P=ymtnQD;q!X`{`MW`DHj%U zss|(Ea?gFP3tdn(d(xhePxbXLA0|_Xx8zwJoUOrTbQL0>{p2Kpy5f8j%0W`^TE^QS zV6eY6R}F9*QRO@Oy7-oX9iM-x-{!9(Bw=An<_b%APr0lFw&ASrJVnJ(B_}y2W4eR9 z)eK`;_M;@kk1Y)FQEI>GRl7_HWntU5hv#t6drv)Ks%I9`YSiK*a8rwpL8AVV} zl#cU!qf@2Il^RYsc#>0#bsqd0J>+bAZ0^j<999~+ND&3R#%})|&<2`1e+d+;;nrBaWTAmp60jgy#rUt~1#RQ+a9oRzhb$h|P0;&p5YN%5>d& zG8|7YPns1$?`Avtf%NE_%cmS~oR>F(kTtQ+HHjGTfS&JEjX{N8%zdTL{isLzzx&lw zp`t_uK6tY%7cBkTgw*YsSf55dssB!&%FB&iY`5lEQi8MA9Our@jfnKMjiL%FMJ_`%5fP91$IlG0jfePa1Rc`eofo5mMIO{@#puTFnk zD=dVELi}??aXl*}x{wPEZ;T{1Uwzylj>9uLw?i=Lzj{aNzFnTAJ5=Vo{0RYa8A>_V z{axmb>t|-tjWQw&kkW6#2R>maF=DW?aZwqo4lVCv439Ld5+{5aPKqkxLo}sDgneb< znMM&_fd6gJ+X+pb{|&aHk}NCAg7SUYL^RhBbFB2_sl*3(@OLzSlepI zlf@KrOO{|PPl8NE(DmY~(P!>mQaOm0fJp#}7f8#XcEux0?z#m~49TJnqV@ z6?MF}3Eop<*Pd$rjEi=TJ>vh)vCxP2$LYBJK)3GcSJmZ-1AF#_Q8|gd>Y=f-7s86J zXsm(QgIoW-?gX53w(xX`w}n3&UQ0BS!KWC=4?8g75MNHvkw%x?ru8@ELL#6o*q09ox z{uj72z5j#K?|($bq8y@tAl z=z|;96q>Ndzl0rNKYDn|FKK{Og$RbnRj#R<)&aKT&L=7aeO2wvur^lDrRA;~OV+6P zOXQqb%@k`NL%Bq{Y#i>ux#j`8eyj|Mee?&eUa}QwQZwhl;a(Ol)jHPmixc z7q@s5Sm;3}?2jtmps{g9);JHUV!9r&CikVM`(knCco{3DuX=V0U^6(YV%I5gFXz(V z>H=A4kL%JDD5n?VzbR7Dek~*D6;0s>PDw-PZ_&943Yx1q;Y?w&dW<97+u}+}{xlFU z{fotRpYSs=F0pKx6=HE(@>oI+!V9d$ZLZMn(F3qUcIYs?l&&8Je!O4L+=VnzQ4>N9 z==DAx`0Bps1f|f<*os^Jqj>V(j*mvwp)zYL8W{*$`7Q+%T5Skyn|_Vgn^w9RZY91G z;OE3`(ZhVyo$D-4-5$$PMft!9IUK6B_AY>@m z4wo)oPgg4T)gZxVq0MJ(1?n=@9IWZ4+V*rF@lr!&I{4>!McF{X<-up*2LYW|J$~uK zX_I$5XmG(R1gdeT?f^_6@TYP37FL!7v{=dxc3ZxK%FZ|oaO~}AeT`f)VC>ovVC1}$Hk?7l9HC# zJH?_z`qjqoSw3v?rIj@XhJH-*71^b^n7?CwLhCC}`4xHE)VcUeWhXZfVv;`(78HT= zym94IV)*5ae2od_moBJC`1e&1)$#G+VF!dvFl|0{KUrwsbm`?h4^lf52|bi4?wE&n zK?yTztX(4R{daEt`|4u%gDVsBXQFb!_fp=6?fZA{grurRYT|;TtMWi6{l7!Yde31j z`DmAxb!zDf0x-`cezHM446j+EM?0ge)7yK=?LyfyAhu|M^ICEv#aa;8fn&7zWPT?( zWTylQuuwt6X_=Nr{qy8h9zp~+6G^59G~Km;Oe;N7Rw!)dUz7n)Su^`Rg@y zzPLZ`ZiB)h(^~Nt+mq0uk_(oSVA{Bes=WT0rt`b*S6OO&ykb!Ki5 zWz`s+Zfdz_U;ww!{_k!ua1F7hfP?8|I)r)w=m4lOXB8@RX;%|%Y`!##%V(;vQI~?W zaSf%fU`uo9UjU`kCU$(dR`s1UN2M0)F`z92rAn7QANIKG;Pz8WT&hFOQYPOc<_h+t zq-x@BUT^wmHQc@P!EY(TTzOECwv9Q9v`n*bU!zMqA3bGTjV%~xVdM?WA$=pKa0O+6 zmgT$wXe&g_%z&6}u@JRmBaNKk8;L9=An!gJMP{abc?b;a0d%pV+NU2EjX~t zn_Uj-aJ=TJITszxX|m*`0e@<=GZxLA6|sW}HrMVg>diD7Y9%O8R-I&;%4<;ZC;LeN z2uJGNRGmJ*ME|8G>b&DM2#xU#y0FbwuJ4DW2->UNFd4&9jAc2`tCl5R^BK%LOC|!( z3B?1{pmLFzXdc-{0G0ekD?j0untQWKhoM-oF1Q7Jn=+|eyZDr*|4;Xt2!pn@I<7Ws z>MfzD;0|h3n<6JEj9k=vdDFYJaZDxJA5ch(IwzawC!lxd%+_4=$A_&%a7;9IJx+F7 zZ$gZFeV62OQzuwcevFNLvoKv;!Wz+yR>0+{4{H7kG7Mq5!_QLmKHR4!T9FuVE_v`M zOz;r~T!Z#n6xE?`h>vyLW@@jZ88>$U9FBY2*5f2_^A(3Cx(B=y2yA5-GWuEuilKBH zb?r86+_pjQs(UmV`Fz|2OJPDIQJL2|^KI`CD4vJRi#IIBXn!IJq+*U>;O{4e45bhn zV)>cUQdy)&?bZjC2o+Z+OZIHZ?2PB$#HCZFIPEKk?T zx*<&>gA2BlY0h6$LpS@SJn&!Ep?4XBA1SND@w(>{mnYtVwnKahLN6vw#_XsSYIKHA zmmB}eYzw@W|NmRa)P*5pEB5xKv$%X}C>}SZRHvKww|t6kVBb7qZR;N6a*B6_NTt9f z9V#E?EFqtvOR?*n!sAxud?V~Hsd89!PGXmK9H0x;I@A|IRVH~2LZCZ50zA=~K9P>y zU&!H(x&D>?jt9Tqo;m@7kU2j?7EYHPP~^gJ9Ta~umYY^p8Ay1$9q#~khGk?wCZl^D zH%Pr}U-6Y3#Df;Ck85MQZ zh+T*;+c&}RBMwF*H%Sy=!%HX&N>MZ>AR{DVu8e+MZc=IG&TIHfGh<&c}^Ni6LW(EMV00 zN2Z{d@H;>Byz8%7HtsAosqZce3MP>_nKUFbYoX`!r2_QjMaQQ?U;3lk6KFB$<-Wxt zvQ(WK3w%-4)B9yG-?SRHm&CNv{%FlPz45r+*q+$_a+o=@u~F5-tXV6v;Twv;5`2aI`|uwM^OJXpF;6q-N^v6t1B*6<@gH=%qyECZR>MFt?Kk$am&5 z_TZ&+v!)YK{ayUlvj41Fw_C`L!Q`-!xR)44#s4*&Y99HxO&{!6Ae#B3**ptrBc)Sj zcHAja(!rI@{!PKI4GluChodR&`VQ@VjdoNKy+)oIhP3Be6-2jdem|P2e+H%t4cGm{ z`45@xk@v~M-G1`+X-aG`w0hZ{YzD!Wv%GTMmxEH0`S);Yj$UW^un%kPsD= z2^$zS7AO2xMjBHlP=vf4LjGBGP6F=4?OB>CKO=wgfL}r4)m2O{I_B}6g5x6TV%KfD zPm_Kriu|`5x$C-wS$^Q#e2{fdg&{ALXAlrcMuuj;qN0EuEu4%Aj63lJ>2T;?><4U7 z)WG2A*XoX2Zq2&CCcyw_4^Po$HPvCk;_6wNw^D41`poWhm<>LvGNI?n>wsC;l%uof z(MPp2P8$^a{_u+6ClAe*L*iv0-~-#RyBhs3{qm;rc24=v#dba$cx!%DcxUHA7h66y z!k@u{^vY7hB^bpT5xjD?J^G9I@x0aaQPecQ%6yuLQr%I5sK2t)0u9%cLHTpl)1@K! zGY@|rXv2cBlV-T>E05E_0rVQx|6-gpy+CkT*MRZ)&UJli7gEpj5Ob}~8W#b)p2HAk z)z&|_a@QX7Bfk5jIP-ou;TFWB9aN3{!w2ZW4v1ZeI?wjUXV$hpT;;I~|Mg~h174>p zh|tl|-9W$BJM^LRUmPdvGwA0kxgi!>Iu96mKA!g;2D0pCL2*xd#1ApQJ0WA;2FWq{ zRhINU8TIcnmbL>BnR+uf@2M)an`ExGy1hGMUXnq5nV%mZey2)9+W?eA*tqx(qG^#@ zHe55A61zluK*e9nIeRX*Lm>y;|D-exAafssQkZgL|ADqVpcqf*oNrQ62jcn0J;u*h zAVk+~I*_QaH{DlBbMp2dt>@3W!#?EhyVS869F5O?+C%(U8@dDP;NeVR(ku5J1zp2I zgJ54{Svi9vv#-KymzG^13+BusK8Wufxj`xB1+_sN(8*miQjldAIS>T)YbE0NxH=W52hCug4;?33sx;{=@xB8%DTZ3+3ki?$~55j z`Pyyz#86G@N{oX<;(Le9YNQkm31yQaG5x=Z@yiA&E%2>7tK=0NrR&F&O59_-jajjK zr~TfAoS9n-)NTlPYZlJ^osYrulnXjLX%1&TexFx)2zr#EfHST|&XM{y=2H3cnry!h zQVl1M6f~4z6Y6FC6_~0(XBC?G7qb z@TnUK>9SKO1V#GO#0&Sk6tE;E+s_$w(dJi5Ou=134J&~DOHH~!rWYL`uL&aL-oC4g zfxBPrJi)}{-WMCN)fxVK%_L*_XZrm3ptp_WJ(9$ER%S$sLtT>tBUvGXxSlym^y)!1 z_Z_%>8n5gEL8HXuON>_99F4cEGsE^blWLl6trXR&X}rik+u>|6$~=-U+&&{a+>AK8 z${ajP&Xat|kbm64{rqwcXW>w*cpou``B}DAk4~%GSR8(zfgVep7TclCF3+34OFcw6 zZ~N3w?&qMWrDTZef#A%4*UI*X>1LZdJ^?NN;8q?qviS}WPj@paC8Y91IiJC4#liRt zVz+sTK$CJ0M3yx`$cGTr8BpvHZK;7W+eT_lfmn?0)cX`)ktH>b{{eV!$5O&7t=~~e zZsl)sK3{S?X5app38DYH1JS7=?F9e;gKL|QT<>wa?QWhRaaDze-^ZTthxihZ85%0I zWy{ACv7JbIz1kF*azda7Vqx360K}7PMXCDbQ!l=sSD%J2w+9Gf@ZXp_uf+r|EELzS z*isp^@?YhS=v%_~?h2^|;f3E%6mNhAA83(Sj4Cv;VK<;CYh}{2e`SHw4+m@aSqTxD z<)5Il+ZHPG_H~#1$h%zFD56m3w5Z@eG`FSup=#0CYN>hwyA*XbObl6{!srau z$7c#d*vb7SI>!^seo|f-lnbfj8|hwm^^d0g^1}?^0Fw=Z>(92DJH+4c#}PyRy+`Z~ z=DHlV+^W&_YX!B9c*wx1rSX+e!eA5&G7)OJ+iMxbOL6rhkfGZ&^)UxX&(; zRkox!6t6wQJmZ9%=61+x`JmuK`m_6ecUrSQCC%P^M%8^4odXLPA)R+U>a=971<~d9 z#_BZ6xZ|oYX3o#JcX)yk$RPC~>IhtzEVo8VMG3uV2Y%%%pl{rSfV7ON^yJFrWD{uC z{$i_~br$1Q3pb0_3jZHdXB8Glw53rzxD(uhySuwP!QBZCjk{}T+&#f1xI4k!f_rdx zX=FNg?tI_$L%&t`%c(l2_TK+mG+yK1^BWdxVFcl0cI?t}oe4fO36N|+BPAAUs84P5 zFSRlamt1^biM(1yA|p`Kmmu4Y7=sUBb!SMU^1X@=j{G5##O+TKdT#nfaJ{wt-lNJm zHn9#N+^~jUCc6xt(xRNlSHNRb>eod)v&9@fWH@zL?AG*fi7V8sJR-vJ)!vgN`>iE~ zg|FJ|dEsp;)$!0It+Qg&Q}!I@y(%Dm&-iNN_#lvMwqcINYa|L%SyxgS&?m?KHM;6 z3b6=G{c>+!A^G+%{&BTXD(p@=BDXA6`wVUh!bCEJOn4mOoydl53SI@HEwHo{=H?nl ztQFD`M;4wY)XdTd?jY#YnT5Y+8^=9UWd*S!^C2206vBTPf!pifMnQpKN!O|WtC>o{ z3s@6af8V~cO({aVHjvy(QUe_C*iX~H>%Ko-V!&%Xs~^WsoBB$m0;RjDv#Am!iorhD zHp=$2_3>uh1uQ>63w#mF5u5A}ng%Dy{3Okq+-ddcYxR#nWTB$=wB1j-bpATY&L`zxUQf9K6+2ai$2G z3;;k<){;i-S!piz%5F@HedpAhBfn6Ms=Ghr^VcqLFl3@qwahp&f+zaNc?eaMStdKk zXfE>zW?s97OLZz6aBS1_qmO}64T!KF3tu~igdOAQSq7S$RnCd%V~ZMO_}-`D-OAPT zDU`zd=NC4w*^D$V-!N~e1+VzwgfwZP3d@5MBK~NLvAf;4TFRVWC1KwdC!JWVDM6W* z@CZ>jEU6#Yy=q=E&Q|ZX0oG#o7F}VNz>TntMLI#J_cmUtF44ji+=pmn`CdEZXWKss z`2+)hms$De=wRa)rIie0UTenRE+^pE&rU=mdnNmopj5xo3@Sf8R$O!Wa)6IYppBz~|#3Fxta^BpV;St!Gk# zoQ}4Dibj=*$1*l`)P##PR}fvwRBjw9TD3VjW&iH-v!VmTp*>3b;mZko7)>FnN_a2( zADFhf4AHM}NEnWAYhXBe)$!IGzi-)?F#7hza;MQjT}<94WN<=xZ*;cmldLvHZc7MO zD5g7>)nAwkJz`%Gc>KBUGU`S;m}(RfXn^|IJ2sMc-1jpn4_CzkOKditlI`^1uf^YV ziEHSBlZ6a(!4!(4ge|P-jAkE`t%cb-IuwQ7dbvFT*nS#9U!@oyCK~J!_q7Jbj(Q zh3svgC2*F-u9JS0W#DyJDq%!qR|K4`YFy8O2&x%i#SmgFEjbOE8ib~5ZFr4g9{DHL zt_Hzlc(ePJjb0j%8ZW(v=j`X;RwRvfB77<9e+t`bia=<1~#XLg5_nPR-RZ~fuk_czg@Th z;jz^yXh)8Mh5Nc8PJ7@Pzpt_`%*MXwKgp~OPZ+z<(9r7r@XKi---qoQbYhjm{J{4r zU^w^}UhO>xNacv*LC!VfLNl$TXV<><;^=FF((=w#7lhxOR@``f7JiU`PqPfrplAPM z(XAdmM@Id;0K6ME%_n5#qYv(vB$Ym!=WO;oE+VDO`fb_DN9q*IQ0_hIx06%{(kYPiW{+v+^*MYI1 zt||^`e5IV(dpxsXU!>Bk&ks!tB1rS%B$x7U>K!gA^{*LI-8PKT;R?WkOk6<-LdQ;m za5J%B(VI!Jy2Qet@6`8omRIlyf6dQiT+h)vVIIjYq=V)*=4YnVV zzWyTXjAdsZTviDBN|PJ28SE`v%%PXp{j2iNM0kh=b)UJ1M*CL#(riGL3zW;sme*0m7T?0_0J4V z1l0YQ8=SB2EFjGPNli1up2ay?*-Llflwyqg5eBU`!CK%r3aaZ|(uKfi#!40_Pb?e`umlKPaSOF8j5Re*weHjmSve801saTe`EDwa9)UJUHWB90_n zTljq)VdZp6-$gZm%ltD*`|I)t4`84{2-cYJJ)4IgA5DtU&B_j~CLMg%d^ugDlE<)e z&g?Y7iI-^2bMo6GtadMk+kFrWn6*<%S|MQzJLE23A@v9GvPse zG}tVt6P;JTT}+}c3jyV0odbstx5-()L*m}`^3IMg8=bSos^xxmS4S8?~axZJ=IN;H44);9zp|<4X zpu<2GqBc93wvq#Bw5*)@0OXNowp_-;ptkS!O5kmG&m#f{AA4iq99RDGjLqGei(BUHw_OA7wI9F0$pSUO7VBbthI_9xeI2d!Zx7b)vK8JPtXeN5aC6g`ctflk zKTZ+dxJCtQil+(gicDF~o^>Q-_~RRtjlMtMwqsb*)j;GEQ)nzV^2EkZp$6Mvz}l_$ zs3{B(OL`H(pE1Hmt?M&=F+w+yKB97-Ng*0{g~?z`^}B68U*_WsGZ5Z-*_5Ra*Bj5> zYrjO%72A4+rB(c1n30`uUh$0%Ks`^sHWQ5sX?(0mqkiMGsWV2Dx&)LVe7bvbZ*Aj_ z;bHbc&uhC9ME1CE%1cip9N*x$dC?q$v01F7`rBY$AI}c=nI-f}9JYng>3|V%^9=R8 z+`-Nak{lVEdrT5-uDhlSwxJ5P`RY%~n6VU#6N_6WF$eU3iuS(3yye1zpCI)bEFXZbWUxJ-(rJj^?%thUi2bc?J6>*8(n&@cuZghX@V)XumY@RP?QI~G!zc)t5B z)|Ma3*4lmQFFz@LjVlGf@>4#f&3|H=p8c|LnJ&iom_saAXDj0@`>(kUY+jh7&b;*C zqk6Asod~lStBQr!Y$WhD1g#KKYM3T{oZT&+j$Bs9Ls6Sgp?3g@s>Ad0PvEWeBR5OX z_2WQpydiGsz(PzBb81tE;Ozh;a%*#JZK_fxb99rUR4ez4!=?b9yow|LTEYu?X- zQ`Rwi!_7!Jc2MSd4b8@W?=68K9)BhlqREob?*by$tDsm{qh}r)W>XpP*nws^6XC-r zUJ2c1?lQGc8hjjvAk4luj8@F z=;GNX3odoTHz=v^YY7)UWm!5f%T)70LBCC(J@W}A>xz z41J|*y+O)~W6w}x#s*|KhB+`9Fy9!(E>rg1A6Y~h6V-6PB-gvG&{@#XB;;mc)7m;} zxUO-rh5fpGVi4{I$qUl9VY8g_BME)|1nV7O|rT#(_ z7Y>(68(yDsoiQET${k>ZT~utDy(^Z0xc27hqz%;(-7rYB90L8KH+pY+S;b7%+TL4 zG4dS46IiF^hr=~@enz;lt4~!{exxA&PEde#9FdJFnxRV#aINF#m_LS5N0?VhT@#mG zvqAi8_q5#XhSq$!8fsQt)thkJcZm`<29sB81}XFwn$dH|8$6>h!%-`GSl-}?UOr_+ z$+5wnkMBMhVtay!qV(%eiS>)#jc^Hmn;QPSq#lGj?%d6)qKZg6%#{Zka*<5IL2pPg zo=&S|OETT#a}fg47x+ueWn~#Akdv!X<0I|HP`${CIDVV@Y|6TfAEPm^3UQ87rrljl z(3YoQ=X2?|UrHL>PW_oje;L#0mz%ALz6qip4!VRu(CpM%>kSh(s)O%=fb6;*5fI!Q ztVg2+T-5~#5xVn%M%=gk>PeR^+wO9cKEUG&i6ig^NnoH$9OF0o)U|MkBL8pk>#nKc zhApLlYLgOy@LcWHu@b9-V!Fa()7|?u7PB*NmuOd*2x7c-fpm2WkiQuc<-gK)L*T8AEUmCRe(dB%~}t6{p7Lj!+BZ+w?V*~r~E%4$*UHAYCTx{GZ`#kxbW4l)7 zRF}14Ph2v?WErF2n?L2ipAX0)X4Bp=H216Dhq+&ApGT?? zfaM&|LoAD@o%z8VaNT-ry$XK85>6$?4~~QSIZVSq(1?v&+vbWt-fb>B&K=&T$n){0 za`Q$Oi^Lp|u-=1Nr>Fi9@x+~mKQS!op5~YXTQu>g3djc)zGU!tTmC<4PWw!CO&ss5Q+CP%xjx< zCC4PunA~WEiR*cbVPoao%y6d1JNUh0aHsE6D;vsKT$6qpz7T9iD8Y}o{G0%FUT2OvxnCi zNcaM!5pYZ+>ObX{_k+}Ly+q=;QU*`7tnaPlG=b2 zDN|BLfMtTUx7hHte#%v!U%>l1yykdDS4CD_R2+VA8Yv(k+|<#JSVhu12|wUZ*f$nC zwEOI>S7}J=hi$?D+J`TbuS}6@2QlQx-FKfXmL|i-ANDYV$cvJWT&tv{J@& zy_wOO0Opq*>PCvVT_$W`^#F>-E*}i|oP%N{DYV>8tcZ-h=Q42q6PjBwM`$%`ypu@o z`b~P||55?Op`s|jH;}!! zV^e=4Frm-`gCwvSM%)&d%Eq)OtAMqzFMt=gUD|TUM!UVgQbpCCP9wO;dFK z?3m<2?My6Z{9IyUkb^qlKp$hW(f&%b72YE?bUid-W-vYH1ewT)Qle3-SySQ5Lf_&= zU$eitmz=yTz+aQ?ygp`mbaABFVu2^#;5~VN<4a7F=gQCT`_jlMv^ZP*hGz(wmzoiJ zY3bBwQyr8(*#loW2Mt#hzW*jjjZlVd+qLsFml0&-DeIRYG zTNi~% zG@fdCby~BT_Dg}&=><8!m+Fp+0{xw_c3q~}X#U)?-(PZQHvLW7BfXs;KOse)DuMR* z#5$)UKA+fuCU>NL4TPtSPTzg~Ad-Hy=bbt_}$3#gFO z$fN34M6*fH6%<*^EjoBRQDMkK=9gb5gf}E&8*}G5TMxWxYl#HB~uS4_x!$833C!OeFe`7#Yo_&2%?ot z`(L>EtmPk(t>nl4J!_bDd{gF?JJg^Jc(%QCky@e(wgB~5WBEEYi8yf+)8?iX>zuDi zUB})}uq*+@&Q;F4dLCM;IY32|XMBT3mjBv!rk3v7F&7LECKlezeRKB5tDa4pkGV}p z%GoT4zNM(=Flo55N1G)AQU2J^4TgojQAG;nZ!Y|3&zn?tU_w12%Vt>MPj6H61H5qb zM#DA($NZ(qub(=~8hVD0MSq^=bs-+dloH;k<`zWGeQI573`koFvphQofuY&po77Vp zu$Bj&RcR2GetZkAAa3MI%L%)Id2n9+gx-kdSTBXbKmb2%#V-jipZt5Zz(xGW$FIDN zSIsL(4y+WHIW*v0dl@iVWlTgR29IP|gLm6|7uN8LlB-r;@Et4b=QJ(}wX)7;t9Me|U2GG!0iksZJZF&cB*c&N2_P{n>g${D{!J#;aW-42hdB}NmmTO)qZ z()y%MnAbKO9VpX}#Kf_fhhXCVbn^=3f%}d%-XYAmedd)yXomw&tTvnZS>>BNw_zf{ z$p>mH391}^_FLW$vN`h)#Z0#nX`rIT^|;78ekt?CU`XmM3}t3s!r-^Bxe3Z&!u>AE zUe%S~Q9bBh73%>R{=)cS8jMJ?l{N^@PEME`hPkT>Y+y4iyhS-k9n!W7>L+G2Kl?G~ z!E`oIQHG@*gj-Y@C>mt&XJQbsk|JezJc%ulGE7`fIoUn*@p+rp8$(ia@*HwC!L&(9(t z;f{N6biM~HWOt{jXv2@wQ?(W&;A`vl|HV6j!lfWUw8;697dPE3^n+bFF%4@5CF%SJ z0IR;rI0(FtdBH)B@=99z;@4uO=E@;*9z3wi`A<5W*705JVp!LR3&oIym6iaH1H;wTc3PUe(m- z?O4pi%=6JT-QKe99+kGEt?nCS`@+b9S#UudJq(RLk8t_;g%XXktkEY;>VqklGDWl_ z4_9ub9SsV=+_1AAmQSD8$gZSo4U)`Vy#P>Hu0)!!0QRr`i#LPy`3RX<^9;$R8Ucq; z;nhCt>=SZi{_OZX7p8n#<50ddH?W4D8A*=fDRKImw^9)9AN*57&sd<5f78h14>3s5_(^o0@nd{lcA^%kvpE&M~N^50uwe_kh)T z9F<5i1?vIffiSf*DR~@4A!8*@fuamq>TrZp5L-UXa* zrUo{(ovpnCz%ZU8-_-am)ds52>1HQvg{?J(V>BtZ-1HyCZH~Ua8H@Jp#>@PVZ9t|^ zIsv2sHD@ZXIsE7r8(Xa!Fj+8%oe5&;Jo?zWx|33m7J_(MjgwkjvxxX1_fDI-I2B8X z7AtX5nLMU;5BDLhh`dQ(0P47uh7O9KX(m!`YXH*_{OvxyIvFKFE%XDLV<^;r%EsMR zI)#J11#w+DZ3U3w&3a_CO=k0=$r%*~6BrRpFwy^15!w)ZZ-3#Nc+ZB(foaZ#%GZH1 zV*I=?*=j!Q*dTP%rqDa`*Kv-r9f~3=i$uauS!779|1rjnO(bimhuMesU{D~`-}RwQ z?R-Y4vkb?migWa0>MoqCTY4xszDJS0xR2{Bee`x#N6@U7a3k}%sDG0PGK1(i7MJNa zCVn#9jz~Vm9;yiDg;Xb@R+!1eXa&d;1TqLo+yI6AsKXkYUBR0RnMTaGYBFz@Rqh2A{~w3(Aln{heLY<;xCUh)q=~glunl2 zs?1%*f>8DUykns+t!#BP8S`3MK$b36nO$-Rued(2*F-VVzX5ZCIq>yfWq0PZ`M7;w(43A)d z9)dYrG#f<7Ka4O4zXi{VP}u4O({_e4#tlb=)ebwLZW5y62nr^;@oZTJC00Yh_uz#| zIuE~3zZQw2Pu$ss@I2`KBuv*WUQV_MaP<@(FEO$+X1pCd62=NB&lAZ{&EoUgz{ zx!@_D@vh_Azt^1lUKl{805&T+0bjv}NyX)s8_~6?=bbItG|5}G5W03sw5AVkiSlKn zMCVk{kQT?fhgLB98M{H`Fm$?7>0g6^d|DExPO{!Qb3){YWJ=z>b5W27>-BxuD`5LZ z=O8B>b-3+}5a`~Xx3U}IHW9Grw%B)2Y$(|MMAWSf)XX0hXgELLT^2l11J2!eLMgRB ztt_QHUPB?Y!g|pP8$744mwBG;GzvnmxPu`sgkLNk8(>>rHf};0^5kszal{=n< z&7Sap4gs5bx*LSQry< <+enT4VIqL+OM+f9(o>bzmXwzs4#LMQC$%;beMj+R)EfMc*_f z5?m}bAxHlewBNcVR#Kb(ndF*C6Pl-NoTiH@s5|R+lXt<4e1~RJ!4IVC@5$|Wu*qbb z#(8=K6aXD^{1z;?8p?LZ=04kByS7#x+7spHl~UbvJXXH7uCwsk1){{QB{P48LqK_W z9KbM1`wWpYe$bSYH%*^HKXP#MZ%V!@&3)zeuhXuH6WUn)TUZ;w^0UR(L%hmJ+fRF6 z4_RNMIW|3t1PZ{Nl9^B8oMepwRxAEu-4AmP0xo~DXD6o9KY2;+j5#fM3TZWxlqB;7 zB^CBg-`5np7^m}>wo2nQmKj8GpY~u&T?~9*<869S?<%Hy zrMXcUBY1d3Mj60^QFeufPAmcg<>WO$csI^Vj!RDP@pPrY=qp{{`K*IWoQ;f4@tY#f z7PrTl10@3@$@s_{YT!NjjD}Zxm}q>P?;VCc2P>^Ua=#ZFL_EJZYI)-l!T}YB-ipCp z@5E+IIz*t0ebyqMR6XC_A{md znf3WhhBZ0atjpoMco+utKeK`oZrSyL62kcfS?AWRD1af%9AcX_zI2#+7`ZSd1D34; z#dl%sx_s_nVj!ubafaqp-i*QL$Jl%vzqmDb+Fh65dFz5&-V=>9-$`w@P^qV2iGOv{ zj?DqOBf-nyOt-7Y-+bCBp4fK@Q}|Y4ukda^@3a}q@x~0=H=Km7*W0>92z%=i8RZ9b z`Y)R8zp%s)tcN+*Z&Qy@K+onITU?;hgVO=qxQUz*qur+*5aFZh8Lk5E*}rL3-Inj5 zVV3Ji!d5Hytp%aC%6h0zkY*eklcxFnBJc$D?QZluj#4!*xDzTp*n=-kHc$2l01G%R zNNe_DWzMt`8JO}szmsyErWY6ulAOsx#TnTk4X1BCifLEuO{>wIYQIud(|csphBen` zP!4I5T8s0BHLwhCvXV+%fMaduK+#6~x;SP?Tcpnu$sllrDNyZCHje6_LLPCBxw0xh zRGK6Nz)1L{+_L}=KN~8ePFRIN^r>Bki;*ka<{vk>b~8FjRsq>;2V)7`9sAmOY!?Z! zFXNNuvv^5Rfo@Pn6xUJIqd=vRX86XR6zaI-BA-CMY$_0pA0#p`U<{HRlM0PwC8EVG zJWv333@k zH9r{U$peQeT$zPq=z`k~BvrIO4bfoIB9d9SzTinjnz<;olP2C?#9W%(^Wl;+zKf_= z)2*@>S{VCd@lp+c89!cG=SYh>eKyxTi16osjEg%Zs(qws3AS!#NMqK@5d7jcWFGx_ zoDOneuimNh$i~u1GlF5za^f!zif;U62cj~9xF>KwPC#QQK3>^TQ-h4bu zMOa~BXIrPLDG{Pinf4x2qnd}@y zrUc3@{_=v0+58cR`NKNTYp&DlhB?=g2_8=39i{V4{(H@W_wQ)Ka@M)Aa|^WV>*#6B zy7bPG4gr7tjp@w&06ZSmF%G_=PcZa53^M%n z%(O>_TyObwAu(`4SEthgKQB`lcAVq(?#nmL@jpuW!&hbwpi7tUGsb_#}Kx}jSjH+ z=SIMeN}@~{M-2;I4(fD&qw=Wf!a(Xs21|%%>+Qtn>P4r{HqWED7?!(y!G&Fa!o0Vz zNVENz{isDGTE%#=jPiCR8YD~mO@V0b&Ic~u!&f968z-Yc!tUoLr$QaZW0$^ZubNz3 z3<|LXOoiSbiL^1UV%}?i&h@&dxS^2=&vDDfHwz^Ff!?cbb@q$bvYz)N*J;Q;&eC^( zP;;7^)Mjq$$*!_buv?Fw=65ViS(K-ur@q^3f9-vI8bNpLJeV#!jQAJL!iJw%c&wYn zKpuZ&@lY`lS*C|ygbPB-B)P*=6G$oyt(BvQnLThH^Ws zHbNbQ_GRx|gC?Coe7A6CzV{YAr0akBZ2vd8c<8m-{!W91(XcP>`wZXEr^K(J+dajSd`4#n&YUJaRA;M|IGP?LY8SWZ_8y?I zWdx9vRPY)#zCr!49-h3{lDQ5Gcg2OtUkiR~~aE5O2iZJfTZJpxUjt za*|+~B#TQF{OQ#Tj)$Vs%_1a^`u1mGQrq@r^{q~eYJpq}laf~Rd|i_?DfjIvNobkU z*;%KTYEU?_=CrXnHzTT64oEuu(+bP)4?WZsOc2f-R6DaUN*m6t^OP)>%DGVxEX>I# z-XU?-KX`aMSLbuQV0G z8~|;0Lm_R(FUIucE-WM*Q+*}o+eAxW%elF7MwzU4+T^^Tw!bY#I0k&5Qh2tsVRsU@ zZ$;%tYx4`X>VkgD`kOnhjNq5|yCks)PK?cuw(mXpI-{L4(^18y>i86;4V}vE7%|0S zCh^kiM7nB8w}zM|Gn~NiEh6rBQ1XkIx=N>k#DGqR|!Nd41dJY?ft(M)e;Nt zBYb2sv*oeYSLHiEEZ6sqolHeBlRPvcgHB0K%@o4_RR&*#%|XBw^-H>VLJ({NY;Pj{ zX-j=O16PCMMlS*(2jC}{)(iIw*gn&FXSu8ark$Sb0$_flchXASD$#M5qmTdCXr)81 z)}}8zXaM`hDxpTk_KVuDwjb=Cy~E_zZ*-|LH= z=`45YBAZCa#h}yT{|oLDMuF{Xig|Czk6B&=e|UjVb{9yw**w&r(|o8KDqVP~4g(`S zkEgu%>#;jE?W%^EOy{49QVDS4zLs1W+c6K5M$`;fYv^A&mG;0J)*&ZB*0v9vhAh?l zy{1(UxQcy?gc|-F=brl+W{p8PXz;Si49_5<lI|dl_ljg_SMS)!$;Tq%LENU!PjI7AVE_|xi_!xov`feu9O@wz}rSx-MRD&*5E=87x zjXQkgOSr^lvY-?rrnTcv6IuDcJ$z^R+i5>`-haMQ{dACKY%VwKm$T3SHSEqfG&VI@ zvJnJfWz3xOv{WA%7kY^u%bL(Oyqk&ovBFZCK6CKAHr4JYRD!n!WS4Z15h|GZ_s$p&y4{$FAc zIF;04$oRtwC|60r0=8l5o+Dgp%_KC>D+`<#OoPA?reYp&qvA)u`rOPY_NH|k_#w1G zIOKe+0LHZN4ULP4Hnm}WBCwh7V5{g8&U+ZXyZ`+7!)i0hMJtWr!d7d{m7&Ohu_Bvg zWj0uGOOR4PKrMH@l4{veb&eR9RuAKflUum_jmK^uQ67q$#uZkR{wvdx1HTKWnLjOj ziWwr8LdWCzm`r-X((2TeFnLJSuN+{vwTKS+;Z=G-=vY=YVz+#$7ETHMLQ%4_1>Suj z`3NeM{SLZHZ{pI@p4zLhFJX80`O*=_GXGZ=lQPZ-p4YdYt5-{4@7~K)h;h=Y4n_v zNo9mGxA1aqw#-RebTownf5T5S1}05dYVh*T@TFY}MO!b2-BV`|=17P|&v)X57DFmK zCF^5U*dKe)vUhj=0`FduAdp2s`}T<7IZ4#s{;6=NT=2BPjjSc6Q^!s+FHaX#z5xJX zPQu*gZ@mpFu%OuziGE-pO8AtoHB*bLxZ>=d6iq|mTgs1WDcU8XjH zud6;fKOOjc#5yD`t(tI{!r+b#>&(0*5Nux;U#udEeA*~}s@rN|dl=xQfpj%~`~JE_c=hht zMGOo)qo{K}rvJIC_7?_TE6W90C3WY?%HGfY6MwtY>k2t*1G5P`y&Gn9$wD}xTuD<; z$?>Oe@}s9H^DQYmd{mIlYCX{*K?gBGYw~SHsBp;gu7ke&DJc zo(v9Ka0c2hM@Qxxv?ZdBadIs$}W!H#^NY1}OB38s?f5w`$$UbnASGr)yKb6xVr zPGHvk5T{Of1DZkCukrueqW*(CWT*tChhevfMbtDh$~JtX(cO`u#eyL0d%8NRLbLq(X^F0uL0F9}SgQ zsq(rTks2#G;?!{MGhO&Vn)`zYlk5+gAZu4wOp*7Vre$HlLK7trH$66z4;kFwX^fe4 z12*H{1F0yci{alYzr=P<);Oa|H^|FOd0^C2W8f&B#d7PmmVi$jd60hZZq7&Dp^)Zb z-!|4Fokv&cnU8p}?BFO`ZM3m&J>$PLxXF&kNZ^g>TU?v{CV7P6OqP3UN{X1AK;@mR zY}DL9U@Q-SfDQ%tRKKI<6N~=xD~!v3KjUe=a9Y|9#?6ViS%7KpXm`GMSW{iRamHn4 z%5A@{i7ypDvN4bd|B{#yC#Mu3jpHb7hTu+6|6BOWCEvN+3El{I<|L9mGwm|txRda-=*7Cy99=>fD45G@AIfP+b4H5vneriax`*ViANuR zSm`7DPfs%P^@H>DwjwnP4#C6Soi>9`yCO;^`AAkO1N4P#T7#BDm^+NC?^7urWVmjv<;i|#)w;C5ZEc4^|wirg{`A2q|L;&+6eS%UJ0FR(&dZSEk47RT#u5hC5G+L;ri0VpQEnk+t&VLPxkf5+G>T!j_)ET9Lb%C2oA|%E#l}0 zDfD6EywX*Q_1H0jQ&UxU7q(E)fdS7(vGZ!C{aPQ)8Pc~!SUaESc*|IwnYCz(rr;QR z<3h%@lZ@+wa6%qrJVYS0x3VMzr(p@T2zYP(I{g-s1N403l9C032?BFb&b24gAO3;}6B-V&7 z);5lHrF07HF6-+sR<9e#!475{egeZryGCnfe(`%#i(%+{H>BVbIU3fs_V96Oej%#7 zHiUti=;F~8E5880OMf&?`Fyf!0&|C+3$kfClsNekPXdtc!jU?BB9meE_6cccDI4$k z6^HiMR`KyU1{Z_?hkW;jmN;K%pdPcB$dT9beC*Mw5!y%SNAQSSK9cn`daYNYF2wxU z%9eU_DmhO;VVUZ}dGeA4dztYyQfvLk1y()`OJ-Kk2hr|A)2>tgXG*1OAanT5!YvQUIB!o|=~-ZhFSiNq>BW>tJ$9r$ z?008f> z7J456hXPyC;4%46wf}pX;TPl@APMM$P6%8Al`SeBN+ z)Q;Ny2Fc8KbzDYbmuqZJr{d^OInUBe$wiTK`j*gFca zS!tIuOh3F>MPbw{+mVE^J$X7i1^*i`vd4M0Q9vUtH%h9`)d=mNc)~@|t1SAYubI_Z zI@FRAj}~yQ)PXOtM1Q&DOasN!&GWZg&yeg;6H;P@{iK^=4~q*_T06%@bqU2`4k$%L zwx3JIOL@B86%$Mq6E85P5-A-2`_sG62gN?lOkC7ZrCxt&It5fQ;l#0A^X*6Zcr5!u z^gvAlJ8d=U&`QcnOKLU6dRH%QdAw9lD#2iPHTXT8wHY?zS#xFTsHcnYz2jpNLZyxE zjl}m6>UKKp&k9zZ>ubeV-ecO=YnLb2iMDAUZn9hawBNUU>s!Tdxz6b*jm@zRra~gf zT({V}FZ|Yi-I;{o!I>~zQ}IvC#D`Wy^@H^gN3_(pmS>Y`wdqrOJOt?8^QW4*+3UXE zB>99c=KQMeD;M;T?eRUa=5qh#NpDcxFAocU{slIA)w%A=zfp9%9V-7Lr3`}OTN->k zqequvKtbDG^N(ARk5J?HoAlO(7w{Dk|D<|e%L614V7b>|E5ki#>w`qadraf*@n6F8 zzss%NO}$`Vp0}BQm7a&&r0B+cV!RVuV{r@VEOYtrdS{3HY;z?POu(TlFdg;b_}urT zi6WdEd*l1@TD)9$z|GXMKWOz}N9kt%;-N=o%ASbXE9Y6}f-deW{~0RE;l(V88|8c> zbY1gvlO9gfCUVR^{aiG>kGUKrLh+Oc#s##p1ONp8`s*D|=!eFU(jdmMESx{zfVwTs zwtP*R*1W^WFv6@)M@J|`0eTTEnbNl1U*jzVl__nCCd8Z#Uzmc)P?Z9$)N=*O#kOeo zmhpnG+elZp)HK03uA87MnF6_VqiT{AUSD*BNUAP5P7OmiWw`RgLX3oITR8Lve4<;X z-qAql>H;Ej-g~x07SojS^&8N|HIXzD3iPI)vLy6%qy1_$E%t#5^rV4dk77ni8AoGj zQuZ9*!u_a9$XIYNBz_F?P(3W;kvu%uiq2DImyu#i3W@S%_xyP+4>)o?3I7SfA1JpDBF_q|q6 zra%^qkn@IhOeA0Kh%Q{eQbF zNeRD+ZnNtnT?!J4q1t?|YY(KNoT%<0h0EJ--fH)g+Fuo`NGJxqLD;FnsY#psSoB~E zC}jr03$e%9rq@owq9m@_&H2h$ab8Mi6&1ivm0IPmkv)VkDrzd%rza74CO_w%(*yRJ z=@Ke=j3P>?0@ththy=-8g-nvJT;1TKVOU@5~tE4d@6_ z=%7wLI+xFW+ARcZ>3;g8ZEinE%eTj<1NJeYkF9(Ny!1GlKZJJW*44ezfcV>!sQ!ws z_rs4-7v|y4K4|3NUtO*F4rbM|m2mBJp9x%3kX2JgX7OGZ8(6(dsXWPTLdtA{kYeJY zufm`;ZNqlElbqk&k5kKD#mJX^3+Dg>(}q1UkzuWgLSJ@M9e7A0Prt7@Vq~BWo~8h`#89Dm&2O0kF zcE)wVmFXa49)1MdX$z~u+nYuCnfAzBFKBFhTG93bj+ljUts-k*70L{GOdODNVTXCB zQ=wdL1@EM@voJ@AI9s+@@BE+#Nu&uwq)=99f4SA|6)RP@xV#)y;{ri&KbqWvF_H_>DDbY{2M}y8fgxV{7+AkoQRU4 z(zV9V>|nHN9ZvX_5V^DNAEng54KY8+u$F;0o1hQGr``%d-!gB{h!pQ>NFjt2$r7Ss&nPv92o=vTR@hQ9x`6dKlE(N~j6f%JTLDR*N& zL%8Idw!gdhN+SdJjqq%WRND?t%(^Kkq^Vd`QQ{I7Xq4_tyO|&7tlh?|K1@Y>y9aIh zFzb?f%C4CeL@$@3nb=M&NjSVa?z!KCYPV#9_XWIQBSq}bzlzDP`>fka?5=Oa5%~8w zi#=%qE_Qsq`M2oKlNxnIf%g!}=d~PGfQkcWy5t5+CA2e08Ni!V-Gh_fMc1+KmEJuo zcQI?7DPooj!h3=E%|Jy-jkiwh#xdU;USIpMrJxcNRb{Ax@L&Z0L&1J_%pFIFO6zXr?7cAb{uSViE#BMF>viFhykCX0u&@Mz z{!_nu%q8Z8d}8#spO;!4hVjf#oCi&3Y@a@1E>pmxTl==%FwM=hPdg|F|1GF)ZofH_ zxM{oIate%X$+>STJ;kjfd^Z<-!OH2zxKfjpz1%3tJfJ0!a(3N!Jr2gJ*d%6XYZ}r7yyIy7@DLh<~g@q@7r%dsi755}w z^E?Nk>HP5BO&0I(G0Z89zCT~DU0b)qWO*Y>1@9to3H}!R9H&T-rQ4yvHP&=7H>W1P zkB2SD$(*}gz}?j(kK7y8n`0I0y`v7)_@W}8{j0fe&P5}pmb7}7Jx~&WizHnL-$a-q z(fF#KGhxcbJ~L$9-GXH%j_?g6Otult9G z{ZCP?zz2xK!2XHB+MUmRcLCnfSDV)e=&*;hibPtp{;GnWW&SeqqGHp%ZZ?SG8pEIO}0a7-URr?6%}@@C8s2T4*>S@U1|Fv!{Kyno>qd`owf;>{PHpBEx~Xtv+^QG?e-IyQ=! z6?FD;N;eZMRQs!sZX~Jy#RA%*S(LuFdZh6FGCIxoV7d;rDCHdS8zIwDJj1eO{!h|M z)18D-_V_4VMLd~5vy1bUU~(fP5wzyUaieD4HNH}!LXr_hukI-n z73R?cTA~Ya2yv+MU<}STV9%?n#rvI=!FhGH&ixg6EYpbcL5w{FHoZkCdvn%KMxLJf zGIJ}V6@3rFIa-^XEBl&G>bophMU9H2ee6`sHXv6kbvwL)a#cYAvdm|MW5j@&Oa6~7 zj}V7kHszU3s-iK;R7QIq^Wd&0NN73LDSSpTVu0l5(W*U0Lp<3FvaQ}tG=i4H;wDWH zcLy{MgH{m;lIJsieEZ@nKw|vFJ#=H4qDNALoaDy4%o+ufze*zTsgz^-fjV#dpWHWx zuT4VoPH^#?zMyuBN&LgxrN1EYU74gM96C{!OUvAwH0(F~^V(yl z5SXJDGf16-Q-G_n82`ZCO5J=uVyJ2zLi1bYsly8I3Zmebb zv05LJg4QT_RHHk1a(=!vcj&@feJolv$8%hzGP67%dPl%%<>ckW-;(g!|-9Q9!qz0&|ZK5wJLE~(r3Dh2RgJQ_Dn@ooI+8TdCge!?%0 zZUbSz{)h_aj%S3m;KrK;g&(+so4G_az)}aQXy9)nNjEp^bP$=C^6vDUC11V!ed*G+ z&+f_nSYC}7Mbrb!@+=9o>vsfr=VL5@@%C!Y--&0ZL3D?4eVG{ec+i>>a<&^A0)?@} z2Z$47x!n)$+G949&_vj4biehpbwOF3&i=+aV# zoA9SHLJLiSiVqZ4Ip*JeM%b=^;I?jXQYo<0sr}Oouj!vOr52-tu&eJNO#XP9*PW%^ zBDzCMR?REj?A29L4S|~MY3k(Lxa1Ug<4Hz;S9)3~bm;l3>+;Q_>$P~e9xsvsGUttu z`&i%Lx!g-wHc^lWxyWISTBmrOH4HbujewWsZK>}IuE2=W zH$J5*0}Jx$i=s7^6y(1aGulbcMHl+K(wn3UzsOW?cm+>*thDkZF#WXpEM0#N?L=67Soa)S*78|A^J$^Im77s!Ta&UD6 zbuZ_XE$%zMb{R+T7#_cyjMJCM7+uI}k-SKw|DK`>QpthBU~Taa0}Y{1fg--3m!%Ti z=x>KGY$6)RZ9kA_cwhhhP~XfqYyHohPfDzc`8YiAlUv%$6+DOShx`E|u#q53>c6Zl zJAjnoTE~Lib6Ii)Q2~XN_Wbj z1{W$P=X3zJiM?WIjxdV6y?(eJ@YSPVL~QHsvaI_#8B7>oom^g$LSy(+sH z?b+%W?5cMnqsC?}80$z-PeIs7#!EqLU>Xca5%B;%h43Q#9GIAB3%61@AIfX}Rwo{c z{};mE?O8rJZ>BekX!9w0KkZYA_k*)R=bSf+lJxPaByv5F%*gA?1n&OTd$yd^2m!% z9k9zlPUO|F3U6ES1bA1lwnT?hY>3v?rnNk%7H;i&RqO1^k$b+u}RZgG6q5Q{# z4j8Jd(pFFLC@;D!iQofY8&elj4(Rx?>dWIE({)(Qmype3<%by5{4B}3G0bMUhvs@K zjw$8TyGoJtflL%gm9TE>2`36`)g}(rQrr>#S2WQA=8bzZ?||oQbp@Fw*Me1K zPSVw;m2X?x;l0hnZug<5

1sh7(}2gI3e&FjZaY?^R0YlK62WT6Pnt(hXeZCj~A( z`vtCqt<}91G@bS^wrCbN8$5b_8Z`x`Kszvx?4=FQYR}pBeB(yD=P@S&qXIhU8uyOzJ=pu!;FVPz#vgoo26w-UtPoI9KL zf4{~5GkD|bSMyi(>>P9w_fzhtebI`IjkStLlW92hIZ*JEn9~FqYZNU;j^#ENVjD?-$X&XAl8eG&@l?_Sl^6#kPTvA5&#k zvt$b0Ka3r1CF~j0kgYiU0I7lYymaK9((B|&R~hf~jr0|AR_6cWmlXN`D9s)LEXqHF^D0~X(4|P(c{9`h=S133lZnkwKh9?Rmx9n>ToR%Y+!qnfrZ)BdgjIpWxy`kn6t+2(EO+@z zSLLF+&YlM730wer5If{y9SRhp{^e-s%gL>N!0`4vg8jb4SG^}%Zt5(!S`M{$A}{{u zz)FR06+z$Sc-5hRu#`Jz)Th=@EjS@SS;&F9=EU_i#)1BhSEq@47Ly6N{rkd1_HT>! z#V*F%QMgc*S*ad;q2;ehb~0uT;3+i%a(PETq;3kj`208JmJ75dX}e6yd2z&RZOV0K zLG~nz(}shV)QT@IB}U*^Y{jefWv2>OV4Li}*vEDa$J=&uVBc-63GsCRxY}r^KBlHO47keAhhBL z>&qu9#(~*XG%iM@DLV^hRl-RiidU_39YW1wZDO<=XaXyf-gA>B}FyRs=gn)Vm787V~)M+^*Ko_{^IFdp+Z| zKUc6Sy|)=2dq2TP-AyD=$D9Ag^W&Q2BM>y2S_Jh_w(_WHLb5^C{uO&n zXm1q&%`KlLc<_qgnD9mir@8K}_M9{$w=P(HpXYOHkViirKHhU{URdHhk&wla5ck~p z_VK1?{4u_vJ2YVW7#M&l_}wJBzVWT@z~6md0QfHXgTVdPnjf-#qb{BU+7Q|hva!H( z5Hvab4xX%D=8S9FNn!eQ5ohd3HQ$QIGN&s-VDk zJ^HL(bl+|#q?nlf%jIg-QO$1$rs-I6g3}Y1)VV&iZkG%O9?Qu5!?I59VuNNIqp z@tp`?9r9tbkSpI)OD5hS{lqFu}bve73`vEHwm!K*=m= z%0}*A2PMImJ%oq(YZ!&iC5)aYbG7v3m}&Z|Wl!kW7dt($fG@`E@yfBG==Yu{cG>D>vd1}lB_={TB===zb$bps~w_BhHjm?X&!DZ~m%EKXR`j7&1;!F}5X zosk%ANkwc@{21zJME11IE9Y9(65=3>5utPD{BEktQnSIcN&*gBSO+9WQV==BumF+` z6OtBL)rC#2iE9MwFASzywN^1Bx!=<^@I+fz*c&gc)Qbxe@rXM4Mn*a322@p7c zT$f8oB>74{&Gd|PlLvHb_ja}82C34?z^Z*G}OK~1NuH`3`%+Y$YZjH!#FYD~@4pa4e z^!vtWBchmkG*bUsMZ7U2>R+vXWH2~+2)l5iN~87xkYuPcFRcC2vVpJM;vShSO_a5ucHllSI>>^{;UlVM_Q&7-s$4;JD5) z#&v2_g~~M+xQZ&?KhY&5?$7(-n}jkbMjGh0N8a%AGhT$6`gq2YZhi-7ZL^ua{wZ>y zL$As3f0`k@1naBVXL4|L;<*OPtEg0LaUGn&UAoK(Ic}H~u*!-%Uk~>k6wtm>_oKq& zrQPqniN37|gs9BS&zA;rg=Au=B(8M&Qe-4|!5}YIxI%K9zBq}u*^_gDVPpDC9*1rBVM-M@#o+@Mm(c61ueVoEUQUH^e*XL{LkP&sE9k_Kakvxk3 zMu=S-BjS^QpDgOYPY5=^g&dW%?iI8eD~k(V+-5cJK+-XF!_!YuMt7X=!wI+XDOGDQ zquPIQw$Ja%@3ms&<+in)wp-C6`EAq2?3`B+-{|H%7^eVHtAChweHeQQX3{Q$5TBJ+% zsn)3fX(mP8M!| zG;|sTL!*#d_yH%gph4!kZ%Nxne}2m7@35PA$f@;k*{^q@g>L)=KDjh{>2(6I6W8mbA_~st?=F*%u^8}aR!;D=gYu>FmBk!Ckw<{5@wU>4lq3pGs_&Z}^((S_ z$!hAC!QeZ!V-#1_?)o>@QbDtIPn>5pyuxLDd zjNQ=4`z4E%P}_b@X~H*8+XL9qoQA&z9Tz*1SF}Zl0Um;+)34|7$HE<|1#yPo%|#o& z$Qgp8RKIw0yZgM__9ANlCr=GQLfdQuuzv)!Pq^qmwtC zKaoVObUsz~@0N(ZYR;a@o?1|Uxbg3 z0<|p9R~unJcSza>hW>l|>^gOPzMzVI$I6rdkiP4rVWRH+e*L}^3A_8=m_^?4vQ~be z-C~YpxU5$+e<(o_!!_xZFE%Mdo=8=nl=b3Wz$e81Z2zP@VRjM8IShUXbg&wkeZqA# z=HCC;s8p`j)V1<2JUUOW5|(tMkLZ58>-ln-ZUunW<~H}Elyq}7A6ULf+xFCQr!^9HG;vqW^iGNgjM z?Tgqv`wgnR(-)|WGk2Q(l4??DT>F*pksJ_QrZm6)6flJ6&BJJAbB?Y82mmmq*Y&>! z%-?$){|cHuaj+lmLGGRm?8}Q}9bO#<-FJVT-U)@r$k-2V7j$eP%Nwl23qkPAxi>6! zR*9QrCWW`)A(hjX+ut)SOC*5zG77T<7}9|U^W8l%*C>pLiH~(*2qtNYuq4sBJcT1&h=Nm5?uWg#bKrTfB6_F{|jMH^wK zq!4Ib*4g;Q3O3U^t3mM!Xtkn-$x1k?&iCrODIa}cy;cDZFmt_6&qN)!uKj!e6xk-M zugXt4>1<5ZRhgCz0RxJAd!g;=>~g*vQqm=tlwTU>(fK!4wpG z4qo6&kz*Z8wUZM_MVOd59X?QvU45SXs~XY}g~Md`mRbDRwMRfTz;^9f^Y-@tQ{*8l z*pP|e_G_AF$6Weedbi2vQ3;p+u)aq*8ATG;;7N@JgHXg5JtD8kwXG0Ab7?Sno5Se> z!_jp~C@~E8#W7bA+nI)*9oZ**P;zE8e#kNd;$&eAzW8KP^k_Y%r|D1uBj(el?s3_gODy6+(g|V;b+SbG1F~;ZYWjkPWE62XDN$R@o{PtCU!GwPUc8mItzi)l>t|6v+a&0GA&rBt+J{80<)%g%GN~aB;x6r46SdF zot)bhGjX~4Sy4Zi!S;wYM_pXt5EF7Oc_j9f7EF-fEoFxIsHmKAiHIfSc1mm-0`3v; zn=9;kOAvU3nXw>X%k3g-XA%w6-+K} zEK|)qqQ_(Uv_wnDVfL){x(I=0kmLwH*2xvfveSK}d`~{rYH=IpW8K2o4qGusxl%#B z>AXoryA;JUVLgJ^!C}*en$Pc~hjjW+(%nYSHSXPr>n*nPLP!Hs4o|S1k>1?vqk;%z zvi#`4{|jb)rUBP_2O4b$sQpq6?=ZcM=M$blIvq{jB>GCzUY}4Rcf%m2d^Jh)(v+q~ ztQCyhE2!!dBTX+pV(Vni%Tx!Lw--2G-D5i^fz3O;R8jQn*{;zB9^XsaC!W{M%!`pJ zL;D3f2>QfPQz9{=nyE!mVvmGLIW?h$_!2LSy#<1-N?Mrb-@}eHSJrpeG6!wW^@jUy z^T({;#z5lA$Mr@;(DNp4u8z~e`@PQQl>Fa_ucn=_u8Yp_nzr5YjpdMBtT{vo`TQ=E z4{}uaDKGoVU)53*4g9lbc>_|U7us=q{G5w#KP$&y^5|Q&DC1mL(QLGxn*~ben2SgK ze%)qCfvxF&p`?WmF?!-$NPv^`Kb9IfYDQwuXpf9*2Bj@Yw7s|!; zf;~3A9$(DZ(5+6oYd@1~x0r=EK%{gnP-Y42Y&H|^r{By%!cv&U!gpQlpJ@LjmX%jU zi~xgmFy5hcjtG~lyZ`F4Ha9;Q;=qp`WKc500EFh(ZfA%dr5<%K!-DNtKd}(}6z_uy=KHo(o+t3-CD{_3w)!1Qs=;{c= z%0YOBi$mID$yFgzxCzqiZn5ZE)jAhCU&3^&!{_c-e|6I>jaHG}W;#lYGDgGjSSJhU zj-M#hq0P&Z-}!InY6ih`-_}(cdD{OP;IW61%T2e#_jHihyo@|CvRtEE`EVUVwE)W6 zT18&e>|G5qQ+fH7Q;vg zU;jrS5OdGzyRtM7QIKCE1lpc6M7?Wi$8;}z?cO!J+c_~7n4W}ydeRfE6~LVr4=YJU zQUdJgE%<&=5F3bwpR4Spj&D<{G*-z1xisz8Sosfk*xb zd=D}DTT*)oNo7k{H5bbDk7YnHg&AYdF*Yr%rbfK99B7^i1!cPIBJvDA%3+J+qnq3D zRB*wLiYR^h#J!oI>iM_k8vVW96GyrzB0*#QrH@+?emm{V7L19kfG&>}J>ciEjf|q# z-{ZNbv18P-8{fmCxfA_1u?vM$jXL@cy-GvHtzbM)l&vPSYVc&8oM_YJ)2$Ast^flt z6Fzj?^GX!iZ6AzZe;iFheiPjDSHA=%E^ukgIhJ_;d@d0LMXCB5;OHnI6fw%709hzc z?sEAR;FD-00Wv{q_o0WZ8Grj&=w_PPu!2+BSLo5(OyHTYnr`kIP(o5%D7l&+%4-#q zG z79%f+M`7<)>c3S8OwqN5rGRA%OW4Nq-dv~5ZnzYT* z>0Kib#`=MxFSK9H8on?0CzjRuZ2fo5^}nkwI7{pY;@-}y;hX8x(x+$N-9H!#HpMSf zZiu-PJyB0OdSs?liFV1QVHv9w%=DWsq7FQTr8}}b!Ukh5aYJ~Wlpm^!Vna-O22OBv zuV`(OGftk6ezsuC38>-2?#CN4E{sl#&72SCg~5%w@ZjRfR%mpoxgpKK$eT^3LPh4> zX)>(a_zT(QyH56R^%RN925M-iJu(+E=Ddz;mZcSeX6~M;vFfr^N!63Gi}|I@F~tkX z&rsM*nzY;czJY*6Qu=Rv7kL4-syW19jWcAWw%E8f7y*;_##2!1+|>c(Tu`xR`7|Tq ze8fs4xgGqbo-t-Sib;3%lWiAXWjuNgXWySU%B*LiX<{B0e&CgaVx)!cN&wIn02Y$q zv=BIzba|DGeKv6c`#}4x5S?oHY13Z0+a3!}VD&@PJZn{0*|z#rnauHvsGjI?QP{!g zeFG*h`Sv+HJp5V)YYUMsKg2Q=J|_Sns`;bnb*tASUm$l~E75a@5uI4A@{3^?R8kJF z`=TpAHgyo#1=TN@bI;-sZ2Wf}wk50@3e%Spzn@c{BoWX?Noe97Xi>!BpK(IWYp$z; zKCOId)(z6~$o;Zd^=#gn8S$_XJM_HXNkbTG8L$~J+irr{dH#nz8F~@%y2XC?aP$-s zJMe73Qit(9oLVXI0ge0zcv3>&u7HdTN|1K-+_5o?1uyt$G?XGQA=jotO4S5Qa%P5@ zpU=dPZivXRa z)TN45w50t2<>osZ&eQ87?2aZTL85D29^vhn`;6aNXGQX3^V)}UuWzN89+-b(j3%R% z@$jZB&fpOfM2P7axP|x4|7I=^>+3HfWO4-0&FL%V9#4K2$QM9DmM)tAC2kD!2=@mo zE5sFOrw%DE0d}%SDH9)m`0xIn28ylr4izI!8nrwxbA}NgUc@rb7o(ZM9M!1EkemL? zz1(x>ZaPeKhgQW|i%!bSH^|jPh!r3A`68vC4yP zx!U}31N$bT5WQ|VnplZpDGWzmEr|)P zX$k<1xHau7O@#r00WC3MMmZ0kK8U$D09C*mmw?^GW+&}I_46D0{lpiqY$rkT*m>!1 z;Uq9Z(0+0xwh{Y1?L1TtqxKTfq8xB;2#tzHEVrweD9`%CJmE@^t%(t7#3-_j_7>J% zeYWMhqE*H2i@r8X23v#xutWZas)p!g+wT(084SiQ6?yq0036Qd^M=VVyqA_J)^q;o z>^v09KO7_K3(i<-ONK&x581{)8MqGLD?svPEJVPoteMwLm1;MOeayN=0@omg{Jn;MF@0s9)_5mBOeEf;sc3*Xz7}-+rQs)%WE)`l}yc zM8?!-MMQjkC2836`XUutmoh>5y59l3s?`6$&up;^Ueu)dDV&{Fr(PUh7#hu0l$hfU zO)2f<#&`CjTom(cKi0XiBB5d!=}>g4k&$}8ea=8T*T7sV{>;9pi!m`iE3izmY=jt% z-{)3%b@28qchhp`Eak#{2=`DePKK3y_He@71iv&@xQovtsZd3D}L-smxfy^oeZwZ=T<8OB?6%AA7W zGS~C4;K^-<@_y!V`2ZAy1<8UBj%2&wPkBBj*6+3LLmObb`0zq&q)vz*+}jD8deHsW z-Ta0V*>+#+pYm|!b%=lJqMT$SVdPxC@vUX#z)3w|g0$dn?ZT!yG`^Tay$l z*KDvRUMlHH_aM(GsKG-JkQ9PhGil%H_JT~u8AxTb%@*X;oPT%~7N6M;52NAV)Jo6Z ztyZcsFS=YIz>!8Ecyf5!mjw7O49^#w2Uu+IB+|_sB1a#?1o2_YBLMEH|AW*BS*T<` zHNG9SzGZnrnz_)gZa-HA-`dSAs_R$(H$eYyJXGl&r4csX^smatP;ZZEFhRLqLrB4% zD}`P+@^C^8a5FM8Qs;SVhJ=I!^9FmFHGt3vN?Va;P7DHSaD?TW_0-}IJ9@xy15?Y3 zAeec%G!K`_3=+Y9%Qv@?i1Hah_!z<8tC}jx!_cW!&Ao=s&Z61!^a*62{neyDa(H#D ztTX$|fJ>Aar=r0BqkX0z^j1le7sdY-xLt4l3oGg1n=rs_rft?1F%mwIm#i#B61MzQ z9xgLzh6LhUN(x=5W3;tGL~;13UW(tzSN2_&K+4&WRj3IE+=hK_;k6cwBooOdl5fKL z8jLljmpK7jpb9P4j&|+R43dtYS!S@yW8b{Ru#djGfwv5t;F*5=G$CGifu*Ctz079V z4e>vGSDWoNQM3mES`25(+ zTO)^nVeiP-Wt1vM@k|M0?hn{ji<4^uzq&1j%y8K#-E>1B3ual|O78DqZ=gZvqr-Jq zIlF9)m1$bj_CR2f%bn{hKE~%hB@5|iWkLpTuk1^fpOB?u97%}|J+l@i&ZZa z*v8RwhE{!ouZGv(hm6LBW%t*K9j@$xSm@( zSAiWysJVGpFrN^y9%>|)mmoChCHjQCxpEC96MV|eF3g_nMO5##5WvY5S`!;BAdf>z zl(V{lxxs>QBZ{+~26lZhC11p987Sjg)qclW)qbd!<#96xs9JBZ=thKpbB(49E~*L+XLgz<+EcS;p@f^h+H} z>WO7^yZWjK<$V)h2 z-i3QwfNlPWQM?k=VV$k%yyT>Nbiq=-eMG3MNhjd0Zh>Vx9=;y*4jS=+)N|E?S}U15 zP4P~BlU%hy~HZH*s7C$2@j9oBuqM(RClO1lNI zoM3{7Qox5^q{R1h{;Odu>K5HjeMk9({5a0baqWWg4$nlyf){Q3R~72r2q2U8<4m{! z)c?(UE4_c8(BmiGCWV3sVV5-Og* zqVI}W+*8CgXG&wyusQBHh~h3L=vsOg(3bmtoyo{>1EDhr@7IHVvEWj30VIMhcvIgP zkb}b4F4spAa5su6ml|s8Juo9YAc!Eq*~-6eSRn0diVV`wYj;T9^A|HO6UjI0;GAs%R;#mS!3uB4A$C0-1P(*f#3{%|7bfKj32&)G{Uu_( z(9PBzJ-38Nrul=<^5vo&HlX1rcHPN%kDChxEe=bYt!p|-5chTwO}bD)%Qa$lgghb? zZ?)%&c_pL;E-&u-$aa$BgyYw`tZMneoRsR+*4=GpsUP`HK@8|dyzkw*+4yN{RZI2W zm&9*p8Vw#~RMaIV7>e(sINn{dcY}uzyPriMQQBy6k;j2fKNPbRh#O{2(s^lao zMEQ{E7FddwnhGCTBeendr zu8#1y7AB6EVgQPvK@k3S-r`KjJ$B}CO_4|Vg}3!RM54K1Co%xUYHAk&|L%@*j>uPa z!8+T2%0YhP zSMMViPr)e~Di&Nm&c_PZR-f;((>niqb9u}43r!%(beI(-LG&yv4B@p}L?6G&vHlsg zHW2itDwim(uUpNYzC@?mm_%C4@ABta_({O9y2CxVIsKsueB=3PH(j7ij^T}y0j6yh z?TeOC?sSrf9sksVswF9%pf;}A0$uKpkRvqkn$2t)m+@PSh$Iokl=V_5-eoH+@N_I) z1^K+k*v;=CEVPQo)cIPMXC`=(Fnm{#fonEz1~Q4r?sqVm5kyj3<_tD3oNz_w+!hEw zW-c;C6rEbX&WX0rfZ%qDvm=H3Usx7XdRa=IAEV$=#^V2VS~sEh#zsJ)6meIFsglpY zi`G%S-y^gi%p7FvbQC<_)&E2 zFOffr|4nep*kfdv5vjK3oTi!&sFvvk>gp`T+OBJjO(yYn^CgnYfr#G3fl&TT$&m;` zZNww1%V^?#1Aejl7$Cojb!%S@VbulkY{D4&_PjhlJaEZg>49>7sHG%o$31{pLTOaw5DL=03(5b3c8s!VaC6%JxJ@v+x?FUwEnaw(*66_0Fs z9%n^>4509(IX-+f-EI(fPVg}Z!5Ssr-+6`0xrFiZExOh0vFKs%j^M0UKx)~NHaakq z%D)ngi>rq-RIVqsV| zr!Ck~>|W0MS)yN7ki)2vGz!-nkFAwH|9ZdwU^l}g2>qr?ael@Mtg<^2BK?X5mD}I0 zn>x0wNkpiyl_+AO!ewKnCGZ1{PKBn{d~VN_JiDE}G1t}U;`Zro-X|NB(Iwx+Ibg2- zl5^-4|K)gC6OXVk!c}GSAY#AKm)?_)4O!{*rK*A3cD+1$g6nXoAqs_3yN|}%26e9Z z)KZBfVeTiy-Bx}1^wGL(Q3dNr>9}>A_0HMCw9H~@gZxesLe8D#h;>IPtEb_iklC7M z@e5Y;{2Fb!vc5S)sUdEdlDu8-+kMvb9bj>Sq5I$5#ZjicTetUvTNvn%hPc(~EXE@p z;DYa%zvTCI<7ygZWmGzF_qp2I3tlN5!LhC=#+OnZ zRw|vXq(S2xYmI1oTCUr@h$9mvuaqYE3u&aRyNStVv$EZvc6!F^qV?x5CR|Q7ZwpG& zIpYlm8XA|$u{>J@x5Oy(o<~6i6)NXLtcrs%{DCdt5Y5Q~RyrC*F~a?VEFkD-$&52?_C8zU z+-wX=%n3YPU4+SgHRECuD^=5QL6(LLAcFYa zql?8qb|nq5RUx>VFT`D?en;uSRMZVq7SBY6aurdqQMl*4F4)%@d&*iaH0J@b(!3C< zXfP^8WN`O%38%PNp};#ZQpWN6%%h|QhdampVbcd{T{MAoG(|S>w{)Mp`N_I;#j6T2 zHCr_t`|*j=bOy5`|Jx85G&;7$H5JBe$)9nem}1T9Y+0m$k&1CaiQK;c+n& z2wRN48!BtDUiP^g?4|YG(ro)YxZX9!%^};H$~E(p9dWSbt+oa z*1|P3E?JWoARQ4B8g%7g(Y}-;?z%0pq*%A={GfO*0li{Wkd6iNHpM%oE z<@tL;t-D4(vaG~Nhm|emt^S-B)cq;Yl>pA>j`p`I2ls~EDMBdPpz2;_AavYfoQL=~OR*lfuD4&z~ZY5$*56zUtl@6zjD zK!c<2o+4Uslds8c)WQ1$*Cii1C3z~{2mP{_)V9)8)?ei$v?k?R6XV?+`6E4~GfN`1 z)dwakS@(<_stbssVZ|o~rVQ}S2?i|nn}+~ZN-%I${xq2vddqp_ic8?BjX zKApE&|9e45Pzs;WTu2fB6v=IOHeYUcre3c1)jIk56%UP!#zW&R{%wz*Q&a8YIAviZB-@o+5Br9>Qls;9jwsfmK)2egQr?|G67ocC4V zQ-n~2XuMB|e6}s%wNfFRuQarsb~%4vcCSb#(jtx68qR`Mf@7Hqt7Wx^`x)JGR`JiM zmO9oi`*MKSkJ)&nDaeBcFGr0M!AwQFITqBPIx>Nk0GAUlS~|Vr$`SSAxtFigi{&ax zy2*E^JLiA?VNHwsh+C*o>mOZ`dvt`{4(ITCUQ2+m;!{VS& z);H?KeIUV6GH5Nyz!(`5<(~)ENjc_M09;5Ye0Z4{LOYCfsW5fLBzaO68CPq3d2wjS z9i@jBlXO%}{FP4$i{xX!7!@GITY@*yMr1l#%?t}g+itTIGAx;Iq^S1imnCeY2~biB zbt2cq?(1e^cdMjd4+xi$ArTw4GIIP~0>#AiE02Wk7|lJq*?D4?L2c)7=FG2BoG@WStmxnfO^9@bRY8J z3qRXctdBcsgPGn7Vl~*AK8CkLi z(r--V9Y^IR#x!%$xSj}hPeO*}tFs+%{;JaU>|{w7LlgbEYKlK8LPgp)A75CrakPkK zFfOM3nHP#fYC-N0vCe=RU$Qr8l2ru9qY#IuFNK4~j>_Rk!rD^->8Kh)u3#-0tzwvr z>NpleBcinyqeIkWYDKD60+`F6As>w}<{`qa+8ynvgey|6qDmaj=T%B%h#X|xWyCBs zB%M@Mu@yiS1_Bp-)6ixb4Cf;zUn=I>E!hTe%JvohG?yRyO$Fi>Hx@E{c_2r1OT(u0#keDjUy@8QE@B3Pn}g* zReTi$usgbHd5Z;1{XcZQbyQT{8$YUq4j?c?cXx*{Lw89@3BmvZDj+!^B_-W00#XtZ zqLjoC(k-osz|bY#3^2q!yzl${t>3zL-L?2*fPpz@pJzY&`NV$qwwK6XwNjBBt%y+3 zc#@zy5@O)YpGJFI*m+`qUSjN*ABDN^6dSI=j3*3>RVFT!i@Zr0O*yej@t4J7zik@! zd^KCo!jI$jFwr4MsrcciDv~i6@KP~B+sGqCc0WNold=ADtb@2YoJ)A; z+4%J{x#v>t4jfwP3zD^(jnufLFv3nDQ!qa9`8HsX)_>mDr42mJP9Yv@jyXg5H3(Pk zu#lS`yTAZZ_1}sPrp5%aveK`b5m~Hne?!S&=ikjSG{#1nNUv1Qd#$X6Mlo$L33^$E z=K9Y?*$xSI?-46WF{F8ef`bJtR>94QL4P7M^>N;GmA+%t~L9E^=E$Z3hVpCvrYTFb2z7Hj7XGW5$y5zwDlD67dYdF9P18Jb=f5Y(VfVUt*%d| zX&(KbZJ`-o+(b$KS-u})16J|sOs_egRaGaz1Lwv2wI*5W;%`CrKbbq+YOsU}b$Nvb z;eAT=OU(c;H8$3Grw^BzrXiXpnh-Xe&*#l@`>WLLVC0=;U}jSLylMu$n0(bJQ^=np zt!%b@lP39X~ad@7|znZuAr>AARF9 zLPl4R@km77ZRz(Q=z~TYMbCJ@$j{+Uyjla15%$$@Q{~YiCmGQ*C)5aD`YM^P`*Dt{ z<_Q_2o5yNpKSYu|C1U;>aauDw|CEG0s4dZv9JJ8KdVXkJl=7tUwd|J32U{_FgBmFh2j@?tuI^c`#T}r+);M9|i{_%bYC+;$@3xpSuQt-zkwxY&;0)JcB7VF!SPnQbDmwa zTnj&>N^l~%7tqi92U|WVw`tmnd+66ZI?NhCX!UzxUuBUeh*~W>W@eSJ2mzaZKEcE} zbu;)_nnD|F-M$X2KR+z_ye}5^kgDC`=Z5(BRmQIxTDs!FEd%aUxiZu*`O%_WcK`5g zRU=cnvT@g=&27(z@Z3qECmh-z(w&uf_yaf~{3+CU;==sT{g*`bBGBX7QV&CmaW`nb*SspHI6kLYe6w}b^0A+4Ge z`xJ-sGk$EloD_SotmZxcCs6L0w#LZQ31!FnVHHwNyl@`7^LXtJ2Tg&(cps<5$y5S* z^FpzqNlyqG)Sj!q{_>Yr*FQ<STy~A7syeqUBK;^n*XuO;q)< z%g<%Xe&N`n=RE_kSO0tezr|%{$8FX5zoEE&!9(%SD)oQ;sKi8T;o<-FJy3vHSFtGZ zw@Ge&S$<+-g*(~e?`v!{@z{n#98u>b?KWwnlsRJKAD0Pw74y*sIjoa|Jy-*U6S_ z$o8Dp2p#_22C$GDM3R3$Zd?ak9`rWx*Q3U3pMarF9$RYCpa?F z+om4rC8az*wUz*!TC=vf{%hj%en)-lx)Q5oXuxxTlvqpe?6&G8guVuz;oB|y6hbvjVA$TpkhTbP87;^w2gbvoI5l0sWfBsKdvkD<4<{!>HI+pu(f3dFSJygxd->^YI_*|SM1@o78O z{}Y;e57rj=?)bD3No`m5t#gsQ?t-Wxb7XuQ-GZ3T+pvlI3VzXLnK!;hv|eA7)%d5G zd)n`#s(KkRJ+vXFCBQM^^t(V05sLP^_s5tc=*AcPZ`XeeuqAm_;p}6uNkO38VIS+N z%PrXh!28P3#cxBHz1DgDrtRuOx`sQ9ftLt$`+Y_vAf&?sl3j+@f&O{9H9=0}IY1Mt z{%numPj`W4o$q%Jo?%*i$)KA+EV0ZiyKnSny!_Blt?Cf;khp2D1@k(r`|XkS@!zps z;P!`QO+%0w#L83kb8mk5U!6?u_A&;(J36oaA@D<1SEq;4!aJ|sS4ZZ=@M%|2FM}`N z7Cz8A(w0>&<>HU|i~38U^lQ0q~g6LSn_T z4o8)UQ=R;8uF$&xN=exwtZ1+Lyzp^lx^sSN*r|S&qZcn;VvVZd_ozVK$eyD?!{Gq$ zr|+->pRc>?8MZkY{TMv{o%08eg6 z*4S?T?H)m0zr*D*JECK2Lo=U%!sJ=d_SRnl1p5UKIdxTCd=DP@0I1dp6#`AbWXG;H3Ouv z;r@8F)4Zaho^JN}biGLL{#uu?c+Hlhph<-Pz7=Y__2zmi(0z8)=?Ly^C1E*(kLYJl z>#OsTle=;-WQMKL@y7E`Vo&$Lrk$I1s&9kYVZ|GPq7se8W*Y-gCFD_h93*3=_O$2KbyT>uXsv4U}t8=4Df#wKfM4sn7 zv`>b~qyo8fd>+MoC2dLu%b2YAZ*miIe}N3Q9apWNsSi#;PrASJXq%a0LA z9IKqhF?K<=o=v`eVzSd`PZJ@*5m z$w6pwXQIrwZhsJ%g-kJI&4QFjsRoOk@8~&}>2oY*(j!3eH!oKJmC;LizH0a8PZ z31TUVGun(IN!|SnarLnkkJ(ls5=#vPY+^lz=z-AEm@bb<6+Rppx;?&@Hn{r`yTIAe zh@9o2bLTY(22H`d9kp^dds-=i>{<1X|kuMiX8rcW;-QXo3 zM9;X$HI%cwcD=d+ruxbUji4qNCj9Y0)yFHiR|FCLhbwp})9fUC@#KxxRCxC8w7#6FG3o|glr;^J$?r?TLnvz&s* zOt~Yl@sWFOB!}n6yw-v?cu5TSaixBhCX>MKS;)kh>~lmiq7z+uBa;pUtrR2v4(-)2 z%sLZD6{V5Rbe1h;L6`^1?Z6~`e37}Vcx@C}Pk`)D3(JUw{uqV-BRjkt%7KpV8A zOf2;K`toSx%iA9($-as`*fH3s5x0u6$!*xWrp@WlKQ%-F$|Um50~1_Zmch9B+DQxE zz)q`f<&ey2{qyzQKxKKtPPTkuCRdTDH)|QT&sl=)G^Fh1mhgG^LE&24kG2?IR<>3#vIP7w6I4?M;rsC#eOYmHp0VG*? z`52sqV7LMrO1XVslnfl#;Edvmc`M|xX^1Gn?f{3qzU*)TNyFa1-5RICNh~x)Ij|DA0&2bv3~tVoTuEHRc=wTIuFE`yg4-z;9|lQexs#QvLTPD=fbpeG??g zBT^%mxXY}2VNCf*^3Jr^>KcM2VLr+_ri5rEut7Bbroa|dt6MpG+^v zF;a3^pcW#O8lw>op^HU1nT~MCCWAaqPaaNLdE;ltT#XbfLzYNE>2$ttm2FsegR}SI z9k`?W+xxMi8&|=^Purg5B3l-gHb?V9B6H)y+!^n4GY{ZTN_AOT)*PJgwcfB0Tr;Jg zyY4KThG3$Aw2jeYN>4mxb@t|9;SrGNvbi8wEQ80p*F|*-r@=x*6A}#>rxOf#@dM{; z=FNE2xSW&=l~9HO7aN=iA~lGt0B9ZthE%yyu_jWaM9?UJjM<1Dwb(+gmMHpoJhjL* zt894uWLIXOik%x?Fid4P2*w`wDz3e)43F(RFtT z$jw~7*KYm(nt9n|-sH*RNQvD`@{s>d?>%DyC$+OI@IXBZo z5{8lIrCF{a7UnWe$ZA1JpP!lNM+66Au|hCM?*&yQBzjgV_0FVfU{H9JT#CCqQsoXc z%yr@Qo_$muH(aj6XvSULTsxnh1>@Ah4yl!{w=^(tZ#p+0z|g zx-UFb@6t@v{&2p|HS877hmv)IxF3pS?%501OuPB7@`StBFVGCKk#S(-6@fY@xM;uA zuoo7AQq2S<>vH}i?1pNb=-GA|wy0Lsy5|3abBydywtA9~4_5>d59NA6%)uoct-->G z3!Ozic?))j8^S96)QGK_bTpZ|5=NmM;_}`fZ2Bc+O28-I#VtENz4##*n46x53rU%R4<^&B@#F98J~@1uj4`%a($-Ow%aSEp zshe@A_)c>fw?!4B8<3Q$zaUBLL5G-Gq+xB&0bB4llijmYtoVsoe3M{9gkZy0JnYnY z;-N|r9MF5dj`kG*OQ{=^;1Uh`^=9EVa_QmO(&uN+7Z=L(t?~`x5`d7h8yNn&KP;yh zSInYy)A?HFi-XE^#kZ?82BC^-{;fUq1`U1nE`>k!j4jEUpAg`wwx<(B98zlL2^;W) z4d3sYgD)=EU|^Aqyv zd`owI2Gda@NsXA@rWfN%krbr%hi`?cdtb;0=;9D6rh+tWmXxXp2@{CFjj7UVP*L>n zi+Py}3+1W3WB-!onbHbQs^#WT3LhgAvhSJ=JHnqNS5YzLc>sH`PPX2hklQK1*bJOb z)*J%I&d*vTt7DpHJon8QOrRF+kvSe!!mS@F%ti$ui;=3#h9W^O+gK1+f7U=IQr|55 z&`^>b?ZyXgl09KttJ4k@{5wl;VoW;3-a7~=QeG)W)>1g&DOrvZh3Z>`gnR~*iFL5| zSyL0hV|fqxkC-AJrq=h1JyM{?5w6oM;hCI=J?75bBMp66zK6W$z9Tj1*%Ct~7uv`J z|JGn(;2M6l?$cTc9u_X2Co9DO5c!jTY&I|^x^?{rix`}-ti6wZ=T81Q0CuAuDHMN( zV#1+Z=6jwCGmg@iryF4RQ_(9IPK`m@@KBzg#c_uo%#Q|Ix_daL9S_|bRv>7ZMt+mW=s91l_3O9Kkt zR@LDk1zcl}SuN`f(1P=)V18>{;_2XJrZgm8WD*KST5ZWw6VgwFn_3e2NXkCYq0h>W zs;wdHZyQ@G?%h!8VF~&4kKQ=00^fmVRLNB`Fm#f5 z*#k4?)*-u(U$P)>V->#jU`J2kQx*78g1q;r!u=@GtZojDvu;V;r~6h1;fXq@+PqMM z@9A|c7fd|+@LyhcJ0QW(cnzE?7#1g(XOM-|KZGen{<8!aF|ib^jH423m50Aby2!m- zw?V9E+%PwO%GI8^hZQ}t0P7-LC&(fz>Imy=L2P@s3O+fYS7NZmflf!Y1-JFj`_MPA zY#6kdQCT7|Vbb9s4`9ISFKLAZo%Ogz;ng5{!1L(~D}E_3AXelC@zPplnQu9m9rnMI zI;LSCvcDVSXNWFxk$7S_w}zo?KYnlK3_;||-UdUmdo~Etb!|OuY&ZDsQQlFIuTZFm zTgEq&_7>(lTL@NMu%fhoZ$Q=jDwaa(9v(ik{VVLr*vPgmc*gNE9D+qc)khH|ku8iakNC0vxHv8sD#$N3L2^&uw+`~K;JfW*rt z*`?websxD-;`OTsH*3 zy;S+KE3??YJXe8_P|(kR8LvnjC`%Z=*Sxy|kz@UUjyy#38sqx~-UWNE+z5cB^>Z`{79Vfp`3X2Spb*#GFZ z*y!&6AMPzyycgg$*5f5NxooMvMs3EM!<#Z18|ns!p!3_mO>7AN$6yRa;bj3IteS%O zV-?X5LM;173<~r(E#3l39fwDrz>T2+w@D*_Y=`}ihM>CuDv7_E1M1T8tFz^VLkkA} zF*VhrZyhc54dlelKa6OAeaU*BU#F)uZgu6@pM-=k*CoitX&THK)eL@2d-k6)ckEthBg z(xF?1e;%$S`xIXa;1nZ<{VCgAl@>HW(Y$sjZzuxzlpiQkU1{OjqsUxfdqTXl*I_@W z)PI-D#kuwmeHlxV4lpXSv@Xqy7Cx)wXrNzm!!3!H8nUZ-;t};+n<+fb(||M9bArAR zIYs%D_4G)nw>lHKh;8BiZLmH|vu^8eY)8%B`0Ul$cGzyr%&F%Mj{l_l_Ym_D4`R2~ zl^;^XuDPc(6JpR+Dub{;z|f&?IZMFi8sE3>d$PF-uoA5GhlSHI~IU69@Rz?;J$TMpY5t%l;gLdHGn2! zL<2akQ4tt#0TOYYlAS+QHnYH^UKy4?((;MlKLi*m{Qyp!-1}Lc)AqY#YK$In%t<9~ zG0vXJX3tZWXWv!bsJHY?#J}m#ra4KYmDukL9#N_;3fUq7W#-OTr){D9nW2->Gst#E zne?mJjCG3v{+f2kA-vk(7Agj=4e(igg&y&$=zbHB*AmgRtLgIhmE_PSM?BqjfY13O z=q6flrD52eZt2)X&usjcPeR8`2?6WKTMI%nvl6_dEVl{S0AV+?%} zOuK)!AwcAj(%Xc0bG>-&y(a*DfogS5ic9ba3~+U+jEfqljB)V@&-Az^SAIYzx*~;M z{<(gyf_Cx!+`-aExt9pbS${iEvt!?p6CwnoMO9R01)9OR{p9B|&fSAfUTF62H`_D`%=ZvZckM{Jxn}ZK`yy$IAA%k@s6# z9v-#86rS%g`Z^g6P|(9Wm7PSlq_S73;iGcWmG#?q^MvkRvG!a*zG zoZnj!CRTkdH!$G;hycnsbfy5m9WDh(1MI!*Rz*A<|B%}N5$FMQ6}eg21NlpHohn62 zE|%f%eZ}wM$GKBiVcpw7Ah-?4>`ea`;ut^jwI!0ucv$eH7vPYZMX2qJ@xfYnvw={Cw6H+djh-hO}{ zNaATGu+CAaf3mymQ0Hk*X(k2EiYLw6Y*N!j6x{cRZ2A1H+U9UxY7K1cFNkQk2{`W? zYT2iG8uYF6i+jTh&+p@LjIyIw$EYxp=-CELhx6cqi;axj9!*n|#2csGfPe!LsMVRE zb5JdsIJEW~s&~?9UH`-*h{+qyG#H21H6dfZQ&{D^=JTFt`cSRT={%=b4EZabvfuXV za*5pecMfk<2uU8|tbXIN=o^#3J)8BJ`|*h7oAU`H+ztz)>TGG~tI=W>u8Y^3Egxww z7q806!u?Oam0bW2)njW18;pOD2N6hlIcyfH(5iLmRk`)cDd?l+ zE9>|zw)hkqudAB?y=&XuU10r6Jc_Cz))Z)X z{sgt+5}CPzynRya_09N-SSb}bzHjz5_c`V7sKx5 z{sc5Lh&n{Z)seZpE6BfNBMhk^HPr*moh|V>ZyN|K^Fw243JT8aywh_jCXagUF3<|p z%`>)DxqFQ!jOh6a#{NB}R==LFmGe$d7oD!f(4Gdp39l{ZeU(p7ma*HlxQ{QJ%XXFm ze6LiYOBm?tyqvU0yxCFVB-Wy{Hgu`iOW80}IN_=x#EB{=2V2Gh6Y^N^w#qh_# z#>T*wz|K^BfpMaC&zB!;AW*XrBNQien<<$0!5hqz`d_D%g>slCnN8&7kw3Zt6>3f3`?3D{Rar%g8&JEr zol3ytU`-P9?}~E+Oala}`&d}w=YWD~>4GRE<--5=G2Z6WRHg!`eC;?gg?n+9jiFT6LqRG@GhYzQwUFyF1Bo+1CPaW>WJ_!=|#>-f*G z2ah<*ZJ`c7%+EFU4~bX`)=%r{Mi&TAwJdt~q5X0qzVVoYK`oRiW|zFk)P}?Uqem zr&^bAwP1duI##U9`1E6&27Nam!3r|(+!oxYlA)~c9(zz|z#<@;fVN=UpXLj|K{0Q+ znVtF8R^(_dQ0?5)aesC&?r=3`*aKV-U`{kNRv zB6R=vNwsafQ)jDg6=mjxn&+XF6&OYUVN(fZ9C;@+Xc^Q!`xKx{N*v>r-eq|q#{3<* zdv1<0F=vfC=AWHkF}?8@BvKAYIJ$HssNj&GF_zd)vZsA;dcS=q_ijZ~sOIX`_T@-% zE@rblWW~Lp?F79+DAm|tJT*2{g(_;d5k+66*uI>7d!D0<>_JNr_4*jks|4h}xVCUc zjqaJ-d=%tNxSlbZs7c96XS8T|IyaJ2q5CFFZ^i!C#}Rg~VqG4!8}Yh%#D@UHjBI)D zIBkQ3F>2r|@+LdzuTR7Zaad1mDU6A2b4e||_P42~VxI&fIXtz{pNZ2}wy*vv$ZciK zJw6v8B1x>{MKhbT`MMI14CvDeTjfJnO;w4kI(EEf#mqsUt0u9siX#}_l)z*mZroa` zTur*I0aq(~Z5`47!Wcc8e=F1Ia3M{U`li-EccDf~;l3(Wv`3;lDS85^8U^A@c4wPn zr0{#m@;1x9R6jaBiDV8Q|u> z^Zb>kcdK$Zi#c=@Z@$^)*m6UC4E@G16(bDpMiV>c_1%+6mpP#>Y4})8EpU7QR4-8&{rODIk8FGFySmXCDhfF|hp)o3)2!zF z(dH1E{)T?Bh<8-7#4^W;ksns5ip(#hCriU9OiS7wCKl-_d3sZHsnRYInU$(LJ}atA z*$a7}Egt=g8&whMA-ABEiv|Y};8Bm=^hvDyyRs7v6tyjVR#UgPxWJ*0qmc3*R*F6S zpQ7XkFqZx&Mv#a7LG^%D6e-xEPASejLLa8?YO7ZWiXh(|hUa~5_=vpEvc+AT#o{yp ze{+rmU?2(rV{91pKRg1D@x#s<HBu}=zq<>O7Rkz}MT``gawp|~WGGDqEc$pX)=4Iw*jy@ttLn0GxUw09^G~{g2 zZ<82JOl74aG(7)qOL}Bm9(pHJy7$>8Xr4(B_3E_-3aEr}Q9OLv2Q9xEoK^X9wU_pK zS52`?jp$NdaSy_-cDaB0dWI3Y%?VLh-}_cid!-gw+C01kE}0jqC+Fe4?UXTjB)@H0fV@GMmdN%Vg9_x$PTjW?d#~ z&H^3)x%B8oC5ER6%^!u#H9n<_lzBhZH}q|DIH(OO44!D|!*|Ml!?(R=>T}gB_p>LDO6zo(b6Z;js!9Sreg)7M>WVfpu9QVt7M>jA z;`8Ps!SAMioA3s?xz=97>%T$UNAogoKAZWKiJ~qYcD6pxc)dTpCI@}waqUP-0!ihvt-f>*pUx9sB81G&%5x!0`J z*VJF$5xc2sB&y-plMY8zMz$5+u_dz(ipuH^0<`aw$seI*;FUvGIvw5`aoicF`fS5+ zl}lmM_izi z^>D|z>+=@T+6y2TunI_@=0@q*9>^r#Biwzl-zG|j@Z{>He@c6i z6`CD@)B#UP{1Qc=EI?>m^(Wlw$?jLRx60k_2y2iSccvA;nAz6-Y3t>vE8qK^tNR33yq>vO5o>Ks=rBwSwdyy&X55}z@TjlWV7NY*+^F9!f!e&5M z7<5_}TAtki9@UMX1t82+bmEWCX7$du$lHU~u`+0-WfPD_^^78aDD=kDe?s1uIAZ|V zoO>fl?lI!iYy(2Ek5&N6C`B!O-lBDk`jeIav58fTv5< z`}*A8$lYtk32MxRevABuuef~(Is2g;LF0_XfV^E^Qu+Ed68DqB(@eDGi(VUN63&AxpD4P|j zl_Tz#`v9x(C^y+50hNukE*;o(N$6+tf%-6ZLpsil{`FzT{{8`Y0$EkcxJqnmWYP() z0HZ-w4594herK{ktdE9SaWeYk)(VyNw_BN~?n!#;z+eN~ zs2S_?7_fMk+-JdcYoM2TT69rl3ISi`TSHZ&c$rg^($|vD+U`I|$OZ1eWPONPI7W`B z4b^aQ)GwmoMKz4YJPnEvI60lsu^^=oPjdi(C|D|;0aIT&7}Qd80+8-Wk7Y07PDkaS zbKV6r08W_&I5YvH7eKDI@FAXAMI!DNI31JcfBvuZqUNg^RZLd;E~aSVg&){G1ho`M zXMOxG7F6{pBC8Q3j#vav7wU|aufh!Y9Y(Uor|<3!Hh^g}N%g;poi_h@nd!uqT>UAg zQ=oajW9s|`*`Nw!T?mwPubh2mJZpu<<T888d*2z>b8}ACEC&Nr5Aw2W+lY~$l`*sqaWb(Kmm*8ZsY3>mNJbG=v^QgK@<$00^ATv zYOk5KjKdXp%YY{$c4;NH6Hwy?h9C0)og`B|52YS!+%~{|zaMDP89>M=+uV*nNe9Rd zWpe+8P0{Mt`niEQ>$Zs%pK?|5LSHg>i8rIh9&jH&bk8S zD5g4>d5extgk8tYHChhg$#dJi-Z693S^keSKs&5rh5d=dq!@8M(fUK-I##3$ia;;s zfBU7c*}sS6Rg0xcB8L_{OQjY*>Liu}Hfed12w397w68Lkl33LSRNhOMwhd_IwfyT2 z6EeN0FADjD&1dMI@EI$4u8ihqr;N{83(D?|tHMR;_gm``;wNCX$~<&gWBHo&XlP#R zc|p+&hp%A0$h&GIy@0|ZS%5I?K;-HH&Q|0)S;6O5qQZ0vX-< zn3p8k9{2$z>O0bAaA<1E&qKg1<^~uXo%g$Anv!W%{rv!);n4KEeV6J;G(+AJz!!R+ z643O%0_?Ph0p)@hETf;*GYPu1rt5lW9G){q7Jpg;FCH288G(|FtzbHt4+{8|EZ}gw z)M3B@HnX4_@rx9`2W0BlfqVCFw&MNXQ+9(>nJ##~iDo)NVN!LW+f;QB8iHN3vclxh8$<7Skgm#LD~!S*@eF z7225XZwV_LY{}7CXQ7#_Iglh3JB~f(%_z(fm-=_*hpCD|qY1JX>T|uQyWbSaZq25C z92GWzwJ*fx(X(7Tf}LeftbdG;P7}+n!1X}A88O}P;DAwd$-$ko?7i31kxDVw2TGM1 z?&QN$k)6qO7(jH_waxZ;e;K##eO8O@rl3rV=@(v>sp<7{+B{pi`%7yyP_4ncpvMe# zeaP%+TyXgg2nP7vx)NJvyvinJ8({wAJ!(Vd{tzBt{$e9+iQEUu`xU@dhKq=Hb1aBA zZaHF}JP*^%@IRfc{gwahdf;qKcGdgt^859_E)^odbox3D1$FZS6t*L!f3 zpB@IdvSPt#$ps$i0uI*G_5l`Npl=lnYVd=+}tOAxlq8?b#vA=__hMV{g@kwa9p0E3axiFK?51n1_yhFi8B~-1Dih zzpG`?5k(M)`L3`c=I#DAU~yMDJSMGf>SKvfx8%Kas_Ld7MZ|a}oAU6ul~Wz=kminL zy-bifO?+*NfLEZT5c7Fq&maNdCdgtm`=oaW?8*qAj*>nmGTLg%Phg`t{RZK;fjt}o z&pSt@==t7F!P5(hwG4eY4>I`c$MrgZ8{|ed{~}&(7O$=wZu~Pr*!eu$1_`8?A7UX@ zZCGy=F-T7o!1Op5XM2(yP>dO}GC&wKs(QqNMxG4{5f9(b|8gqf-(y=1PIww=_eeI^ zDa&`a;VHAk@SoV96g|II`cqb6dWmtE7pG=J#7KFp&!onc3qV6Jjm#2( zd5YvJ+En6oSXnoUE0H+uU^v=EqI1Xuw&-_4DLsvEX!6{xPizBVxHE@6Y;KiielX_v zI%`jN*Q{Z$n^|SfM^RY}&8$e+AXRYaMbh0BEV)FqV4{yiuUb5z57pW|@c@x)WkH-j zKBjt=CC+SE0*)Ge8!2Qr`q9zi4abrmmJ!u1yB%X`e!5!o%{4~Ca%)d8H!2hFZc0FG z@Trg-68PaK7a^s6Dc6ya?=oXHApJo?yAX<(FLXL&Sz=wk{Iv|F*u`XE?)Yc_=q687 z#B_a6jE)YI=gN!ZJ)-fTa!Y9cvz*g;^98m->k@Vm69~mc$feOhA|u+))n*z33DI|1 z1U#s~+`@nFTzv|&%Nsohqc0VyZ05Eyo%46yH41vfy_urVb?k5~Q29K6mjt>#cBZ!v zsSknTC6;Na3ZxV80K&$p-g#E}@h{ouIU|bqt_nMx^KKIu$mduFOJrR(|KX8)^m%Z+ zZLBHC|6{K4-|vVE5yn_XdgACtGsL=k4h3y^Jn#EcgtKV9?bsb{Tq|>2-5%=6$I3SF zLT$uQMiOAJ3ugM|GbA=irk6zENOh<;45+V5`YTwE`M!+0Le@2d1R-7b1*pC#p65}a z9#%>Y>9&BM8XYJRBZVqSg3o$Yl8hW3*F$Sae+S)(dA1aB5{gHV1=fii!i^f?^kcXM zP!MwDv!eiK{SrGJP;+o*bS1>Hpb7WHfw1-njbg@HzWEC=YKik83r*?EPLoOZXR8 zgw11~W8SN-Gy>k2sCQ$wdMbqv3M3Sew#>nT_T!d9rHiI*R1^F0JspHv4uZp@R7m0F zd#Mwa|HyGK`P4rZrub1bgITX?bdbIIyJ6??-JhaFlPYy7+Koor!@8fFShZ)5siVV$X|ab6W^!RMyCvuRIXQbSZ4 zh;6S)>&L|ulP%@L`uOOIO&4==fvLfVO1@!)U|B_v{FtcIw;z-ZQ~2^i;1lx*{t^+< zZ|i>O9R7*10bbT8KY=5~SgzPDA(%fztJC_uZr%~|?s@kauO|bgYyy}8B6?NlI(Q;R z6=`V4PadkWHo)VIwe!+~PW;Yl!DF*O6i0{q{*{t|Yif{R=!y(8$F*dUlFw8_FH8+d z9a)9*|JH~CB?RO{;E~_c+g(==9}B%jWHm5|cZ=Do_5hV%ur%8j*RwosD=^2o;ma#sX^8Yu9fPcLucYlqKH6wyc=KDtR_` zM-^s9N-JTlVPw*n1`Sj-AWt}K>rMv`6!2LI9W2nTyDxljC#$f4_%fBlTiVjd2(dGNo8+RWLdfd`9Bdr zQsV4p(m4F)V&|voy;sHe$}FtT_^)4|M}UeG=dMJaE5mtj!n{O<@UIn?Ngs2f=pBro z(;{2}zWcLScjf4qd=FjlaJdBeeX2rx(knn zy|U~lbY85Ni|9xDQw2W&)rsUyW@YLTwwcKb#kuio)s@hk{T{tUQNLBg1%{NtVKX(u}2s;ZRWZkrw5u zO@rWnFXO^M92ARe=!S*0P@!zr1Zn+gEm}Oh@z90PU9fET{L{Sds1I8&-|w?Hqw*;d z!Ql|~jKW)G%8Bx@oifv%K7xTD%5Tq}i=SH;jMcXudBjP_@dM{Wm}(35xirVRso0E{ z`1|Ri9z_$5d@%X}>{o|?>MkuvLJfpN@$^T=4TIN*HAO=(Rpi`KQ&s~73q3($!$-N8 zs5u_A?3n57^;7LhqN98l^8E}QW!ZAFLrK&r?nVIWMFxS(A!8N`GcVysQVa7WPKw|kK68^* z&UlCa9ZH1g$;`LkdpH5ICtm9K(*alDc`#3|d96Df1wThD!`%VG=l*R|9SDJ##q>Y=;u`FVYxcBgh1p!y2laO6^^ z+zVBsTlV0J+p=N95%6_mDrG+k45FhNq&w5!Y4QLSI4-A5c5sdYnqXC^NR%!NTT9&( zeSPdWfPIlA+phc;@9j~N>`N_j10?dX87$ye{WC`vQ&uLHNNdHmqVxeK{weg@{Cb(!9;r`RYz@egOMV7~_UpJcdYLn~r7)kUP@ z3qA6@av~cxVpL-(v`<4v^$*FhCk30P{t4CIVM7AKTSJ-w_L} z)>psubd`4zE zCcflxcIQkQ0;?%x=GpL?Mes-zkEuHQYaAR!B}fz)r!S?V;gFVKY5$gW70_=9sg1wm zgC-jv7@a5Mu}VrkJv=x4%20*17^Y4}C|2CsF!>nl2BDAo;t=hhUw#+;1lfYDXVE6M z$@_z)l=$BRg;d#7CW(P$KCtw8;pk7^xf>Hb4x8-brKQMP@^h{ly{Sn6F%Q$nWA_@W z3@EPKl^+pAloPXvFOkQ~jMGEj3|6fjEh$DmbW*k}Xd}YnT*|=DIwmYv9=sz>92wAE zSh9>v%GZp}Ecf<3qu?8fDCPkiDJI!}VCv}e3?s*L`A z4~rC?yPQ0H3R)_ZTu5K!cyd{_Yw3Hpmp`BF9w_XZ&4|)zT_%?QRF42!+MYKGB-40h z$OtFE9IK_Ge+II3%3)9VCjuNs$(^%cX993=a7-nYiN>lbxHzaIO%f`*lEXIgfVW1= z#I4=ICuibusJ8R(bnw|i-Aa#KR!EA`nX->d&v3$3db!)XWbMR=#k zL|N$uMrKLx*QJDaw{+6mn{7ua4-IOnu!FV z(jQGjVWBW-{V$CdiN#Tg1<1!%$wFU+w6u=c6QQ@{dsw&Pp_ai){GKJnUBXT~^92ev zct)aIezfb9+b%^WPrp#?cqP~acqc1Khf!axMjz4A8c*3578UomQRIO?FXcn^7Sh>X z$BeQt5t9z94w0(-Rihe;Q&Pvz`+vAP^Ju8w|LPkqv6>*>6QMn(oGUv!EfO6@9E9Z%FtVhy74+k6Ioy8Z9R-iS5`;T;T}hfu&lv=kqZ;g#j{ zoWRnf7s8g1g`VvY8jWQ!nCSVKQg%Z{=)1@Rr}vqIxhR}`d5nmi!d1&swW|M zEV7L?H)Z$0`yu4n!uo8H))+c~DLigw<4&HnQ3_gcffdQC72~Yxt#XfVI>@dBeOc=O zD@60s7@t4ud5$bO`NV5~k&FI^iAK&FM19X$Gm`;L@V;(kR7|I~vntYbGXT*`z6sAc z=nk}ymn`m-fPdc+(e&X#S_CBl-)&PirGM2*@Q4}Q45s7@8huWCOf}`lAP}Sf8|4kN zQ;_+$&##;QbF?DoKgu5YmuUa}CGhQkzVhw=zbtWYA2>ZOoB@Z{m8RWEe}B)xi@O96 z1MX4`1Ab)lcfZ5c@f{{VS#ffc?B~5a!j!#@;-PyP0sp_a&uoHH=<=a48*f%fd?t>*-9r) zsOkM|D7(t6JPZ8*s_ymA!*I3aqBjVVjHCo_5L{#q>wsBN2g;z|nYiVe6}iY!*NHnx z#zZoOAiB5f|7NM9#VDs;$Z1#^;~aHgB2WQQ-zWX|rfIzuILKY_L*OJ}N*}Eezu5rP z0BExO@Bk6Xk80}svuxx{F=6ic&4H9CkZb+AN{*6!RtA}3balj2jC+r0Is6E88Ov*G z{$VU6~{s3%kG{?0For{FPkB2NJou_Zr9*#lROZe65xIFSN6E?E=Fe^xB2<&x7X| z$@sU)Pc{kqUS@&LcDbbTMl+R7sh}I#C%GQzMI_+L%gYBI|NN|jaRQ1hPFI0V+~iSP zILpJ04;xK}G?!k>)GHZM1Xk+Bo!L}f>jsHY&5&C6Azt{DF%xqy5N`&vftLEM$p&0D zHz298PwxSL8w*bS6*upf77~LPkZHb5c_2uzHgWqV;4h@P9iqnk4_B40&)UhiEfl8S zV)c|BWe>5)cmIFhqQbPZP7@%hjd4V8u>tmpO{L1p`09z>a$PL$k=pW6pRWxGCtJ`C%8-_HI- zMbnAYblFlfd6%w(DJ?I50#buHM~C3`?XPhFJ#^>?)+4b0BZmUlz~6Zcs>F{#=Rf%9 zW7-o-OUqh$hfchvCbC|_d5dgGw05W;uFQbejfT>M%R2*qlMIC(Ul0M^+?4=ld>@#S z_xJCfldDK@^4&jVHI$zI2jgK3Q@afq5~;2rJgrs^^0nhWz?`j5we`FHq6yp`i1cS) zPu{*JYdJs$cLz>J3hZ&(BJR^lR?(DSI)Qg zfOsx);s}Hb?`YsqouRJ6oXDCndv{_O6Q5WY^(DRB>&HNkJercag%-j zAXwcCP#b2&XO77I{M`od3YI$!zBt#&Wqq6C11L{LOfchq0{aO2-(q2OA%NNt0Byq1 zj4gR)ObxiCnL(n6(T4H*LGS%u0zx_GKrZ!4(dkwp(tfm#((Il9#uD*uw>p9*BAcJ&vT0AT7`No(UZ;nu;+ygO`R_ zlIOKSC}%s+1?}lx!eZD6>2ZZ2(8Y{&S}tHRQjMGP$ol0!sha4x)E9ydiGWt_bRPOny#qVZVLsz+xJnbv|HM=-`|>^cV`~ z8GSl%N?8GR&YK^cc~7@nqS2kuS>6YBP^H?_*pn|}XFz)3ag69dV_46~-Esj;{oNPd z^DfR8yC78;=nq;v@4O>4<37E|nlVO)gIB08@>-!$+7fWpr zM9jx^U3j~9hwl+6lT4F+l-fbP_D$_N9MTW)pU%naEozNvUA^;m;1F9Uv?Fm8Gm20U zJb0dZ?+&+nI7?uqg zdc{`*r4{h0#9QD?A)oM*E3~btVWJP@g|eF9hVV9sbEu~N))p%wI=p8@0I%8Hc!~sX z6>fD>{{V00w3lAHVaAZWHCA9I37dl@D1JSoBrFB+GX=y@L9}azI>wBB} zbQNdV?xr_8Z9e(qQ;vU4zLfI_;$2R;Mcde6#Zinf5<75=88v~w#2?Ww=wv0+Pvgp& zEodm7B5GY4pdSDN?BGnJ6zWolsc|sc#hjJZy9R zRO#Nggi`t^rIj25FPk7nhk(=JEY9OoOk-H=-`nKy<`i0s+KzHy7loj)zv6JaHAZ5w z{vGrPyCDPY^@R0Hi|8?XtqMU%rA+7{Bt)p4<5ra5k}4`Q&xV}p{h4Fd{4M<5d3x$Z zttn~hSMRB|M6}$$6-{1Khq#5j;rybcj^c#{!CVw*PUR9IHweuTQ{Bq5Au64Vo@hY< zj4xq)@mj1X$w?l%)Q>Yq>DEGayFeRC*26F>m9V8Bb!tCkULs>@Ois7Qvq%0^R!#tR z$seg@Z#}iUrF1a0-Ck(3g1Rd$m+t2J;J3#EBzjl-==~XeLO|LT(rWxW>I_$Nxl0mpb8#(`a z&E3J889JnKyloEayLo=rUg~#Pb>Wm)h({pDhTLox55UFDO8xtp`rYiyxqF|`+pXLs zg2~owK32}{nG=~TcrlpIbkd}VNrynGGXVMa`kFEXXVp?zI?>@_8b!cOosqoOtynI# zmWsQ%f4r8T!>7k+ioFr^r?z8-%8pdHRuSi?ZZfu^Hdx^@xD36d=%UU{m{fRZFVuS6 zvar$I65+w+Bm(wSjP9o84s5zxaqe(U{x?sNOV41umPZ!u5!KOcC4(}LvgGCE7DCDQ zpB4{%0!ACVe?OB?)$OQCZ_jg#=2eb)?_){gh1F4ebA+J%TbWo@``R4Y3#o_PyVX0w zQ-ryv|5#(ygpuLd*>)eqT#i`GQYdXTYrWF2rLY=!$xhM0ZXQ_Ep)H(B`}| zHGWif6d^MgL`5tBquA+AVVE!J6Vo%F2b2k^dZkmd9Y3!jacpC^z!z{dK??b?b_iP_it;(=`XY$b0Vd)Z0QHi zWjUe53@PMkiW4&!2w;MyDEzJzWG+u~e1seHnQrbIK-Nt4_(!Ic;npvaI*}WvqNXw? z<)z)`f{zks-J{t)U$LFiMWa7!Aw%vys5_^N&aXrB%07qfw03byaktc^9U!j@AW_kMgoSrHQ7b?Gebf#WvDx!fXF zG_P76x`^7DO{DIZHAqu0UC?)!lC^5r>7sUsW2d!K=*wKbglwHTH`&j*rh6x$L%7 zg6|BCWN4ad(7%~`Fcd+=O>rgYeA1c#)N-ZaiGx*?fGi)F*8cYSoL7bIpr0U<=R> zgX&wWpJrLh-cv=$1krV5lk)8LP|PJ~g~&2J6r+{SsUmZ-Zhd?jq2J4G(Pf8(mbF?o>>pv* zK4FF~>|9}(ijRA5-TT-jlBP>!Mu1jo-vc%Qt%UN-%a8&a4t>yLLW%{?+saZw}DK0WTaBBOnPe3k5b=BBdHpypU; zx!Pw?kP!PC7xN+}rO9RLlfj<|9m_Rw~fx(oOTx%)HcM&4!cE;CG_@7a@|E{tZ=Q;ARCB8cdF)8hG_*N z%FHqGIJbW`(yqRm$=YT?44)$ER#alr6UnNSR}I3$Cak-XdBSIlt5amJARE~8r(29u z#oUYH2tp2_k*k~DaF#c61``l-QfG#&!cJ65Cpf+;@VyG`)~&x6wZ?Y%DHU!TJKL@d z@>+b`qDmTYr~cm|FIU!!uT&k=&o+>(w>mmv;QP37RuwwZY3eiy98yl~-x725^Uy;( z_zk=t@g43@&{%PYEP+dhps6s7#lC_pAIoA{KKb(Px24Ytv*Y4Ak0oGc>{O%^7AMYq z^$}kyY2p`CMP9qmRqSNExuB_y?vhg!iDkU z0p2Vo3ZG$i%~Op$!_SXzH?}RO3(GrA?a2>Lk4fN{SJ-yjRahL#U#`_*uuTFNy!LWi zaWB1CwxIKj9bv`V=Dl7;?6g&LK?s1_rvFehp_E+uZ3rm^DC4!Qv@1^OZ{} z(EFT+>^7Wz87{KPT5@^dWVoX5I6#?OOEd_DP};iR$q;KM zs)mHIc&wg9h<9{V3-ByJIzr27!J1YS)2G4nY`dvQ5YqNL!Xsk&&HN{{!avn6(m&(| zi(LDJ-fLZSP{TkYmZeFeDmqA^><0>6L0imv;$73fx&%@eoMjg>c1lf^|94_I3l*GY z%1U&pj4Unlv_nx`XCm2m(6n<&%ry7&aM`q9Za0y+(N2@bz&tVYkeF-(4r!ZkN!TGp`D&=j?7czUFdhm9Q4lZJ7NO8KrEC zu?u9g<5@r+n?QQVc{|$-mn7^lR>0jM)Vhc3mDTSZ8k6tEK=;y%l~=O#sU2QdV}X3B z&Lm1jGZ697rj0}SR{K$_*E-J(RxR~%$+Mkq6fwweP8I8_ko?7FlgglVo>28A6HRT) z359Mcu7r=u#ad*!Nxx2>;Hm}(#o_0-?Kmg~-HUj_Oz8wOgz`$U13n4fyg~e=yo7(K z(pc==?wKe^z5P1Qt?Nd~pX;G zT-0LJHqs_)>9<|N2Sfyfb-;g_|6-sK`Yhyb7sC=x;0lW3p4Nao!{_6DAnwyqjE6Cw zlJ(eMn{lwZW4+(ndrXIN^)~HGqqWE1P>Kr{{d9sMS^@YUE-3iwx2@eAV}i*cWp3(- zXuCnP&gDIS_Sf;a;Mkif$JcO4nVx7q~b>k}a>r-m?%u z;N7!4TGUGqQ&vB-K=PY^wRnRbS?vq#HO?D6$RgY8tBwuwrxpE0^TZJTHv>m*VFcl{ z#LCxKm-2%CJyioSltou)zM*e9ZFkzaL+BXjW~#zWr=i4g^c~&w^bE@R%)W~61Y9Ku-~Fpcr}2VLV3JuI1vZ>j zEdH$NBRKug%5y_)o;1G5@Wd`Wuh?!b<(C1z$@{ z@?D{}-{fvENgXT(Cnf4RoaKA_3axePHV4(NKyEYd6DAaD1Q*U119f4F5c@j8l@Hx+ z<(N2S8bwS}7bzE$rBmjf(K7Rd7aeHc5%x*XiruHy4Eb7FmayUWLtyTQiwU%)Teb%` z1kMd79wZGZ~ntzrsa2cNn;QPP!eT`^5>) z5GypYu}F2$kQ^C~)4W|osgk4pOd?Br@^FOadSJf4q*w^vM%u!L3}9_HHtME4)NeHX zAMqc2Lrx$ET_u4dwRwmLx?T=qhz~~nz;1IeP!>nt*Sw{FMjeuc5}}AXR@>?m_NJzL zGp|g~f3HdyUMRAnqu*|WpJ541y1xRdtb}?}pGm)F z9AZXoaS(-dQV)-O3=+}d^*}__(L_fJuVfBh(%fcXR8+DU$bVyDx4?ZBf>+B5Ii6W0 zI>cQpV9|@=6+PynnO;U|mOhHr<`haNX%ueTVf5{qtH@B)!W`K9d*Up&r9UsIU523o z)pL7M4!TkDKr*%c%=O=o5m}szK)kr(rO_5AwGP-XVg9GJ1_Ygw(d$1xeh2>6IUBFH zEUm0sW=L3{Tn1~1QC20S&+mTlWtw00GMYbbQ9mTVY|dw~8b%g|lBR}#A6VfcnF|ff zykm?1W#)nR4jv?XHP3_%-xvcyeNj)z{c8ZOVfO(j-n~r|L4>~^&%ghkuH)Z%Euz}i z$ADui?0sF_IAb=9k%v@XzoznkT^(@Wz>s|{-5xlIPyai=;oobSFIwvU??dTSc5vQA zwc*vAFYm$xK8yFm6FD5b)pT;2pv56{{}34E|ed2%0D7{y)qn8umU5XX2YD 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 Tvd8q22yo$SoUzpyzr_CnfSnz? diff --git a/docs/screenshots/busymark-welcome.png b/docs/screenshots/busymark-welcome.png new file mode 100644 index 0000000000000000000000000000000000000000..743d9d3a908ba28553a2a2d400483b37ab1febef GIT binary patch literal 32705 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 literal 0 HcmV?d00001 diff --git a/test/src/visualization_packaging_audit_test.dart b/test/src/visualization_packaging_audit_test.dart index 4e5463f0..07206460 100644 --- a/test/src/visualization_packaging_audit_test.dart +++ b/test/src/visualization_packaging_audit_test.dart @@ -4,6 +4,24 @@ import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; void main() { + test('README screenshot references resolve to checked-in images', () { + final readme = File('README.md').readAsStringSync(); + final screenshotPaths = RegExp( + r' match.group(1)!).toSet(); + + expect(screenshotPaths, hasLength(5)); + for (final path in screenshotPaths) { + final screenshot = File(path); + expect(screenshot.existsSync(), isTrue, reason: '$path is missing'); + expect( + screenshot.lengthSync(), + greaterThan(1024), + reason: '$path is not a usable screenshot', + ); + } + }); + test('release metadata is consistent and production-grade', () { final pubspec = File('pubspec.yaml').readAsStringSync(); final snapcraft = File('snap/snapcraft.yaml').readAsStringSync(); From db6a0c9e8b222c2acd249b2b4d7ba7505aaac3a0 Mon Sep 17 00:00:00 2001 From: albert Date: Sat, 5 Sep 2026 02:22:36 -0700 Subject: [PATCH 03/37] Fix Writerside reuse and source resolution --- .../export/markdown_visualization_export.dart | 4 +- .../export/writerside_pdf_export_service.dart | 1 + lib/src/markdown/markdown_parser.dart | 17 +- .../presentation/workspace_screen.dart | 6 +- lib/src/workspace/workspace_service.dart | 14 +- .../writerside/writerside_code_selection.dart | 190 ++++++++++++++ .../writerside_diagram_source_loader.dart | 75 +----- lib/src/writerside/writerside_document.dart | 65 +++++ .../writerside_document_parser.dart | 109 ++++++++ .../writerside_document_renderer.dart | 57 ++++- .../writerside_document_resolver.dart | 240 +++++++++++++++++- lib/src/writerside/writerside_model.dart | 7 + .../writerside/writerside_module_service.dart | 2 + lib/src/writerside/writerside_parsers.dart | 23 +- lib/src/writerside/writerside_project.dart | 2 +- .../writerside/writerside_source_loader.dart | 146 +++++++++++ ...writerside_resolution_regression_test.dart | 240 ++++++++++++++++++ 17 files changed, 1093 insertions(+), 105 deletions(-) create mode 100644 lib/src/writerside/writerside_code_selection.dart create mode 100644 lib/src/writerside/writerside_source_loader.dart create mode 100644 test/src/writerside_resolution_regression_test.dart diff --git a/lib/src/export/markdown_visualization_export.dart b/lib/src/export/markdown_visualization_export.dart index 9c45d1c0..deccfecf 100644 --- a/lib/src/export/markdown_visualization_export.dart +++ b/lib/src/export/markdown_visualization_export.dart @@ -1,3 +1,4 @@ +import '../writerside/writerside_source_loader.dart'; import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; @@ -151,7 +152,8 @@ class MarkdownVisualizationExportRenderer { try { var source = block.plainText; final sourceReference = block.attributes['src']?.trim() ?? ''; - if (sourceReference.isNotEmpty) { + if (sourceReference.isNotEmpty && + !block.attributes.containsKey(writersideResolvedSourceAttribute)) { source = await diagramSourceLoader.load( reference: sourceReference, documentPath: documentPath, diff --git a/lib/src/export/writerside_pdf_export_service.dart b/lib/src/export/writerside_pdf_export_service.dart index 7b73a512..cbc1fbec 100644 --- a/lib/src/export/writerside_pdf_export_service.dart +++ b/lib/src/export/writerside_pdf_export_service.dart @@ -382,6 +382,7 @@ class WritersidePdfExportService { final attributes = {...block.attributes}; final source = sourceContext(attributes); for (final name in ['src', 'preview-src']) { + if (name == 'src' && block.kind == BusyBlockKind.codeBlock) continue; final value = attributes[name]; if (value == null || value.trim().isEmpty) { continue; diff --git a/lib/src/markdown/markdown_parser.dart b/lib/src/markdown/markdown_parser.dart index 3e609f5b..8f2c4e45 100644 --- a/lib/src/markdown/markdown_parser.dart +++ b/lib/src/markdown/markdown_parser.dart @@ -1226,22 +1226,7 @@ class MarkdownParser { r'^\s{0,3}<([A-Za-z][A-Za-z0-9_-]*)\b', ).firstMatch(lines[startIndex].line); final tag = match?.group(1)?.toLowerCase(); - if (tag == null || - !{ - 'note', - 'tip', - 'warning', - 'quote', - 'tabs', - 'tab', - 'procedure', - 'step', - 'chapter', - 'code-block', - 'deflist', - 'def', - 'video', - }.contains(tag)) { + if (tag == null || !WritersideSchema.isMarkdownSemanticBlock(tag)) { return null; } var balance = 0; diff --git a/lib/src/workspace/presentation/workspace_screen.dart b/lib/src/workspace/presentation/workspace_screen.dart index 3cd7f635..e9ff4943 100644 --- a/lib/src/workspace/presentation/workspace_screen.dart +++ b/lib/src/workspace/presentation/workspace_screen.dart @@ -1,3 +1,4 @@ +import '../../writerside/writerside_source_loader.dart'; import 'dart:async'; import 'dart:io'; import 'dart:math' as math; @@ -11384,7 +11385,10 @@ class _PreviewBlockView extends ConsumerWidget { key: ValueKey('visualization-$documentPath-$blockIdentity'), descriptor: descriptor, source: block.text, - sourceReference: block.attributes['src'], + sourceReference: + block.attributes.containsKey(writersideResolvedSourceAttribute) + ? null + : block.attributes['src'], sourceFence: _visualizationSourceFence(block, descriptor), documentPath: documentPath, workspaceRoot: workspace?.rootPath ?? '', diff --git a/lib/src/workspace/workspace_service.dart b/lib/src/workspace/workspace_service.dart index 4325f18d..fd3a2c4d 100644 --- a/lib/src/workspace/workspace_service.dart +++ b/lib/src/workspace/workspace_service.dart @@ -1,3 +1,4 @@ +import '../writerside/writerside_source_loader.dart'; import 'dart:convert'; import 'dart:io'; @@ -1365,14 +1366,14 @@ class WorkspaceService { ); } - Workspace _workspaceWithReparsedWritersideTopic( + Future _workspaceWithReparsedWritersideTopic( Workspace workspace, WritersideModule module, WritersideTopic previousTopic, WritersideTopic parsedTopic, - ) { + ) async { final activePath = parsedTopic.filePath; - final updatedModule = module.copyWith( + var updatedModule = module.copyWith( topics: List.unmodifiable([ for (final topic in module.topics) if (p.equals(topic.filePath, activePath)) parsedTopic else topic, @@ -1387,6 +1388,11 @@ class WorkspaceService { normalizePath(activePath): parsedTopic.document.source, }, ); + updatedModule = updatedModule.copyWith( + sourceFiles: await const WritersideSourceLoader().loadModule( + updatedModule, + ), + ); final previousProject = workspace.writersideProject; final updatedProject = previousProject?.withModule(updatedModule); final indexedWorkspace = workspace.copyWith( @@ -1468,6 +1474,8 @@ class WorkspaceService { final config = module.config; final candidates = { config.filePath, + for (final source in module.sourceFiles.values) + if (source.path case final path?) path, for (final instance in module.instances) instance.sourceTreePath, for (final instance in config.instances) _moduleConfiguredPath(module.rootPath, instance.src), diff --git a/lib/src/writerside/writerside_code_selection.dart b/lib/src/writerside/writerside_code_selection.dart new file mode 100644 index 00000000..9618f3c1 --- /dev/null +++ b/lib/src/writerside/writerside_code_selection.dart @@ -0,0 +1,190 @@ +/// Source selection operates on original text, with comments and strings masked +/// only while locating declarations and balancing their delimiters. +class WritersideCodeSelection { + const WritersideCodeSelection(); + + String select(String source, Map attributes) { + final lines = attributes['include-lines']; + final symbol = attributes['include-symbol']; + if (lines != null && symbol != null) { + throw const FormatException('conflicting-selection'); + } + if (lines != null) { + final input = source.replaceAll('\r\n', '\n').split('\n'); + if (input.last.isEmpty) input.removeLast(); + final selected = []; + for (final part in lines.split(',')) { + final range = RegExp( + r'^\s*(\d+)(?:\s*-\s*(\d+))?\s*$', + ).firstMatch(part); + if (range == null) throw const FormatException('invalid-lines'); + final first = int.parse(range[1]!); + final last = int.parse(range[2] ?? range[1]!); + if (first < 1 || last < first || last > input.length) { + throw const FormatException('invalid-lines'); + } + selected.addAll(input.sublist(first - 1, last)); + } + return selected.join('\n'); + } + if (symbol == null) return source; + final language = (attributes['lang'] ?? attributes['language'] ?? '') + .toLowerCase(); + if (language == 'python' || language == 'py') { + return _python(source, symbol); + } + if (!{ + 'java', + 'kotlin', + 'kt', + 'javascript', + 'js', + 'typescript', + 'ts', + 'jsx', + 'tsx', + 'dart', + 'c', + 'cpp', + 'c++', + 'csharp', + 'c#', + 'cs', + 'go', + 'rust', + 'rs', + 'swift', + 'php', + }.contains(language)) { + throw FormatException('unsupported-symbol-language: $language'); + } + return _braced(source, symbol); + } + + String _python(String source, String symbol) { + final lines = source.split('\n'); + final name = RegExp.escape(symbol.split('.').last); + final declaration = RegExp( + '^(\\s*)(?:async\\s+)?(?:def|class)\\s+$name\\b', + ); + final matches = []; + for (var i = 0; i < lines.length; i++) { + if (declaration.hasMatch(lines[i])) matches.add(i); + } + if (matches.length != 1) { + throw const FormatException('missing-or-ambiguous-symbol'); + } + var start = matches.single; + final indent = declaration.firstMatch(lines[start])![1]!.length; + var end = start + 1; + while (end < lines.length) { + final line = lines[end]; + if (line.trim().isNotEmpty && + line.length - line.trimLeft().length <= indent) { + break; + } + end++; + } + while (start > 0 && lines[start - 1].trimLeft().startsWith('@')) { + start--; + } + return lines.sublist(start, end).join('\n').trimRight(); + } + + String _braced(String source, String symbol) { + final masked = _mask(source); + final name = RegExp.escape(symbol.split('.').last); + final candidate = RegExp('\\b$name\\s*(?:<[^;{}]*>)?\\s*\\('); + final matches = <(int, int)>[]; + for (final match in candidate.allMatches(masked)) { + final lineStart = masked.lastIndexOf('\n', match.start) + 1; + final prefix = masked.substring(lineStart, match.start).trim(); + // Calls and control flow are not declarations. A bare method name is + // accepted for JavaScript/TypeScript class methods. + if (prefix.contains('=') || + prefix.contains('.') || + prefix.contains('(') || + RegExp(r'\b(return|throw|new|await)\b').hasMatch(prefix)) { + continue; + } + var cursor = masked.indexOf('(', match.start); + var depth = 0; + do { + if (masked[cursor] == '(') depth++; + if (masked[cursor] == ')') depth--; + cursor++; + } while (cursor < masked.length && depth > 0); + final body = masked.indexOf('{', cursor); + final terminator = masked.indexOf(';', cursor); + final expression = masked.indexOf('=', cursor); + if (body < 0 || + (terminator >= 0 && terminator < body) || + (expression >= 0 && expression < body)) { + continue; + } + final between = masked.substring(cursor, body); + if (between.contains('(') || between.contains('}')) continue; + matches.add((lineStart, _closingBrace(masked, body))); + } + final typePattern = RegExp( + '\\b(?:class|interface|enum|struct|object|trait)\\s+$name\\b[^;{]*\\{', + ); + for (final match in typePattern.allMatches(masked)) { + matches.add(( + masked.lastIndexOf('\n', match.start) + 1, + _closingBrace(masked, match.end - 1), + )); + } + if (matches.length != 1) { + throw const FormatException('missing-or-ambiguous-symbol'); + } + var (start, end) = matches.single; + while (start > 0) { + final previous = source.lastIndexOf('\n', start - 2) + 1; + if (!source.substring(previous, start).trimLeft().startsWith('@')) break; + start = previous; + } + return source.substring(start, end).trimRight(); + } + + int _closingBrace(String source, int start) { + var depth = 0; + for (var i = start; i < source.length; i++) { + if (source[i] == '{') depth++; + if (source[i] == '}' && --depth == 0) return i + 1; + } + throw const FormatException('unclosed-symbol'); + } + + String _mask(String source) { + final result = source.split(''); + var i = 0; + while (i < source.length) { + final start = i; + if (source.startsWith('//', i)) { + while (i < source.length && source[i] != '\n') { + i++; + } + } else if (source.startsWith('/*', i)) { + final end = source.indexOf('*/', i + 2); + i = end < 0 ? source.length : end + 2; + } else if ('\'"`'.contains(source[i])) { + final quote = source[i++]; + while (i < source.length) { + if (source[i] == '\\') { + i = (i + 2).clamp(0, source.length); + continue; + } + if (source[i++] == quote) break; + } + } else { + i++; + continue; + } + for (var j = start; j < i; j++) { + if (result[j] != '\n' && result[j] != '\r') result[j] = ' '; + } + } + return result.join(); + } +} diff --git a/lib/src/writerside/writerside_diagram_source_loader.dart b/lib/src/writerside/writerside_diagram_source_loader.dart index 6a3a3dda..72fd6c38 100644 --- a/lib/src/writerside/writerside_diagram_source_loader.dart +++ b/lib/src/writerside/writerside_diagram_source_loader.dart @@ -1,9 +1,4 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:path/path.dart' as p; - -import '../core/anchored_path_guard.dart'; +import 'writerside_source_loader.dart'; enum WritersideDiagramSourceFailure { invalidReference, @@ -31,61 +26,19 @@ class WritersideDiagramSourceLoader { required String documentPath, required String workspaceRoot, }) async { - final source = reference.trim(); - final parsed = Uri.tryParse(source); - if (source.isEmpty || - source.contains('\u0000') || - p.isAbsolute(source) || - (parsed?.hasScheme ?? false) || - documentPath.trim().isEmpty || - workspaceRoot.trim().isEmpty) { - throw const WritersideDiagramSourceException( - WritersideDiagramSourceFailure.invalidReference, - ); - } - - try { - final anchor = await captureCanonicalDirectoryAnchor(workspaceRoot); - final candidate = p.normalize(p.join(p.dirname(documentPath), source)); - final resolved = await resolveAnchoredPath( - anchor, - candidate, - allowRoot: false, - ); - if (resolved.type != FileSystemEntityType.file) { - throw const WritersideDiagramSourceException( - WritersideDiagramSourceFailure.missing, - ); - } - final file = File(resolved.path); - if (await file.length() > maximumBytes) { - throw const WritersideDiagramSourceException( - WritersideDiagramSourceFailure.tooLarge, - ); - } - final bytes = await file.readAsBytes(); - if (bytes.length > maximumBytes) { - throw const WritersideDiagramSourceException( - WritersideDiagramSourceFailure.tooLarge, - ); - } - try { - return utf8.decode(bytes, allowMalformed: false); - } on FormatException { - throw const WritersideDiagramSourceException( - WritersideDiagramSourceFailure.invalidUtf8, + final result = await WritersideSourceLoader(maximumBytes: maximumBytes) + .load( + reference: reference, + documentPath: documentPath, + workspaceRoot: workspaceRoot, ); - } - } on WritersideDiagramSourceException { - rethrow; - } on AnchoredPathViolation { - throw const WritersideDiagramSourceException( - WritersideDiagramSourceFailure.outsideWorkspace, - ); - } on FileSystemException { - throw const WritersideDiagramSourceException( - WritersideDiagramSourceFailure.missing, - ); - } + if (result.text case final text?) return text; + throw WritersideDiagramSourceException(switch (result.failure) { + 'invalid-reference' => WritersideDiagramSourceFailure.invalidReference, + 'outside-workspace' => WritersideDiagramSourceFailure.outsideWorkspace, + 'too-large' => WritersideDiagramSourceFailure.tooLarge, + 'invalid-utf8' => WritersideDiagramSourceFailure.invalidUtf8, + _ => WritersideDiagramSourceFailure.missing, + }); } } diff --git a/lib/src/writerside/writerside_document.dart b/lib/src/writerside/writerside_document.dart index 32efec6b..838c0ac4 100644 --- a/lib/src/writerside/writerside_document.dart +++ b/lib/src/writerside/writerside_document.dart @@ -9,6 +9,14 @@ const writersideSourceModuleRootAttribute = const writersideSourceTopicPathAttribute = 'busymark-writerside-source-topic-path'; +bool writersideIgnorableRaw(String source) { + final value = source.trim(); + return value.isEmpty || + value.startsWith(' B'); + await File( + p.join(fixture.module.path, 'topics', 'advanced.topic'), + ).writeAsString( + '

Windows instructions

', + ); + final exporter = _RecordingMarkdownExporter(); + await WritersidePdfExportService(markdownExporter: exporter).export( + WritersidePdfExportRequest( + moduleRoot: fixture.module.path, + projectRoot: fixture.root.path, + instanceId: 'guide', + destinationPath: p.join(fixture.root.path, 'tabs.pdf'), + overwrite: false, + ), + ); + final blocks = _allBlocks(exporter.request!.document!.blocks).toList(); + final code = blocks.singleWhere( + (block) => block.kind == BusyBlockKind.codeBlock, + ); + expect(code.plainText, 'flowchart LR\nA --> B'); + expect(code.attributes['src'], 'graph.mmd'); + expect( + blocks.map((block) => block.plainText), + containsAll(['Linux', 'Windows', 'Windows instructions']), + ); + }, + ); + test('pre-cancelled native export never starts PDF compilation', () async { final fixture = await _WritersideFixture.create(); addTearDown(fixture.dispose); diff --git a/test/src/writerside_resolution_regression_test.dart b/test/src/writerside_resolution_regression_test.dart index 195359b3..a4deb263 100644 --- a/test/src/writerside_resolution_regression_test.dart +++ b/test/src/writerside_resolution_regression_test.dart @@ -222,6 +222,62 @@ Nested **tab** content. }, ); + test( + 'summaries stay metadata and starting pages suppress outside content', + () async { + await write( + 'topics/main.topic', + 'Hidden summary

Outside body

Start hereVisible introGuides
', + ); + final rendered = await render(); + final text = walk( + rendered.blocks, + ).map((block) => block.plainText).join(' '); + expect(text, isNot(contains('Outside body'))); + expect(text, isNot(contains('Hidden summary'))); + expect(rendered.frontMatter['link-summary'], 'Hidden summary'); + expect(text, contains('Start here')); + expect(text, contains('Target title')); + expect(text, contains('Card description')); + }, + ); + + test( + 'configured shortcuts, glossary and binary resources have visible references', + () async { + await write( + 'cfg/buildprofiles.xml', + 'keymap.xml', + ); + await write( + 'cfg/glossary.xml', + 'Hypertext Transfer Protocol', + ); + await write( + 'keymap.xml', + 'Ctrl+CCmd+C', + ); + await write('resources/example.zip', 'binary placeholder'); + await write( + 'topics/main.topic', + '

', + ); + final inlines = (await render()).blocks.single.inlines; + expect(inlines.first.text, 'Ctrl+C'); + expect( + inlines + .singleWhere((inline) => inline.attributes['element'] == 'tooltip') + .attributes['summary'], + 'Hypertext Transfer Protocol', + ); + final resource = inlines.singleWhere( + (inline) => inline.attributes['element'] == 'resource', + ); + expect(resource.text, 'example.zip'); + expect(resource.destination, endsWith('/resources/example.zip')); + }, + ); + test('line and symbol selectors reject invalid selections', () { const selection = WritersideCodeSelection(); expect(selection.select('a\nb\nc\n', {'include-lines': '1,3'}), 'a\nc'); diff --git a/test/src/writerside_semantic_widgets_test.dart b/test/src/writerside_semantic_widgets_test.dart new file mode 100644 index 00000000..5ccdf823 --- /dev/null +++ b/test/src/writerside_semantic_widgets_test.dart @@ -0,0 +1,226 @@ +import 'package:busymark/src/markdown/preview_model.dart'; +import 'package:busymark/src/writerside/writerside_tabs_view.dart'; +import 'package:busymark/src/writerside/writerside_table_view.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + PreviewBlock tabs(String suffix) => PreviewBlock( + kind: PreviewBlockKind.tabs, + text: '', + attributes: const {'group': 'os'}, + children: [ + for (final label in ['Linux', 'Windows']) + PreviewBlock( + kind: PreviewBlockKind.tabs, + text: '$label $suffix', + attributes: {'group-key': label}, + children: [ + PreviewBlock( + kind: PreviewBlockKind.paragraph, + text: '$label body $suffix', + ), + ], + ), + ], + ); + Widget panel(List blocks) => + Column(children: [for (final block in blocks) Text(block.text)]); + testWidgets('tabs synchronize and support arrow, Home and End keys', ( + tester, + ) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: WritersidePreviewScope( + child: Column( + children: [ + WritersideTabsView(block: tabs('A'), panelBuilder: panel), + WritersideTabsView(block: tabs('B'), panelBuilder: panel), + ], + ), + ), + ), + ), + ); + expect(find.text('Linux body A'), findsOneWidget); + expect(find.text('Windows body A'), findsNothing); + await tester.tap(find.text('Windows A')); + await tester.pump(); + expect(find.text('Windows body A'), findsOneWidget); + expect(find.text('Windows body B'), findsOneWidget); + final button = tester.widget( + find.widgetWithText(TextButton, 'Windows A'), + ); + button.focusNode!.requestFocus(); + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.home); + await tester.pump(); + expect(find.text('Linux body B'), findsOneWidget); + await tester.sendKeyEvent(LogicalKeyboardKey.end); + await tester.pump(); + expect(find.text('Windows body B'), findsOneWidget); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); + await tester.pump(); + expect(find.text('Linux body A'), findsOneWidget); + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.pump(); + expect(button.focusNode!.hasFocus, isFalse); + expect(tester.takeException(), isNull); + }); + + testWidgets('table sorting is numeric and excludes disabled columns', ( + tester, + ) async { + final block = PreviewBlock( + kind: PreviewBlockKind.table, + text: '', + attributes: const {'sortable': 'true', 'sticky-header': 'true'}, + children: [ + const PreviewBlock( + kind: PreviewBlockKind.table, + text: '', + attributes: {'header': 'true'}, + children: [ + PreviewBlock(kind: PreviewBlockKind.paragraph, text: 'Score'), + PreviewBlock( + kind: PreviewBlockKind.paragraph, + text: 'Notes', + attributes: {'sortable': 'false'}, + ), + ], + ), + for (final score in ['10', '2', '1']) + PreviewBlock( + kind: PreviewBlockKind.table, + text: '', + children: [ + PreviewBlock(kind: PreviewBlockKind.paragraph, text: score), + PreviewBlock( + kind: PreviewBlockKind.paragraph, + text: 'Note $score', + ), + ], + ), + ], + ); + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SingleChildScrollView( + child: WritersideTableView( + block: block, + cellBuilder: (cell, header) => Text(cell.text), + ), + ), + ), + ), + ); + await tester.tap(find.text('Score')); + await tester.pump(); + expect( + tester.getTopLeft(find.text('1')).dy, + lessThan(tester.getTopLeft(find.text('2')).dy), + ); + expect( + tester.getTopLeft(find.text('2')).dy, + lessThan(tester.getTopLeft(find.text('10')).dy), + ); + await tester.tap(find.text('Score')); + await tester.pump(); + expect( + tester.getTopLeft(find.text('10')).dy, + lessThan(tester.getTopLeft(find.text('2')).dy), + ); + expect( + find.ancestor(of: find.text('Notes'), matching: find.byType(InkWell)), + findsNothing, + ); + expect(tester.takeException(), isNull); + }); + + testWidgets('table spans preserve geometry and sticky header position', ( + tester, + ) async { + final block = PreviewBlock( + kind: PreviewBlockKind.table, + text: '', + attributes: const {'sticky-header': 'true', 'column-width': 'fixed'}, + children: [ + const PreviewBlock( + kind: PreviewBlockKind.table, + text: '', + attributes: {'header': 'true'}, + children: [ + PreviewBlock( + kind: PreviewBlockKind.paragraph, + text: 'Wide header', + attributes: {'colspan': '2'}, + ), + ], + ), + const PreviewBlock( + kind: PreviewBlockKind.table, + text: '', + children: [ + PreviewBlock( + kind: PreviewBlockKind.paragraph, + text: 'Tall', + attributes: {'rowspan': '2'}, + ), + PreviewBlock(kind: PreviewBlockKind.paragraph, text: 'Right'), + ], + ), + const PreviewBlock( + kind: PreviewBlockKind.table, + text: '', + children: [ + PreviewBlock(kind: PreviewBlockKind.paragraph, text: 'Below right'), + ], + ), + for (var i = 0; i < 25; i++) + PreviewBlock( + kind: PreviewBlockKind.table, + text: '', + children: [ + PreviewBlock(kind: PreviewBlockKind.paragraph, text: 'Row $i'), + const PreviewBlock( + kind: PreviewBlockKind.paragraph, + text: 'Value', + ), + ], + ), + ], + ); + final controller = ScrollController(); + addTearDown(controller.dispose); + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + height: 300, + child: SingleChildScrollView( + controller: controller, + child: WritersideTableView( + block: block, + cellBuilder: (cell, header) => Text(cell.text), + ), + ), + ), + ), + ), + ); + expect( + tester.getTopLeft(find.text('Right')).dx, + tester.getTopLeft(find.text('Below right')).dx, + ); + controller.jumpTo(160); + await tester.pump(); + expect( + tester.getTopLeft(find.text('Wide header')).dy, + inInclusiveRange(0, 20), + ); + expect(tester.takeException(), isNull); + }); +} From 4df82dbe4eb44731f5ab11717ad98b0a5da33b00 Mon Sep 17 00:00:00 2001 From: albert Date: Sat, 5 Sep 2026 03:35:57 -0700 Subject: [PATCH 05/37] Complete Writerside editing and conformance --- assets/export/markdown.typ | 16 +- docs/writerside-pdf-export.md | 14 +- docs/writerside-support.md | 103 + lib/l10n/app_en.arb | 53 +- lib/l10n/generated/app_localizations.dart | 64 + lib/l10n/generated/app_localizations_ar.dart | 45 + lib/l10n/generated/app_localizations_de.dart | 45 + lib/l10n/generated/app_localizations_en.dart | 45 + lib/l10n/generated/app_localizations_es.dart | 45 + lib/l10n/generated/app_localizations_et.dart | 45 + lib/l10n/generated/app_localizations_fa.dart | 45 + lib/l10n/generated/app_localizations_fr.dart | 45 + lib/l10n/generated/app_localizations_hi.dart | 45 + lib/l10n/generated/app_localizations_id.dart | 45 + lib/l10n/generated/app_localizations_it.dart | 45 + lib/l10n/generated/app_localizations_ja.dart | 45 + lib/l10n/generated/app_localizations_ko.dart | 45 + lib/l10n/generated/app_localizations_nb.dart | 45 + lib/l10n/generated/app_localizations_nl.dart | 45 + lib/l10n/generated/app_localizations_pl.dart | 45 + lib/l10n/generated/app_localizations_pt.dart | 45 + lib/l10n/generated/app_localizations_ru.dart | 45 + lib/l10n/generated/app_localizations_tr.dart | 45 + lib/l10n/generated/app_localizations_uk.dart | 45 + lib/l10n/generated/app_localizations_vi.dart | 45 + lib/l10n/generated/app_localizations_zh.dart | 45 + lib/src/core/diagnostic_localizations.dart | 34 + lib/src/editor/editor_text_context_menu.dart | 5 + .../editor/source/source_autocomplete.dart | 136 +- lib/src/editor/source/source_editor.dart | 45 + lib/src/export/markdown_export_mapper.dart | 49 +- .../export/openapi_static_export_mapper.dart | 208 +- .../export/writerside_pdf_export_service.dart | 46 +- .../presentation/workspace_screen.dart | 284 ++- lib/src/workspace/workspace_controller.dart | 135 +- lib/src/workspace/workspace_service.dart | 30 + .../writerside/writerside_code_selection.dart | 8 + .../writerside_document_parser.dart | 97 +- .../writerside_document_renderer.dart | 281 ++- .../writerside_document_resolver.dart | 239 +- lib/src/writerside/writerside_parsers.dart | 66 +- lib/src/writerside/writerside_project.dart | 511 +++- lib/src/writerside/writerside_schema.dart | 104 +- .../writerside/writerside_schema_data.dart | 2209 +++++++++++++++++ .../writerside/writerside_source_loader.dart | 8 +- .../writerside/conformance_semantics.json | 78 + test/src/source_autocomplete_test.dart | 4 +- test/src/source_editor_widget_test.dart | 29 + test/src/workspace_controller_test.dart | 55 + test/src/writerside_api_test.dart | 38 +- test/src/writerside_identity_test.dart | 170 ++ test/src/writerside_pdf_export_test.dart | 110 + test/src/writerside_project_test.dart | 198 +- ...writerside_resolution_regression_test.dart | 149 ++ tools/extract_writerside_semantics.py | 91 + tools/generate_writerside_schema.py | 108 + tools/validate_writerside_conformance.sh | 20 +- 57 files changed, 6464 insertions(+), 276 deletions(-) create mode 100644 docs/writerside-support.md create mode 100644 lib/src/writerside/writerside_schema_data.dart create mode 100644 test/fixtures/writerside/conformance_semantics.json create mode 100644 test/src/writerside_identity_test.dart create mode 100644 tools/extract_writerside_semantics.py create mode 100644 tools/generate_writerside_schema.py diff --git a/assets/export/markdown.typ b/assets/export/markdown.typ index a7668ed2..1f38aa93 100644 --- a/assets/export/markdown.typ +++ b/assets/export/markdown.typ @@ -1,14 +1,14 @@ // BusyMark Markdown PDF renderer. All document data enters through JSON; // Markdown text is never evaluated as Typst source. #let data = json("document.json") -#let metadata = data.metadata +#let document-metadata = data.metadata #let options = data.options #set document( - title: metadata.title, - author: if metadata.author == "" { () } else { (metadata.author,) }, - description: metadata.description, - keywords: metadata.keywords, + title: document-metadata.title, + author: if document-metadata.author == "" { () } else { (document-metadata.author,) }, + description: document-metadata.description, + keywords: document-metadata.keywords, ) #set page( paper: options.paper, @@ -23,7 +23,7 @@ #set text( fallback: true, size: 10.5pt, - lang: metadata.language, + lang: document-metadata.language, ) #set par(leading: 0.68em) #set heading(numbering: none) @@ -102,6 +102,8 @@ emph(body) } else if kind == "underline" { underline(body) + let summary = value-or(item, "summary", "") + if summary != "" { footnote(text(summary)) } } else if kind == "strikethrough" { strike(body) } else if kind == "code" { @@ -232,6 +234,8 @@ let kind = block-data.kind let inlines = value-or(block-data, "inlines", ()) let children = value-or(block-data, "children", ()) + let block-anchor = value-or(block-data, "anchor", "") + if block-anchor != "" { [#metadata(block-anchor) #label(block-anchor)] } if kind == "heading" { let element = heading( level: value-or(block-data, "level", 1), diff --git a/docs/writerside-pdf-export.md b/docs/writerside-pdf-export.md index 8804c37f..9f9f5814 100644 --- a/docs/writerside-pdf-export.md +++ b/docs/writerside-pdf-export.md @@ -26,7 +26,14 @@ admonitions, collapsible content, videos, math, Mermaid, PlantUML, and D2 use th same export semantics as BusyMark's editor and preview. `.topic` XML content is converted into the corresponding native PDF blocks for headings, paragraphs, procedures, steps, admonitions, code, lists, images, videos, links, and math. -Malformed XML remains visible as source instead of disappearing. +Preview and PDF share the Writerside resolver and renderer. XML chapters retain +nested content, and links use unique PDF anchors. Every tab and topic variant is +included as a labeled section. Tables preserve header styles, spans, column +widths and nested cell content. Configured shortcuts, glossary descriptions, +resources and API references participate in the same resolution. + +Unsupported markup produces a visible fallback and warning. Malformed XML or +unresolved required content stops export with an explicit error. ## Offline and security behavior @@ -59,7 +66,10 @@ JetBrains' separate CI tooling outside BusyMark. Focused tests cover instance selection, TOC ordering, variables, Markdown and `.topic` XML composition, local asset rebasing, cancellation, failure mapping, -and an end-to-end native PDF build of the repository's Writerside demo. +and the repository's Writerside demo through a test compiler runner. A separate +integration test compiles semantic content using the real bundled Typst binary +when available. See [Writerside support](writerside-support.md) for the official +builder fixture comparison and the limits of that evidence. Run: diff --git a/docs/writerside-support.md b/docs/writerside-support.md new file mode 100644 index 00000000..44f34804 --- /dev/null +++ b/docs/writerside-support.md @@ -0,0 +1,103 @@ +# Writerside support + +BusyMark's semantic baseline is Writerside **2026.08.0328**, documented by +JetBrains on September 1, 2026. Preview and native PDF export use the same +`WritersideDocumentResolver` and `WritersideDocumentRenderer`. + +## Resolved content + +- Includes accept XML IDs and Markdown block IDs. A Markdown heading identifies + its chapter through the next heading of the same or higher level. Snippets + render at their declaration site in ordinary topics as well as at include sites. +- Blank-line-delimited Markdown inside semantic containers retains formatting + and original source positions. Fenced code and CDATA remain literal. +- Instance-conditioned globals, local scopes, snippet defaults and include + arguments resolve before rendering. Include arguments override defaults; + dependent variable values use the final scope. Escaped percentages and + `ignore-vars` remain supported. +- Links resolve topic/element titles, separate anchors, summaries and selected + instance availability. Missing nullable targets render as text. +- Code, diagrams and API samples share guarded source loading. Configured + directories and paths relative to the originating topic work through includes. + Referenced code supports line lists/ranges and language-aware symbol selection. + Symbol selection uses indentation or lexical declaration/delimiter matching; + unsupported languages, ambiguous declarations and invalid selections produce + source diagnostics rather than selecting arbitrary text. +- Configured glossary terms, keymap actions and resources produce visible, + meaningful references. Resource links are checked again before opening. +- Unsaved open dependency buffers participate in preview and reference indexing. + +## Presentation and export + +| Content | Preview | PDF | +| --- | --- | --- | +| Tabs | Selectable panels, synchronized `group`/`group-key`, arrow/Home/End/Tab navigation | Every panel, with its label | +| Topic switchers | Separate topic-wide `switcher-key` selection | Every variant, with its label | +| Tables | Default first-row headers; header styles, spans, widths, nested content, sticky headers and natural numeric sorting | Structural tables with spans, widths and nested content | +| Shortcuts | Configured action combinations; selectable layouts | Labeled combinations for configured layouts | +| Glossary | Term description tooltip | Term and description footnote | +| Starting pages | Section/card/link groups, titles and descriptions; outside topic content suppressed | Same resolved sections and cards in reading order | +| Summaries | Link/card/web metadata stays out of body text | Metadata stays out of body text | +| API elements | Existing OpenAPI pipeline selects tags, operations, schemas and webhooks; inherited specification references, nested schemas and sample overrides | Same resolved reference and all sample panels | +| Unsupported content | Visible source fallback and source-linked diagnostic | Visible fallback with a warning, or an explicit resolution failure | + +Native export resolves local topic links to unique PDF destinations, including +non-heading IDs. Source references carry resolved text, while image/resource +locations carry paths; asset rewriting therefore cannot turn a diagram reference +into a rejected `file:` source. Export requires saved project changes, as before. + +OpenAPI schema depth controls inline expansion; this editor does not generate +website pages for schema objects. File resources in a PDF remain local links, +so a shared PDF does not bundle those downloadable files automatically. + +## Source assistance + +Source-editor menus and shortcuts provide **Go to Declaration** (`Ctrl+B`), +**Find Usages** (`Alt+F7`) and **Rename** (`Shift+F6`). Identities include the +module, topic file and symbol, with lexical scope for local variables. Find +Usages searches all indexed topics, including those outside the selected +instance. Rename verifies every source range and stages normal undoable edits in +document tabs. Existing topic-file and instance operations remain available. + +Completion filters by syntactic context and prefix before limiting results. +Attribute values use reference kinds and, for element IDs, the referenced topic. +The authoring registry incorporates JetBrains' official topic XSD and documented +release overlays such as sortable tables. Recognizing an element in this +registry does not imply a semantic renderer: unsupported content is diagnosed. +Build-profile validation accepts `true` and rejects the old +`single-file` form. + +## Verification + +`test/src/writerside_*_test.dart` covers resolution, source preservation, file +bounds, instance changes, widgets, editing and export. A native Typst integration +test runs when the bundled compiler is present; otherwise it is explicitly skipped. +API unit tests inject the existing platform parser interface; they do not claim +to run that native parser. + +`test/fixtures/writerside/conformance_semantics.json` was extracted from the +**2026.08.0328** official builder output. The fixture's builder report had 181 +passing checks with no warnings or errors. BusyMark tests compare paragraphs, +quotes, shortcuts, tooltip descriptions, table cell structure and See also links +against this snapshot. This is a comparison for that fixture, not a claim of +complete website artifact parity. + +```bash +flutter test --no-pub test/src/writerside*_test.dart \ + test/src/source_autocomplete_test.dart test/src/source_editor_widget_test.dart \ + test/src/workspace_controller_test.dart test/src/markdown_export_mapper_test.dart +bash tools/validate_writerside_conformance.sh +``` + +The builder check uses temporary source copies and checks both the builder report +and normalized semantic snapshot. Set `WRITERSIDE_CONFORMANCE_OUTPUT` to retain +its generated artifacts. Schema extraction is reproducible with +`python3 tools/generate_writerside_schema.py /path/to/topic.v2.xsd`; the generated +file records the XSD URL and SHA-256. Format the result with `dart format`. + +## Official references + +- [2026.08.0328 release notes](https://www.jetbrains.com/help/writerside/0328.html) +- [Content reuse](https://www.jetbrains.com/help/writerside/reuse-pieces-of-content.html), [variables](https://www.jetbrains.com/help/writerside/variables.html), [links](https://www.jetbrains.com/help/writerside/links-and-references.html), [code](https://www.jetbrains.com/help/writerside/code.html) +- [Tabs](https://www.jetbrains.com/help/writerside/tabs.html), [tables](https://www.jetbrains.com/help/writerside/tables.html), [shortcuts](https://www.jetbrains.com/help/writerside/shortcuts.html), [tooltips](https://www.jetbrains.com/help/writerside/tooltips.html), [resources](https://www.jetbrains.com/help/writerside/downloadable-resources.html) +- [Summaries](https://www.jetbrains.com/help/writerside/summary-elements.html), [starting pages](https://www.jetbrains.com/help/writerside/section-starting-page.html), [API reference](https://www.jetbrains.com/help/writerside/generate-api-reference.html), [API sample overrides](https://www.jetbrains.com/help/writerside/generate-a-single-api-endpoint-reference.html) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 344b6553..14b3cd54 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -2328,6 +2328,55 @@ "inlineMath": "Inline math", "@inlineMath": {"description": "Editor action that inserts an inline mathematical expression."}, "displayMath": "Display math", - "@displayMath": {"description": "Editor action that inserts a display mathematical expression."} - + "@displayMath": {"description": "Editor action that inserts a display mathematical expression."}, + "goToDeclaration": "Go to Declaration", + "findUsages": "Find Usages", + "cannotRenameSymbol": "The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.", + "keyboardLayout": "Keyboard layout", + "diagnosticWritersideUnsupported": "Unsupported or malformed content is displayed as source.", + "diagnosticWritersideSource": "Cannot resolve source “{reference}”: {reason}", + "diagnosticWritersideLink": "Link target is unavailable in this instance: {destination}", + "diagnosticWritersideSchema": "Invalid Writerside markup: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Use true or false; single-file is no longer supported.", + "diagnosticWritersideReference": "Cannot resolve {kind}: {reference}", + "@diagnosticWritersideSource": { + "placeholders": { + "reference": { + "type": "String" + }, + "reason": { + "type": "String" + } + } + }, + "@diagnosticWritersideLink": { + "placeholders": { + "destination": { + "type": "String" + } + } + }, + "@diagnosticWritersideSchema": { + "placeholders": { + "element": { + "type": "String" + }, + "attribute": { + "type": "String" + }, + "reason": { + "type": "String" + } + } + }, + "@diagnosticWritersideReference": { + "placeholders": { + "kind": { + "type": "String" + }, + "reference": { + "type": "String" + } + } + } } diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 53b6bdb2..893180bd 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -6156,6 +6156,70 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Display math'** String get displayMath; + + /// No description provided for @goToDeclaration. + /// + /// In en, this message translates to: + /// **'Go to Declaration'** + String get goToDeclaration; + + /// No description provided for @findUsages. + /// + /// In en, this message translates to: + /// **'Find Usages'** + String get findUsages; + + /// No description provided for @cannotRenameSymbol. + /// + /// In en, this message translates to: + /// **'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'** + String get cannotRenameSymbol; + + /// No description provided for @keyboardLayout. + /// + /// In en, this message translates to: + /// **'Keyboard layout'** + String get keyboardLayout; + + /// No description provided for @diagnosticWritersideUnsupported. + /// + /// In en, this message translates to: + /// **'Unsupported or malformed content is displayed as source.'** + String get diagnosticWritersideUnsupported; + + /// No description provided for @diagnosticWritersideSource. + /// + /// In en, this message translates to: + /// **'Cannot resolve source “{reference}”: {reason}'** + String diagnosticWritersideSource(String reference, String reason); + + /// No description provided for @diagnosticWritersideLink. + /// + /// In en, this message translates to: + /// **'Link target is unavailable in this instance: {destination}'** + String diagnosticWritersideLink(String destination); + + /// No description provided for @diagnosticWritersideSchema. + /// + /// In en, this message translates to: + /// **'Invalid Writerside markup: {element}, {attribute}. {reason}'** + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ); + + /// No description provided for @diagnosticWritersideLlmsTxt. + /// + /// In en, this message translates to: + /// **'Use true or false; single-file is no longer supported.'** + String get diagnosticWritersideLlmsTxt; + + /// No description provided for @diagnosticWritersideReference. + /// + /// In en, this message translates to: + /// **'Cannot resolve {kind}: {reference}'** + String diagnosticWritersideReference(String kind, String reference); } class _AppLocalizationsDelegate diff --git a/lib/l10n/generated/app_localizations_ar.dart b/lib/l10n/generated/app_localizations_ar.dart index a47e3daa..addfe4d9 100644 --- a/lib/l10n/generated/app_localizations_ar.dart +++ b/lib/l10n/generated/app_localizations_ar.dart @@ -3704,4 +3704,49 @@ class AppLocalizationsAr extends AppLocalizations { @override String get displayMath => 'رياضيات معروضة'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 027da5b7..b63f65b7 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -3697,4 +3697,49 @@ class AppLocalizationsDe extends AppLocalizations { @override String get displayMath => 'Mathematische Formel als Block'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index df809f94..cbc7eb2c 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -3692,4 +3692,49 @@ class AppLocalizationsEn extends AppLocalizations { @override String get displayMath => 'Display math'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart index d90d6f25..67c4547d 100644 --- a/lib/l10n/generated/app_localizations_es.dart +++ b/lib/l10n/generated/app_localizations_es.dart @@ -3701,4 +3701,49 @@ class AppLocalizationsEs extends AppLocalizations { @override String get displayMath => 'Matemáticas en bloque'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_et.dart b/lib/l10n/generated/app_localizations_et.dart index 445c301a..44c88389 100644 --- a/lib/l10n/generated/app_localizations_et.dart +++ b/lib/l10n/generated/app_localizations_et.dart @@ -3664,4 +3664,49 @@ class AppLocalizationsEt extends AppLocalizations { @override String get displayMath => 'Plokina matemaatika'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_fa.dart b/lib/l10n/generated/app_localizations_fa.dart index 0d846dda..d409c519 100644 --- a/lib/l10n/generated/app_localizations_fa.dart +++ b/lib/l10n/generated/app_localizations_fa.dart @@ -3709,4 +3709,49 @@ class AppLocalizationsFa extends AppLocalizations { @override String get displayMath => 'ریاضی نمایشی'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_fr.dart b/lib/l10n/generated/app_localizations_fr.dart index 90c79db9..9e88f4ce 100644 --- a/lib/l10n/generated/app_localizations_fr.dart +++ b/lib/l10n/generated/app_localizations_fr.dart @@ -3696,4 +3696,49 @@ class AppLocalizationsFr extends AppLocalizations { @override String get displayMath => 'Formule en bloc'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_hi.dart b/lib/l10n/generated/app_localizations_hi.dart index f78bdba2..ef72233e 100644 --- a/lib/l10n/generated/app_localizations_hi.dart +++ b/lib/l10n/generated/app_localizations_hi.dart @@ -3654,4 +3654,49 @@ class AppLocalizationsHi extends AppLocalizations { @override String get displayMath => 'डिस्प्ले गणित'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_id.dart b/lib/l10n/generated/app_localizations_id.dart index 51c0f9ed..2476c3c6 100644 --- a/lib/l10n/generated/app_localizations_id.dart +++ b/lib/l10n/generated/app_localizations_id.dart @@ -3671,4 +3671,49 @@ class AppLocalizationsId extends AppLocalizations { @override String get displayMath => 'Matematika tampilan'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_it.dart b/lib/l10n/generated/app_localizations_it.dart index 9c87f4d6..492e415d 100644 --- a/lib/l10n/generated/app_localizations_it.dart +++ b/lib/l10n/generated/app_localizations_it.dart @@ -3693,4 +3693,49 @@ class AppLocalizationsIt extends AppLocalizations { @override String get displayMath => 'Formula in blocco'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_ja.dart b/lib/l10n/generated/app_localizations_ja.dart index ab027c77..2941ce97 100644 --- a/lib/l10n/generated/app_localizations_ja.dart +++ b/lib/l10n/generated/app_localizations_ja.dart @@ -3565,4 +3565,49 @@ class AppLocalizationsJa extends AppLocalizations { @override String get displayMath => 'ディスプレイ数式'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_ko.dart b/lib/l10n/generated/app_localizations_ko.dart index 9ad1bfda..2705395c 100644 --- a/lib/l10n/generated/app_localizations_ko.dart +++ b/lib/l10n/generated/app_localizations_ko.dart @@ -3560,4 +3560,49 @@ class AppLocalizationsKo extends AppLocalizations { @override String get displayMath => '수학 표시'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_nb.dart b/lib/l10n/generated/app_localizations_nb.dart index 73c8ceb1..59685712 100644 --- a/lib/l10n/generated/app_localizations_nb.dart +++ b/lib/l10n/generated/app_localizations_nb.dart @@ -3664,4 +3664,49 @@ class AppLocalizationsNb extends AppLocalizations { @override String get displayMath => 'Matematikkblokk'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_nl.dart b/lib/l10n/generated/app_localizations_nl.dart index f21c59e6..0b02c3bb 100644 --- a/lib/l10n/generated/app_localizations_nl.dart +++ b/lib/l10n/generated/app_localizations_nl.dart @@ -3707,4 +3707,49 @@ class AppLocalizationsNl extends AppLocalizations { @override String get displayMath => 'Wiskunde weergeven'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_pl.dart b/lib/l10n/generated/app_localizations_pl.dart index 82b0f244..10b2144f 100644 --- a/lib/l10n/generated/app_localizations_pl.dart +++ b/lib/l10n/generated/app_localizations_pl.dart @@ -3716,4 +3716,49 @@ class AppLocalizationsPl extends AppLocalizations { @override String get displayMath => 'Matematyka blokowa'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart index 29230f9b..17ba9d9f 100644 --- a/lib/l10n/generated/app_localizations_pt.dart +++ b/lib/l10n/generated/app_localizations_pt.dart @@ -3695,6 +3695,51 @@ class AppLocalizationsPt extends AppLocalizations { @override String get displayMath => 'Display math'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } /// The translations for Portuguese, as used in Brazil (`pt_BR`). diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart index a512c800..1b21d3ae 100644 --- a/lib/l10n/generated/app_localizations_ru.dart +++ b/lib/l10n/generated/app_localizations_ru.dart @@ -3715,4 +3715,49 @@ class AppLocalizationsRu extends AppLocalizations { @override String get displayMath => 'Формула отдельным блоком'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_tr.dart b/lib/l10n/generated/app_localizations_tr.dart index 360e5ba4..f821150f 100644 --- a/lib/l10n/generated/app_localizations_tr.dart +++ b/lib/l10n/generated/app_localizations_tr.dart @@ -3666,4 +3666,49 @@ class AppLocalizationsTr extends AppLocalizations { @override String get displayMath => 'Blok matematik'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_uk.dart b/lib/l10n/generated/app_localizations_uk.dart index 64ce8ecd..bb717697 100644 --- a/lib/l10n/generated/app_localizations_uk.dart +++ b/lib/l10n/generated/app_localizations_uk.dart @@ -3723,4 +3723,49 @@ class AppLocalizationsUk extends AppLocalizations { @override String get displayMath => 'Формула окремим блоком'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_vi.dart b/lib/l10n/generated/app_localizations_vi.dart index 1f1b09a9..65254a87 100644 --- a/lib/l10n/generated/app_localizations_vi.dart +++ b/lib/l10n/generated/app_localizations_vi.dart @@ -3660,4 +3660,49 @@ class AppLocalizationsVi extends AppLocalizations { @override String get displayMath => 'Toán hiển thị'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } diff --git a/lib/l10n/generated/app_localizations_zh.dart b/lib/l10n/generated/app_localizations_zh.dart index 68324e13..6754b464 100644 --- a/lib/l10n/generated/app_localizations_zh.dart +++ b/lib/l10n/generated/app_localizations_zh.dart @@ -3686,6 +3686,51 @@ class AppLocalizationsZh extends AppLocalizations { @override String get displayMath => 'Display math'; + + @override + String get goToDeclaration => 'Go to Declaration'; + + @override + String get findUsages => 'Find Usages'; + + @override + String get cannotRenameSymbol => + 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + + @override + String get keyboardLayout => 'Keyboard layout'; + + @override + String get diagnosticWritersideUnsupported => + 'Unsupported or malformed content is displayed as source.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Cannot resolve source “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'Link target is unavailable in this instance: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Invalid Writerside markup: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true or false; single-file is no longer supported.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Cannot resolve $kind: $reference'; + } } /// The translations for Chinese, as used in China (`zh_CN`). diff --git a/lib/src/core/diagnostic_localizations.dart b/lib/src/core/diagnostic_localizations.dart index 464c837f..d3e9147f 100644 --- a/lib/src/core/diagnostic_localizations.dart +++ b/lib/src/core/diagnostic_localizations.dart @@ -252,6 +252,40 @@ String localizeDiagnostic(BuildContext context, Diagnostic diagnostic) { l10n.diagnosticWritersideCategoryUnresolved(value('ref')), 'writerside.topic.ambiguous-reference' => l10n.diagnosticWritersideTopicAmbiguousReference(value('reference')), + 'writerside.content.unsupported' => l10n.diagnosticWritersideUnsupported, + 'writerside.source.invalid' || + 'writerside.api.unresolved' || + 'writerside.api.invalid-selection' => l10n.diagnosticWritersideSource( + value('reference'), + value('reason'), + ), + 'writerside.link.unavailable' => l10n.diagnosticWritersideLink( + value('destination'), + ), + 'writerside.schema.invalid-parent' || + 'writerside.schema.invalid-attribute-value' || + 'writerside.schema.unknown-attribute' || + 'writerside.schema.missing-required-attribute' || + 'writerside.schema.invalid-sortable-style' => + l10n.diagnosticWritersideSchema( + value('element'), + value('attribute'), + value('reason'), + ), + 'writerside.build-profiles.invalid-llms-txt' => + l10n.diagnosticWritersideLlmsTxt, + 'writerside.shortcut.unresolved' => l10n.diagnosticWritersideReference( + 'shortcut', + value('key'), + ), + 'writerside.tooltip.unresolved' => l10n.diagnosticWritersideReference( + 'glossary term', + value('term'), + ), + 'writerside.resource.unresolved' => l10n.diagnosticWritersideReference( + 'resource', + value('src'), + ), _ => l10n.diagnosticUnknown(code), }; } diff --git a/lib/src/editor/editor_text_context_menu.dart b/lib/src/editor/editor_text_context_menu.dart index a3e6380b..9482657f 100644 --- a/lib/src/editor/editor_text_context_menu.dart +++ b/lib/src/editor/editor_text_context_menu.dart @@ -11,11 +11,13 @@ Widget buildBusyMarkEditorTextContextMenu( EditableTextState editableTextState, { required String refineWithAiLabel, VoidCallback? onRefineWithAi, + List> additionalItems = const [], }) { return _BusyMarkEditorTextContextMenu( editableTextState: editableTextState, refineWithAiLabel: refineWithAiLabel, onRefineWithAi: onRefineWithAi, + additionalItems: additionalItems, ); } @@ -24,11 +26,13 @@ class _BusyMarkEditorTextContextMenu extends StatefulWidget { required this.editableTextState, required this.refineWithAiLabel, required this.onRefineWithAi, + required this.additionalItems, }); final EditableTextState editableTextState; final String refineWithAiLabel; final VoidCallback? onRefineWithAi; + final List> additionalItems; @override State<_BusyMarkEditorTextContextMenu> createState() => @@ -123,6 +127,7 @@ class _BusyMarkEditorTextContextMenuState ), ); } + items.addAll(widget.additionalItems); return items; } } diff --git a/lib/src/editor/source/source_autocomplete.dart b/lib/src/editor/source/source_autocomplete.dart index 9851869c..6edd162b 100644 --- a/lib/src/editor/source/source_autocomplete.dart +++ b/lib/src/editor/source/source_autocomplete.dart @@ -40,6 +40,7 @@ class SourceAutocompleteContext { this.currentElement, this.projectIndex, this.moduleId, + this.filePath, }); final List projectFiles; @@ -50,6 +51,7 @@ class SourceAutocompleteContext { final String? currentElement; final WritersideProjectIndex? projectIndex; final String? moduleId; + final String? filePath; SourceAutocompleteContext atCaret(String source, int offset) { final xml = writersideXmlCaretContext(source, offset); @@ -62,6 +64,7 @@ class SourceAutocompleteContext { currentElement: currentElement ?? xml.currentElement, projectIndex: projectIndex, moduleId: moduleId, + filePath: filePath, ); } } @@ -87,10 +90,128 @@ class SourceAutocompleteProvider { }) { context = context.atCaret(document.fullText, fullOffset); final prefix = _prefixBefore(document.fullText, fullOffset).toLowerCase(); + final before = document.fullText.substring( + 0, + fullOffset.clamp(0, document.fullText.length), + ); + final opening = before.lastIndexOf('<'); + final fragment = opening < 0 ? '' : before.substring(opening); + final inTag = opening >= 0 && !fragment.contains('>'); + final valueMatch = inTag + ? RegExp(r'''([\w-]+)\s*=\s*(["'])([^"']*)$''').firstMatch(fragment) + : null; + if (valueMatch != null && context.currentElement != null) { + final attribute = valueMatch[1]!; + var kind = WritersideSchema.referenceKind( + context.currentElement!, + attribute, + ); + final typedValue = valueMatch[3]!; + final hash = typedValue.indexOf('#'); + if (kind == WritersideAttributeReferenceKind.topic && hash >= 0) { + kind = WritersideAttributeReferenceKind.element; + } + final valuePrefix = + (hash >= 0 ? typedValue.substring(hash + 1) : typedValue) + .toLowerCase(); + final symbolKind = switch (kind) { + WritersideAttributeReferenceKind.topic => WritersideSymbolKind.topic, + WritersideAttributeReferenceKind.element => + WritersideSymbolKind.element, + WritersideAttributeReferenceKind.variable => + WritersideSymbolKind.variable, + WritersideAttributeReferenceKind.instance => + WritersideSymbolKind.instance, + WritersideAttributeReferenceKind.resource => + WritersideSymbolKind.resource, + WritersideAttributeReferenceKind.apiSpecification => + WritersideSymbolKind.apiSpecification, + WritersideAttributeReferenceKind.image => WritersideSymbolKind.image, + WritersideAttributeReferenceKind.category => + WritersideSymbolKind.category, + WritersideAttributeReferenceKind.module => WritersideSymbolKind.module, + null => null, + }; + final attributes = { + for (final match in RegExp( + r'''([\w-]+)\s*=\s*(["'])(.*?)\2''', + ).allMatches(fragment)) + match[1]!: match[3]!, + }; + final moduleId = attributes['origin'] ?? context.moduleId; + final module = context.projectIndex?.modulesById[moduleId]; + final current = module?.topics + .where((topic) => topic.filePath == context.filePath) + .firstOrNull; + final topicReference = hash >= 0 + ? typedValue.substring(0, hash) + : attributes['from'] ?? attributes['href']; + final target = topicReference == null || topicReference.isEmpty + ? current + : module?.topicByReference( + topicReference.split('#').first, + fromTopic: current, + ); + final values = + { + ...WritersideSchema.valuesFor( + context.currentElement!, + attribute, + ), + if (attribute == 'lang') ..._codeLanguages, + if (symbolKind != null) + for (final symbol + in context.projectIndex?.symbols ?? + const []) + if ((moduleId == null || symbol.moduleId == moduleId) && + (symbolKind == WritersideSymbolKind.element + ? { + WritersideSymbolKind.element, + WritersideSymbolKind.snippet, + WritersideSymbolKind.seealso, + }.contains(symbol.kind) && + (target != null && + symbol.filePath == target.filePath) + : symbol.kind == symbolKind)) + symbol.name, + if (kind == WritersideAttributeReferenceKind.variable) + ...context.variables, + if (kind == WritersideAttributeReferenceKind.topic) + ...context.topicIds, + if (kind == WritersideAttributeReferenceKind.category) + ...context.categories, + if (attribute == 'src' && kind == null) ...context.projectFiles, + } + .where((value) => value.toLowerCase().startsWith(valuePrefix)) + .toList() + ..sort(); + return values + .take(limit) + .map( + (value) => SourceAutocompleteSuggestion( + label: value, + insertText: value, + kind: switch (kind) { + WritersideAttributeReferenceKind.topic => + SourceAutocompleteKind.topic, + WritersideAttributeReferenceKind.variable => + SourceAutocompleteKind.variable, + WritersideAttributeReferenceKind.image => + SourceAutocompleteKind.image, + WritersideAttributeReferenceKind.category => + SourceAutocompleteKind.category, + _ => SourceAutocompleteKind.link, + }, + ), + ) + .toList(); + } + final tagNameContext = inTag && RegExp(r'^[ for (final tag in WritersideSchema.childElementNames( context.parentElement, - ).take(context.parentElement == null ? 15 : 60)) + )) SourceAutocompleteSuggestion( label: tag, insertText: tag, @@ -188,12 +309,21 @@ class SourceAutocompleteProvider { final filtered = [ for (final suggestion in suggestions) - if (seen.add('${suggestion.kind.name}:${suggestion.label}') && + if ((!tagNameContext || + suggestion.kind == SourceAutocompleteKind.xmlTag) && + (!attributeContext || + suggestion.kind == SourceAutocompleteKind.xmlAttribute) && + seen.add('${suggestion.kind.name}:${suggestion.label}') && (prefix.isEmpty || suggestion.label.toLowerCase().startsWith(prefix))) suggestion, ]..sort((a, b) { - final kind = a.kind.index.compareTo(b.kind.index); + int rank(SourceAutocompleteKind kind) => switch (kind) { + SourceAutocompleteKind.heading => -2, + SourceAutocompleteKind.codeLanguage => -1, + _ => kind.index, + }; + final kind = rank(a.kind).compareTo(rank(b.kind)); if (kind != 0) { return kind; } diff --git a/lib/src/editor/source/source_editor.dart b/lib/src/editor/source/source_editor.dart index c41a7ea1..28c1569b 100644 --- a/lib/src/editor/source/source_editor.dart +++ b/lib/src/editor/source/source_editor.dart @@ -47,6 +47,8 @@ typedef BusyMarkSourceSessionChanged = Set foldedRegionKeys, ); +enum SourceSymbolAction { declaration, usages, rename } + var _sourceEditorUndoSessionSequence = 0; class BusyMarkSourceEditor extends StatefulWidget { @@ -78,6 +80,7 @@ class BusyMarkSourceEditor extends StatefulWidget { this.initialFoldedRegionKeys = const {}, this.onSessionChanged, this.autocompleteContext = const SourceAutocompleteContext(), + this.onSymbolAction, }); final String text; @@ -106,6 +109,7 @@ class BusyMarkSourceEditor extends StatefulWidget { final Set initialFoldedRegionKeys; final BusyMarkSourceSessionChanged? onSessionChanged; final SourceAutocompleteContext autocompleteContext; + final void Function(SourceSymbolAction action, int offset)? onSymbolAction; @override State createState() => BusyMarkSourceEditorState(); @@ -348,6 +352,19 @@ class BusyMarkSourceEditorState extends State { _showAutocomplete(); return KeyEventResult.handled; } + if (widget.onSymbolAction != null) { + final action = key == LogicalKeyboardKey.keyB && keyboard.isControlPressed + ? SourceSymbolAction.declaration + : key == LogicalKeyboardKey.f7 && keyboard.isAltPressed + ? SourceSymbolAction.usages + : key == LogicalKeyboardKey.f6 && keyboard.isShiftPressed + ? SourceSymbolAction.rename + : null; + if (action != null) { + widget.onSymbolAction!(action, _controller.fullSelection.extentOffset); + return KeyEventResult.handled; + } + } final commands = BusyMarkCommandRegistryScope.read(context) ?? BusyMarkCommandCatalog.metadata; @@ -547,6 +564,34 @@ class BusyMarkSourceEditorState extends State { context, editableTextState, refineWithAiLabel: context.l10n.aiRefineWithAi, + additionalItems: [ + if (widget.onSymbolAction != null) + for (final action + in SourceSymbolAction.values) + BusyMarkPopupMenuItem( + value: () => widget.onSymbolAction!( + action, + _controller + .fullSelection + .extentOffset, + ), + label: switch (action) { + SourceSymbolAction.declaration => + 'Go to Declaration', + SourceSymbolAction.usages => + 'Find Usages', + SourceSymbolAction.rename => + context.l10n.rename, + }, + shortcut: switch (action) { + SourceSymbolAction.declaration => + 'Ctrl+B', + SourceSymbolAction.usages => 'Alt+F7', + SourceSymbolAction.rename => + 'Shift+F6', + }, + ), + ], onRefineWithAi: widget.onAiEdit == null ? null : () => unawaited(_runAiEdit()), diff --git a/lib/src/export/markdown_export_mapper.dart b/lib/src/export/markdown_export_mapper.dart index b25653bf..29c3c1d0 100644 --- a/lib/src/export/markdown_export_mapper.dart +++ b/lib/src/export/markdown_export_mapper.dart @@ -77,12 +77,28 @@ class MarkdownExportMapper { ) { final result = []; var index = 0; + String? currentVariant; while (index < blocks.length) { final block = blocks[index]; if (block.isSourceOnly) { index++; continue; } + final variant = block.attributes['switcher-key']; + if (variant != null && variant != currentVariant) { + result.add( + MarkdownExportBlock( + kind: MarkdownExportBlockKind.paragraph, + inlines: [ + MarkdownExportInline( + kind: MarkdownExportInlineKind.strong, + text: variant, + ), + ], + ), + ); + } + currentVariant = variant; final override = blockOverrides[block.id]; if (override != null) { result.add(override); @@ -122,7 +138,19 @@ class MarkdownExportMapper { } final mapped = _mapBlock(block, blockOverrides); if (mapped != null) { - result.add(mapped); + result.add( + mapped.copyWith( + attributes: { + ...mapped.attributes, + if (block.attributes['pdf-anchor'] case final anchor?) + 'anchor': anchor, + }, + ), + ); + if (block.kind == BusyBlockKind.heading || + block.kind == BusyBlockKind.paragraph) { + result.addAll(_mapBlocks(block.children, blockOverrides)); + } } index++; } @@ -412,6 +440,10 @@ class MarkdownExportMapper { kind: MarkdownExportInlineKind.underline, text: inline.text, children: children, + attributes: { + if (inline.attributes['summary'] case final summary?) + 'summary': summary, + }, ), BusyInlineKind.strikethrough => MarkdownExportInline( kind: MarkdownExportInlineKind.strikethrough, @@ -437,8 +469,21 @@ class MarkdownExportMapper { BusyInlineKind.link => MarkdownExportInline( kind: MarkdownExportInlineKind.link, text: inline.text, - destination: _safeLinkDestination(inline.destination), + destination: + inline.attributes['element'] == 'resource' && + inline.attributes['resolved-resource-path']?.isNotEmpty == + true && + Uri.file( + inline.attributes['resolved-resource-path']!, + ).toString() == + inline.destination + ? inline.destination + : _safeLinkDestination(inline.destination), children: children, + attributes: { + if (inline.attributes['summary'] case final summary?) + 'summary': summary, + }, ), BusyInlineKind.image => MarkdownExportInline( kind: MarkdownExportInlineKind.image, diff --git a/lib/src/export/openapi_static_export_mapper.dart b/lib/src/export/openapi_static_export_mapper.dart index 95754d82..b809556d 100644 --- a/lib/src/export/openapi_static_export_mapper.dart +++ b/lib/src/export/openapi_static_export_mapper.dart @@ -24,7 +24,8 @@ class OpenApiStaticExportMapper { required Map attributes, Map> overrides = const {}, }) { - final root = reference.document; + final root = _resolveReferences(reference); + final depth = int.tryParse(attributes['depth'] ?? ''); final blocks = []; if (element == 'api-schema') { final name = attributes['name'] ?? ''; @@ -33,7 +34,7 @@ class OpenApiStaticExportMapper { _map(root['definitions'])[name], ); if (schema.isEmpty) throw FormatException('Unknown API schema: $name'); - blocks.addAll(_schemaBlocks(name, schema)); + blocks.addAll(_schemaBlocks(name, schema, depth: depth)); } else { final selected = {}; final sources = { @@ -84,6 +85,8 @@ class OpenApiStaticExportMapper { {...root, 'paths': selected}, overrides: overrides, generateSamples: attributes['generate-samples']?.toLowerCase() ?? 'all', + schemaDepth: depth, + writerside: true, ); } return MarkdownExportBlock( @@ -125,6 +128,93 @@ class OpenApiStaticExportMapper { ); } + Map _resolveReferences(OpenApiReferenceModel reference) { + final documents = { + '': reference.document, + for (final external in reference.externalDocuments) + external.id: external.document, + }; + Object? expand( + Object? value, + String documentId, + Set active, + int level, + ) { + if (level > 64) return value; + if (value is List) { + return [ + for (final item in value) expand(item, documentId, active, level + 1), + ]; + } + if (value is! Map) return value; + final object = _map(value); + final ref = object[r'$ref']; + if (ref is String) { + final hash = ref.indexOf('#'); + final id = hash < 0 ? ref : ref.substring(0, hash); + final targetId = id.isEmpty ? documentId : id; + final pointer = hash < 0 ? '' : ref.substring(hash + 1); + final identity = '$targetId#$pointer'; + if (!active.contains(identity)) { + Object? target = documents[targetId]; + for (final part in pointer.split('/').skip(1)) { + target = target is Map + ? target[Uri.decodeComponent( + part, + ).replaceAll('~1', '/').replaceAll('~0', '~')] + : null; + } + if (target is Map) { + return expand( + { + ..._map(target), + for (final entry in object.entries) + if (entry.key != r'$ref') entry.key: entry.value, + }, + targetId, + {...active, identity}, + level + 1, + ); + } + } + return object; + } + return { + for (final entry in object.entries) + entry.key: expand(entry.value, documentId, active, level + 1), + }; + } + + return _map(expand(reference.document, '', {}, 0)); + } + + Object? _schemaExample(Map schema, [int depth = 0]) { + if (depth > 16) return null; + if (schema.containsKey('example')) return schema['example']; + if (schema.containsKey('default')) return schema['default']; + if (schema.containsKey('const')) return schema['const']; + if (_list(schema['enum']).isNotEmpty) return _list(schema['enum']).first; + if (schema['type'] == 'object' || schema.containsKey('properties')) { + return { + for (final property in _map(schema['properties']).entries) + property.key: _schemaExample(_map(property.value), depth + 1), + }; + } + if (schema['type'] == 'array') { + return [_schemaExample(_map(schema['items']), depth + 1)]; + } + if (schema['type'] == 'boolean') return false; + if (schema['type'] == 'integer' || schema['type'] == 'number') { + return schema['minimum'] ?? 0; + } + for (final key in ['oneOf', 'anyOf', 'allOf']) { + if (_list(schema[key]).isNotEmpty) { + return _schemaExample(_map(_list(schema[key]).first), depth + 1); + } + } + return schema['type'] == 'null' ? null : 'string'; + } + void _addServers( List blocks, Map document, @@ -159,6 +249,8 @@ class OpenApiStaticExportMapper { Map document, { Map> overrides = const {}, String generateSamples = 'none', + int? schemaDepth, + bool writerside = false, }) { final paths = _map(document['paths']); if (paths.isEmpty) { @@ -177,10 +269,20 @@ class OpenApiStaticExportMapper { if (operation.isEmpty) { continue; } - blocks.add(_heading(4, '${method.toUpperCase()} ${pathEntry.key}')); final summary = _string(operation['summary']); + blocks.add( + _heading( + 4, + writerside && summary.isNotEmpty + ? summary + : '${method.toUpperCase()} ${pathEntry.key}', + ), + ); + if (writerside) { + blocks.add(_paragraph('${method.toUpperCase()} ${pathEntry.key}')); + } final description = _string(operation['description']); - _addText(blocks, summary); + if (!writerside) _addText(blocks, summary); if (description != summary) { _addText(blocks, description); } @@ -205,27 +307,61 @@ class OpenApiStaticExportMapper { _addParameters(blocks, parameters, headingLevel: 5); _addRequestBody(blocks, operation['requestBody'], headingLevel: 5); _addResponses(blocks, operation['responses'], headingLevel: 5); - final replacement = overrides['$method ${pathEntry.key}']; + final operationKey = '$method ${pathEntry.key}'; + final replacement = overrides[operationKey]; if (replacement != null) { blocks.addAll(replacement); } else { - if ({'all', 'request'}.contains(generateSamples)) { + final request = overrides['$operationKey request']; + if (request != null) { + blocks.addAll(request); + } else if ({'all', 'request'}.contains(generateSamples)) { _addExamples( blocks, 'Request sample', _map(operation['requestBody']), ); } - if ({'all', 'response'}.contains(generateSamples)) { - for (final response in _map(operation['responses']).entries) { + final responseCodes = { + ..._map(operation['responses']).keys, + for (final key in overrides.keys) + if (key.startsWith('$operationKey response ')) + key.substring('$operationKey response '.length), + }; + for (final code in responseCodes) { + final response = overrides['$operationKey response $code']; + if (response != null) { + blocks.addAll(response); + } else if ({'all', 'response'}.contains(generateSamples)) { _addExamples( blocks, - 'Response ${response.key}', - _map(response.value), + 'Response $code', + _map(_map(operation['responses'])[code]), ); } } } + if (writerside) { + final schemaSources = { + 'Request schema': _map(operation['requestBody']), + for (final response in _map(operation['responses']).entries) + 'Response ${response.key} schema': _map(response.value), + }; + for (final source in schemaSources.entries) { + for (final media in _map(source.value['content']).entries) { + final schema = _map(_map(media.value)['schema']); + if (schema.isNotEmpty) { + blocks.addAll( + _schemaBlocks( + '${source.key} (${media.key})', + schema, + depth: schemaDepth, + ), + ); + } + } + } + } final callbacks = _map(operation['callbacks']); if (callbacks.isNotEmpty) { @@ -242,7 +378,9 @@ class OpenApiStaticExportMapper { String title, Map object, ) { - for (final media in _map(object['content']).values.map(_map)) { + for (final entry in _map(object['content']).entries) { + if (!entry.key.toLowerCase().contains('json')) continue; + final media = _map(entry.value); final examples = [ if (media['example'] != null) media['example'], for (final example in _map(media['examples']).values) @@ -251,6 +389,11 @@ class OpenApiStaticExportMapper { _map(media['examples']).isEmpty && _map(media['schema'])['example'] != null) _map(media['schema'])['example'], + if (media['example'] == null && + _map(media['examples']).isEmpty && + _map(media['schema'])['example'] == null && + _map(media['schema']).isNotEmpty) + _schemaExample(_map(media['schema'])), ]; for (final example in examples.where((value) => value != null)) { blocks @@ -453,8 +596,10 @@ class OpenApiStaticExportMapper { List _schemaBlocks( String name, - Map schema, - ) { + Map schema, { + int? depth, + int level = 0, + }) { final blocks = [_heading(4, name)]; _addText(blocks, _string(schema['description'])); final details = >[]; @@ -484,6 +629,43 @@ class OpenApiStaticExportMapper { _table(const ['Property', 'Type', 'Required', 'Description'], rows), ); } + if ((depth == null || level + 1 < depth) && level < 32) { + for (final property in _map(schema['properties']).entries) { + final child = _map(property.value); + if (_map(child['properties']).isNotEmpty || child['items'] != null) { + blocks.addAll( + _schemaBlocks( + '$name.${property.key}', + child, + depth: depth, + level: level + 1, + ), + ); + } + } + if (schema['items'] != null) { + blocks.addAll( + _schemaBlocks( + '$name[]', + _map(schema['items']), + depth: depth, + level: level + 1, + ), + ); + } + for (final keyword in ['allOf', 'oneOf', 'anyOf']) { + for (final (index, part) in _list(schema[keyword]).indexed) { + blocks.addAll( + _schemaBlocks( + '$name $keyword ${index + 1}', + _map(part), + depth: depth, + level: level + 1, + ), + ); + } + } + } return blocks; } diff --git a/lib/src/export/writerside_pdf_export_service.dart b/lib/src/export/writerside_pdf_export_service.dart index cbc1fbec..9008978a 100644 --- a/lib/src/export/writerside_pdf_export_service.dart +++ b/lib/src/export/writerside_pdf_export_service.dart @@ -1,4 +1,6 @@ import 'dart:io'; +import 'dart:convert'; +import 'package:crypto/crypto.dart'; import 'package:path/path.dart' as p; @@ -326,6 +328,9 @@ class WritersidePdfExportService { Map modulesByOrigin, ) async { final modules = {module, ...modulesByOrigin.values}; + final seenAnchors = {}; + String anchor(String path, String id) => + 'ws-${sha256.convert(utf8.encode('$path#$id')).toString().substring(0, 24)}'; ({WritersideModule module, WritersideTopic topic}) sourceContext( Map attributes, @@ -362,6 +367,19 @@ class WritersidePdfExportService { destination; } final attributes = {...inline.attributes}; + if (inline.kind == BusyInlineKind.link && + destination != null && + !(Uri.tryParse(destination)?.hasScheme ?? false)) { + final hash = destination.indexOf('#'); + final path = hash < 0 ? destination : destination.substring(0, hash); + final id = hash < 0 ? '' : destination.substring(hash + 1); + final target = path.isEmpty ? topic.filePath : path; + if (modules.any( + (module) => module.topics.any((topic) => topic.filePath == target), + )) { + destination = '#${anchor(target, id)}'; + } + } for (final name in ['src', 'preview-src']) { final value = attributes[name]; if (value == null || value.trim().isEmpty) { @@ -371,16 +389,42 @@ class WritersidePdfExportService { await _resolvedAssetUri(source.module, source.topic, value) ?? value; } + var text = inline.text; + var children = await Future.wait(inline.children.map(resolveInline)); + if (attributes['shortcut-layouts'] case final layoutsJson?) { + final layouts = (jsonDecode(layoutsJson) as Map).cast(); + if (layouts.length > 1) { + text = layouts.entries + .map((entry) => '${entry.key}: ${entry.value}') + .join('; '); + children = const []; + } + } + if (attributes['switcher-key'] case final key?) { + text = '[$key] ${inline.plainText}'; + children = const []; + } return inline.copyWith( + text: text, destination: destination, attributes: attributes, - children: await Future.wait(inline.children.map(resolveInline)), + children: children, ); } Future resolveBlock(BusyBlock block) async { final attributes = {...block.attributes}; final source = sourceContext(attributes); + final id = attributes['id']; + final candidate = block.id == 'writerside-document-title' + ? anchor(topic.filePath, '') + : id == null + ? null + : anchor(topic.filePath, id); + if (candidate != null && seenAnchors.add(candidate)) { + attributes['pdf-anchor'] = candidate; + } + if (id != null) attributes.remove('id'); for (final name in ['src', 'preview-src']) { if (name == 'src' && block.kind == BusyBlockKind.codeBlock) continue; final value = attributes[name]; diff --git a/lib/src/workspace/presentation/workspace_screen.dart b/lib/src/workspace/presentation/workspace_screen.dart index 59bd15de..a89bebac 100644 --- a/lib/src/workspace/presentation/workspace_screen.dart +++ b/lib/src/workspace/presentation/workspace_screen.dart @@ -76,6 +76,7 @@ import '../../search/search_replace_service.dart'; import '../../visualization/visualization_card.dart'; import '../../visualization/visualization_models.dart'; import '../../writerside/writerside_model.dart'; +import '../../writerside/writerside_project.dart'; import '../../writerside/writerside_toc_editor.dart'; import '../../writerside/writerside_topic_creator.dart'; import '../../writerside/writerside_topic_removal_service.dart'; @@ -9918,6 +9919,11 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { diagnostics: widget.state.workspace?.allDiagnostics ?? const [], + onSymbolAction: + widget.state.workspace?.writersideProject == null + ? null + : (action, offset) => + unawaited(_handleSymbolAction(action, offset)), autocompleteContext: _sourceAutocompleteContext( widget.state.workspace, ), @@ -10285,6 +10291,125 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { }; } + Future _handleSymbolAction( + SourceSymbolAction action, + int offset, + ) async { + final controller = ref.read(workspaceControllerProvider.notifier); + final path = widget.state.workspace?.activeFilePath; + if (path == null) return; + final index = await controller.writersideEditorIndex(); + if (!mounted || index == null) return; + final symbols = index.symbolsAt(path, offset); + final symbol = symbols.firstOrNull; + if (symbol == null) { + await showBusyMarkModalDialog( + context, + builder: (context) => AlertDialog( + content: Text(context.l10n.noResults), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text(context.l10n.close), + ), + ], + ), + ); + return; + } + Future navigate(String filePath, SourceSpan? span) async { + await controller.openActiveFile(filePath); + if (!mounted) return; + WidgetsBinding.instance.addPostFrameCallback((_) { + _sourceEditorKey.currentState?.scrollToLine(span?.startLine ?? 1); + }); + } + + if (action == SourceSymbolAction.declaration) { + await navigate(symbol.filePath, symbol.span); + } else if (action == SourceSymbolAction.usages) { + final usages = index.findUsages(symbol).toList(); + final selected = await showBusyMarkModalDialog( + context, + builder: (context) => AlertDialog( + title: Text('${context.l10n.findUsages}: ${symbol.name}'), + content: SizedBox( + width: 600, + height: 360, + child: usages.isEmpty + ? Text(context.l10n.noResults) + : ListView( + children: [ + for (final usage in usages) + ListTile( + title: Text( + p.relative( + usage.filePath, + from: widget.state.workspace?.rootPath, + ), + ), + subtitle: Text( + '${usage.span.startLine}:${usage.span.startColumn} ${usage.value}', + ), + onTap: () => Navigator.pop(context, usage), + ), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text(context.l10n.close), + ), + ], + ), + ); + if (selected != null) await navigate(selected.filePath, selected.span); + } else { + var pendingName = symbol.name; + final newName = await showBusyMarkModalEditorDialog( + context, + builder: (context) => AlertDialog( + title: Text('${context.l10n.rename}: ${symbol.name}'), + content: TextFormField( + initialValue: pendingName, + onChanged: (value) => pendingName = value, + autofocus: true, + onFieldSubmitted: (value) => Navigator.pop(context, value), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text(context.l10n.cancel), + ), + TextButton( + onPressed: () => Navigator.pop(context, pendingName), + child: Text(context.l10n.rename), + ), + ], + ), + ); + if (newName == null || !mounted) return; + final applied = await controller.applyWritersideRename( + index.safeRenameEdits(symbol, newName), + ); + if (!applied && mounted) { + await showBusyMarkModalDialog( + context, + builder: (context) => AlertDialog( + content: Text(context.l10n.cannotRenameSymbol), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text(context.l10n.close), + ), + ], + ), + ); + } + } + } + SourceAutocompleteContext _sourceAutocompleteContext(Workspace? workspace) { final project = workspace?.writersideProject; if (workspace == null || project == null) { @@ -10294,6 +10419,7 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { projectFiles: [for (final file in workspace.files) file.relativePath], projectIndex: project.index, moduleId: project.activeModuleId, + filePath: workspace.activeFilePath, ); } @@ -10368,15 +10494,58 @@ class _EditorPreviewSplitState extends ConsumerState<_EditorPreviewSplit> { void _scrollPreviewToHeading(String headingId) { final blocks = widget.state.preview?.blocks ?? const []; - final index = blocks.indexWhere( - (block) => - block.kind == PreviewBlockKind.heading && - block.attributes['id'] == headingId, - ); - if (index < 0 || !_previewScrollController.isAttached) { - return; - } - unawaited(_scrollPreviewToIndex(index, alignment: 0.0)); + bool contains(PreviewBlock block) => + block.attributes['id'] == headingId || block.children.any(contains); + final index = blocks.indexWhere(contains); + if (index < 0 || !_previewScrollController.isAttached) return; + unawaited(() async { + await _scrollPreviewToIndex(index, alignment: 0); + if (!mounted) return; + final blockContext = _previewBlockContexts[index]; + if (blockContext == null || !blockContext.mounted) return; + final selection = WritersidePreviewScope.of(blockContext); + void reveal(PreviewBlock block) { + if (!contains(block)) return; + if (block.attributes['switcher-key'] case final keys?) { + selection?.select( + 'busymark-topic-switcher', + keys.split(',').first.trim(), + ); + } + if (block.kind == PreviewBlockKind.tabs) { + final panel = block.children.where(contains).firstOrNull; + if (panel != null && block.attributes['group'] != null) { + selection?.select( + block.attributes['group']!, + panel.attributes['group-key'] ?? panel.text, + ); + } + } + for (final child in block.children) { + reveal(child); + } + } + + reveal(blocks[index]); + await WidgetsBinding.instance.endOfFrame; + if (!mounted || !blockContext.mounted) return; + BuildContext? target; + void find(Element element) { + if (element.widget.key == ValueKey('writerside-anchor-$headingId')) { + target = element; + } + element.visitChildElements(find); + } + + (blockContext as Element).visitChildElements(find); + if (target != null) { + await Scrollable.ensureVisible( + target!, + alignment: 0, + duration: BusyMarkMotion.scroll, + ); + } + }()); } Future _scrollPreviewToIndex( @@ -11316,6 +11485,38 @@ class _PreviewBlockView extends ConsumerWidget { editRevision: editRevision, childrenBuilder: (blocks) => _previewChildBlocks(blocks, first: true), ), + PreviewBlockKind.container + when displayBlock.attributes['writerside-card'] == 'true' => + Card( + child: Padding( + padding: const EdgeInsets.all(16), + child: _previewChildBlocks(displayBlock.children, first: true), + ), + ), + PreviewBlockKind.container + when displayBlock.attributes['writerside-grid'] == 'true' => + LayoutBuilder( + builder: (context, constraints) { + final columns = constraints.maxWidth < 500 + ? 1 + : displayBlock.attributes['narrow'] == 'true' + ? 3 + : 2; + return Wrap( + spacing: 16, + runSpacing: 16, + children: [ + for (final child in displayBlock.children) + SizedBox( + width: child.kind == PreviewBlockKind.heading + ? constraints.maxWidth + : (constraints.maxWidth - 16 * (columns - 1)) / columns, + child: _previewChildBlocks([child], first: true), + ), + ], + ); + }, + ), PreviewBlockKind.container when displayBlock.attributes['htmlTag'] == 'figure' => _PreviewFigure(block: displayBlock, workspace: workspace, first: first), @@ -11344,9 +11545,15 @@ class _PreviewBlockView extends ConsumerWidget { ), ), }; - return blockDirection == inheritedDirection + final anchored = displayBlock.attributes['id'] == null ? child - : Directionality(textDirection: blockDirection, child: child); + : KeyedSubtree( + key: ValueKey("writerside-anchor-${displayBlock.attributes['id']}"), + child: child, + ); + return blockDirection == inheritedDirection + ? anchored + : Directionality(textDirection: blockDirection, child: anchored); } void _reportMathDiagnostic( @@ -12234,6 +12441,15 @@ InlineSpan _previewInlineSpan( String? inheritedLinkDestination, TextStyle? inheritedStyle, }) { + final selected = + WritersidePreviewScope.of(context)?.selected('busymark-topic-switcher') ?? + inline.attributes['switcher-default']; + final keys = inline.attributes['switcher-key']; + if (keys != null && + selected != null && + !keys.split(',').map((key) => key.trim()).contains(selected)) { + return const TextSpan(text: ''); + } final shortcutLayouts = inline.attributes['shortcut-layouts']; if (shortcutLayouts != null) { final layouts = (jsonDecode(shortcutLayouts) as Map).cast(); @@ -12245,7 +12461,7 @@ InlineSpan _previewInlineSpan( alignment: PlaceholderAlignment.baseline, baseline: TextBaseline.alphabetic, child: PopupMenuButton( - tooltip: 'Keyboard layout', + tooltip: context.l10n.keyboardLayout, onSelected: (value) => controller?.select('busymark-keymap', value), itemBuilder: (context) => [ for (final entry in layouts.entries) @@ -12635,7 +12851,28 @@ Future _openPreviewLink( } final uri = parseSchemedUri(target); if (uri != null) { - if (!isLaunchableExternalUri(uri)) { + var isResource = false; + if (uri.scheme == 'file') { + final workspace = ref.read(workspaceControllerProvider).workspace; + final modules = + workspace?.writersideProject?.modules ?? + [if (workspace?.writersideModule case final module?) module]; + for (final module in modules) { + for (final resource in module.referenceData.resources.values) { + if (resource.path != null && Uri.file(resource.path!) == uri) { + final checked = await const WritersideSourceLoader().load( + reference: p.relative(resource.path!, from: module.rootPath), + documentPath: module.config.filePath, + workspaceRoot: module.rootPath, + readText: false, + ); + isResource = + checked.path == resource.path && checked.failure == null; + } + } + } + } + if (!isResource && !isLaunchableExternalUri(uri)) { if (context.mounted) { _showPreviewLinkMessage( context, @@ -12791,7 +13028,19 @@ void _navigatePreviewAnchor( slugForHeading(heading.text) == slug, ) .firstOrNull; - if (heading == null) { + PreviewBlock? findAnchor(Iterable blocks) { + for (final block in blocks) { + if ({normalizedAnchor, decodedAnchor}.contains(block.attributes['id'])) { + return block; + } + final nested = findAnchor(block.children); + if (nested != null) return nested; + } + return null; + } + + final element = findAnchor(state.preview?.blocks ?? const []); + if (heading == null && element == null) { _showPreviewLinkMessage(context, context.l10n.anchorNotFound(anchor)); return; } @@ -12801,9 +13050,10 @@ void _navigatePreviewAnchor( _OutlineNavigationTarget( workspaceId: workspace.id, filePath: workspace.activeFilePath, - headingId: heading.id, - line: heading.sourceStartLine, - editorBlockId: heading.editorBlockId, + headingId: heading?.id ?? element!.attributes['id']!, + line: heading?.sourceStartLine ?? element?.sourceStartLine, + editorBlockId: + heading?.editorBlockId ?? element?.attributes['editorBlockId'], ), ); } diff --git a/lib/src/workspace/workspace_controller.dart b/lib/src/workspace/workspace_controller.dart index 88d0d1a5..b2c09a27 100644 --- a/lib/src/workspace/workspace_controller.dart +++ b/lib/src/workspace/workspace_controller.dart @@ -14,6 +14,7 @@ import '../markdown/busymark_document.dart'; import '../markdown/document_outline.dart'; import '../markdown/preview_model.dart'; import '../writerside/writerside_project_creator.dart'; +import '../writerside/writerside_project.dart'; import '../writerside/writerside_instance_service.dart'; import '../writerside/writerside_topic_removal_service.dart'; import '../writerside/writerside_topic_creator.dart'; @@ -1777,6 +1778,99 @@ class WorkspaceController extends Notifier { return true; } + /// Rebuilds identities from the current editor buffers before navigation or + /// refactoring; an inactive, unsaved dependency is still authoritative. + Future writersideEditorIndex() async { + var project = state.workspace?.writersideProject; + if (project == null) return null; + final buffers = state.documentBuffers; + for (final module in project.modules.toList()) { + final loaded = await _service.writersideService.load( + module.rootPath, + sourceOverrides: { + ...module.sourceOverrides, + for (final buffer in buffers) + if (buffer.filePath != null && + p.isWithin(module.rootPath, buffer.filePath!)) + buffer.filePath!: buffer.text, + }, + ); + project = project!.withModule(loaded); + } + return project!.index; + } + + /// Stages a rename in normal undoable document buffers. All source ranges + /// are verified before any buffer is changed, including already dirty tabs. + Future applyWritersideRename(List edits) async { + if (edits.isEmpty) return false; + final workspaceId = state.workspace?.id; + final initialBuffers = state.documentBuffers; + final byPath = >{}; + for (final edit in edits) { + byPath.putIfAbsent(edit.filePath, () => []).add(edit); + } + final staged = {}; + for (final entry in byPath.entries) { + final buffer = + initialBuffers + .where((buffer) => buffer.filePath == entry.key) + .firstOrNull ?? + _fileBuffer( + entry.key, + await _service.loadTextWithSnapshot(entry.key), + ); + var source = buffer.text; + var previousStart = source.length + 1; + entry.value.sort( + (a, b) => b.span.startOffset.compareTo(a.span.startOffset), + ); + for (final edit in entry.value) { + final span = edit.span; + if (edit.expectedText == null || + span.startOffset < 0 || + span.endOffset > source.length || + span.endOffset > previousStart || + source.substring(span.startOffset, span.endOffset) != + edit.expectedText) { + return false; + } + source = source.replaceRange( + span.startOffset, + span.endOffset, + edit.replacement, + ); + previousStart = span.startOffset; + } + staged[entry.key] = buffer.edited(source); + } + if (!ref.mounted || + state.workspace?.id != workspaceId || + initialBuffers.any( + (initial) => + state.documentBuffers + .where((current) => current.id == initial.id) + .firstOrNull + ?.text != + initial.text, + )) { + return false; + } + final buffers = [ + for (final buffer in state.documentBuffers) + staged.remove(buffer.filePath) ?? buffer, + ...staged.values, + ]; + state = state.copyWith(documentBuffers: buffers); + _editRevision = state.activeBuffer?.revision ?? _editRevision; + _schedulePersistence(); + _fileMonitor.updateOpenFilePaths( + buffers.map((buffer) => buffer.filePath).whereType(), + ); + _requestDerivedRefresh(rebuildPreview: true, refreshOutline: true); + return true; + } + void updateActiveEditorMode(DocumentViewModePreference mode) { final buffer = state.activeBuffer; if (buffer == null || buffer.editorState.mode == mode) { @@ -2097,7 +2191,7 @@ class WorkspaceController extends Notifier { } _derivedRefreshRunning = true; try { - while (_derivedRefreshPending) { + while (ref.mounted && _derivedRefreshPending) { _derivedRefreshPending = false; final rebuildPreview = _pendingPreviewRefresh; final refreshOutline = _pendingOutlineRefresh; @@ -2113,7 +2207,7 @@ class WorkspaceController extends Notifier { } } finally { _derivedRefreshRunning = false; - if (_derivedRefreshPending) { + if (ref.mounted && _derivedRefreshPending) { unawaited(_drainDerivedRefreshes()); } } @@ -2138,7 +2232,14 @@ class WorkspaceController extends Notifier { final editRevision = buffer.revision; final operationRevision = _activeDocumentRevision; try { - final reparsed = await _service.reparseActive(workspace, text); + final overlaid = await _service.withWritersideSources(workspace, { + for (final buffer in state.documentBuffers) + if (buffer.filePath != null && + buffer.filePath != workspace.activeFilePath && + buffer.dirty) + buffer.filePath!: buffer.text, + }); + final reparsed = await _service.reparseActive(overlaid, text); if (!_isCurrentActiveDocument( operationRevision, workspaceId: workspaceId, @@ -2178,7 +2279,14 @@ class WorkspaceController extends Notifier { final editRevision = state.activeBuffer?.revision ?? _editRevision; final operationRevision = _activeDocumentRevision; try { - final reparsed = await _service.reparseActive(workspace, text); + final overlaid = await _service.withWritersideSources(workspace, { + for (final buffer in state.documentBuffers) + if (buffer.filePath != null && + buffer.filePath != workspace.activeFilePath && + buffer.dirty) + buffer.filePath!: buffer.text, + }); + final reparsed = await _service.reparseActive(overlaid, text); final preview = await _service.buildPreviewAsync(reparsed, text); if (!_isCurrentActiveDocument( operationRevision, @@ -2363,7 +2471,14 @@ class WorkspaceController extends Notifier { return; } try { - final reparsed = await _service.reparseActive(workspace, text); + final overlaid = await _service.withWritersideSources(workspace, { + for (final buffer in state.documentBuffers) + if (buffer.filePath != null && + buffer.filePath != workspace.activeFilePath && + buffer.dirty) + buffer.filePath!: buffer.text, + }); + final reparsed = await _service.reparseActive(overlaid, text); final currentWorkspace = state.workspace; final currentBuffer = state.documentBuffers .where((buffer) => buffer.id == bufferId) @@ -3010,7 +3125,14 @@ class WorkspaceController extends Notifier { final editRevision = state.activeBuffer?.revision ?? _editRevision; final operationRevision = _activeDocumentRevision; try { - final reparsed = await _service.reparseActive(workspace, text); + final overlaid = await _service.withWritersideSources(workspace, { + for (final buffer in state.documentBuffers) + if (buffer.filePath != null && + buffer.filePath != workspace.activeFilePath && + buffer.dirty) + buffer.filePath!: buffer.text, + }); + final reparsed = await _service.reparseActive(overlaid, text); final currentWorkspace = state.workspace; if (!_isCurrentActiveDocument( operationRevision, @@ -3239,6 +3361,7 @@ class WorkspaceController extends Notifier { required String? workspaceId, required String? activeFilePath, }) { + if (!ref.mounted) return false; final workspace = state.workspace; return operationRevision == _activeDocumentRevision && workspace != null && diff --git a/lib/src/workspace/workspace_service.dart b/lib/src/workspace/workspace_service.dart index db76e9f0..51a1f9a0 100644 --- a/lib/src/workspace/workspace_service.dart +++ b/lib/src/workspace/workspace_service.dart @@ -1297,6 +1297,36 @@ class WorkspaceService { } } + Future withWritersideSources( + Workspace workspace, + Map sources, + ) async { + final project = workspace.writersideProject; + if (project == null) return workspace; + var updated = project; + for (final module in project.modules) { + final overrides = { + for (final entry in sources.entries) + if (p.isWithin(module.rootPath, entry.key) && + module.sourceOverrides[entry.key] != entry.value) + entry.key: entry.value, + }; + if (overrides.isEmpty) continue; + updated = updated.withModule( + await writersideService.load( + module.rootPath, + options: _useWorkspaceScanOptionsForWriterside ? scanOptions : null, + sourceOverrides: {...module.sourceOverrides, ...overrides}, + ), + ); + } + return workspace.copyWith( + writersideProject: updated, + writersideModule: updated.activeModule, + diagnostics: updated.diagnostics, + ); + } + Future reparseActive(Workspace workspace, String source) async { final active = workspace.activeFilePath ?? workspace.markdown?.filePath; if (active == null) { diff --git a/lib/src/writerside/writerside_code_selection.dart b/lib/src/writerside/writerside_code_selection.dart index 9618f3c1..6c0944e3 100644 --- a/lib/src/writerside/writerside_code_selection.dart +++ b/lib/src/writerside/writerside_code_selection.dart @@ -28,6 +28,14 @@ class WritersideCodeSelection { return selected.join('\n'); } if (symbol == null) return source; + if (symbol.contains('.')) { + final parts = symbol.split('.'); + var selected = source; + for (final part in parts) { + selected = select(selected, {...attributes, 'include-symbol': part}); + } + return selected; + } final language = (attributes['lang'] ?? attributes['language'] ?? '') .toLowerCase(); if (language == 'python' || language == 'py') { diff --git a/lib/src/writerside/writerside_document_parser.dart b/lib/src/writerside/writerside_document_parser.dart index 760ebf4b..53442e4c 100644 --- a/lib/src/writerside/writerside_document_parser.dart +++ b/lib/src/writerside/writerside_document_parser.dart @@ -63,8 +63,8 @@ class WritersideDocumentParser { continue; } } on Object { - // Retain the original Markdown block when an in-progress XML - // fragment is temporarily malformed. + nodes.add(WritersideRawNode(span: span, rawSource: raw)); + continue; } } nodes.add( @@ -99,7 +99,7 @@ class WritersideDocumentParser { } for (final event in parseEvents( - source, + markdownContent ? _maskMarkdownCode(source) : source, withLocation: true, validateNesting: true, validateDocument: false, @@ -149,31 +149,44 @@ class WritersideDocumentParser { if (markdownContent && _markdownContainers.contains(frame.name)) { final inner = fullSource.substring(frame.openingEndOffset, start); if (RegExp(r'^\s*\n\s*\n').hasMatch(inner) && - RegExp(r'\n\s*\n\s*$').hasMatch(inner) && - !inner.contains('() + .where((node) => node.rawSource.startsWith('[]; + var segmentStart = frame.openingEndOffset; + void markdownSegment(int end) { + final segment = fullSource.substring(segmentStart, end); + if (segment.trim().isEmpty) return; + final parsed = const MarkdownParser().parse( + filePath: filePath, + source: segment, + mode: MarkdownMode.writersideMarkdown, + validateLocalReferences: false, + ); + final mixed = parseMarkdown( + filePath: filePath, + source: segment, + markdown: parsed.busyDocument, + ); + mixedChildren.addAll( mixed.nodes.map( - (node) => _rebaseNode( - node, - frame.openingEndOffset, - filePath, - fullSource, - ), + (node) => + _rebaseNode(node, segmentStart, filePath, fullSource), ), ); + } + + for (final literal in literals) { + markdownSegment(literal.span.startOffset); + mixedChildren.add(literal); + segmentStart = literal.span.endOffset; + } + markdownSegment(start); + frame.children + ..clear() + ..addAll(mixedChildren); } } append(frame.build(filePath: filePath, source: fullSource, end: end)); @@ -182,7 +195,11 @@ class WritersideDocumentParser { if (event is XmlTextEvent) { append( WritersideTextNode( - text: event.value, + text: markdownContent + ? event.value + .replaceAll('\uE000', '<') + .replaceAll('\uE001', '&') + : event.value, span: SourceSpan.fromOffsets( filePath: filePath, source: fullSource, @@ -416,3 +433,31 @@ String? _safeSubstring(String value, int start, int end) { } return value.substring(start, end); } + +// XML events still own element boundaries. Mask only fenced Markdown bodies +// for that scan; the Markdown parser subsequently reads the original source. +String _maskMarkdownCode(String source) { + final chars = source.split(''); + String? fence; + var minimum = 0; + var offset = 0; + for (final line in source.split('\n')) { + final match = RegExp(r'^ {0,3}(`{3,}|~{3,})').firstMatch(line); + if (fence == null && match != null) { + fence = match[1]![0]; + minimum = match[1]!.length; + } else if (fence != null && + match != null && + match[1]![0] == fence && + match[1]!.length >= minimum) { + fence = null; + } else if (fence != null) { + for (var index = offset; index < offset + line.length; index++) { + if (chars[index] == '<') chars[index] = '\uE000'; + if (chars[index] == '&') chars[index] = '\uE001'; + } + } + offset += line.length + 1; + } + return chars.join(); +} diff --git a/lib/src/writerside/writerside_document_renderer.dart b/lib/src/writerside/writerside_document_renderer.dart index 900cfa60..a191442b 100644 --- a/lib/src/writerside/writerside_document_renderer.dart +++ b/lib/src/writerside/writerside_document_renderer.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import '../export/openapi_static_export_mapper.dart'; import '../export/markdown_export_document.dart'; +import '../export/markdown_export_mapper.dart'; import '../visualization/visualization_models.dart'; import '../markdown/busymark_document.dart'; import '../markdown/markdown_model.dart'; @@ -34,12 +35,25 @@ class WritersideDocumentRenderer { ..._blocks(document.nodes, headingLevel: titleHeadingLevel + 1), ]; final keys = {}; + void inlineKeys(Iterable values) { + for (final value in values) { + keys.addAll( + (value.attributes['switcher-key'] ?? '') + .split(',') + .map((key) => key.trim()) + .where((key) => key.isNotEmpty), + ); + inlineKeys(value.children); + } + } + void findKeys(Iterable values) { for (final block in values) { final key = block.attributes['switcher-key']; if (key != null && key.isNotEmpty) { keys.addAll(key.split(',').map((value) => value.trim())); } + inlineKeys(block.inlines); findKeys(block.children); } } @@ -47,7 +61,12 @@ class WritersideDocumentRenderer { findKeys(blocks); if (keys.isNotEmpty) { final chapterScopes = <(int, String?)>[]; + BusyInline annotateInline(BusyInline inline) => inline.copyWith( + attributes: {...inline.attributes, 'switcher-default': keys.first}, + children: inline.children.map(annotateInline).toList(), + ); BusyBlock annotate(BusyBlock block) => block.copyWith( + inlines: block.inlines.map(annotateInline).toList(), attributes: {...block.attributes, 'switcher-default': keys.first}, children: block.children.map(annotate).toList(), ); @@ -197,17 +216,37 @@ class WritersideDocumentRenderer { ); case WritersideSemanticKind.condition: case WritersideSemanticKind.container: + case WritersideSemanticKind.snippet: result.addAll(_blocks(element.children, headingLevel: headingLevel)); case WritersideSemanticKind.startingPage: case WritersideSemanticKind.section: case WritersideSemanticKind.seealso: case WritersideSemanticKind.category: - final title = _elementTitle(element); + final title = _elementTitle(element).isNotEmpty + ? _elementTitle(element) + : element.name == 'request' + ? 'Request samples' + : element.name == 'response' + ? 'Response ${element.attributes['type'] ?? 'default'} samples' + : ''; + final content = _sectionChildren(element); result.add( BusyBlock( id: _nodeId(element), kind: BusyBlockKind.htmlBlock, - attributes: {...attributes, 'writerside-section': 'true'}, + attributes: { + ...attributes, + 'writerside-section': 'true', + if ({ + 'spotlight', + 'primary', + 'secondary', + 'cards', + 'misc', + 'links', + }.contains(element.name)) + 'writerside-grid': 'true', + }, children: [ if (title.isNotEmpty || kind == WritersideSemanticKind.seealso) BusyBlock( @@ -222,10 +261,7 @@ class WritersideDocumentRenderer { attributes: {'level': '${headingLevel.clamp(1, 6)}'}, sourceSpan: element.span, ), - ..._blocks( - _contentChildren(element), - headingLevel: headingLevel + 1, - ), + ..._blocks(content, headingLevel: headingLevel + 1), ], sourceSpan: element.span, ), @@ -237,13 +273,42 @@ class WritersideDocumentRenderer { kind: BusyBlockKind.htmlBlock, attributes: {...attributes, 'writerside-card': 'true'}, children: [ + if (attributes['image'] ?? attributes['icon'] case final image?) + BusyBlock( + id: '${_nodeId(element)}-image', + kind: BusyBlockKind.image, + attributes: attributes, + sourceSpan: element.span, + inlines: [ + BusyInline( + kind: BusyInlineKind.image, + destination: image, + text: '', + ), + ], + ), + if (attributes['badge'] case final badge?) + BusyBlock( + id: '${_nodeId(element)}-badge', + kind: BusyBlockKind.paragraph, + inlines: [ + BusyInline(kind: BusyInlineKind.code, text: badge), + ], + ), BusyBlock( id: '${_nodeId(element)}-link', kind: BusyBlockKind.paragraph, inlines: [ BusyInline( - kind: BusyInlineKind.link, + kind: + attributes['nullable'] == 'true' && + attributes['resolved-available'] == 'false' + ? BusyInlineKind.text + : BusyInlineKind.link, text: + (element.plainText.trim().isEmpty + ? null + : element.plainText.trim()) ?? attributes['resolved-label'] ?? attributes['href'] ?? element.plainText, @@ -476,7 +541,13 @@ class WritersideDocumentRenderer { _contentChildren(element), headingLevel: headingLevel, ), - attributes: attributes, + attributes: { + ...attributes, + if (kind == WritersideSemanticKind.tabs && + !attributes.containsKey('group')) + 'group': + 'busymark-tabs:${element.span.filePath}:${element.span.startOffset}', + }, sourceSpan: element.span, ), ); @@ -540,7 +611,6 @@ class WritersideDocumentRenderer { case WritersideSemanticKind.title: case WritersideSemanticKind.metadata: case WritersideSemanticKind.variable: - case WritersideSemanticKind.snippet: break; case WritersideSemanticKind.include: result.add( @@ -586,6 +656,92 @@ class WritersideDocumentRenderer { return result; } + List _sectionChildren(WritersideElementNode element) { + final children = _contentChildren(element).toList(); + if ({'request', 'response'}.contains(element.name)) { + final samples = children + .whereType() + .where((node) => node.name == 'sample') + .toList(); + if (samples.isNotEmpty) { + WritersideElementNode wrap( + WritersideSemanticKind kind, + String name, + WritersideElementNode source, + List nodes, + Map attributes, + ) => WritersideSemanticElementNode( + kind: kind, + name: name, + qualifiedName: name, + attributes: attributes, + qualifiedAttributes: const [], + attributeSpans: const {}, + children: nodes, + span: source.span, + rawSource: source.rawSource, + provenance: source.provenance, + ); + return [ + wrap(WritersideSemanticKind.tabs, 'tabs', element, [ + for (final sample in samples) + wrap( + WritersideSemanticKind.tab, + 'tab', + sample, + [sample], + { + 'title': + sample.attributes['title'] ?? + '${sample.attributes['lang'] ?? 'JSON'} example', + }, + ), + ], const {}), + ...children.where((node) => !samples.contains(node)), + ]; + } + } + if (element.semanticKind == WritersideSemanticKind.seealso) { + children.sort( + (a, b) => + (a is WritersideElementNode + ? int.tryParse(a.attributes['order'] ?? '') ?? 0 + : 0) + .compareTo( + b is WritersideElementNode + ? int.tryParse(b.attributes['order'] ?? '') ?? 0 + : 0, + ), + ); + } + WritersideDocumentNode cards(WritersideDocumentNode node) { + if (node is! WritersideElementNode) return node; + if (node.name != 'a') { + return node.copyWith(children: node.children.map(cards).toList()); + } + return WritersideSemanticElementNode( + kind: WritersideSemanticKind.card, + name: 'card', + qualifiedName: node.qualifiedName, + attributes: { + ...node.attributes, + if (node.attributes['card-summary'] case final summary?) + 'summary': summary, + }, + qualifiedAttributes: node.qualifiedAttributes, + attributeSpans: node.attributeSpans, + children: node.children, + span: node.span, + rawSource: node.rawSource, + provenance: node.provenance, + ); + } + + return element.attributes['style'] == 'cards' || element.name == 'cards' + ? children.map(cards).toList() + : children; + } + List _apiBlocks(WritersideElementNode element, int headingLevel) { final selections = element.children .whereType() @@ -605,15 +761,43 @@ class WritersideDocumentRenderer { final reference = OpenApiReferenceModel.fromJson( (jsonDecode(json) as Map).cast(), ); - final hasSamples = element.children - .whereType() - .any((child) => {'request', 'response'}.contains(child.name)); + final samples = element.children.whereType().where( + (child) => {'request', 'response'}.contains(child.name), + ); + final operationKey = + "${element.attributes['method']?.toLowerCase() ?? ''} ${element.attributes['endpoint'] ?? element.attributes['webhook'] ?? ''}"; + final sampleBlocks = { + for (final sample in samples) + '${sample.span.startOffset}': _blocks([ + sample, + ], headingLevel: headingLevel + 1).single, + }; final mapped = const OpenApiStaticExportMapper().mapWriterside( reference, element: element.name, - attributes: { - ...element.attributes, - if (hasSamples) 'generate-samples': 'none', + attributes: element.attributes, + overrides: { + for (final sample in samples) + '$operationKey ${sample.name}${sample.name == 'response' ? ' ${sample.attributes['type'] ?? 'default'}' : ''}': + [ + MarkdownExportBlock( + kind: MarkdownExportBlockKind.group, + attributes: { + 'writerside-override': '${sample.span.startOffset}', + }, + children: const MarkdownExportMapper() + .map( + BusyDocument( + filePath: element.span.filePath, + mode: MarkdownMode.writersideMarkdown, + blocks: [ + sampleBlocks['${sample.span.startOffset}']!, + ], + ), + ) + .blocks, + ), + ], }, ); var index = 0; @@ -626,37 +810,40 @@ class WritersideDocumentRenderer { destination: value.attributes['destination'], children: value.children.map(inline).toList(), ); - BusyBlock block(MarkdownExportBlock value) => BusyBlock( - id: '${_nodeId(element)}-api-${index++}', - kind: switch (value.kind) { - MarkdownExportBlockKind.heading => BusyBlockKind.heading, - MarkdownExportBlockKind.code => BusyBlockKind.codeBlock, - MarkdownExportBlockKind.table || - MarkdownExportBlockKind.tableRow => BusyBlockKind.table, - MarkdownExportBlockKind.group || - MarkdownExportBlockKind.openApiReference => BusyBlockKind.htmlBlock, - _ => BusyBlockKind.paragraph, - }, - inlines: value.inlines.isEmpty && value.text.isNotEmpty - ? [BusyInline(kind: BusyInlineKind.text, text: value.text)] - : value.inlines.map(inline).toList(), - children: value.children.map(block).toList(), - attributes: { - ..._attributes(element), - for (final entry in value.attributes.entries) - entry.key: '${entry.value}', - if (value.kind == MarkdownExportBlockKind.heading) - 'level': - '${((value.attributes['level'] as int? ?? 2) - 3 + headingLevel).clamp(1, 6)}', - }, - sourceSpan: element.span, - isGenerated: true, - ); - return [ - block(mapped), - if (hasSamples) - ..._blocks(element.children, headingLevel: headingLevel + 1), - ]; + BusyBlock block(MarkdownExportBlock value) { + if (sampleBlocks[value.attributes['writerside-override']] + case final original?) { + return original; + } + return BusyBlock( + id: '${_nodeId(element)}-api-${index++}', + kind: switch (value.kind) { + MarkdownExportBlockKind.heading => BusyBlockKind.heading, + MarkdownExportBlockKind.code => BusyBlockKind.codeBlock, + MarkdownExportBlockKind.table || + MarkdownExportBlockKind.tableRow => BusyBlockKind.table, + MarkdownExportBlockKind.group || + MarkdownExportBlockKind.openApiReference => BusyBlockKind.htmlBlock, + _ => BusyBlockKind.paragraph, + }, + inlines: value.inlines.isEmpty && value.text.isNotEmpty + ? [BusyInline(kind: BusyInlineKind.text, text: value.text)] + : value.inlines.map(inline).toList(), + children: value.children.map(block).toList(), + attributes: { + ..._attributes(element), + for (final entry in value.attributes.entries) + entry.key: '${entry.value}', + if (value.kind == MarkdownExportBlockKind.heading) + 'level': + '${((value.attributes['level'] as int? ?? 2) - 3 + headingLevel).clamp(1, 6)}', + }, + sourceSpan: element.span, + isGenerated: true, + ); + } + + return [block(mapped)]; } on FormatException catch (error) { return [ BusyBlock( @@ -832,6 +1019,7 @@ class WritersideDocumentRenderer { result.add( BusyInline( kind: BusyInlineKind.strong, + attributes: _attributes(node), text: text, children: children, ), @@ -840,6 +1028,7 @@ class WritersideDocumentRenderer { result.add( BusyInline( kind: BusyInlineKind.emphasis, + attributes: _attributes(node), text: text, children: children, ), diff --git a/lib/src/writerside/writerside_document_resolver.dart b/lib/src/writerside/writerside_document_resolver.dart index d04ebacb..23e58343 100644 --- a/lib/src/writerside/writerside_document_resolver.dart +++ b/lib/src/writerside/writerside_document_resolver.dart @@ -104,12 +104,14 @@ class _ResolveState { final name = node.attributes['name']?.trim(); final value = node.attributes['value']; if (name != null && name.isNotEmpty && value != null) { - scopedVariables[name] = _interpolate( - value, - scopedVariables, - node, - ignore: inheritedIgnoreVariables, - ); + scopedVariables[name] = value.contains('%$name%') + ? _interpolate( + value, + scopedVariables, + node, + ignore: inheritedIgnoreVariables, + ) + : value; } } scopedVariables.addAll(arguments); @@ -119,7 +121,21 @@ class _ResolveState { moduleRoot: module.rootPath, topicPath: topic.filePath, ); + final markdownChapters = <(int, bool)>[]; for (final node in nodes) { + if (node is WritersideMarkdownBlockNode && + node.block.kind == BusyBlockKind.heading) { + final level = int.tryParse(node.block.attributes['level'] ?? '') ?? 1; + while (markdownChapters.isNotEmpty && + markdownChapters.last.$1 >= level) { + markdownChapters.removeLast(); + } + markdownChapters.add(( + level, + _matchesConditions(node.block.attributes, activeFilters, module), + )); + } + if (markdownChapters.any((chapter) => !chapter.$2)) continue; if (node is WritersideTextNode) { result.add( node.copyWith( @@ -178,7 +194,20 @@ class _ResolveState { if (element.semanticKind == WritersideSemanticKind.include) { result.addAll( _resolveInclude( - element, + element.copyWith( + attributes: { + for (final entry in element.attributes.entries) + entry.key: _interpolate( + entry.value, + scopedVariables, + element, + ignore: _ignoreVariablesFor( + element, + inheritedIgnoreVariables, + ), + ), + }, + ), module: module, topic: topic, variables: scopedVariables, @@ -209,13 +238,17 @@ class _ResolveState { for (final child in element.children) if (element.semanticKind == WritersideSemanticKind.api && child is WritersideElementNode && - child.semanticKind == WritersideSemanticKind.api && - !child.attributes.containsKey('openapi-path')) + child.semanticKind == WritersideSemanticKind.api) child.copyWith( attributes: { + for (final name in [ + 'openapi-path', + 'depth', + 'generate-samples', + 'display-links-if-available', + ]) + if (attributes[name] != null) name: attributes[name]!, ...child.attributes, - if (attributes['openapi-path'] case final path?) - 'openapi-path': path, }, ) else @@ -316,6 +349,8 @@ class _ResolveState { final src = attributes['src'] ?? ''; final resource = referenceData.resources[src]; attributes['resolved-label'] = p.basename(src); + attributes['resolved-resource-path'] = resource?.path ?? ''; + attributes.remove('resolved-destination'); if (resource?.path case final path?) { attributes['resolved-destination'] = Uri.file(path).toString(); } else { @@ -436,6 +471,17 @@ class _ResolveState { targetTopic.filePath; }); } + if (available && target != null) { + for (final ancestor in targetTopic!.document.elements.where( + (element) => + element.span.startOffset <= target.span.startOffset && + element.span.endOffset >= target.span.endOffset, + )) { + available = + available && + _matchesInstance(ancestor.attributes['instance'], targetModule!); + } + } if (target is WritersideElementNode) { available = available && @@ -445,28 +491,84 @@ class _ResolveState { available && _matchesInstance(target.block.attributes['instance'], targetModule!); } + String? titleOf(WritersideElementNode? element) => + element?.children + .whereType() + .where( + (child) => + child.name == 'title' && + _matchesInstance(child.attributes['instance'], targetModule!), + ) + .firstOrNull + ?.plainText ?? + element?.attributes['title']; + if (targetTopic?.document.rootElement case final root?) { + available = + available && + _matchesInstance(root.attributes['instance'], targetModule!); + } final targetTitle = target is WritersideElementNode - ? target.attributes['title'] ?? - target.children - .whereType() - .where((element) => element.name == 'title') - .firstOrNull - ?.plainText ?? - target.plainText + ? titleOf(target) ?? target.plainText : target?.plainText; final label = targetTitle?.trim().isNotEmpty == true ? targetTitle! - : targetTopic?.title ?? destination; + : titleOf(targetTopic?.document.rootElement) ?? + targetTopic?.title ?? + destination; + final targetVariables = { + for (final variable + in targetModule?.variables ?? const []) + if (_matchesInstance(variable.instanceCondition, targetModule!)) + variable.name: variable.value, + for (final variable + in targetTopic?.document.rootElement?.children + .whereType() ?? + const []) + if (variable.semanticKind == WritersideSemanticKind.variable && + _matchesInstance(variable.attributes['instance'], targetModule!)) + if (variable.attributes['name'] != null) + variable.attributes['name']!: variable.attributes['value'] ?? '', + }; + String? summaryFor(String name) { + final element = targetTopic?.document.elements + .where( + (element) => + element.name == name && + _matchesInstance(element.attributes['instance'], targetModule!), + ) + .firstOrNull; + final selected = element?.attributes['rel'] == null + ? element + : targetTopic?.document + .contentById(element!.attributes['rel']!) + ?.firstOrNull; + final fallback = targetTopic?.document.elements + .where( + (element) => + element.name == 'p' && + _matchesInstance(element.attributes['instance'], targetModule!), + ) + .firstOrNull; + final summaryNode = selected ?? fallback; + return summaryNode == null + ? null + : _interpolate( + summaryNode.plainText, + targetVariables, + summaryNode, + ignore: false, + ).trim(); + } + final summary = attributes['summary'] ?? - targetTopic?.document.elements - .where((element) => element.name == 'link-summary') - .firstOrNull - ?.plainText ?? - targetTopic?.document.elements - .where((element) => element.name == 'p') - .firstOrNull - ?.plainText; + summaryFor( + node is WritersideElementNode && + node.semanticKind == WritersideSemanticKind.card + ? 'card-summary' + : 'link-summary', + ); + final cardSummary = attributes['summary'] ?? summaryFor('card-summary'); if (!available && attributes['nullable'] != 'true') { _referenceDiagnostic( code: 'writerside.link.unavailable', @@ -475,12 +577,18 @@ class _ResolveState { ); } return { - 'resolved-label': label, + 'resolved-label': _interpolate( + label, + targetVariables, + node, + ignore: false, + ), 'resolved-destination': path.isEmpty ? '#$anchor' : '${targetTopic?.filePath ?? path}${anchor.isEmpty ? '' : '#$anchor'}', 'resolved-available': '$available', if (summary != null) 'summary': summary.trim(), + if (cardSummary != null) 'card-summary': cardSummary, }; } @@ -502,7 +610,7 @@ class _ResolveState { node: include, args: {'origin': origin}, ); - return const []; + return [include]; } final from = include.attributes['from']?.trim(); @@ -520,7 +628,7 @@ class _ResolveState { node: include, args: {'from': from}, ); - return const []; + return [include]; } targetTopic = matches.firstOrNull; } @@ -533,7 +641,7 @@ class _ResolveState { args: {'from': from}, ); } - return const []; + return nullable ? const [] : [include]; } final elementId = include.attributes['element-id']?.trim(); @@ -544,7 +652,7 @@ class _ResolveState { node: include, args: {'from': from, 'elementId': elementId}, ); - return const []; + return [include]; } try { Iterable selected; @@ -558,7 +666,7 @@ class _ResolveState { args: {'from': from, 'elementId': elementId}, ); } - return const []; + return nullable ? const [] : [include]; } final first = target.first; selected = @@ -575,8 +683,7 @@ class _ResolveState { : root.children.where((node) { return node is! WritersideElementNode || (node.semanticKind != WritersideSemanticKind.title && - node.semanticKind != WritersideSemanticKind.metadata && - node.semanticKind != WritersideSemanticKind.snippet); + node.semanticKind != WritersideSemanticKind.metadata); }); } @@ -788,36 +895,44 @@ class _ResolveState { Map variables, WritersideDocumentNode node, { required bool ignore, + Set resolving = const {}, }) { if (ignore || !value.contains('%')) { - return value; + return value.replaceAll('%', '%'); } - return value.replaceAllMapped( - RegExp(r'%(\\)?([A-Za-z_][A-Za-z0-9_.-]*)%'), - (match) { - final name = match.group(2)!; - if (match.group(1) != null) { - return '%$name%'; - } - final replacement = variables[name]; - if (replacement != null) { - return replacement; - } - final key = '${node.span.filePath}:${node.span.startOffset}:$name'; - if (_unresolvedVariables.add(key)) { - diagnostics.add( - Diagnostic( - code: 'writerside.variable.unresolved', - severity: DiagnosticSeverity.warning, - filePath: node.span.filePath, - args: {'name': name}, - sourceSpan: node.span, - ), - ); - } - return match.group(0)!; - }, - ); + return value + .replaceAllMapped(RegExp(r'%(\\)?([A-Za-z_][A-Za-z0-9_.-]*)%'), ( + match, + ) { + final name = match.group(2)!; + if (match.group(1) != null) { + return '%$name%'; + } + final replacement = variables[name]; + if (replacement != null && !resolving.contains(name)) { + return _interpolate( + replacement, + variables, + node, + ignore: false, + resolving: {...resolving, name}, + ); + } + final key = '${node.span.filePath}:${node.span.startOffset}:$name'; + if (_unresolvedVariables.add(key)) { + diagnostics.add( + Diagnostic( + code: 'writerside.variable.unresolved', + severity: DiagnosticSeverity.warning, + filePath: node.span.filePath, + args: {'name': name}, + sourceSpan: node.span, + ), + ); + } + return match.group(0)!; + }) + .replaceAll('%', '%'); } String? titleFor(WritersideDocument document) { diff --git a/lib/src/writerside/writerside_parsers.dart b/lib/src/writerside/writerside_parsers.dart index 7e58d148..9d86b034 100644 --- a/lib/src/writerside/writerside_parsers.dart +++ b/lib/src/writerside/writerside_parsers.dart @@ -298,6 +298,27 @@ class WritersideBuildProfilesParser { ); } + for (final element + in const WritersideDocumentParser() + .parseXml(filePath: filePath, source: source) + .elements + .where((element) => element.name == 'llms-txt')) { + if (element.attributes.containsKey('single-file') || + !{'true', 'false'}.contains(element.plainText.trim())) { + diagnostics.add( + Diagnostic( + code: 'writerside.build-profiles.invalid-llms-txt', + severity: DiagnosticSeverity.warning, + filePath: filePath, + sourceSpan: element.span, + args: const { + 'expected': 'true', + 'builderVersion': WritersideSchema.builderVersion, + }, + ), + ); + } + } final globalValues = _valuesFromParent(filePath, source, root, diagnostics); final instanceValues = {}; for (final profile in root.childElements.where( @@ -852,10 +873,21 @@ class WritersideVariablesParser { return (variables, diagnostics); } final seen = {}; + final declarations = const WritersideDocumentParser() + .parseXml(filePath: filePath, source: source) + .elements + .where((element) => element.name == 'var') + .toList(); + var declarationIndex = 0; for (final element in document.findAllElements('var')) { final name = element.getAttribute('name'); final value = element.getAttribute('value'); - final span = _elementSpan(filePath, source, 'var', name); + final semantic = declarationIndex < declarations.length + ? declarations[declarationIndex++] + : null; + final span = + semantic?.attributeSpans['name'] ?? + _elementSpan(filePath, source, 'var', name); if (name == null || value == null) { diagnostics.add( Diagnostic( @@ -915,12 +947,23 @@ class WritersideCategoriesParser { if (document == null) { return (categories, diagnostics); } + final declarations = const WritersideDocumentParser() + .parseXml(filePath: filePath, source: source) + .elements + .where((element) => element.name == 'category') + .toList(); + var declarationIndex = 0; final ids = {}; final orders = {}; for (final element in document.findAllElements('category')) { final id = element.getAttribute('id') ?? ''; final order = int.tryParse(element.getAttribute('order') ?? ''); - final span = _elementSpan(filePath, source, 'category', id); + final declaration = declarationIndex < declarations.length + ? declarations[declarationIndex++] + : null; + final span = + declaration?.attributeSpans['id'] ?? + _elementSpan(filePath, source, 'category', id); if (id.isEmpty) { diagnostics.add( Diagnostic( @@ -1010,6 +1053,25 @@ class WritersideTopicParser { if (element.attributes['id'] case final id?) WritersideElementId(id: id, span: element.span), ]; + void collectMarkdownIds(BusyBlock block) { + final id = block.attributes['id']; + if (id != null && !ids.any((candidate) => candidate.id == id)) { + ids.add( + WritersideElementId( + id: id, + span: block.sourceSpan ?? SourceSpan.entireFile(filePath, source), + ), + ); + } + for (final child in block.children) { + collectMarkdownIds(child); + } + } + + for (final node + in document.nodes.whereType()) { + collectMarkdownIds(node.block); + } final includes = [ for (final element in document.elements) if (element.semanticKind == WritersideSemanticKind.include) diff --git a/lib/src/writerside/writerside_project.dart b/lib/src/writerside/writerside_project.dart index d9a85372..e56470e4 100644 --- a/lib/src/writerside/writerside_project.dart +++ b/lib/src/writerside/writerside_project.dart @@ -9,6 +9,7 @@ import 'writerside_document.dart'; import 'writerside_model.dart'; import 'writerside_module_service.dart'; import 'writerside_schema.dart'; +import 'writerside_source_loader.dart'; enum WritersideSymbolKind { module, @@ -35,6 +36,8 @@ class WritersideSymbol { required this.moduleId, required this.filePath, this.span, + this.instanceCondition, + this.scopeSpan, }); final String name; @@ -43,6 +46,8 @@ class WritersideSymbol { final String moduleId; final String filePath; final SourceSpan? span; + final String? instanceCondition; + final SourceSpan? scopeSpan; } class WritersideReference { @@ -54,6 +59,7 @@ class WritersideReference { required this.span, this.origin, this.sourceValue, + this.scopeReference, }); final String value; @@ -63,6 +69,7 @@ class WritersideReference { final SourceSpan span; final String? origin; final String? sourceValue; + final String? scopeReference; } class WritersideRenameEdit { @@ -70,11 +77,13 @@ class WritersideRenameEdit { required this.filePath, required this.span, required this.replacement, + this.expectedText, }); final String filePath; final SourceSpan span; final String replacement; + final String? expectedText; } class WritersideProjectIndex { @@ -82,11 +91,13 @@ class WritersideProjectIndex { required this.symbols, required this.references, required this.diagnostics, + this.modulesById = const {}, }); final List symbols; final List references; final List diagnostics; + final Map modulesById; factory WritersideProjectIndex.build( List modules, { @@ -136,7 +147,47 @@ class WritersideProjectIndex { ); } final indexedElementIds = {}; + final parents = {}; + for (final parent in topic.document.elements) { + for (final child + in parent.children.whereType()) { + parents[child] = parent; + } + } for (final element in topic.document.elements) { + if (element.semanticKind == WritersideSemanticKind.variable) { + final name = element.attributes['name']; + final parent = parents[element]; + if (name != null && + parent?.semanticKind == WritersideSemanticKind.include) { + references.add( + WritersideReference( + value: name, + kind: WritersideSymbolKind.variable, + moduleId: moduleId, + filePath: topic.filePath, + span: element.attributeSpans['name'] ?? element.span, + sourceValue: name, + origin: parent!.attributes['origin'], + scopeReference: + "${parent.attributes['from'] ?? ''}#${parent.attributes['element-id'] ?? ''}", + ), + ); + } else if (name != null) { + symbols.add( + WritersideSymbol( + name: name, + qualifiedName: '$moduleId:${topic.id}:%$name%', + kind: WritersideSymbolKind.variable, + moduleId: moduleId, + filePath: topic.filePath, + span: element.attributeSpans['name'], + scopeSpan: parent?.span ?? element.span, + instanceCondition: element.attributes['instance'], + ), + ); + } + } final id = element.attributes['id']?.trim(); if (id != null && id.isNotEmpty) { indexedElementIds.add(id); @@ -161,9 +212,78 @@ class WritersideProjectIndex { moduleId: moduleId, filePath: topic.filePath, ); - final capability = WritersideSchema.capabilityFor(element.name); + final parent = parents[element]; + void schemaDiagnostic( + String code, { + String? attribute, + String? reason, + }) { + diagnostics.add( + Diagnostic( + code: 'writerside.schema.$code', + severity: DiagnosticSeverity.warning, + filePath: topic.filePath, + sourceSpan: element.attributeSpans[attribute] ?? element.span, + args: { + 'element': element.name, + if (attribute != null) 'attribute': attribute, + if (reason != null) 'reason': reason, + }, + ), + ); + } + + if (parent != null && + WritersideSchema.isKnownElement(parent.name) && + !WritersideSchema.childElementNames( + parent.name, + ).contains(element.name)) { + schemaDiagnostic('invalid-parent', reason: parent.name); + } + for (final attribute in element.attributes.entries) { + if (attribute.key.startsWith('xmlns') || + element.qualifiedAttributes.any( + (qualified) => + qualified.name == attribute.key && + qualified.qualifiedName.contains(':'), + )) { + continue; + } + if (!WritersideSchema.attributesFor( + element.name, + ).contains(attribute.key) && + !attribute.key.startsWith('data-')) { + schemaDiagnostic('unknown-attribute', attribute: attribute.key); + } + final invalid = WritersideSchema.invalidAttributeValue( + element.name, + attribute.key, + attribute.value, + ); + if (invalid != null) { + schemaDiagnostic( + 'invalid-attribute-value', + attribute: attribute.key, + reason: invalid, + ); + } + } for (final requiredAttribute - in capability?.requiredAttributes ?? const {}) { + in WritersideSchema.requiredAttributesFor(element.name)) { + if (requiredAttribute == 'href' && + element.attributes.containsKey('anchor')) { + continue; + } + if (requiredAttribute == 'openapi-path' && + parent?.name == 'api-doc') { + continue; + } + if (requiredAttribute == 'title' && + element.children.whereType().any( + (child) => child.name == 'title', + )) { + continue; + } if ((element.attributes[requiredAttribute] ?? '').trim().isEmpty) { diagnostics.add( Diagnostic( @@ -180,6 +300,11 @@ class WritersideProjectIndex { ); } } + if (element.name == 'table' && + element.attributes['sortable'] == 'true' && + !{'header-row', null}.contains(element.attributes['style'])) { + schemaDiagnostic('invalid-sortable-style', attribute: 'style'); + } } for (final elementId in topic.elementIds.where( (candidate) => !indexedElementIds.contains(candidate.id), @@ -191,18 +316,35 @@ class WritersideProjectIndex { kind: WritersideSymbolKind.element, moduleId: moduleId, filePath: topic.filePath, - span: elementId.span, + span: _markdownIdSpan( + topic.document, + elementId.id, + elementId.span, + ), ), ); } - for (final link in topic.links) { + for (final link in topic.links.where( + (link) => !references.any( + (reference) => + reference.filePath == topic.filePath && + reference.span.startOffset >= link.span.startOffset && + reference.span.endOffset <= link.span.endOffset && + (reference.kind == WritersideSymbolKind.topic || + reference.kind == WritersideSymbolKind.element), + ), + )) { references.add( WritersideReference( value: link.destination, kind: WritersideSymbolKind.topic, moduleId: moduleId, filePath: topic.filePath, - span: link.span, + span: _referenceValueSpan( + topic.document, + link.span, + link.destination, + ), sourceValue: link.destination, ), ); @@ -243,6 +385,7 @@ class WritersideProjectIndex { moduleId: moduleId, filePath: variable.span.filePath, span: variable.span, + instanceCondition: variable.instanceCondition, ), ); } @@ -344,7 +487,7 @@ class WritersideProjectIndex { .putIfAbsent( '${symbol.moduleId}:${symbol.kind.name}:' '${symbol.kind == WritersideSymbolKind.element || symbol.kind == WritersideSymbolKind.snippet ? symbol.filePath : ''}:' - '${symbol.name}', + '${symbol.name}:${symbol.instanceCondition ?? ''}:${symbol.scopeSpan?.startOffset ?? ''}', () => [], ) .add(symbol); @@ -422,26 +565,187 @@ class WritersideProjectIndex { symbols: List.unmodifiable(symbols), references: List.unmodifiable(references), diagnostics: sortDiagnostics(diagnostics), + modulesById: modulesById, ); } + /// Uses the complete project index, including topics outside the active TOC. + List symbolsAt(String filePath, int offset) { + bool contains(SourceSpan span) => + span.filePath == filePath && + span.startOffset <= offset && + offset <= span.endOffset; + final declarations = + symbols + .where((symbol) => symbol.span != null && contains(symbol.span!)) + .toList() + ..sort( + (a, b) => (a.span!.endOffset - a.span!.startOffset).compareTo( + b.span!.endOffset - b.span!.startOffset, + ), + ); + final matches = + references.where((reference) => contains(reference.span)).toList() + ..sort( + (a, b) => (a.span.endOffset - a.span.startOffset).compareTo( + b.span.endOffset - b.span.startOffset, + ), + ); + if (matches.isNotEmpty) { + final reference = matches.first; + return definitions( + reference.value, + moduleId: reference.moduleId, + origin: reference.origin, + filePath: reference.filePath, + referenceOffset: reference.span.startOffset, + scopeReference: reference.scopeReference, + kind: reference.kind == WritersideSymbolKind.apiReference + ? WritersideSymbolKind.apiSpecification + : reference.kind, + ).toList(); + } + return declarations.isEmpty ? const [] : [declarations.first]; + } + Iterable definitions( String reference, { String? moduleId, String? origin, WritersideSymbolKind? kind, + String? filePath, + int? referenceOffset, + String? scopeReference, }) { final targetModule = origin ?? moduleId; - final normalized = reference.trim().split('#').last; + final value = reference.trim(); + if (kind == WritersideSymbolKind.variable) { + var scopedPath = filePath; + var scopedOffset = referenceOffset; + if (scopeReference != null) { + final target = definitions( + scopeReference, + moduleId: targetModule, + kind: WritersideSymbolKind.snippet, + filePath: filePath, + ).firstOrNull; + scopedPath = target?.filePath; + final module = modulesById[targetModule]; + final topic = module?.topics + .where((topic) => topic.filePath == scopedPath) + .firstOrNull; + final node = topic?.document + .contentById(scopeReference.split('#').last) + ?.firstOrNull; + scopedOffset = node?.span.startOffset; + } + final candidates = symbols + .where( + (symbol) => + symbol.kind == kind && + symbol.name == value && + (targetModule == null || symbol.moduleId == targetModule), + ) + .toList(); + final local = + candidates + .where( + (symbol) => + symbol.scopeSpan != null && + symbol.filePath == scopedPath && + scopedOffset != null && + symbol.scopeSpan!.startOffset <= scopedOffset && + symbol.scopeSpan!.endOffset >= scopedOffset, + ) + .toList() + ..sort( + (a, b) => (a.scopeSpan!.endOffset - a.scopeSpan!.startOffset) + .compareTo(b.scopeSpan!.endOffset - b.scopeSpan!.startOffset), + ); + return local.isEmpty + ? candidates.where((symbol) => symbol.scopeSpan == null) + : local.where( + (symbol) => + symbol.scopeSpan!.startOffset == + local.first.scopeSpan!.startOffset, + ); + } + final hash = value.indexOf('#'); + final normalized = hash < 0 ? value : value.substring(hash + 1); + final module = modulesById[targetModule]; + final fromTopic = module?.topics + .where((topic) => topic.filePath == filePath) + .firstOrNull; + final targetPath = hash < 0 ? value : value.substring(0, hash); + final topic = + targetPath.isEmpty || + (hash < 0 && + { + WritersideSymbolKind.element, + WritersideSymbolKind.snippet, + WritersideSymbolKind.seealso, + }.contains(kind)) + ? fromTopic + : module?.topicByReference(targetPath, fromTopic: fromTopic) ?? + module?.topicsById[targetPath]; + if (hash >= 0 && targetPath.isNotEmpty && module != null && topic == null) { + return const []; + } + final wantsElement = + hash >= 0 || + { + WritersideSymbolKind.element, + WritersideSymbolKind.snippet, + WritersideSymbolKind.seealso, + }.contains(kind); + if ({ + WritersideSymbolKind.resource, + WritersideSymbolKind.image, + WritersideSymbolKind.apiSpecification, + }.contains(kind)) { + final candidates = symbols.where( + (symbol) => + symbol.kind == kind && + (targetModule == null || symbol.moduleId == targetModule), + ); + final exact = candidates + .where( + (symbol) => symbol.name == value || symbol.qualifiedName == value, + ) + .toList(); + if (exact.isNotEmpty) return exact; + final loadedPath = kind == WritersideSymbolKind.resource + ? module?.referenceData.resources[value]?.path + : module + ?.sourceFiles[WritersideSourceLoader.key(filePath ?? '', value)] + ?.path; + if (loadedPath != null) { + return candidates.where((symbol) => symbol.filePath == loadedPath); + } + return candidates.where((symbol) => p.basename(symbol.name) == value); + } return symbols.where((symbol) { final resourceMatch = symbol.kind == WritersideSymbolKind.image || symbol.kind == WritersideSymbolKind.resource || symbol.kind == WritersideSymbolKind.apiSpecification; return (targetModule == null || symbol.moduleId == targetModule) && - (kind == null || symbol.kind == kind) && + (wantsElement + ? { + WritersideSymbolKind.element, + WritersideSymbolKind.snippet, + WritersideSymbolKind.seealso, + }.contains(symbol.kind) + : kind == null || symbol.kind == kind) && + (!wantsElement || + (topic == null + ? filePath == null || symbol.filePath == filePath + : symbol.filePath == topic.filePath)) && (symbol.name == normalized || symbol.qualifiedName == reference || + (!wantsElement && + symbol.kind == WritersideSymbolKind.topic && + topic?.filePath == symbol.filePath) || (resourceMatch && p.basename(symbol.name) == p.basename(normalized))); }); @@ -449,20 +753,36 @@ class WritersideProjectIndex { Iterable findUsages(WritersideSymbol symbol) { return references.where((reference) { - final normalized = reference.value.trim().split('#').last; final compatibleKind = switch (symbol.kind) { - WritersideSymbolKind.element => + WritersideSymbolKind.element || + WritersideSymbolKind.snippet || + WritersideSymbolKind.seealso => reference.kind == WritersideSymbolKind.snippet || - reference.kind == WritersideSymbolKind.topic, + reference.kind == WritersideSymbolKind.topic || + reference.kind == WritersideSymbolKind.element, WritersideSymbolKind.apiSpecification => reference.kind == WritersideSymbolKind.apiReference, _ => reference.kind == symbol.kind, }; - return compatibleKind && - normalized == symbol.name && - (reference.origin == null - ? reference.moduleId == symbol.moduleId - : reference.origin == symbol.moduleId); + if (!compatibleKind) return false; + final value = symbol.kind == WritersideSymbolKind.topic + ? reference.value.split('#').first + : reference.value; + return definitions( + value, + moduleId: reference.moduleId, + origin: reference.origin, + kind: symbol.kind, + filePath: reference.filePath, + referenceOffset: reference.span.startOffset, + scopeReference: reference.scopeReference, + ).any( + (target) => + target.moduleId == symbol.moduleId && + target.filePath == symbol.filePath && + target.name == symbol.name && + target.scopeSpan?.startOffset == symbol.scopeSpan?.startOffset, + ); }); } @@ -478,26 +798,65 @@ class WritersideProjectIndex { symbol.name.length) { return const []; } + if (symbols.any( + (candidate) => + (candidate.kind == symbol.kind || + ({ + WritersideSymbolKind.element, + WritersideSymbolKind.snippet, + WritersideSymbolKind.seealso, + }.contains(candidate.kind) && + { + WritersideSymbolKind.element, + WritersideSymbolKind.snippet, + WritersideSymbolKind.seealso, + }.contains(symbol.kind))) && + candidate.moduleId == symbol.moduleId && + candidate.name == normalized && + candidate.filePath == symbol.filePath && + candidate.name != symbol.name && + candidate.scopeSpan?.startOffset == symbol.scopeSpan?.startOffset, + )) { + return const []; + } final usages = findUsages(symbol).where((reference) { return reference.value == symbol.name || reference.value.endsWith('#${symbol.name}'); }); + final seen = {}; return [ - WritersideRenameEdit( - filePath: symbol.filePath, - span: symbol.span!, - replacement: normalized, - ), + for (final declaration in symbols.where( + (candidate) => + candidate.kind == symbol.kind && + candidate.moduleId == symbol.moduleId && + candidate.filePath == symbol.filePath && + candidate.name == symbol.name && + candidate.scopeSpan?.startOffset == symbol.scopeSpan?.startOffset && + candidate.span != null, + )) + if (seen.add( + '${declaration.filePath}:${declaration.span!.startOffset}:${declaration.span!.endOffset}', + )) + WritersideRenameEdit( + filePath: declaration.filePath, + span: declaration.span!, + replacement: normalized, + expectedText: declaration.name, + ), for (final usage in usages) - WritersideRenameEdit( - filePath: usage.filePath, - span: usage.span, - replacement: _renamedReferenceValue( - usage.sourceValue ?? usage.value, - symbol.name, - normalized, + if (seen.add( + '${usage.filePath}:${usage.span.startOffset}:${usage.span.endOffset}', + )) + WritersideRenameEdit( + filePath: usage.filePath, + span: usage.span, + expectedText: usage.sourceValue ?? usage.value, + replacement: _renamedReferenceValue( + usage.sourceValue ?? usage.value, + symbol.name, + normalized, + ), ), - ), ]; } @@ -848,10 +1207,48 @@ void _collectElementReferences( required String moduleId, required String filePath, }) { + for (final attribute in ['instance', 'in']) { + final value = element.attributes[attribute]; + final span = element.attributeSpans[attribute]; + if (value == null || span == null) continue; + for (final match in RegExp(r'[A-Za-z_][A-Za-z0-9_.-]*').allMatches(value)) { + references.add( + WritersideReference( + value: match[0]!, + kind: WritersideSymbolKind.instance, + moduleId: moduleId, + filePath: filePath, + sourceValue: match[0], + span: SourceSpan( + filePath: filePath, + startOffset: span.startOffset + match.start, + endOffset: span.startOffset + match.end, + startLine: span.startLine, + startColumn: span.startColumn + match.start, + endLine: span.startLine, + endColumn: span.startColumn + match.end, + ), + ), + ); + } + } final kind = element.semanticKind; if (kind == WritersideSemanticKind.include) { final from = element.attributes['from']; final id = element.attributes['element-id']; + if (from != null) { + references.add( + WritersideReference( + value: from, + kind: WritersideSymbolKind.topic, + moduleId: moduleId, + filePath: filePath, + span: element.attributeSpans['from'] ?? element.span, + origin: element.attributes['origin'], + sourceValue: from, + ), + ); + } if (from != null || id != null) { references.add( WritersideReference( @@ -867,7 +1264,8 @@ void _collectElementReferences( ), ); } - } else if (kind == WritersideSemanticKind.link) { + } else if (kind == WritersideSemanticKind.link || + kind == WritersideSemanticKind.card) { final href = element.attributes['href']; if (href != null) { references.add( @@ -882,6 +1280,20 @@ void _collectElementReferences( ), ); } + final anchor = element.attributes['anchor']; + if (anchor != null) { + references.add( + WritersideReference( + value: '${href?.split('#').first ?? ''}#$anchor', + kind: WritersideSymbolKind.element, + moduleId: moduleId, + filePath: filePath, + span: element.attributeSpans['anchor'] ?? element.span, + origin: element.attributes['origin'], + sourceValue: anchor, + ), + ); + } } else if (kind == WritersideSemanticKind.image) { final src = element.attributes['src']; if (src != null) { @@ -936,8 +1348,6 @@ void _collectElementReferences( 'openapi-path', 'src', 'spec', - 'name', - 'endpoint', ].where(element.attributes.containsKey).firstOrNull; final value = attribute == null ? null : element.attributes[attribute]; if (attribute != null && value != null) { @@ -970,6 +1380,43 @@ String _moduleId(WritersideModule module) => ? module.config.moduleName!.trim() : p.basename(module.rootPath); +SourceSpan _referenceValueSpan( + WritersideDocument document, + SourceSpan fallback, + String value, +) { + final start = document.source.indexOf(value, fallback.startOffset); + if (start < 0 || start + value.length > fallback.endOffset) return fallback; + return SourceSpan.fromOffsets( + filePath: document.filePath, + source: document.source, + startOffset: start, + endOffset: start + value.length, + ); +} + +SourceSpan _markdownIdSpan( + WritersideDocument document, + String id, + SourceSpan fallback, +) { + final raw = document.source.substring( + fallback.startOffset, + fallback.endOffset, + ); + final match = RegExp( + r'''\bid\s*=\s*(["'])(.*?)\1''', + ).allMatches(raw).where((match) => match[2] == id).firstOrNull; + if (match == null) return fallback; + final start = fallback.startOffset + match.end - 1 - id.length; + return SourceSpan.fromOffsets( + filePath: document.filePath, + source: document.source, + startOffset: start, + endOffset: start + id.length, + ); +} + bool _insideModule(WritersideModule module, String candidate) { final root = normalizePath(module.rootPath); final normalized = normalizePath(candidate); diff --git a/lib/src/writerside/writerside_schema.dart b/lib/src/writerside/writerside_schema.dart index 67511d4e..462b2ce5 100644 --- a/lib/src/writerside/writerside_schema.dart +++ b/lib/src/writerside/writerside_schema.dart @@ -1,3 +1,17 @@ +import 'writerside_schema_data.dart'; + +enum WritersideAttributeReferenceKind { + topic, + element, + variable, + instance, + resource, + apiSpecification, + image, + category, + module, +} + /// Writerside builder version against which BusyMark's semantic capabilities /// are defined and tested. const writersideDefaultBuilderVersion = '2026.08.0328'; @@ -704,14 +718,21 @@ class WritersideSchema { static bool isKnownElement(String name) => elements.containsKey(name.toLowerCase()) || - genericElementNames.contains(name.toLowerCase()); + genericElementNames.contains(name.toLowerCase()) || + writersideOfficialRules.containsKey(name.toLowerCase()); static WritersideElementCapability? capabilityFor(String name) => elements[name.toLowerCase()]; static Iterable childElementNames(String? parent) { final normalizedParent = parent?.toLowerCase(); - return {...elements.keys, ...genericElementNames}.where((name) { + return { + ...elements.keys, + ...genericElementNames, + ...writersideOfficialRules.keys, + }.where((name) { + final official = writersideOfficialRules[normalizedParent]; + if (official != null) return official.children.contains(name); final allowedParents = elements[name]?.parents ?? const {}; return allowedParents.isEmpty || allowedParents.contains(normalizedParent); @@ -719,7 +740,84 @@ class WritersideSchema { } static Iterable attributesFor(String element) => { - ...commonConditionalAttributes, + ...?writersideOfficialRules[element.toLowerCase()]?.attributes.keys, ...?elements[element.toLowerCase()]?.attributes, }; + + static Set requiredAttributesFor(String element) => { + ...?writersideOfficialRules[element]?.required, + ...?elements[element]?.requiredAttributes, + }; + + static Set valuesFor(String element, String attribute) { + if (attribute == 'sortable') return const {'true', 'false'}; + if (attribute == 'generate-samples') { + return const {'all', 'request', 'response', 'none'}; + } + if (element == 'api-doc' && attribute == 'display') { + return const {'all', 'endpoints', 'operations', 'webhooks'}; + } + final rule = writersideOfficialRules[element]; + if (rule?.attributes[attribute] == 'boolean') { + return const {'true', 'false'}; + } + return rule?.values[attribute] ?? const {}; + } + + static String? invalidAttributeValue( + String element, + String attribute, + String value, + ) { + if (value.contains('%')) return null; + final values = valuesFor(element, attribute); + if (values.isNotEmpty && !values.contains(value)) { + return 'allowed: ${values.join(', ')}'; + } + final type = writersideOfficialRules[element]?.attributes[attribute]; + if ({ + 'integer', + 'int', + 'positiveInteger', + 'nonNegativeInteger', + }.contains(type) || + {'colspan', 'rowspan'}.contains(attribute)) { + final number = int.tryParse(value); + if (number == null || + ((type == 'positiveInteger' || + {'colspan', 'rowspan'}.contains(attribute)) && + number < 1) || + (type == 'nonNegativeInteger' && number < 0)) { + return 'invalid integer'; + } + } + if (attribute == 'width' && + element == 'td' && + (double.tryParse(value) == null || double.parse(value) <= 0)) { + return 'expected positive pixel width'; + } + return null; + } + + static WritersideAttributeReferenceKind? referenceKind( + String element, + String attribute, + ) => switch (attribute) { + 'href' || 'from' => WritersideAttributeReferenceKind.topic, + 'anchor' || + 'element-id' || + 'rel' => WritersideAttributeReferenceKind.element, + 'instance' => WritersideAttributeReferenceKind.instance, + 'origin' => WritersideAttributeReferenceKind.module, + 'openapi-path' => WritersideAttributeReferenceKind.apiSpecification, + 'name' when element == 'var' => WritersideAttributeReferenceKind.variable, + 'ref' when element == 'category' => + WritersideAttributeReferenceKind.category, + 'src' when element == 'resource' => + WritersideAttributeReferenceKind.resource, + 'src' || 'preview-src' || 'dark-src' + when element == 'img' || element == 'video' => + WritersideAttributeReferenceKind.image, + _ => null, + }; } diff --git a/lib/src/writerside/writerside_schema_data.dart b/lib/src/writerside/writerside_schema_data.dart new file mode 100644 index 00000000..bb6f85b2 --- /dev/null +++ b/lib/src/writerside/writerside_schema_data.dart @@ -0,0 +1,2209 @@ +// Generated by tools/generate_writerside_schema.py. Do not edit. +// ignore_for_file: prefer_single_quotes +// Source: https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd +// SHA256: 85dc6239961014b8656118f48726c02cc0e6495fd462b164a1bf29118c4ec49e +class WritersideSchemaElementRules { + const WritersideSchemaElementRules({ + required this.children, + required this.attributes, + required this.required, + required this.values, + }); + final Set children; + final Map attributes; + final Set required; + final Map> values; +} + +const writersideOfficialRules = { + "a": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "anchor": "string", + "caps": "string", + "filter": "string", + "href": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "nullable": "boolean", + "origin": "string", + "summary": "string", + "switcher-key": "string", + "target-switcher-key": "string", + }, + required: {}, + values: >{ + "caps": {"aswritten", "lower", "sentence", "title", "upper"}, + }, + ), + "anchor": WritersideSchemaElementRules( + children: {}, + attributes: {"name": "string"}, + required: {"name"}, + values: >{}, + ), + "api-doc": WritersideSchemaElementRules( + children: {"api-endpoint", "api-webhook"}, + attributes: { + "depth": "string", + "display": "string", + "display-links-if-available": "boolean", + "filter": "string", + "generate-samples": "string", + "id": "string", + "instance": "string", + "openapi-path": "string", + "tag": "string", + }, + required: {"openapi-path"}, + values: >{}, + ), + "api-endpoint": WritersideSchemaElementRules( + children: {"request", "response"}, + attributes: { + "depth": "string", + "display-links-if-available": "boolean", + "endpoint": "string", + "filter": "string", + "generate-samples": "string", + "id": "string", + "instance": "string", + "method": "string", + "openapi-path": "string", + }, + required: {"endpoint", "method"}, + values: >{}, + ), + "api-schema": WritersideSchemaElementRules( + children: {}, + attributes: { + "depth": "string", + "display-links-if-available": "boolean", + "filter": "string", + "id": "string", + "instance": "string", + "name": "string", + "openapi-path": "string", + }, + required: {"name", "openapi-path"}, + values: >{}, + ), + "api-webhook": WritersideSchemaElementRules( + children: {"request", "response"}, + attributes: { + "depth": "string", + "display-links-if-available": "boolean", + "filter": "string", + "generate-samples": "string", + "id": "string", + "instance": "string", + "method": "string", + "openapi-path": "string", + "webhook": "string", + }, + required: {"method", "webhook"}, + values: >{}, + ), + "b": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "br": WritersideSchemaElementRules( + children: {}, + attributes: {}, + required: {}, + values: >{}, + ), + "card": WritersideSchemaElementRules( + children: {}, + attributes: { + "alt": "string", + "anchor": "string", + "badge": "string", + "caps": "string", + "filter": "string", + "href": "string", + "icon": "string", + "id": "string", + "ignore-vars": "boolean", + "image": "string", + "instance": "string", + "nullable": "boolean", + "origin": "string", + "summary": "string", + "target-switcher-key": "string", + "type": "string", + }, + required: {}, + values: >{ + "caps": {"aswritten", "lower", "sentence", "title", "upper"}, + }, + ), + "card-summary": WritersideSchemaElementRules( + children: {"if", "include", "snippet", "var"}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "rel": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "cards": WritersideSchemaElementRules( + children: {"a", "card", "title"}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "narrow": "boolean", + }, + required: {}, + values: >{}, + ), + "category": WritersideSchemaElementRules( + children: {"a", "include", "res", "resource", "snippet"}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "ref": "string", + "sorted": "string", + }, + required: {"ref"}, + values: >{ + "sorted": {"asc", "desc", "none"}, + }, + ), + "chapter": WritersideSchemaElementRules( + children: { + "a", + "api-doc", + "api-endpoint", + "api-schema", + "api-webhook", + "b", + "br", + "chapter", + "code", + "code-block", + "compare", + "control", + "deflist", + "emphasis", + "format", + "help-id", + "i", + "icon", + "if", + "img", + "include", + "inline-frame", + "link-summary", + "list", + "math", + "note", + "p", + "path", + "primary-label", + "procedure", + "property", + "res", + "resource", + "s", + "secondary-label", + "shortcut", + "snippet", + "sub", + "sup", + "table", + "tabs", + "tip", + "title", + "tldr", + "toc", + "tooltip", + "u", + "ui-path", + "var", + "video", + "warning", + }, + attributes: { + "caps": "string", + "collapsible": "boolean", + "default-state": "string", + "filter": "string", + "help-id": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "level": "string", + "switcher-key": "string", + "title": "string", + }, + required: {}, + values: >{ + "caps": {"aswritten", "lower", "sentence", "title", "upper"}, + "default-state": {"collapsed", "expanded"}, + }, + ), + "code": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "code-block": WritersideSchemaElementRules( + children: {}, + attributes: { + "collapsed-title": "string", + "collapsed-title-line-number": "integer", + "collapsible": "boolean", + "default-state": "string", + "disable-links": "boolean", + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "include-lines": "string", + "include-symbol": "string", + "instance": "string", + "lang": "string", + "noinject": "boolean", + "prompt": "string", + "show-white-spaces": "boolean", + "src": "string", + "switcher-key": "string", + "validate": "boolean", + }, + required: {}, + values: >{ + "default-state": {"collapsed", "expanded"}, + }, + ), + "compare": WritersideSchemaElementRules( + children: {"code-block"}, + attributes: { + "filter": "string", + "first-title": "string", + "id": "string", + "instance": "string", + "second-title": "string", + "style": "string", + "switcher-key": "string", + "type": "string", + }, + required: {}, + values: >{ + "style": {"left-right", "top-bottom"}, + "type": {"left-right", "top-bottom"}, + }, + ), + "contribute-url": WritersideSchemaElementRules( + children: {}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + }, + required: {}, + values: >{}, + ), + "control": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "def": WritersideSchemaElementRules( + children: { + "a", + "api-doc", + "api-endpoint", + "api-schema", + "api-webhook", + "b", + "br", + "code", + "code-block", + "control", + "deflist", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "inline-frame", + "list", + "math", + "note", + "p", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "table", + "tabs", + "tip", + "title", + "toc", + "tooltip", + "u", + "ui-path", + "var", + "video", + "warning", + }, + attributes: { + "collapsible": "boolean", + "default-state": "string", + "filter": "string", + "help-id": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + "title": "string", + }, + required: {}, + values: >{ + "default-state": {"collapsed", "expanded", "inherited"}, + }, + ), + "deflist": WritersideSchemaElementRules( + children: {"def", "if", "include", "snippet", "title", "var"}, + attributes: { + "collapsible": "boolean", + "default-state": "string", + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "sorted": "string", + "style": "string", + "switcher-key": "string", + "type": "string", + }, + required: {}, + values: >{ + "default-state": {"collapsed", "expanded"}, + "sorted": {"asc", "desc", "none"}, + "style": {"compact", "full", "medium", "narrow", "wide"}, + "type": {"compact", "full", "medium", "narrow", "wide"}, + }, + ), + "description": WritersideSchemaElementRules( + children: {"if", "include", "snippet", "var"}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "emphasis": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "format": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "color": "string", + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "style": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "group": WritersideSchemaElementRules( + children: {"a", "title"}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + }, + required: {}, + values: >{}, + ), + "help-id": WritersideSchemaElementRules( + children: {}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "i": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "icon": WritersideSchemaElementRules( + children: {}, + attributes: { + "alt": "string", + "dark-src": "string", + "filter": "string", + "height": "long", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "origin": "string", + "src": "string", + "switcher-key": "string", + "width": "long", + }, + required: {"src"}, + values: >{}, + ), + "if": WritersideSchemaElementRules( + children: { + "a", + "api-doc", + "api-endpoint", + "api-schema", + "api-webhook", + "b", + "br", + "card-summary", + "category", + "chapter", + "code", + "code-block", + "compare", + "control", + "def", + "deflist", + "emphasis", + "format", + "help-id", + "i", + "icon", + "if", + "img", + "include", + "include-in-head", + "inline-frame", + "li", + "link-summary", + "list", + "math", + "note", + "p", + "path", + "primary-label", + "procedure", + "property", + "res", + "resource", + "s", + "secondary-label", + "seealso", + "shortcut", + "snippet", + "step", + "sub", + "sup", + "table", + "tabs", + "td", + "tip", + "title", + "tldr", + "toc", + "tooltip", + "tr", + "u", + "ui-path", + "var", + "video", + "warning", + "web-summary", + }, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "img": WritersideSchemaElementRules( + children: {}, + attributes: { + "alt": "string", + "border-effect": "string", + "dark-src": "string", + "filter": "string", + "height": "long", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "origin": "string", + "preview-src": "string", + "scale": "integer", + "src": "string", + "style": "string", + "switcher-key": "string", + "theme": "string", + "thumbnail": "boolean", + "width": "long", + }, + required: {"alt", "src"}, + values: >{ + "border-effect": {"line", "none", "rounded"}, + "style": {"block", "inline"}, + "theme": {"dark", "light"}, + }, + ), + "include": WritersideSchemaElementRules( + children: {"if", "include", "snippet", "var"}, + attributes: { + "element-id": "string", + "filter": "string", + "from": "string", + "id": "string", + "instance": "string", + "nullable": "boolean", + "origin": "string", + "use-filter": "string", + }, + required: {"from"}, + values: >{}, + ), + "include-in-head": WritersideSchemaElementRules( + children: {"if", "include", "snippet", "var"}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "rel": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "inline-frame": WritersideSchemaElementRules( + children: {}, + attributes: { + "height": "string", + "src": "string", + "width": "string", + }, + required: {"src"}, + values: >{}, + ), + "li": WritersideSchemaElementRules( + children: { + "a", + "api-doc", + "api-endpoint", + "api-schema", + "api-webhook", + "b", + "br", + "code", + "code-block", + "compare", + "control", + "deflist", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "inline-frame", + "list", + "math", + "note", + "p", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "table", + "tabs", + "tip", + "toc", + "tooltip", + "u", + "ui-path", + "var", + "video", + "warning", + }, + attributes: { + "filter": "string", + "help-id": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "link-summary": WritersideSchemaElementRules( + children: {"if", "include", "snippet", "var"}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "rel": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "links": WritersideSchemaElementRules( + children: {"a", "group", "title"}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "narrow": "boolean", + }, + required: {}, + values: >{}, + ), + "list": WritersideSchemaElementRules( + children: {"if", "include", "li", "snippet", "var"}, + attributes: { + "columns": "integer", + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "sorted": "string", + "start": "integer", + "style": "string", + "switcher-key": "string", + "type": "string", + }, + required: {}, + values: >{ + "sorted": {"asc", "desc", "none"}, + "style": {"alpha-lower", "bullet", "decimal", "none"}, + "type": {"alpha-lower", "bullet", "decimal", "none"}, + }, + ), + "math": WritersideSchemaElementRules( + children: {}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "misc": WritersideSchemaElementRules( + children: {"cards", "links"}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + }, + required: {}, + values: >{}, + ), + "no-index": WritersideSchemaElementRules( + children: {}, + attributes: {}, + required: {}, + values: >{}, + ), + "note": WritersideSchemaElementRules( + children: { + "a", + "api-doc", + "api-endpoint", + "api-schema", + "api-webhook", + "b", + "br", + "code", + "code-block", + "control", + "deflist", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "inline-frame", + "list", + "math", + "p", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tabs", + "title", + "toc", + "tooltip", + "u", + "ui-path", + "var", + "video", + }, + attributes: { + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + "title": "string", + }, + required: {}, + values: >{}, + ), + "p": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "filter": "string", + "help-id": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "path": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "primary": WritersideSchemaElementRules( + children: {"a", "card", "title"}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + }, + required: {}, + values: >{}, + ), + "primary-label": WritersideSchemaElementRules( + children: {}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "ref": "string", + }, + required: {"ref"}, + values: >{}, + ), + "procedure": WritersideSchemaElementRules( + children: { + "a", + "api-doc", + "api-endpoint", + "api-schema", + "api-webhook", + "b", + "br", + "code", + "code-block", + "control", + "deflist", + "emphasis", + "format", + "help-id", + "i", + "icon", + "if", + "img", + "include", + "inline-frame", + "list", + "math", + "note", + "p", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "step", + "sub", + "sup", + "table", + "tabs", + "tip", + "title", + "toc", + "tooltip", + "u", + "ui-path", + "var", + "video", + "warning", + }, + attributes: { + "caps": "string", + "collapsible": "boolean", + "default-state": "string", + "filter": "string", + "help-id": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "style": "string", + "switcher-key": "string", + "title": "string", + "type": "string", + }, + required: {}, + values: >{ + "caps": {"aswritten", "lower", "sentence", "title", "upper"}, + "default-state": {"collapsed", "expanded"}, + "style": {"choices", "steps"}, + "type": {"choices", "steps"}, + }, + ), + "property": WritersideSchemaElementRules( + children: {}, + attributes: { + "args": "string", + "bundle": "string", + "cleanup-mode": "string", + "cleanup-pattern": "string", + "filter": "string", + "from-product": "string", + "id": "string", + "instance": "string", + "key": "string", + "origin": "string", + "switcher-key": "string", + }, + required: {"bundle", "key"}, + values: >{ + "cleanup-mode": {"default", "override"}, + }, + ), + "request": WritersideSchemaElementRules( + children: {"sample"}, + attributes: {}, + required: {}, + values: >{}, + ), + "res": WritersideSchemaElementRules( + children: {}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "resource-id": "string", + "switcher-key": "string", + }, + required: {"resource-id"}, + values: >{}, + ), + "resource": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "origin": "string", + "src": "string", + "switcher-key": "string", + }, + required: {"src"}, + values: >{}, + ), + "response": WritersideSchemaElementRules( + children: {"sample"}, + attributes: {"type": "string"}, + required: {"type"}, + values: >{}, + ), + "s": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "sample": WritersideSchemaElementRules( + children: {}, + attributes: { + "filter": "string", + "id": "string", + "include-lines": "string", + "instance": "string", + "lang": "string", + "src": "string", + "title": "string", + }, + required: {}, + values: >{}, + ), + "secondary": WritersideSchemaElementRules( + children: {"a", "card", "title"}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + }, + required: {}, + values: >{}, + ), + "secondary-label": WritersideSchemaElementRules( + children: {}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "ref": "string", + }, + required: {"ref"}, + values: >{}, + ), + "section-starting-page": WritersideSchemaElementRules( + children: { + "description", + "misc", + "primary", + "secondary", + "spotlight", + "title", + }, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + }, + required: {}, + values: >{}, + ), + "seealso": WritersideSchemaElementRules( + children: {"category", "if", "include", "snippet", "var"}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "style": "string", + "switcher-key": "string", + "title": "string", + }, + required: {}, + values: >{ + "style": {"cards", "links"}, + }, + ), + "shortcut": WritersideSchemaElementRules( + children: {}, + attributes: { + "filter": "string", + "force-layout": "string", + "from-keymap-of": "string", + "id": "string", + "instance": "string", + "key": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "show-structure": WritersideSchemaElementRules( + children: {}, + attributes: { + "depth": "nonNegativeInteger", + "filter": "string", + "for": "string", + "id": "string", + "instance": "string", + }, + required: {}, + values: >{}, + ), + "snippet": WritersideSchemaElementRules( + children: { + "a", + "api-doc", + "api-endpoint", + "api-schema", + "api-webhook", + "b", + "br", + "card-summary", + "category", + "chapter", + "code", + "code-block", + "compare", + "control", + "def", + "deflist", + "emphasis", + "format", + "help-id", + "i", + "icon", + "if", + "img", + "include", + "include-in-head", + "inline-frame", + "li", + "link-summary", + "list", + "math", + "note", + "p", + "path", + "primary-label", + "procedure", + "property", + "res", + "resource", + "s", + "secondary-label", + "seealso", + "shortcut", + "snippet", + "step", + "sub", + "sup", + "table", + "tabs", + "td", + "tip", + "title", + "tldr", + "toc", + "tooltip", + "tr", + "u", + "ui-path", + "var", + "video", + "warning", + "web-summary", + }, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "spotlight": WritersideSchemaElementRules( + children: {"a", "card", "title"}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + }, + required: {}, + values: >{}, + ), + "step": WritersideSchemaElementRules( + children: { + "a", + "api-doc", + "api-endpoint", + "api-schema", + "b", + "br", + "code", + "code-block", + "compare", + "control", + "deflist", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "inline-frame", + "list", + "math", + "note", + "p", + "path", + "procedure", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "table", + "tabs", + "tip", + "toc", + "tooltip", + "u", + "ui-path", + "var", + "video", + "warning", + }, + attributes: { + "filter": "string", + "help-id": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "sub": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "sup": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "tab": WritersideSchemaElementRules( + children: { + "a", + "api-doc", + "api-endpoint", + "api-schema", + "api-webhook", + "b", + "br", + "chapter", + "code", + "code-block", + "compare", + "control", + "deflist", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "inline-frame", + "list", + "math", + "note", + "p", + "path", + "procedure", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "table", + "tabs", + "tip", + "title", + "toc", + "tooltip", + "u", + "ui-path", + "var", + "video", + "warning", + }, + attributes: { + "filter": "string", + "group-key": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + "title": "string", + }, + required: {}, + values: >{}, + ), + "table": WritersideSchemaElementRules( + children: {"if", "include", "snippet", "tr", "var"}, + attributes: { + "border": "string", + "column-width": "string", + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "style": "string", + "switcher-key": "string", + "width": "int", + }, + required: {}, + values: >{ + "border": {"false", "true"}, + "column-width": {"auto", "fixed"}, + "style": {"both", "header-column", "header-row", "none"}, + }, + ), + "tabs": WritersideSchemaElementRules( + children: {"code-block", "if", "include", "snippet", "tab", "var"}, + attributes: { + "filter": "string", + "group": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "td": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "code-block", + "compare", + "control", + "deflist", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "list", + "math", + "note", + "p", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "table", + "tabs", + "tip", + "toc", + "tooltip", + "u", + "ui-path", + "var", + "video", + "warning", + }, + attributes: { + "colspan": "long", + "filter": "string", + "help-id": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "rowspan": "long", + "sorted": "string", + "width": "string", + }, + required: {}, + values: >{ + "sorted": {"asc", "desc", "none"}, + }, + ), + "tip": WritersideSchemaElementRules( + children: { + "a", + "api-doc", + "api-endpoint", + "api-schema", + "api-webhook", + "b", + "br", + "code", + "code-block", + "control", + "deflist", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "inline-frame", + "list", + "math", + "p", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tabs", + "title", + "toc", + "tooltip", + "u", + "ui-path", + "var", + "video", + }, + attributes: { + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + "title": "string", + }, + required: {}, + values: >{}, + ), + "title": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "caps": "string", + "filter": "string", + "id": "string", + "instance": "string", + }, + required: {}, + values: >{ + "caps": {"aswritten", "lower", "sentence", "title", "upper"}, + }, + ), + "tldr": WritersideSchemaElementRules( + children: {"if", "include", "p", "snippet", "var"}, + attributes: { + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "toc": WritersideSchemaElementRules( + children: {}, + attributes: { + "depth": "string", + "filter": "string", + "id": "string", + "instance": "string", + "start-from": "string", + }, + required: {}, + values: >{}, + ), + "tooltip": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + "term": "string", + }, + required: {"term"}, + values: >{}, + ), + "topic": WritersideSchemaElementRules( + children: { + "a", + "anchor", + "api-doc", + "api-endpoint", + "api-schema", + "api-webhook", + "b", + "br", + "card-summary", + "chapter", + "code", + "code-block", + "compare", + "contribute-url", + "control", + "deflist", + "emphasis", + "format", + "help-id", + "i", + "icon", + "if", + "img", + "include", + "include-in-head", + "inline-frame", + "link-summary", + "list", + "math", + "no-index", + "note", + "p", + "path", + "primary-label", + "procedure", + "property", + "res", + "resource", + "s", + "secondary-label", + "section-starting-page", + "seealso", + "shortcut", + "show-structure", + "snippet", + "sub", + "sup", + "table", + "tabs", + "tip", + "title", + "tldr", + "toc", + "tooltip", + "u", + "ui-path", + "var", + "video", + "warning", + "web-file-name", + "web-summary", + }, + attributes: { + "help-id": "string", + "id": "string", + "ignore-vars": "boolean", + "is-library": "boolean", + "last-modified": "string", + "switcher-label": "string", + "title": "string", + }, + required: {}, + values: >{}, + ), + "tr": WritersideSchemaElementRules( + children: {"if", "include", "snippet", "td", "var"}, + attributes: { + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "u": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "ui-path": WritersideSchemaElementRules( + children: { + "a", + "b", + "br", + "code", + "control", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "math", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tooltip", + "u", + "ui-path", + "var", + }, + attributes: { + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), + "value": WritersideSchemaElementRules( + children: {}, + attributes: {}, + required: {}, + values: >{}, + ), + "var": WritersideSchemaElementRules( + children: {"value"}, + attributes: { + "default": "string", + "filter": "string", + "id": "string", + "instance": "string", + "name": "string", + "value": "string", + }, + required: {"name"}, + values: >{}, + ), + "video": WritersideSchemaElementRules( + children: {}, + attributes: { + "border-effect": "string", + "filter": "string", + "height": "integer", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "mini-player": "boolean", + "origin": "string", + "preview-src": "string", + "src": "string", + "switcher-key": "string", + "width": "integer", + }, + required: {"src"}, + values: >{ + "border-effect": {"line", "none", "rounded"}, + }, + ), + "warning": WritersideSchemaElementRules( + children: { + "a", + "api-doc", + "api-endpoint", + "api-schema", + "api-webhook", + "b", + "br", + "code", + "code-block", + "control", + "deflist", + "emphasis", + "format", + "i", + "icon", + "if", + "img", + "include", + "inline-frame", + "list", + "math", + "p", + "path", + "property", + "res", + "resource", + "s", + "shortcut", + "snippet", + "sub", + "sup", + "tabs", + "title", + "toc", + "tooltip", + "u", + "ui-path", + "var", + "video", + }, + attributes: { + "filter": "string", + "id": "string", + "ignore-vars": "boolean", + "instance": "string", + "switcher-key": "string", + "title": "string", + }, + required: {}, + values: >{}, + ), + "web-file-name": WritersideSchemaElementRules( + children: {}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + }, + required: {}, + values: >{}, + ), + "web-summary": WritersideSchemaElementRules( + children: {"if", "include", "snippet", "var"}, + attributes: { + "filter": "string", + "id": "string", + "instance": "string", + "rel": "string", + "switcher-key": "string", + }, + required: {}, + values: >{}, + ), +}; diff --git a/lib/src/writerside/writerside_source_loader.dart b/lib/src/writerside/writerside_source_loader.dart index dfac7a81..4ed548ba 100644 --- a/lib/src/writerside/writerside_source_loader.dart +++ b/lib/src/writerside/writerside_source_loader.dart @@ -113,8 +113,12 @@ class WritersideSourceLoader { final reference = attributes['openapi-path'] ?? attributes['src']; if (reference == null || reference.isEmpty) return; final identity = key(path, reference); - if (result.containsKey(identity)) return; - result[identity] = await load( + if (result.containsKey(identity) && + (!attributes.containsKey('openapi-path') || + result[identity]!.api != null)) { + return; + } + result[identity] ??= await load( reference: reference, documentPath: path, workspaceRoot: module.rootPath, diff --git a/test/fixtures/writerside/conformance_semantics.json b/test/fixtures/writerside/conformance_semantics.json new file mode 100644 index 00000000..74164f3f --- /dev/null +++ b/test/fixtures/writerside/conformance_semantics.json @@ -0,0 +1,78 @@ +{ + "builderVersion": "2026.08.0328", + "topics": { + "features": { + "paragraphs": [ + "Use Settings, docs/index.md, Ctrl+S, busymark, sample-resource.txt, and semantic markup.", + "Writerside", + "Reusable semantic content." + ], + "quotes": [ + "Lossless semantic quote." + ], + "shortcuts": [ + "Ctrl+S" + ], + "tooltips": [ + { + "text": "semantic markup", + "summary": "Markup that conveys the meaning of content." + } + ], + "tables": [ + [ + [ + { + "text": "Feature", + "header": true, + "colspan": 1, + "rowspan": 1 + }, + { + "text": "State", + "header": true, + "colspan": 1, + "rowspan": 1 + } + ], + [ + { + "text": "Semantic model", + "header": false, + "colspan": 1, + "rowspan": 1 + }, + { + "text": "Enabled", + "header": false, + "colspan": 1, + "rowspan": 1 + } + ] + ] + ], + "seealso": [] + }, + "semantic": { + "paragraphs": [ + "Welcome to BusyMark.", + "Reusable semantic content." + ], + "quotes": [], + "shortcuts": [], + "tooltips": [], + "tables": [], + "seealso": [ + { + "title": "Related", + "links": [ + { + "title": "Semantic topic", + "topic": "features" + } + ] + } + ] + } + } +} diff --git a/test/src/source_autocomplete_test.dart b/test/src/source_autocomplete_test.dart index 461674f2..f52b3c4e 100644 --- a/test/src/source_autocomplete_test.dart +++ b/test/src/source_autocomplete_test.dart @@ -53,7 +53,7 @@ void main() { references: [], diagnostics: [], ); - const source = '[]; + final offsets = []; + final controller = await _pumpAutocompleteSourceEditor( + tester, + onSymbolAction: (action, offset) { + actions.add(action); + offsets.add(offset); + }, + ); + controller.selection = const TextSelection.collapsed(offset: 5); + for (final keys in [ + (LogicalKeyboardKey.controlLeft, LogicalKeyboardKey.keyB), + (LogicalKeyboardKey.altLeft, LogicalKeyboardKey.f7), + (LogicalKeyboardKey.shiftLeft, LogicalKeyboardKey.f6), + ]) { + await tester.sendKeyDownEvent(keys.$1); + await tester.sendKeyEvent(keys.$2); + await tester.sendKeyUpEvent(keys.$1); + } + expect(actions, SourceSymbolAction.values); + expect(offsets, [5, 5, 5]); + expect(controller.text, _autocompleteSource); + }); + testWidgets('Ctrl+Space opens project-aware source completion', ( tester, ) async { @@ -1427,6 +1454,7 @@ const _autocompleteSource = '

fea'; Future _pumpAutocompleteSourceEditor( WidgetTester tester, { BusyMarkSourceChanged? onChanged, + void Function(SourceSymbolAction action, int offset)? onSymbolAction, }) async { const index = WritersideProjectIndex( symbols: [ @@ -1454,6 +1482,7 @@ Future _pumpAutocompleteSourceEditor( width: 900, height: 600, child: BusyMarkSourceEditor( + onSymbolAction: onSymbolAction, text: _autocompleteSource, language: SourceSyntaxLanguage.xml, filePath: '/project/topics/current.topic', diff --git a/test/src/workspace_controller_test.dart b/test/src/workspace_controller_test.dart index 30d3e01b..d568e321 100644 --- a/test/src/workspace_controller_test.dart +++ b/test/src/workspace_controller_test.dart @@ -14,6 +14,7 @@ import 'package:busymark/src/workspace/workspace_message.dart'; import 'package:busymark/src/workspace/workspace_model.dart'; import 'package:busymark/src/workspace/workspace_service.dart'; import 'package:busymark/src/writerside/writerside_project_creator.dart'; +import 'package:busymark/src/writerside/writerside_project.dart'; import 'package:busymark/src/writerside/writerside_topic_creator.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -21,6 +22,60 @@ import 'package:path/path.dart' as p; import 'package:xml/xml.dart'; void main() { + test( + 'Writerside rename stages verified edits across unsaved tabs with undo', + () async { + final root = await Directory.systemTemp.createTemp('busymark-rename-'); + addTearDown(() => root.delete(recursive: true)); + for (final entry in { + 'writerside.cfg': + '', + 'guide.tree': + '', + 'topics/a.topic': + '

Original

', + 'topics/b.topic': + '
', + }.entries) { + final file = File(p.join(root.path, entry.key)); + await file.parent.create(recursive: true); + await file.writeAsString(entry.value); + } + final harness = await _createControllerHarness(); + final controller = harness.controller._notifier; + await controller.openPath(root.path); + final aPath = p.join(root.path, 'topics/a.topic'); + final bPath = p.join(root.path, 'topics/b.topic'); + await controller.openActiveFile(bPath); + controller.updateActiveText( + '

Unsaved

', + sourceFilePath: bPath, + ); + await controller.openActiveFile(aPath); + final index = (await controller.writersideEditorIndex())!; + final symbol = index + .definitions('a.topic#anchor', moduleId: 'docs') + .single; + final edits = index.safeRenameEdits(symbol, 'renamed'); + expect(await controller.applyWritersideRename(edits), isTrue); + final state = harness.controller.state; + expect( + state.documentBuffers + .singleWhere((buffer) => buffer.filePath == bPath) + .text, + '

Unsaved

', + ); + expect( + state.documentBuffers.where((buffer) => buffer.dirty), + hasLength(2), + ); + expect(await File(bPath).readAsString(), isNot(contains('renamed'))); + expect(controller.undoActiveBuffer(), isTrue); + expect(harness.controller.state.activeText, contains('id="anchor"')); + expect(await controller.applyWritersideRename(edits), isFalse); + }, + ); + test( 'records opened Markdown files by file path in recent workspaces', () async { diff --git a/test/src/writerside_api_test.dart b/test/src/writerside_api_test.dart index 4fb884d2..412cdab2 100644 --- a/test/src/writerside_api_test.dart +++ b/test/src/writerside_api_test.dart @@ -28,8 +28,22 @@ void main() { 'post': { 'summary': 'Add users', 'tags': ['User'], + 'requestBody': { + 'content': { + 'application/json': { + 'schema': {r'$ref': '#/components/schemas/Pet'}, + }, + }, + }, 'responses': { - '201': {'description': 'User created'}, + '201': { + 'description': 'User created', + 'content': { + 'application/json': { + 'example': {'status': 'generated-response'}, + }, + }, + }, }, }, }, @@ -50,6 +64,15 @@ void main() { 'type': 'object', 'properties': { 'name': {'type': 'string'}, + 'owner': { + 'type': 'object', + 'properties': { + 'id': { + 'type': 'integer', + 'description': 'Nested owner identifier', + }, + }, + }, }, }, }, @@ -133,9 +156,22 @@ void main() { expect(resolved.diagnostics, isEmpty); expect(text, contains('Add users')); expect(text, contains('custom request')); + expect(text, contains('generated-response')); expect(text, isNot(contains('List pets'))); }, ); + test('API schemas resolve references and honor nesting depth', () async { + final (full, _) = await render( + '', + ); + expect(full, contains('Nested owner identifier')); + expect(full, contains('"name": "string"')); + final (shallow, _) = await render( + '', + ); + expect(shallow, isNot(contains('Nested owner identifier'))); + expect(shallow, contains('owner')); + }); test('schema and webhook elements are visible', () async { final (text, resolved) = await render( '', diff --git a/test/src/writerside_identity_test.dart b/test/src/writerside_identity_test.dart new file mode 100644 index 00000000..9480b484 --- /dev/null +++ b/test/src/writerside_identity_test.dart @@ -0,0 +1,170 @@ +import 'dart:io'; + +import 'package:busymark/src/editor/source/source_autocomplete.dart'; +import 'package:busymark/src/editor/source/source_document.dart'; +import 'package:busymark/src/writerside/writerside_project.dart'; +import 'package:busymark/src/writerside/writerside_parsers.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart' as p; + +void main() { + late Directory directory; + late WritersideProject project; + late Map sources; + setUp(() async { + directory = await Directory.systemTemp.createTemp('writerside-identities-'); + sources = { + 'writerside.cfg': + '', + 'one.tree': + '', + 'two.tree': + '', + 'v.list': + '', + 'topics/a.topic': + '

A

%product%

', + 'topics/b.topic': + '

B

%product%

%label%

', + 'topics/extra.md': + '# Extra\n\n## Section {id="same"}\n\n[First](a.topic#same)\n\n[Second](b.topic#same)\n', + }; + for (final entry in sources.entries) { + final file = File(p.join(directory.path, entry.key)); + await file.parent.create(recursive: true); + await file.writeAsString(entry.value.replaceAll(r'\n', '\n')); + } + project = await const WritersideProjectService().load(directory.path); + }); + tearDown(() => directory.delete(recursive: true)); + + test( + 'anchor identity includes topic and all instances participate in usages', + () { + final index = project.index; + final a = index.definitions('a.topic#same', moduleId: 'docs').single; + final b = index.definitions('b.topic#same', moduleId: 'docs').single; + expect(a.filePath, isNot(b.filePath)); + expect(index.findUsages(a), hasLength(3)); + expect(index.findUsages(b), hasLength(2)); + final edits = index.safeRenameEdits(a, 'first'); + expect(edits, hasLength(4)); + final contents = {}; + for (final path in edits.map((edit) => edit.filePath).toSet()) { + var text = File(path).readAsStringSync(); + final changes = edits.where((edit) => edit.filePath == path).toList() + ..sort((a, b) => b.span.startOffset.compareTo(a.span.startOffset)); + for (final edit in changes) { + expect( + text.substring(edit.span.startOffset, edit.span.endOffset), + edit.expectedText, + ); + text = text.replaceRange( + edit.span.startOffset, + edit.span.endOffset, + edit.replacement, + ); + } + contents[p.basename(path)] = text; + } + expect(contents['b.topic'], contains(''), + ); + expect(contents['extra.md'], contains('[First](a.topic#first)')); + expect(contents['extra.md'], contains('[Second](b.topic#same)')); + }, + ); + + test('conditional globals and snippet variables have distinct scopes', () { + final index = project.index; + expect( + index.diagnostics.where( + (d) => d.code == 'writerside.index.duplicate-symbol', + ), + isEmpty, + ); + final global = index.symbols.firstWhere((s) => s.name == 'product'); + final edits = index.safeRenameEdits(global, 'app'); + expect(edits, hasLength(4)); + expect( + edits.map((e) => e.expectedText), + containsAll(['product', '%product%']), + ); + final local = index.symbols.firstWhere((s) => s.name == 'label'); + expect(index.findUsages(local), hasLength(2)); + expect(index.safeRenameEdits(local, 'caption'), hasLength(3)); + }); + + test('completion filters context and target identity before limiting', () { + List suggest(String text, {int limit = 40}) => + const SourceAutocompleteProvider() + .suggestions( + document: SourceDocument(fullText: text), + fullOffset: text.length, + limit: limit, + context: SourceAutocompleteContext( + projectIndex: project.index, + moduleId: 'docs', + filePath: p.join(directory.path, 'topics/a.topic'), + ), + ) + .map((item) => item.insertText) + .toList(); + expect(suggest('
', + topicsRoot: p.join(directory.path, 'topics'), + ); + final index = WritersideProjectIndex.build([ + module.copyWith(topics: [topic]), + ]); + expect( + index.diagnostics.map((d) => d.code), + containsAll([ + 'writerside.schema.invalid-parent', + 'writerside.schema.invalid-attribute-value', + ]), + ); + expect( + index.diagnostics.where((d) => d.args['attribute'] == 'href'), + isEmpty, + ); + const profiles = WritersideBuildProfilesParser(); + expect( + profiles + .parse( + '/cfg/buildprofiles.xml', + 'true', + ) + .diagnostics, + isEmpty, + ); + expect( + profiles + .parse( + '/cfg/buildprofiles.xml', + '', + ) + .diagnostics, + isNotEmpty, + ); + }, + ); +} diff --git a/test/src/writerside_pdf_export_test.dart b/test/src/writerside_pdf_export_test.dart index 19ed225e..272118a2 100644 --- a/test/src/writerside_pdf_export_test.dart +++ b/test/src/writerside_pdf_export_test.dart @@ -1,8 +1,12 @@ import 'dart:io'; +import 'dart:convert'; import 'package:busymark/src/export/markdown_pdf_export_service.dart'; import 'package:busymark/src/export/markdown_pdf_models.dart'; +import 'package:busymark/src/export/markdown_export_mapper.dart'; +import 'package:busymark/src/export/markdown_export_document.dart'; import 'package:busymark/src/export/typst_compiler.dart'; +import 'package:busymark/src/export/typst_payload_builder.dart'; import 'package:busymark/src/export/writerside_pdf_export_service.dart'; import 'package:busymark/src/export/writerside_pdf_models.dart'; import 'package:busymark/src/markdown/markdown_model.dart'; @@ -11,6 +15,112 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:path/path.dart' as p; void main() { + const compiler = 'build/linux/x64/release/bundle/libexec/busymark/typst'; + test( + 'bundled Typst compiles semantic tables, anchors and glossary footnotes', + () async { + final fixture = await _WritersideFixture.create(); + addTearDown(fixture.dispose); + final glossary = File(p.join(fixture.module.path, 'cfg/glossary.xml')); + await glossary.parent.create(recursive: true); + await glossary.writeAsString( + 'Glossary definition', + ); + await File( + p.join(fixture.module.path, 'topics/advanced.topic'), + ).writeAsString( + '

Body

Header
Nested codeA
B
', + ); + final recording = _RecordingMarkdownExporter(); + await WritersidePdfExportService(markdownExporter: recording).export( + WritersidePdfExportRequest( + moduleRoot: fixture.module.path, + projectRoot: fixture.root.path, + instanceId: 'guide', + destinationPath: p.join(fixture.root.path, 'recording.pdf'), + overwrite: false, + ), + ); + final payload = const TypstPayloadBuilder().build( + document: const MarkdownExportMapper().map( + recording.request!.document!, + ), + options: const MarkdownPdfOptions(), + assets: {}, + ); + await File( + p.join(fixture.root.path, 'document.json'), + ).writeAsString(jsonEncode(payload)); + await File( + 'assets/export/markdown.typ', + ).copy(p.join(fixture.root.path, 'main.typ')); + final pdf = p.join(fixture.root.path, 'semantic.pdf'); + final result = await Process.run(p.absolute(compiler), [ + 'compile', + p.join(fixture.root.path, 'main.typ'), + pdf, + ]); + expect(result.exitCode, 0, reason: '${result.stderr}'); + expect(await File(pdf).length(), greaterThan(1000)); + }, + skip: !File(compiler).existsSync(), + ); + + test( + 'PDF retains nested chapter bodies and resolves unique internal destinations', + () async { + final fixture = await _WritersideFixture.create(); + addTearDown(fixture.dispose); + await File( + p.join(fixture.module.path, 'topics/advanced.topic'), + ).writeAsString( + '

Nested body

', + ); + final exporter = _RecordingMarkdownExporter(); + await WritersidePdfExportService(markdownExporter: exporter).export( + WritersidePdfExportRequest( + moduleRoot: fixture.module.path, + projectRoot: fixture.root.path, + instanceId: 'guide', + destinationPath: p.join(fixture.root.path, 'anchors.pdf'), + overwrite: false, + ), + ); + final document = const MarkdownExportMapper().map( + exporter.request!.document!, + ); + Iterable walk( + List blocks, + ) sync* { + for (final block in blocks) { + yield block; + yield* walk(block.children); + } + } + + final blocks = walk(document.blocks).toList(); + expect( + blocks.expand((block) => block.inlines).map((inline) => inline.text), + contains('Nested body'), + ); + final anchors = blocks + .map((block) => block.attributes['anchor']) + .whereType() + .toList(); + expect(anchors.toSet(), hasLength(anchors.length)); + final destination = blocks + .expand((block) => block.inlines) + .singleWhere( + (inline) => + inline.text == 'Nested body' && + inline.kind == MarkdownExportInlineKind.link, + ) + .destination!; + expect(destination, startsWith('#ws-')); + expect(anchors, contains(destination.substring(1))); + }, + ); + test( 'native export composes the selected instance without a container runtime', () async { diff --git a/test/src/writerside_project_test.dart b/test/src/writerside_project_test.dart index 05f210c4..1a565df7 100644 --- a/test/src/writerside_project_test.dart +++ b/test/src/writerside_project_test.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'dart:convert'; import 'package:busymark/src/workspace/workspace_model.dart'; import 'package:busymark/src/workspace/workspace_service.dart'; @@ -162,8 +163,8 @@ void main() { moduleId: moduleId, ); final completion = const SourceAutocompleteProvider().suggestions( - document: SourceDocument(fullText: '[]; + test( + 'BusyMark matches the official builder semantic snapshot for the fixture', + () async { + final root = p.absolute('test/fixtures/writerside/conformance_project'); + final expected = + jsonDecode( + await File( + 'test/fixtures/writerside/conformance_semantics.json', + ).readAsString(), + ) + as Map; + final project = await const WritersideProjectService().load(root); + String normalized(String text) => + text.replaceAll(RegExp(r'\s+'), ' ').trim(); + Iterable inlines(Iterable values) sync* { + for (final value in values) { + yield value; + yield* inlines(value.children); + } + } + + for (final topic in project.activeModule!.topics) { + final resolved = const WritersideDocumentResolver().resolve( + topic.document, + WritersideResolveContext( + module: project.activeModule!, + topic: topic, + instance: project.activeInstance, + ), + ); + final document = const WritersideDocumentRenderer().toBusyDocument( + resolved.document, + ); + final blocks = _walkBlocks(document.blocks).toList(); + final spans = blocks.expand((block) => inlines(block.inlines)).toList(); + final actual = { + 'paragraphs': document.blocks + .where((block) => block.kind == BusyBlockKind.paragraph) + .map((block) => normalized(block.plainText)) + .toList(), + 'quotes': blocks + .where((block) => block.attributes['style'] == 'quote') + .map((block) => normalized(block.plainText)) + .toList(), + 'shortcuts': spans + .where((inline) => inline.attributes['element'] == 'shortcut') + .map((inline) => inline.text) + .toList(), + 'tooltips': [ + for (final inline in spans.where( + (inline) => inline.attributes['element'] == 'tooltip', + )) + { + 'text': inline.plainText, + 'summary': inline.attributes['summary'], + }, + ], + 'tables': [ + for (final table in blocks.where( + (block) => block.attributes['element'] == 'table', + )) + [ + for (final row in table.children) + [ + for (final cell in row.children) + { + 'text': normalized(cell.plainText), + 'header': cell.attributes['header'] == 'true', + 'colspan': + int.tryParse(cell.attributes['colspan'] ?? '') ?? 1, + 'rowspan': + int.tryParse(cell.attributes['rowspan'] ?? '') ?? 1, + }, + ], + ], + ], + 'seealso': [ + for (final category in blocks.where( + (block) => block.attributes['element'] == 'category', + )) + { + 'title': category.attributes['title'], + 'links': [ + for (final inline + in _walkBlocks(category.children) + .expand((block) => inlines(block.inlines)) + .where( + (inline) => inline.kind == BusyInlineKind.link, + )) + { + 'title': inline.plainText, + 'topic': p.basenameWithoutExtension(inline.destination!), + }, + ], + }, + ], + }; + expect(actual, expected['topics'][topic.id], reason: topic.filePath); + } + }, + ); + + test( + 'conformance fixture preserves source and resolves semantic content', + () async { + final root = p.join( + Directory.current.path, + 'test', + 'fixtures', + 'writerside', + 'conformance_project', + ); + final project = await const WritersideProjectService().load(root); + final module = project.activeModule!; + final instance = project.activeInstance!; + final renderedText = StringBuffer(); + final diagnostics = []; + + for (final topic in module.topics) { + expect( + const WritersideDocumentSerializer().serialize(topic.document), + topic.document.source, + ); + final resolved = const WritersideDocumentResolver().resolve( + topic.document, + WritersideResolveContext( + module: module, + topic: topic, + instance: instance, + modulesByOrigin: project.modulesByOrigin, + ), + ); + diagnostics.addAll(resolved.diagnostics); + final rendered = const WritersideDocumentRenderer().toBusyDocument( + resolved.document, + title: resolved.title, + ); + for (final block in _walkBlocks(rendered.blocks)) { + renderedText.writeln(block.plainText); + } + } - for (final topic in module.topics) { expect( - const WritersideDocumentSerializer().serialize(topic.document), - topic.document.source, - ); - final resolved = const WritersideDocumentResolver().resolve( - topic.document, - WritersideResolveContext( - module: module, - topic: topic, - instance: instance, - modulesByOrigin: project.modulesByOrigin, + diagnostics.where( + (diagnostic) => diagnostic.severity == DiagnosticSeverity.error, ), + isEmpty, ); - diagnostics.addAll(resolved.diagnostics); - final rendered = const WritersideDocumentRenderer().toBusyDocument( - resolved.document, - title: resolved.title, - ); - for (final block in _walkBlocks(rendered.blocks)) { - renderedText.writeln(block.plainText); - } - } - - expect( - diagnostics.where( - (diagnostic) => diagnostic.severity == DiagnosticSeverity.error, - ), - isEmpty, - ); - expect(renderedText.toString(), contains('Lossless semantic quote')); - expect(renderedText.toString(), contains('Reusable semantic content')); - expect(renderedText.toString(), contains('BusyMark')); - }); + expect(renderedText.toString(), contains('Lossless semantic quote')); + expect(renderedText.toString(), contains('Reusable semantic content')); + expect(renderedText.toString(), contains('BusyMark')); + }, + ); } Iterable _walkBlocks(Iterable blocks) sync* { diff --git a/test/src/writerside_resolution_regression_test.dart b/test/src/writerside_resolution_regression_test.dart index a4deb263..f379de35 100644 --- a/test/src/writerside_resolution_regression_test.dart +++ b/test/src/writerside_resolution_regression_test.dart @@ -69,6 +69,155 @@ void main() { return const WritersideDocumentRenderer().toBusyDocument(resolved.document); } + test( + 'mixed Markdown protects fenced code and CDATA while preserving spans', + () async { + const source = '''# Library + + + +Before **bold**. + +]]> + +After *emphasis*. + +```xml +&literal +``` + + +'''; + await write('topics/library.md', source); + await write( + 'topics/main.topic', + '', + ); + final blocks = walk((await render()).blocks).toList(); + expect( + blocks.map((block) => block.plainText), + containsAll([ + 'Before bold.', + '*literal* ', + 'After emphasis.', + '&literal', + ]), + ); + final after = blocks.singleWhere( + (block) => block.plainText == 'After emphasis.', + ); + expect( + after.inlines.map((inline) => inline.kind), + contains(BusyInlineKind.emphasis), + ); + expect( + source.substring( + after.sourceSpan!.startOffset, + after.sourceSpan!.endOffset, + ), + contains('After *emphasis*.'), + ); + }, + ); + + test('lazy defaults respect caller arguments and percent escaping', () async { + await write( + 'topics/main.topic', + r'

%path% %\base% %base%

%base%
', + ); + final blocks = walk((await render()).blocks).toList(); + expect( + blocks.map((block) => block.plainText), + contains('caller/file %base% %base%'), + ); + expect( + blocks + .where((block) => block.kind == BusyBlockKind.codeBlock) + .map((block) => block.plainText), + everyElement('%base%'), + ); + }); + + test('empty links use the target title for the selected instance', () async { + await write( + 'topics/target.topic', + 'Web titleMobile titleMobile chapter

Summary

', + ); + await write( + 'topics/main.topic', + '
', + ); + final document = await render(instance: 'mobile'); + expect( + walk( + document.blocks, + ).expand((block) => block.inlines).map((inline) => inline.text), + containsAll(['Mobile title', 'Mobile chapter']), + ); + }); + + test( + 'conditional chapter content and links follow the selected instance', + () async { + await write( + 'topics/library.md', + '# Library\n\n## Web {instance="web" id="web"}\n\nWeb body\n\n## All\n\nShared body\n', + ); + await write( + 'topics/target.topic', + '

Hidden

', + ); + await write( + 'topics/main.topic', + '
Conditional link', + ); + final web = walk( + (await render()).blocks, + ).map((block) => block.plainText).join('\n'); + final mobile = walk((await render(instance: 'mobile')).blocks).toList(); + expect(web, contains('Web body')); + expect( + mobile.map((block) => block.plainText).join('\n'), + isNot(contains('Web body')), + ); + expect( + mobile.map((block) => block.plainText).join('\n'), + contains('Shared body'), + ); + expect( + mobile + .expand((block) => block.inlines) + .singleWhere((inline) => inline.text == 'Conditional link') + .kind, + BusyInlineKind.text, + ); + }, + ); + + test( + 'malformed markup and unresolved reuse stay visible with diagnostics', + () async { + await write( + 'topics/main.topic', + '', + ); + final module = await const WritersideModuleService().load(root.path); + final topic = module.topicByReference('main.topic')!; + final resolved = const WritersideDocumentResolver().resolve( + topic.document, + WritersideResolveContext(module: module, topic: topic), + ); + final rendered = const WritersideDocumentRenderer().toBusyDocument( + resolved.document, + ); + expect( + rendered.blocks.single.plainText, + contains('Unresolved Writerside include'), + ); + expect(resolved.diagnostics.single.sourceSpan!.filePath, topic.filePath); + }, + ); + test( 'Markdown IDs include whole chapters and retain mixed-content spans', () async { diff --git a/tools/extract_writerside_semantics.py b/tools/extract_writerside_semantics.py new file mode 100644 index 00000000..90488790 --- /dev/null +++ b/tools/extract_writerside_semantics.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +"""Normalize observable fixture semantics from an official Writerside web ZIP. + +Usage: extract_writerside_semantics.py ARTIFACT.zip SNAPSHOT.json [--check] +The snapshot excludes generated IDs, dates, CSS and navigation chrome. +""" +import json +import pathlib +import sys +import zipfile +from html.parser import HTMLParser + + +class Topic(HTMLParser): + def __init__(self): + super().__init__() + self.stack = [] + self.captures = [] + self.topic_id = None + self.result = dict(paragraphs=[], quotes=[], shortcuts=[], tooltips=[], tables=[], seealso=[]) + self.table = None + self.row = None + + def handle_starttag(self, tag, attrs): + attrs = dict(attrs) + if tag == 'body': + self.topic_id = attrs.get('data-id') + props = json.loads(attrs.get('data-article-props', '{}')) + self.result['seealso'] = [dict(title=category['title'], links=[ + dict(title=link['text'], topic=pathlib.PurePosixPath(link['url']).stem) + for link in category.get('links', [])]) for category in props.get('seeAlso', [])] + in_article = 'article' in self.stack + parent = self.stack[-1] if self.stack else None + if in_article: + if tag == 'table': + self.table = [] + self.result['tables'].append(self.table) + if tag == 'tr' and self.table is not None: + self.row = [] + self.table.append(self.row) + kind = ('paragraphs' if tag == 'p' and parent == 'article' else + 'quotes' if tag == 'blockquote' else + 'shortcuts' if tag == 'kbd' else + 'tooltips' if 'tooltip' in attrs.get('class', '').split() else + 'cell' if tag in ('td', 'th') else None) + if kind: + self.captures.append([len(self.stack), tag, kind, attrs, []]) + if tag not in {'meta', 'link', 'img', 'br', 'hr', 'input', 'source', 'wbr'}: + self.stack.append(tag) + + def handle_data(self, text): + for capture in self.captures: + capture[4].append(text) + + def handle_endtag(self, tag): + if tag not in self.stack: + return + depth = len(self.stack) - 1 - self.stack[::-1].index(tag) + completed = [capture for capture in self.captures if capture[0] >= depth] + self.captures = [capture for capture in self.captures if capture[0] < depth] + for _, _, kind, attrs, chunks in completed: + text = ' '.join(''.join(chunks).split()) + if kind == 'cell': + self.row.append(dict(text=text, header=tag == 'th', + colspan=int(attrs.get('colspan', 1)), rowspan=int(attrs.get('rowspan', 1)))) + elif kind == 'tooltips': + self.result[kind].append(dict(text=text, summary=attrs.get('title', ''))) + else: + self.result[kind].append(text) + self.stack = self.stack[:depth] + + +def extract(archive): + result = {} + with zipfile.ZipFile(archive) as bundle: + for name in sorted(bundle.namelist()): + if name.endswith('.html') and name != 'index.html': + topic = Topic() + topic.feed(bundle.read(name).decode('utf-8')) + if topic.topic_id: + result[topic.topic_id] = topic.result + return {'builderVersion': '2026.08.0328', 'topics': result} + + +if __name__ == '__main__': + result = extract(sys.argv[1]) + snapshot = pathlib.Path(sys.argv[2]) + if '--check' in sys.argv: + assert result == json.loads(snapshot.read_text()), 'Official semantic output differs from the checked-in snapshot' + else: + snapshot.write_text(json.dumps(result, indent=2, ensure_ascii=False) + '\n') diff --git a/tools/generate_writerside_schema.py b/tools/generate_writerside_schema.py new file mode 100644 index 00000000..7b3e9236 --- /dev/null +++ b/tools/generate_writerside_schema.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +"""Extract authoring rules from JetBrains' topic.v2.xsd (pass local XSD path). + +Download: https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd +The published XSD lags some releases; versioned overlays live in writerside_schema.dart. +""" +import hashlib +import json +import pathlib +import sys +import xml.etree.ElementTree as ET + +source = pathlib.Path(sys.argv[1]) +root = ET.fromstring(source.read_bytes()) +ns = '{http://www.w3.org/2001/XMLSchema}' +by_kind = {kind: {node.get('name'): node for node in root.findall(ns + kind)} + for kind in ('element', 'group', 'attribute', 'attributeGroup', 'complexType', 'simpleType')} + +def effective(node): + if node.get('type') in by_kind['complexType']: + return by_kind['complexType'][node.get('type')] + if node.get('substitutionGroup') and node.find(ns + 'complexType') is None: + return effective(by_kind['element'][node.get('substitutionGroup')]) + return node + +def concrete(name): + node = by_kind['element'].get(name) + result = set() if node is not None and node.get('abstract') == 'true' else {name} + for child_name, child in by_kind['element'].items(): + if child.get('substitutionGroup') == name: + result |= concrete(child_name) + return result + +def children(node, seen=frozenset()): + result = set() + for child in node: + name = child.tag.removeprefix(ns) + if name == 'element': + result |= concrete(child.get('ref') or child.get('name')) + elif name in ('group', 'complexType') and child.get('ref') and child.get('ref') not in seen: + ref = child.get('ref') + result |= children(by_kind[name][ref], seen | {ref}) + elif name in ('sequence', 'choice', 'all', 'complexType', 'complexContent', 'extension', 'restriction', 'group'): + base = by_kind['complexType'].get(child.get('base')) + if base is not None: + result |= children(base, seen) + result |= children(child, seen) + return result + +def type_info(node): + node_type = node.get('type', 'xs:string') + simple = node.find(ns + 'simpleType') + if simple is None: + simple = by_kind['simpleType'].get(node_type) + values = [] + if simple is not None: + values = [x.get('value') for x in simple.iter(ns + 'enumeration')] + restriction = simple.find(ns + 'restriction') + if restriction is not None: + node_type = restriction.get('base', node_type) + return node_type.removeprefix('xs:'), values + +def attributes(node, seen=frozenset()): + result = {} + for child in node: + kind = child.tag.removeprefix(ns) + if kind == 'attribute': + name = child.get('name') or child.get('ref') + definition = by_kind['attribute'].get(child.get('ref'), child) + typ, vals = type_info(definition) + result[name] = (typ, vals, child.get('use', definition.get('use')) == 'required') + elif kind == 'attributeGroup' and child.get('ref') and child.get('ref') not in seen: + ref = child.get('ref') + result.update(attributes(by_kind[kind][ref], seen | {ref})) + elif kind in ('complexType', 'complexContent', 'simpleContent', 'extension', 'restriction'): + base = by_kind['complexType'].get(child.get('base')) + if base is not None: + result.update(attributes(base, seen)) + result.update(attributes(child, seen)) + return result + +def quoted(value): + return json.dumps(value, ensure_ascii=False).replace('$', r'\$') +def strings(values): + return '{' + ', '.join(map(quoted, sorted(values))) + '}' + +out = ["// Generated by tools/generate_writerside_schema.py. Do not edit.", + "// ignore_for_file: prefer_single_quotes", + "// Source: https://resources.jetbrains.com/writerside/1.0/topic.v2.xsd", + "// SHA256: " + hashlib.sha256(source.read_bytes()).hexdigest(), + "class WritersideSchemaElementRules {", + " const WritersideSchemaElementRules({required this.children, required this.attributes, required this.required, required this.values});", + " final Set children;", " final Map attributes;", + " final Set required;", " final Map> values;", "}", + "const writersideOfficialRules = {"] +for name, node in sorted(by_kind['element'].items()): + if node.get('abstract') == 'true': + continue + node = effective(node) + attrs = attributes(node) + out.append(f' {quoted(name)}: WritersideSchemaElementRules(') + out.append(' children: ' + strings(children(node)) + ',') + out.append(' attributes: {' + ', '.join(quoted(k) + ': ' + quoted(v[0]) for k, v in sorted(attrs.items())) + '},') + out.append(' required: ' + strings(k for k, v in attrs.items() if v[2]) + ',') + out.append(' values: >{' + ', '.join(quoted(k) + ': ' + strings(v[1]) for k, v in sorted(attrs.items()) if v[1]) + '},'), + out.append(' ),') +out.append('};') +pathlib.Path('lib/src/writerside/writerside_schema_data.dart').write_text('\n'.join(out) + '\n') diff --git a/tools/validate_writerside_conformance.sh b/tools/validate_writerside_conformance.sh index 94ee762b..49d5eb79 100755 --- a/tools/validate_writerside_conformance.sh +++ b/tools/validate_writerside_conformance.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -readonly builder_version="2026.07.8925" +readonly builder_version="2026.08.0328" readonly source_root="${1:-test/fixtures/writerside/conformance_project}" readonly module_instance="${2:-Conformance/conformance}" readonly work_root="$(mktemp -d)" @@ -27,4 +27,20 @@ if ! docker run --rm \ exit 1 fi -find "$output_root/artifacts" -type f -size +0c -print -quit | grep -q . +python3 - "$output_root/artifacts/report.json" <<'PYREPORT' +import json, sys +report = json.load(open(sys.argv[1])) +assert report['testsErrorsCount'] == 0, report['testsErrors'] +assert report['testsWarningsCount'] == 0, report['testsWarnings'] +print(f"Official builder: {report['testsPassedCount']} checks passed") +PYREPORT +if [[ "$source_root" == "test/fixtures/writerside/conformance_project" ]]; then + python3 tools/extract_writerside_semantics.py \ + "$output_root/artifacts/webHelpCONFORMANCE2-all.zip" \ + test/fixtures/writerside/conformance_semantics.json --check +fi + +if [[ -n "${WRITERSIDE_CONFORMANCE_OUTPUT:-}" ]]; then + mkdir -p -- "$WRITERSIDE_CONFORMANCE_OUTPUT" + cp -a -- "$output_root/artifacts/." "$WRITERSIDE_CONFORMANCE_OUTPUT/" +fi From 8bbb89486078efd5fabc35d0ec2e9e6ca81a3a59 Mon Sep 17 00:00:00 2001 From: albert Date: Sat, 5 Sep 2026 05:01:34 -0700 Subject: [PATCH 06/37] Add native offline HTML export --- README.md | 1 + assets/export/html.css | 5 + docs/html-export-verification.md | 65 + docs/html-export.md | 174 +++ lib/l10n/app_ar.arb | 23 +- lib/l10n/app_de.arb | 23 +- lib/l10n/app_en.arb | 18 + lib/l10n/app_es.arb | 23 +- lib/l10n/app_et.arb | 23 +- lib/l10n/app_fa.arb | 23 +- lib/l10n/app_fr.arb | 23 +- lib/l10n/app_hi.arb | 23 +- lib/l10n/app_id.arb | 23 +- lib/l10n/app_it.arb | 23 +- lib/l10n/app_ja.arb | 23 +- lib/l10n/app_ko.arb | 23 +- lib/l10n/app_nb.arb | 23 +- lib/l10n/app_nl.arb | 23 +- lib/l10n/app_pl.arb | 23 +- lib/l10n/app_pt.arb | 23 +- lib/l10n/app_pt_BR.arb | 23 +- lib/l10n/app_ru.arb | 23 +- lib/l10n/app_tr.arb | 23 +- lib/l10n/app_uk.arb | 23 +- lib/l10n/app_vi.arb | 23 +- lib/l10n/app_zh.arb | 23 +- lib/l10n/app_zh_CN.arb | 23 +- lib/l10n/generated/app_localizations.dart | 66 + lib/l10n/generated/app_localizations_ar.dart | 58 +- lib/l10n/generated/app_localizations_de.dart | 58 +- lib/l10n/generated/app_localizations_en.dart | 38 + lib/l10n/generated/app_localizations_es.dart | 58 +- lib/l10n/generated/app_localizations_et.dart | 58 +- lib/l10n/generated/app_localizations_fa.dart | 58 +- lib/l10n/generated/app_localizations_fr.dart | 58 +- lib/l10n/generated/app_localizations_hi.dart | 58 +- lib/l10n/generated/app_localizations_id.dart | 58 +- lib/l10n/generated/app_localizations_it.dart | 58 +- lib/l10n/generated/app_localizations_ja.dart | 59 +- lib/l10n/generated/app_localizations_ko.dart | 58 +- lib/l10n/generated/app_localizations_nb.dart | 58 +- lib/l10n/generated/app_localizations_nl.dart | 58 +- lib/l10n/generated/app_localizations_pl.dart | 58 +- lib/l10n/generated/app_localizations_pt.dart | 141 +- lib/l10n/generated/app_localizations_ru.dart | 58 +- lib/l10n/generated/app_localizations_tr.dart | 58 +- lib/l10n/generated/app_localizations_uk.dart | 58 +- lib/l10n/generated/app_localizations_vi.dart | 58 +- lib/l10n/generated/app_localizations_zh.dart | 137 +- lib/src/app/busymark_app.dart | 20 + lib/src/app/busymark_main_menu.dart | 11 + lib/src/app/command_registry.dart | 7 + lib/src/core/atomic_file_writer.dart | 4 +- lib/src/core/linux_atomic_file_api.dart | 7 +- lib/src/export/html_document_writer.dart | 1182 +++++++++++++++++ lib/src/export/html_export_assets.dart | 277 ++++ lib/src/export/html_export_links.dart | 158 +++ lib/src/export/html_export_models.dart | 105 ++ lib/src/export/html_export_publisher.dart | 254 ++++ lib/src/export/html_export_service.dart | 418 ++++++ lib/src/export/html_export_ui.dart | 308 +++++ lib/src/export/html_publication_plan.dart | 376 ++++++ lib/src/export/html_release_smoke.dart | 151 +++ lib/src/export/html_rich_content.dart | 220 +++ lib/src/export/markdown_export_assets.dart | 5 +- lib/src/markdown/markdown_ast_adapter.dart | 99 +- lib/src/markdown/markdown_parser.dart | 7 +- .../platform/header_bar_configuration.dart | 10 + .../platform/linux_header_bar_service.dart | 3 + .../visualization_coordinator.dart | 47 +- .../visualization/visualization_models.dart | 2 +- .../visualization_raster_sizing.dart | 3 + .../visualization_release_smoke.dart | 11 + .../presentation/settings_screen.dart | 2 + .../presentation/welcome_screen.dart | 2 + .../presentation/workspace_screen.dart | 8 + .../writerside_document_resolver.dart | 35 +- lib/src/writerside/writerside_table_view.dart | 10 +- linux/runner/my_application.cc | 15 +- pubspec.yaml | 1 + test/src/header_bar_configuration_test.dart | 1 + test/src/html_export_test.dart | 412 ++++++ test/src/html_export_ui_test.dart | 303 +++++ test/src/html_publication_test.dart | 307 +++++ test/src/html_rich_export_test.dart | 325 +++++ test/src/localization_audit_test.dart | 1 + test/src/workspace_controller_test.dart | 1 - .../src/writerside_semantic_widgets_test.dart | 7 + tools/verify_html_export_browser.py | 143 ++ 89 files changed, 7212 insertions(+), 242 deletions(-) create mode 100644 assets/export/html.css create mode 100644 docs/html-export-verification.md create mode 100644 docs/html-export.md create mode 100644 lib/src/export/html_document_writer.dart create mode 100644 lib/src/export/html_export_assets.dart create mode 100644 lib/src/export/html_export_links.dart create mode 100644 lib/src/export/html_export_models.dart create mode 100644 lib/src/export/html_export_publisher.dart create mode 100644 lib/src/export/html_export_service.dart create mode 100644 lib/src/export/html_export_ui.dart create mode 100644 lib/src/export/html_publication_plan.dart create mode 100644 lib/src/export/html_release_smoke.dart create mode 100644 lib/src/export/html_rich_content.dart create mode 100644 test/src/html_export_test.dart create mode 100644 test/src/html_export_ui_test.dart create mode 100644 test/src/html_publication_test.dart create mode 100644 test/src/html_rich_export_test.dart create mode 100644 tools/verify_html_export_browser.py diff --git a/README.md b/README.md index 2abe8a5f..dc607599 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ projects. explicitly selected context through Ollama, OpenAI, or Gemini, with diff-before-apply review. - Export Markdown documents as accessible, tagged PDF files. +- Export the current Markdown document or a Writerside instance as portable, offline HTML. See [HTML export](docs/html-export.md). - Navigate project files, table of contents, and document outline. - Review, stage, commit, branch, synchronize, and inspect history in Git-backed documentation workspaces using the user's normal Git configuration and tools. diff --git a/assets/export/html.css b/assets/export/html.css new file mode 100644 index 00000000..82058e60 --- /dev/null +++ b/assets/export/html.css @@ -0,0 +1,5 @@ +:root{color-scheme:light;font-family:system-ui,sans-serif;font-size:17px;line-height:1.65;color:#20242b;background:#fff} +*{box-sizing:border-box}body{margin:0}main{max-width:54rem;margin:auto;padding:2rem 3rem 5rem;min-width:0}article{overflow-wrap:anywhere}h1,h2,h3,h4,h5,h6{line-height:1.25;color:#111827;scroll-margin-top:1rem}h1{font-size:2.3rem;margin:0 0 1.2rem}h2{font-size:1.75rem;margin-top:2.1rem}h3{font-size:1.3rem;margin-top:1.8rem}p{margin:1rem 0}a{color:#1559aa;text-underline-offset:.16em}a:hover{text-decoration-thickness:2px}a:focus-visible,summary:focus-visible,[tabindex]:focus-visible{outline:3px solid #a34200;outline-offset:4px;border-radius:2px}img,video{max-width:100%;height:auto}figure{margin:1.5rem 0}figcaption,caption{font-size:.9rem;color:#4b5563;text-align:start}pre{overflow:auto;white-space:pre;max-width:100%;padding:1rem;border:1px solid #d8dee6;border-radius:.35rem;background:#f6f8fa;font-size:.86rem;line-height:1.55;overflow-wrap:normal}code,kbd,samp{font-family:ui-monospace,monospace;font-size:.9em}p code,li code{background:#f1f3f5;padding:.1rem .25rem;border-radius:.2rem}kbd{border:1px solid #cbd2da;padding:.1rem .3rem;border-radius:.2rem}ul,ol{padding-inline-start:1.6rem}li{margin:.35rem 0}.task{list-style:none}.task input{margin-inline-start:-1.5rem;margin-inline-end:.5rem}blockquote,.admonition{margin:1.4rem 0;padding:.25rem 1.2rem;border-inline-start:4px solid #6b7280;background:#f5f6f8}.warning{border-color:#a34200;background:#fff6e9}.tip{border-color:#247550;background:#f0faf4}.note{border-color:#2366aa;background:#f1f7fd}.admonition-title{font-weight:650;text-transform:capitalize}details{border:1px solid #d8dee6;border-radius:.35rem;padding:.7rem 1rem;margin:1rem 0}summary{cursor:pointer;font-weight:600}details>summary+*{margin-top:1rem}dl{margin:1rem 0}dt{font-weight:650;margin-top:1rem}dd{margin-inline-start:1.5rem}.table-scroll{overflow-x:auto;max-width:100%;margin:1.5rem 0}table{border-collapse:collapse;min-width:60%;font-size:.94rem}th,td{padding:.6rem .8rem;border:1px solid #ccd4dd;vertical-align:top;text-align:start}th{background:#eef2f6;font-weight:650}td>:first-child,th>:first-child{margin-top:0}td>:last-child,th>:last-child{margin-bottom:0}.align-left{text-align:left}.align-center{text-align:center}.align-right{text-align:right}.math-inline{max-width:none}.display-math{overflow-x:auto;text-align:center;margin:1.5rem 0}.math-display{display:inline-block}.unavailable-image,.unsupported,.math-fallback{color:#713b12}.tab-panel,.card,.switcher-section{border:1px solid #d8dee6;padding:1rem;margin:1rem 0;border-radius:.4rem}.tab-panel>h3:first-child{margin-top:0}.variant-label,.status{font-size:.85rem;font-weight:600;color:#713b12}.outline{font-size:.9rem;margin-bottom:2rem}.outline ul{columns:2}.instance-nav{padding:1rem 1.5rem;background:#f5f7fa;border-bottom:1px solid #d8dee6}.instance-nav ul{list-style:none;padding-inline-start:1rem}.instance-nav details{border:none;padding:.2rem;margin:.2rem 0}.instance-nav a[aria-current=page]{font-weight:700;color:#111827;text-decoration-thickness:2px}.skip-link{position:absolute;inset-inline-start:1rem;top:-10rem;background:white;padding:.5rem;z-index:2}.skip-link:focus{top:.5rem}.footnotes{font-size:.9rem;border-top:1px solid #ccd4dd;margin-top:3rem;padding-top:1rem}hr{border:0;border-top:1px solid #ccd4dd;margin:2rem 0} +@media(min-width:78rem){body:has(.instance-nav){display:grid;grid-template-columns:19rem minmax(0,1fr)}.instance-nav{height:100vh;position:sticky;top:0;overflow:auto;border-bottom:0;border-inline-end:1px solid #d8dee6}main{width:100%}} +@media(max-width:40rem){main{padding:1.5rem 1rem}.outline ul{columns:1}h1{font-size:1.9rem}} +@media print{.instance-nav,.outline,.skip-link{display:none!important}body{display:block!important}main{max-width:none;padding:0}details{border:0}details::details-content{display:block!important;content-visibility:visible!important}details>*{display:block!important}summary{font-weight:bold}pre{white-space:pre-wrap;overflow:visible;font-size:9pt}.table-scroll{overflow:visible}table{width:100%;font-size:9pt}thead{display:table-header-group}tr,img,figure{break-inside:avoid}a{color:inherit}img,video{max-width:100%}.math-inline{max-width:none}.tab-panel,.card{break-inside:avoid}h1,h2,h3{break-after:avoid}} diff --git a/docs/html-export-verification.md b/docs/html-export-verification.md new file mode 100644 index 00000000..ee78f396 --- /dev/null +++ b/docs/html-export-verification.md @@ -0,0 +1,65 @@ +# HTML export verification — September 5, 2026 + +The implementation and reproduction commands are described in +[HTML export](html-export.md). Validation used Flutter 3.47.0 on Linux and the +application's bundled rendering executables; no dependency was added to the +application for HTML serialization or browser-side rendering. + +| Check | Executed result | +| --- | --- | +| Dart formatting of changed handwritten sources | Passed; no formatting changes required | +| Repository-wide `flutter analyze --no-pub` | Passed; no issues | +| `flutter gen-l10n` | Passed; new HTML and missing Writerside messages supplied for all shipped regional locales | +| Full `flutter test --no-pub`, with `BUSYMARK_TYPST_PATH` and `BUSYMARK_D2_PATH` pointing to the release bundle | **1,438 passed, no skips** | +| Focused rich-export checks after improving renderer failure messages | Passed; profiles, snapshots, timeout fallback, active cancellation and output preservation | +| `flutter build linux --release --no-pub` | Passed | +| Native release smoke under Xvfb | Passed; real MathJax 4.1.3, Mermaid, PlantUML, D2, static OpenAPI and existing PDF smoke; zero HTML warnings | +| Relocated browser checks | **20 passed**: five pages × two URL modes × two browsers | +| `git diff --check` and Python browser-check syntax compilation | Passed | + +The full suite includes the existing PDF exports and native configuration, +localization, source preservation, and editor regression tests. Base `pt` and +`zh` localization templates remain partial as before; the shipped `pt_BR` and +`zh_CN` locales have complete messages and pass the localization audit. + +Browser verification used **Chromium/Chrome 151.0.7922.137** and **Firefox +154.0.1**. Each opened the relocated Markdown page and all four Writerside HTML +files directly through `file:` URLs and through a local static HTTP server. +Outbound proxy connections were unavailable, and BiDi observation recorded no +unexpected external request. HTTP-only favicon probes were local 404s and are +not export dependencies. + +Checks covered stylesheet/CSP hashing, image loading, internal anchors, +footnote references and return links, current navigation, keyboard focus, +disclosure interaction, horizontal overflow, script blocking, and printing. +PDF text extraction confirmed that collapsed disclosure content and every tab +were printed. Representative Chromium and Firefox screenshots were also +visually inspected. The footnote case crosses a raw HTML disclosure block, +exercising the corrected shared reference context. + +Representative outputs from the real release binary: + +- `/tmp/busymark-html-final/offline.html` and `offline.assets/`: unsaved-source + export path, Unicode headings, nested/task lists, tables, disclosure, a local + SVG, inline/display math, three diagram engines, static API reference, and a + structured footnote. +- `/tmp/busymark-html-final/writerside/index.html`: selected-instance entry point, + also preserved as `Welcome.html`; includes with caller variable overrides, + all tabs, procedure steps, custom filename, hidden-page links and WIP status. +- `/tmp/busymark-html-final/writerside/reference.html`: spanning table, + collapsible chapter, and a diagram loaded from the configured snippets folder. +- `/tmp/busymark-html-final/writerside/hidden.html`: link-accessible hidden topic. +- `/tmp/busymark-html-final/visualization-smoke.pdf`: existing PDF verification. + +Native results are recorded in `/tmp/busymark-html-final/report.json`. Browser +results, screenshots, and printed PDFs are under +`/tmp/busymark-html-browser-final/`; its `browser-report.json` identifies the +separate relocated root. Sources and engine temporary directories were removed +before the relocated copies were opened. These paths are verification artifacts, +not dependencies of the exported documents, and may be removed by temporary-file +cleanup. The committed scripts reproduce them. + +No requested automated check remains unavailable. Browser interaction and print +verification ran headlessly; physical-printer output and assistive-technology +certification were not tested. This is behavioral validation of BusyMark's native +export, not an assertion of pixel parity with JetBrains' website builder. diff --git a/docs/html-export.md b/docs/html-export.md new file mode 100644 index 00000000..b8bbe11b --- /dev/null +++ b/docs/html-export.md @@ -0,0 +1,174 @@ +# HTML export + +Use **Main menu → Export as HTML…** or the command palette's **Export as HTML…** +command. The GTK header menu and Flutter menu have the same availability. PDF's +Ctrl+Shift+E shortcut is unchanged; HTML has no default shortcut. + +An active Markdown document exports its current editor text, including unsaved +and untitled content, to a complete UTF-8 `.html` document. Text-only documents +need just that file. Local images, media, downloadable resources, and generated +graphics use a companion `.assets` directory. Keep that directory beside +the HTML file when copying the export. + +For Writerside, resolve unsaved project changes using Save/Discard/Cancel, select +one non-library instance, and choose a dedicated output directory. The export +contains separate topic pages, ordinary navigation links, shared `assets`, and +an `index.html` entry point. Hidden topics retain pages but no navigation entry; +work-in-progress entries retain their status. Repeated TOC references share a +page. Topic titles, TOC labels, module origins, instance title overrides, and +custom web filenames remain distinct. Filename collisions stop publication. +The start page retains its declared filename and also supplies `index.html`. + +The result dialog offers **Open**, **Show in Folder**, and individual diagnostics +with source paths and line numbers. Missing required links are diagnostics with +visible labels, rather than fabricated destinations; missing nullable links +become ordinary text. Single-document Markdown export does not export other +linked documents. Unavailable visual content retains alternative text, a safe +link, or escaped source, with a diagnostic. + +## Semantic output and offline rendering + +The HTML writer consumes BusyDocument and the existing selected Markdown mode. +Writerside first passes through the shared project loader, document resolver, +and document renderer. It does not use Typst, Pandoc, screenshots, or a second +Markdown dialect. Ordinary HTML export does not require a Typst executable. + +Headings and explicit IDs, nested lists and task states, tables and cell spans, +code whitespace, footnotes and return links, procedures, definition lists, +admonitions, and supported raw HTML structure remain semantic HTML. Disclosures +use native `details`/`summary`. Every Writerside tab and topic variant is included +as a labeled section. Page-local generated IDs use BusyMark's Unicode-aware slug +rules and disambiguate repeated headings. Duplicate explicit IDs are diagnosed. + +An HTML-only projection in the existing Markdown AST adapter preserves raw HTML +structure and cross-block footnote/reference context. Default editor and PDF +projections, original source text, and source serialization are unchanged. + +Math uses MathCoordinator with a separate HTML profile and standalone SVG glyphs. +Mermaid, PlantUML, and D2 use VisualizationCoordinator's HTML profile, normalized +SVG, or the existing raster fallback. OpenAPI uses the existing local dependency +resolver and static reference mapper, producing headings, tables and examples. +Renderer dependencies are captured before rendering starts. Jobs use export, +page, and occurrence identity, including repeated includes. No browser-side +renderer, webfont, JavaScript, runtime fetch, or live API client is needed. + +The light stylesheet is independent of the editor theme. It includes responsive +media, table/code overflow, focus outlines, navigation landmarks, heading +outlines, language/direction metadata, and print rules that expose disclosure +bodies and every tab. + +## Ownership, confinement, and failure handling + +Source attributes are never copied wholesale into output. DOM text/attribute +escaping, URL validation, structural raw HTML allowlists, and final output checks +are separate controls. Unsupported or active source markup is shown as escaped +source with a diagnostic. SVG validation rejects active content, unsafe CSS, +and external references before normalization; SVGs are loaded as images. + +Local assets must canonicalize inside the document/workspace or configured +Writerside module/resource roots. Symlink escapes, unsupported formats, missing +files, and remote assets produce diagnostics. Remote resources are not fetched. +Validated asset content determines immutable hashed filenames, so identically +named files from different topics do not collide. Internal origin paths remain +available during resolution but are not serialized as HTML attributes or URLs. + +The generated meta CSP disables scripts, connections, objects, frames, forms, +base-URL changes, and fonts. Its style hash authorizes only exporter-owned CSS. +Image/media policies allow the generated relative resources over HTTP and +`file:` origins; final URL validation and asset confinement provide the narrower +resource boundary. The meta policy does not claim unsupported `frame-ancestors` +or sandbox protection. CSP complements sanitization. + +Assets are staged before a document entry point is atomically replaced. Existing +companion assets are append-only and content-verified; replacing HTML never +removes files used by the previous HTML. A `.busymark-html-export.json` ownership +marker identifies exporter directories. Unowned or modified output directories +are refused. Writerside stages a complete sibling directory and uses Linux atomic +rename/exchange only when supported; the file hard-link fallback is never used +for directories. Publication checks the displaced output too and rolls back a +concurrent change. If rollback itself fails, the retained recovery directory is +reported instead of deleted. + +Cancellation and ordinary publication failures clean temporary staging files +and retain an existing export. Default processing limits are 2,000 topics, +64 MiB UTF-8 source, 16 MiB per asset, 128 MiB total assets, 2,048 assets, +512 generated graphics, 64 nesting levels, and 45 seconds per render/preparation. +Generated HTML is bounded to four times the source-byte limit. Oversized output +fails before publication. Unused immutable companion assets can accumulate across +replacements; automatic deletion would risk older HTML copies. + +## Implementation map + +| Responsibility | Files under `lib/src/export/` | +| --- | --- | +| Requests, results, limits, cancellation | `html_export_models.dart` | +| Input capture and orchestration | `html_export_service.dart`, `html_export_ui.dart` | +| Writerside publication identities and navigation | `html_publication_plan.dart` | +| Link and anchor resolution | `html_export_links.dart` | +| Semantic DOM writer and final safety boundary | `html_document_writer.dart` | +| Confined, validated, content-addressed resources | `html_export_assets.dart` | +| Existing math, diagram, and static API engines | `html_rich_content.dart` | +| Atomic publication and ownership checks | `html_export_publisher.dart` | +| Real-engine release fixture | `html_release_smoke.dart` | + +Other integration changes are in `assets/export/html.css`, `pubspec.yaml`, the +Markdown AST adapter/parser, visualization profiles/coordinator, atomic-file +helpers, application command/menu dispatch, the Linux header-bar bridge and GTK +runner, and ARBs/generated localization output. Verification also corrected +Writerside link-summary variable scopes and completed missing Writerside UI +translations and table-sort glyph/localization integration. + +## Verification + +Structural, asset, publication, renderer, and widget coverage lives in +`test/src/html_export_test.dart`, `html_publication_test.dart`, +`html_rich_export_test.dart`, and `html_export_ui_test.dart`. Header-bar and +localization/source audits cover shared integration. Tests include unsafe URLs, +raw HTML and SVG, metadata injection, duplicate/non-Latin IDs, module-relative +assets, hidden/WIP pages, collisions, dependency snapshots, timeout fallback, +permission failure, overwrite refusal, ownership checks, and staging cleanup. + +The existing Linux visualization release smoke also writes a representative +Markdown export (`offline.html` plus assets) and a Writerside instance +(`writerside/index.html`, `Welcome.html`, `reference.html`, and `hidden.html`). It +uses real packaged MathJax, Mermaid, PlantUML, D2, OpenAPI, and the existing PDF +smoke. Run after a release build: + +```bash +BUSYMARK_RELEASE_SMOKE=1 xvfb-run -a build/linux/x64/release/bundle/busymark \ + --visualization-release-smoke=/tmp/busymark-html-verification/report.json +``` + +`tools/verify_html_export_browser.py` copies those exports to a new location, +starts a local static server, and checks both direct file opening and HTTP in +installed Chromium and Firefox. It uses an unavailable outbound proxy and BiDi +request observation, verifies assets, anchors, footnotes, responsive layout, +keyboard disclosure controls and navigation, probes CSP script blocking, saves +screenshots, prints every page, and checks printed disclosure/tab text. It needs +Selenium 4.48+, matching browser drivers, and `pdftotext`: + +```bash +python3 tools/verify_html_export_browser.py /tmp/busymark-html-verification \ + --output /tmp/busymark-html-browser-verification +``` + +The test does not require internet access to render exports. Install browsers, +drivers and Selenium beforehand; explicit browser/driver paths are configurable. +Printed PDF text checks complement screenshot inspection; they do not establish +accessibility conformance or pixel equality with the Writerside website builder. + +## Documentation decisions + +Separate topic filenames, titles, and start-page behavior follow JetBrains' +[topics documentation](https://www.jetbrains.com/help/writerside/topics.html). +Hidden/WIP handling follows the +[instance documentation](https://www.jetbrains.com/help/writerside/instances.html), +and missing/nullable link behavior follows +[links and references](https://www.jetbrains.com/help/writerside/links-and-references.html). +Native disclosure behavior follows +[MDN details](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/details). +Standalone math reuses the approach described by +[MathJax conversion documentation](https://docs.mathjax.org/en/v4.1/web/convert.html). +The final boundary combines controls described in +[OWASP XSS prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html) +and [OWASP CSP guidance](https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html). diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index 4264497d..03d30278 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -3074,5 +3074,26 @@ "aiExplicitEditingDescription": "لا يبدأ التحرير بالذكاء الاصطناعي إلا بإجراء صريح. لا يرسل BusyMark إلا السياق المعروض إلى المزوّد المحدد، ولا يطبّق أي اقتراح من دون مراجعته.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "تصدير بتنسيق HTML…", + "fileTypeHtml": "مستند HTML", + "exportingHtml": "جارٍ تصدير HTML…", + "htmlExported": "اكتمل تصدير HTML", + "htmlExportFailed": "فشل تصدير HTML", + "htmlKeepAssetsTogether": "عند نسخ التصدير، احتفظ بملف HTML ومجلد الموارد المرافق له معًا.", + "htmlInstanceDescription": "صدّر نسخة واحدة على هيئة صفحات مترابطة تعمل دون اتصال. اختر اسمًا لمجلد إخراج مخصص.", + "htmlInstance": "النسخة", + "htmlOwnedDirectoryOnly": "يمكن استبدال مجلد أنشأه تصدير HTML في BusyMark فقط. ستُحفظ الملفات المعدّلة أو غير المرتبطة.", + "showInFolder": "إظهار في المجلد", + "goToDeclaration": "الانتقال إلى التصريح", + "findUsages": "البحث عن الاستخدامات", + "cannotRenameSymbol": "لا يمكن إعادة تسمية الرمز بأمان. تحقق من الاسم وحدّث المرجع قبل المحاولة مجددًا.", + "keyboardLayout": "تخطيط لوحة المفاتيح", + "diagnosticWritersideUnsupported": "يُعرض المحتوى غير المدعوم أو المشوّه كنص مصدر.", + "diagnosticWritersideSource": "تعذّر حل المصدر «{reference}»: {reason}", + "diagnosticWritersideLink": "هدف الرابط غير متاح في هذه النسخة: {destination}", + "diagnosticWritersideSchema": "ترميز Writerside غير صالح: {element}، {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "استخدم true أو false؛ لم يعد single-file مدعومًا.", + "diagnosticWritersideReference": "تعذّر حل {kind}: {reference}", + "sortTableColumn": "فرز {column}" } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index be296031..18f71484 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -3074,5 +3074,26 @@ "aiExplicitEditingDescription": "KI-Bearbeitung erfolgt nur auf ausdrücklichen Befehl. BusyMark sendet ausschließlich den angezeigten Kontext an den ausgewählten Anbieter und übernimmt keinen Vorschlag ohne Prüfung.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "Als HTML exportieren…", + "fileTypeHtml": "HTML-Dokument", + "exportingHtml": "HTML wird exportiert…", + "htmlExported": "HTML-Export abgeschlossen", + "htmlExportFailed": "HTML-Export fehlgeschlagen", + "htmlKeepAssetsTogether": "Lassen Sie beim Kopieren die HTML-Datei und den zugehörigen Ressourcenordner zusammen.", + "htmlInstanceDescription": "Exportieren Sie eine Instanz als verknüpfte Offline-Seiten. Wählen Sie einen Namen für einen eigenen Ausgabeordner.", + "htmlInstance": "Instanz", + "htmlOwnedDirectoryOnly": "Nur ein vom BusyMark-HTML-Export erstellter Ordner kann ersetzt werden. Geänderte oder fremde Dateien bleiben erhalten.", + "showInFolder": "Im Ordner anzeigen", + "goToDeclaration": "Zur Deklaration wechseln", + "findUsages": "Verwendungen suchen", + "cannotRenameSymbol": "Das Symbol kann nicht sicher umbenannt werden. Prüfen Sie den Namen und aktualisieren Sie die Referenz, bevor Sie es erneut versuchen.", + "keyboardLayout": "Tastaturbelegung", + "diagnosticWritersideUnsupported": "Nicht unterstützter oder fehlerhafter Inhalt wird als Quelltext angezeigt.", + "diagnosticWritersideSource": "Quelle „{reference}“ kann nicht aufgelöst werden: {reason}", + "diagnosticWritersideLink": "Das Linkziel ist in dieser Instanz nicht verfügbar: {destination}", + "diagnosticWritersideSchema": "Ungültiges Writerside-Markup: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Verwenden Sie true oder false; single-file wird nicht mehr unterstützt.", + "diagnosticWritersideReference": "{kind} kann nicht aufgelöst werden: {reference}", + "sortTableColumn": "{column} sortieren" } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 14b3cd54..8bb27012 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -2378,5 +2378,23 @@ "type": "String" } } + }, + "exportAsHtml": "Export as HTML…", + "fileTypeHtml": "HTML document", + "exportingHtml": "Exporting HTML…", + "htmlExported": "HTML export complete", + "htmlExportFailed": "HTML export failed", + "htmlKeepAssetsTogether": "Keep the HTML file and its companion assets directory together when copying this export.", + "htmlInstanceDescription": "Export one instance as linked offline pages. Choose a name for a dedicated output directory.", + "htmlInstance": "Instance", + "htmlOwnedDirectoryOnly": "Only a directory created by BusyMark HTML export can be replaced. Modified or unrelated files will be preserved.", + "showInFolder": "Show in Folder", + "sortTableColumn": "Sort {column}", + "@sortTableColumn": { + "placeholders": { + "column": { + "type": "String" + } + } } } diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 403205e0..ead71529 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -3074,5 +3074,26 @@ "aiExplicitEditingDescription": "La edición con IA solo se ejecuta de forma explícita. BusyMark envía únicamente el contexto mostrado al proveedor seleccionado y nunca aplica una propuesta sin revisarla.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "Exportar como HTML…", + "fileTypeHtml": "Documento HTML", + "exportingHtml": "Exportando HTML…", + "htmlExported": "Exportación HTML completada", + "htmlExportFailed": "Error al exportar HTML", + "htmlKeepAssetsTogether": "Al copiar esta exportación, mantenga juntos el archivo HTML y su carpeta de recursos.", + "htmlInstanceDescription": "Exporte una instancia como páginas enlazadas sin conexión. Elija un nombre para una carpeta de salida exclusiva.", + "htmlInstance": "Instancia", + "htmlOwnedDirectoryOnly": "Solo se puede reemplazar una carpeta creada por la exportación HTML de BusyMark. Se conservarán los archivos modificados o ajenos.", + "showInFolder": "Mostrar en carpeta", + "goToDeclaration": "Ir a la declaración", + "findUsages": "Buscar usos", + "cannotRenameSymbol": "No se puede cambiar el nombre del símbolo de forma segura. Compruebe el nombre y actualice la referencia antes de volver a intentarlo.", + "keyboardLayout": "Distribución del teclado", + "diagnosticWritersideUnsupported": "El contenido no compatible o mal formado se muestra como código fuente.", + "diagnosticWritersideSource": "No se puede resolver el origen «{reference}»: {reason}", + "diagnosticWritersideLink": "El destino del enlace no está disponible en esta instancia: {destination}", + "diagnosticWritersideSchema": "Marcado Writerside no válido: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Use true o false; single-file ya no es compatible.", + "diagnosticWritersideReference": "No se puede resolver {kind}: {reference}", + "sortTableColumn": "Ordenar {column}" } diff --git a/lib/l10n/app_et.arb b/lib/l10n/app_et.arb index 77364d17..5df05efd 100644 --- a/lib/l10n/app_et.arb +++ b/lib/l10n/app_et.arb @@ -3534,5 +3534,26 @@ "aiExplicitEditingDescription": "Tehisintellektiga redigeerimine käivitatakse ainult selgesõnaliselt. BusyMark saadab valitud teenusepakkujale üksnes kuvatud konteksti ega rakenda ettepanekut ilma ülevaatuseta.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "Ekspordi HTML-ina…", + "fileTypeHtml": "HTML-dokument", + "exportingHtml": "HTML-i eksportimine…", + "htmlExported": "HTML-i eksport on valmis", + "htmlExportFailed": "HTML-i eksport ebaõnnestus", + "htmlKeepAssetsTogether": "Hoia eksporti kopeerides HTML-fail ja selle ressursikaust koos.", + "htmlInstanceDescription": "Ekspordi üks eksemplar lingitud võrguühenduseta lehtedena. Vali eraldi väljundkaustale nimi.", + "htmlInstance": "Eksemplar", + "htmlOwnedDirectoryOnly": "Asendada saab ainult BusyMarki HTML-ekspordiga loodud kausta. Muudetud ja kõrvalised failid säilitatakse.", + "showInFolder": "Näita kaustas", + "goToDeclaration": "Mine deklaratsiooni juurde", + "findUsages": "Otsi kasutusi", + "cannotRenameSymbol": "Sümbolit ei saa turvaliselt ümber nimetada. Kontrolli nime ja värskenda viidet enne uuesti proovimist.", + "keyboardLayout": "Klaviatuuripaigutus", + "diagnosticWritersideUnsupported": "Toetamata või vigane sisu kuvatakse lähtekoodina.", + "diagnosticWritersideSource": "Allikat „{reference}” ei saa lahendada: {reason}", + "diagnosticWritersideLink": "Lingi siht pole selles eksemplaris saadaval: {destination}", + "diagnosticWritersideSchema": "Vigane Writerside’i märgistus: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Kasuta true või false; single-file ei ole enam toetatud.", + "diagnosticWritersideReference": "{kind} ei saa lahendada: {reference}", + "sortTableColumn": "Sordi {column}" } diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index dfdb73d6..f6f4086d 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -3116,5 +3116,26 @@ "aiExplicitEditingDescription": "ویرایش با هوش مصنوعی فقط با اقدام صریح آغاز می‌شود. BusyMark تنها زمینهٔ نمایش‌داده‌شده را برای ارائه‌دهندهٔ انتخابی می‌فرستد و هیچ پیشنهادی را بدون بازبینی اعمال نمی‌کند.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "خروجی به‌صورت HTML…", + "fileTypeHtml": "سند HTML", + "exportingHtml": "در حال ایجاد خروجی HTML…", + "htmlExported": "خروجی HTML کامل شد", + "htmlExportFailed": "ایجاد خروجی HTML ناموفق بود", + "htmlKeepAssetsTogether": "هنگام کپی کردن خروجی، فایل HTML و پوشهٔ منابع همراه آن را کنار هم نگه دارید.", + "htmlInstanceDescription": "یک نمونه را به‌صورت صفحه‌های آفلاین پیوندخورده خروجی بگیرید. نامی برای پوشهٔ خروجی اختصاصی انتخاب کنید.", + "htmlInstance": "نمونه", + "htmlOwnedDirectoryOnly": "فقط پوشه‌ای که با خروجی HTML در BusyMark ایجاد شده باشد قابل جایگزینی است. فایل‌های تغییریافته یا نامرتبط حفظ می‌شوند.", + "showInFolder": "نمایش در پوشه", + "goToDeclaration": "رفتن به اعلان", + "findUsages": "یافتن کاربردها", + "cannotRenameSymbol": "نمی‌توان نام نماد را با اطمینان تغییر داد. نام را بررسی و ارجاع را تازه‌سازی کنید، سپس دوباره تلاش کنید.", + "keyboardLayout": "چیدمان صفحه‌کلید", + "diagnosticWritersideUnsupported": "محتوای پشتیبانی‌نشده یا نامعتبر به‌صورت منبع نمایش داده می‌شود.", + "diagnosticWritersideSource": "منبع «{reference}» قابل حل نیست: {reason}", + "diagnosticWritersideLink": "مقصد پیوند در این نمونه در دسترس نیست: {destination}", + "diagnosticWritersideSchema": "نشانه‌گذاری نامعتبر Writerside: {element}، {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "از true یا false استفاده کنید؛ single-file دیگر پشتیبانی نمی‌شود.", + "diagnosticWritersideReference": "{kind} قابل حل نیست: {reference}", + "sortTableColumn": "مرتب‌سازی {column}" } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 3924c4e9..1c155693 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -3074,5 +3074,26 @@ "aiExplicitEditingDescription": "L’édition par IA est déclenchée explicitement. BusyMark envoie uniquement le contexte affiché au fournisseur sélectionné et n’applique jamais une proposition sans validation.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "Exporter au format HTML…", + "fileTypeHtml": "Document HTML", + "exportingHtml": "Exportation HTML…", + "htmlExported": "Exportation HTML terminée", + "htmlExportFailed": "Échec de l’exportation HTML", + "htmlKeepAssetsTogether": "Lors de la copie, conservez le fichier HTML et son dossier de ressources ensemble.", + "htmlInstanceDescription": "Exportez une instance sous forme de pages liées hors ligne. Choisissez un nom pour un dossier de sortie dédié.", + "htmlInstance": "Instance", + "htmlOwnedDirectoryOnly": "Seul un dossier créé par l’exportation HTML de BusyMark peut être remplacé. Les fichiers modifiés ou étrangers seront conservés.", + "showInFolder": "Afficher dans le dossier", + "goToDeclaration": "Aller à la déclaration", + "findUsages": "Rechercher les utilisations", + "cannotRenameSymbol": "Impossible de renommer ce symbole en toute sécurité. Vérifiez son nom et actualisez la référence avant de réessayer.", + "keyboardLayout": "Disposition du clavier", + "diagnosticWritersideUnsupported": "Le contenu non pris en charge ou mal formé est affiché sous forme de source.", + "diagnosticWritersideSource": "Impossible de résoudre la source « {reference} » : {reason}", + "diagnosticWritersideLink": "La cible du lien est indisponible dans cette instance : {destination}", + "diagnosticWritersideSchema": "Balisage Writerside invalide : {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Utilisez true ou false ; single-file n’est plus pris en charge.", + "diagnosticWritersideReference": "Impossible de résoudre {kind} : {reference}", + "sortTableColumn": "Trier {column}" } diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index 6486cc24..47c60dc3 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -3074,5 +3074,26 @@ "aiExplicitEditingDescription": "AI संपादन केवल स्पष्ट कार्रवाई से शुरू होता है। BusyMark चयनित प्रदाता को केवल दिखाया गया संदर्भ भेजता है और समीक्षा के बिना किसी प्रस्ताव को लागू नहीं करता।", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "HTML के रूप में निर्यात करें…", + "fileTypeHtml": "HTML दस्तावेज़", + "exportingHtml": "HTML निर्यात हो रहा है…", + "htmlExported": "HTML निर्यात पूरा हुआ", + "htmlExportFailed": "HTML निर्यात विफल हुआ", + "htmlKeepAssetsTogether": "इस निर्यात को कॉपी करते समय HTML फ़ाइल और उसके संसाधन फ़ोल्डर को साथ रखें।", + "htmlInstanceDescription": "एक इंस्टेंस को लिंक किए गए ऑफ़लाइन पृष्ठों के रूप में निर्यात करें। एक अलग आउटपुट फ़ोल्डर का नाम चुनें।", + "htmlInstance": "इंस्टेंस", + "htmlOwnedDirectoryOnly": "केवल BusyMark HTML निर्यात द्वारा बनाया गया फ़ोल्डर बदला जा सकता है। बदली गई या असंबंधित फ़ाइलें सुरक्षित रहेंगी।", + "showInFolder": "फ़ोल्डर में दिखाएँ", + "goToDeclaration": "घोषणा पर जाएँ", + "findUsages": "उपयोग खोजें", + "cannotRenameSymbol": "प्रतीक का नाम सुरक्षित रूप से नहीं बदला जा सकता। नाम जाँचें और दोबारा प्रयास करने से पहले संदर्भ रीफ़्रेश करें।", + "keyboardLayout": "कीबोर्ड लेआउट", + "diagnosticWritersideUnsupported": "असमर्थित या गलत प्रारूप वाली सामग्री स्रोत के रूप में दिखाई जाती है।", + "diagnosticWritersideSource": "स्रोत “{reference}” हल नहीं किया जा सकता: {reason}", + "diagnosticWritersideLink": "इस इंस्टेंस में लिंक का लक्ष्य उपलब्ध नहीं है: {destination}", + "diagnosticWritersideSchema": "अमान्य Writerside मार्कअप: {element}, {attribute}। {reason}", + "diagnosticWritersideLlmsTxt": "true या false का उपयोग करें; single-file अब समर्थित नहीं है।", + "diagnosticWritersideReference": "{kind} हल नहीं किया जा सकता: {reference}", + "sortTableColumn": "{column} क्रमबद्ध करें" } diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index cb7e8090..f4c379c1 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -4633,5 +4633,26 @@ "aiExplicitEditingDescription": "Pengeditan AI bersifat eksplisit. BusyMark hanya mengirimkan konteks yang ditampilkan untuk penyedia yang dipilih dan tidak pernah menerapkan proposal tanpa peninjauan.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "Ekspor sebagai HTML…", + "fileTypeHtml": "Dokumen HTML", + "exportingHtml": "Mengekspor HTML…", + "htmlExported": "Ekspor HTML selesai", + "htmlExportFailed": "Ekspor HTML gagal", + "htmlKeepAssetsTogether": "Saat menyalin hasil ekspor, simpan berkas HTML bersama folder aset pendampingnya.", + "htmlInstanceDescription": "Ekspor satu instans sebagai halaman luring yang saling tertaut. Pilih nama untuk folder keluaran khusus.", + "htmlInstance": "Instans", + "htmlOwnedDirectoryOnly": "Hanya folder yang dibuat oleh ekspor HTML BusyMark yang dapat diganti. Berkas yang diubah atau tidak terkait akan dipertahankan.", + "showInFolder": "Tampilkan dalam Folder", + "goToDeclaration": "Buka Deklarasi", + "findUsages": "Cari Penggunaan", + "cannotRenameSymbol": "Nama simbol tidak dapat diubah dengan aman. Periksa nama dan segarkan referensi sebelum mencoba lagi.", + "keyboardLayout": "Tata letak papan ketik", + "diagnosticWritersideUnsupported": "Konten yang tidak didukung atau salah format ditampilkan sebagai sumber.", + "diagnosticWritersideSource": "Tidak dapat menyelesaikan sumber “{reference}”: {reason}", + "diagnosticWritersideLink": "Tujuan tautan tidak tersedia dalam instans ini: {destination}", + "diagnosticWritersideSchema": "Markup Writerside tidak valid: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Gunakan true atau false; single-file tidak lagi didukung.", + "diagnosticWritersideReference": "Tidak dapat menyelesaikan {kind}: {reference}", + "sortTableColumn": "Urutkan {column}" } diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 77fd1f0e..3cb7c4fb 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -3074,5 +3074,26 @@ "aiExplicitEditingDescription": "La modifica con IA viene avviata solo esplicitamente. BusyMark invia esclusivamente il contesto mostrato al fornitore selezionato e non applica mai una proposta senza revisione.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "Esporta come HTML…", + "fileTypeHtml": "Documento HTML", + "exportingHtml": "Esportazione HTML…", + "htmlExported": "Esportazione HTML completata", + "htmlExportFailed": "Esportazione HTML non riuscita", + "htmlKeepAssetsTogether": "Durante la copia, mantieni insieme il file HTML e la relativa cartella delle risorse.", + "htmlInstanceDescription": "Esporta un’istanza come pagine collegate offline. Scegli un nome per una cartella di destinazione dedicata.", + "htmlInstance": "Istanza", + "htmlOwnedDirectoryOnly": "È possibile sostituire solo una cartella creata dall’esportazione HTML di BusyMark. I file modificati o estranei verranno conservati.", + "showInFolder": "Mostra nella cartella", + "goToDeclaration": "Vai alla dichiarazione", + "findUsages": "Trova utilizzi", + "cannotRenameSymbol": "Impossibile rinominare il simbolo in sicurezza. Verifica il nome e aggiorna il riferimento prima di riprovare.", + "keyboardLayout": "Disposizione della tastiera", + "diagnosticWritersideUnsupported": "Il contenuto non supportato o malformato viene mostrato come sorgente.", + "diagnosticWritersideSource": "Impossibile risolvere la sorgente «{reference}»: {reason}", + "diagnosticWritersideLink": "La destinazione del collegamento non è disponibile in questa istanza: {destination}", + "diagnosticWritersideSchema": "Markup Writerside non valido: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Usa true o false; single-file non è più supportato.", + "diagnosticWritersideReference": "Impossibile risolvere {kind}: {reference}", + "sortTableColumn": "Ordina {column}" } diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 0678b9ab..dd5a037a 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -4633,5 +4633,26 @@ "aiExplicitEditingDescription": "AI による編集は明示的に実行されます。BusyMark は選択したプロバイダーに表示されたコンテキストのみを送信し、確認なしに提案を適用することはありません。", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "HTML としてエクスポート…", + "fileTypeHtml": "HTML ドキュメント", + "exportingHtml": "HTML をエクスポート中…", + "htmlExported": "HTML のエクスポートが完了しました", + "htmlExportFailed": "HTML のエクスポートに失敗しました", + "htmlKeepAssetsTogether": "コピーするときは、HTML ファイルと付属のアセットフォルダーを一緒に移動してください。", + "htmlInstanceDescription": "1 つのインスタンスを、リンクでつながるオフラインページとしてエクスポートします。専用の出力フォルダー名を選んでください。", + "htmlInstance": "インスタンス", + "htmlOwnedDirectoryOnly": "BusyMark の HTML エクスポートで作成されたフォルダーのみ置き換えられます。変更されたファイルや無関係なファイルは保持されます。", + "showInFolder": "フォルダーで表示", + "goToDeclaration": "宣言へ移動", + "findUsages": "使用箇所を検索", + "cannotRenameSymbol": "シンボル名を安全に変更できません。名前を確認し、参照を更新してから再試行してください。", + "keyboardLayout": "キーボード配列", + "diagnosticWritersideUnsupported": "未対応または不正な形式の内容はソースとして表示されます。", + "diagnosticWritersideSource": "ソース「{reference}」を解決できません: {reason}", + "diagnosticWritersideLink": "このインスタンスではリンク先を利用できません: {destination}", + "diagnosticWritersideSchema": "無効な Writerside マークアップ: {element}、{attribute}。{reason}", + "diagnosticWritersideLlmsTxt": "true または false を使用してください。single-file はサポートされなくなりました。", + "diagnosticWritersideReference": "{kind} を解決できません: {reference}", + "sortTableColumn": "{column} を並べ替え" } diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index b992e68a..75f90d8e 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -4633,5 +4633,26 @@ "aiExplicitEditingDescription": "AI 편집은 명시적입니다. BusyMark는 선택한 공급자에 대해 표시된 컨텍스트만 보내고 검토 없이 제안을 적용하지 않습니다.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "HTML로 내보내기…", + "fileTypeHtml": "HTML 문서", + "exportingHtml": "HTML 내보내는 중…", + "htmlExported": "HTML 내보내기 완료", + "htmlExportFailed": "HTML 내보내기 실패", + "htmlKeepAssetsTogether": "내보낸 결과를 복사할 때 HTML 파일과 관련 리소스 폴더를 함께 유지하세요.", + "htmlInstanceDescription": "인스턴스 하나를 연결된 오프라인 페이지로 내보냅니다. 전용 출력 폴더의 이름을 선택하세요.", + "htmlInstance": "인스턴스", + "htmlOwnedDirectoryOnly": "BusyMark HTML 내보내기로 만든 폴더만 교체할 수 있습니다. 수정되거나 관련 없는 파일은 보존됩니다.", + "showInFolder": "폴더에서 보기", + "goToDeclaration": "선언으로 이동", + "findUsages": "사용 위치 찾기", + "cannotRenameSymbol": "기호 이름을 안전하게 바꿀 수 없습니다. 이름을 확인하고 참조를 새로 고친 후 다시 시도하세요.", + "keyboardLayout": "키보드 배열", + "diagnosticWritersideUnsupported": "지원하지 않거나 잘못된 형식의 내용은 소스로 표시됩니다.", + "diagnosticWritersideSource": "소스 “{reference}”를 확인할 수 없습니다: {reason}", + "diagnosticWritersideLink": "이 인스턴스에서 링크 대상을 사용할 수 없습니다: {destination}", + "diagnosticWritersideSchema": "잘못된 Writerside 마크업: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "true 또는 false를 사용하세요. single-file은 더 이상 지원되지 않습니다.", + "diagnosticWritersideReference": "{kind}을(를) 확인할 수 없습니다: {reference}", + "sortTableColumn": "{column} 정렬" } diff --git a/lib/l10n/app_nb.arb b/lib/l10n/app_nb.arb index b333cadc..c65572b4 100644 --- a/lib/l10n/app_nb.arb +++ b/lib/l10n/app_nb.arb @@ -3074,5 +3074,26 @@ "aiExplicitEditingDescription": "KI-redigering startes bare eksplisitt. BusyMark sender kun den viste konteksten til den valgte leverandøren og bruker aldri et forslag uten gjennomgang.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "Eksporter som HTML…", + "fileTypeHtml": "HTML-dokument", + "exportingHtml": "Eksporterer HTML…", + "htmlExported": "HTML-eksport fullført", + "htmlExportFailed": "HTML-eksport mislyktes", + "htmlKeepAssetsTogether": "Hold HTML-filen og den tilhørende ressursmappen sammen når du kopierer eksporten.", + "htmlInstanceDescription": "Eksporter én instans som lenkede frakoblede sider. Velg et navn for en egen utdatamappe.", + "htmlInstance": "Instans", + "htmlOwnedDirectoryOnly": "Bare en mappe opprettet av BusyMarks HTML-eksport kan erstattes. Endrede eller uvedkommende filer beholdes.", + "showInFolder": "Vis i mappe", + "goToDeclaration": "Gå til deklarasjon", + "findUsages": "Finn bruk", + "cannotRenameSymbol": "Symbolet kan ikke gis nytt navn trygt. Kontroller navnet og oppdater referansen før du prøver igjen.", + "keyboardLayout": "Tastaturoppsett", + "diagnosticWritersideUnsupported": "Innhold som ikke støttes eller er feilformet, vises som kildekode.", + "diagnosticWritersideSource": "Kan ikke løse kilden «{reference}»: {reason}", + "diagnosticWritersideLink": "Lenkemålet er ikke tilgjengelig i denne instansen: {destination}", + "diagnosticWritersideSchema": "Ugyldig Writerside-markering: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Bruk true eller false; single-file støttes ikke lenger.", + "diagnosticWritersideReference": "Kan ikke løse {kind}: {reference}", + "sortTableColumn": "Sorter {column}" } diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 7720dbde..483fa604 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -4633,5 +4633,26 @@ "aiExplicitEditingDescription": "AI-bewerking is expliciet. BusyMark stuurt alleen de weergegeven context naar de geselecteerde provider en past nooit een voorstel toe zonder beoordeling.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "Exporteren als HTML…", + "fileTypeHtml": "HTML-document", + "exportingHtml": "HTML exporteren…", + "htmlExported": "HTML-export voltooid", + "htmlExportFailed": "HTML-export mislukt", + "htmlKeepAssetsTogether": "Houd het HTML-bestand en de bijbehorende middelenmap bij elkaar wanneer u deze export kopieert.", + "htmlInstanceDescription": "Exporteer één instantie als gekoppelde offline pagina’s. Kies een naam voor een aparte uitvoermap.", + "htmlInstance": "Instantie", + "htmlOwnedDirectoryOnly": "Alleen een map die door BusyMark HTML-export is gemaakt kan worden vervangen. Gewijzigde of andere bestanden blijven behouden.", + "showInFolder": "Tonen in map", + "goToDeclaration": "Ga naar declaratie", + "findUsages": "Gebruik zoeken", + "cannotRenameSymbol": "Het symbool kan niet veilig worden hernoemd. Controleer de naam en vernieuw de verwijzing voordat u het opnieuw probeert.", + "keyboardLayout": "Toetsenbordindeling", + "diagnosticWritersideUnsupported": "Niet-ondersteunde of ongeldige inhoud wordt als broncode getoond.", + "diagnosticWritersideSource": "Bron ‘{reference}’ kan niet worden gevonden: {reason}", + "diagnosticWritersideLink": "Het linkdoel is niet beschikbaar in deze instantie: {destination}", + "diagnosticWritersideSchema": "Ongeldige Writerside-opmaak: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Gebruik true of false; single-file wordt niet meer ondersteund.", + "diagnosticWritersideReference": "{kind} kan niet worden gevonden: {reference}", + "sortTableColumn": "{column} sorteren" } diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 71da4ca2..e1e8ec89 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -3100,5 +3100,26 @@ "aiExplicitEditingDescription": "Edycja z użyciem SI jest uruchamiana wyłącznie jawnie. BusyMark wysyła do wybranego dostawcy tylko pokazany kontekst i nigdy nie stosuje propozycji bez jej sprawdzenia.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "Eksportuj jako HTML…", + "fileTypeHtml": "Dokument HTML", + "exportingHtml": "Eksportowanie HTML…", + "htmlExported": "Eksport HTML zakończony", + "htmlExportFailed": "Eksport HTML nie powiódł się", + "htmlKeepAssetsTogether": "Podczas kopiowania zachowaj razem plik HTML i towarzyszący mu katalog zasobów.", + "htmlInstanceDescription": "Wyeksportuj jedną instancję jako połączone strony offline. Wybierz nazwę osobnego katalogu wyjściowego.", + "htmlInstance": "Instancja", + "htmlOwnedDirectoryOnly": "Można zastąpić tylko katalog utworzony przez eksport HTML BusyMark. Zmienione lub obce pliki zostaną zachowane.", + "showInFolder": "Pokaż w folderze", + "goToDeclaration": "Przejdź do deklaracji", + "findUsages": "Znajdź użycia", + "cannotRenameSymbol": "Nie można bezpiecznie zmienić nazwy symbolu. Sprawdź nazwę i odśwież odwołanie przed ponowną próbą.", + "keyboardLayout": "Układ klawiatury", + "diagnosticWritersideUnsupported": "Nieobsługiwana lub nieprawidłowa treść jest wyświetlana jako źródło.", + "diagnosticWritersideSource": "Nie można rozwiązać źródła „{reference}”: {reason}", + "diagnosticWritersideLink": "Cel odnośnika jest niedostępny w tej instancji: {destination}", + "diagnosticWritersideSchema": "Nieprawidłowy znacznik Writerside: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Użyj true lub false; single-file nie jest już obsługiwane.", + "diagnosticWritersideReference": "Nie można rozwiązać {kind}: {reference}", + "sortTableColumn": "Sortuj {column}" } diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index e2730191..220ec7e8 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -75,5 +75,26 @@ "syntaxReferenceSemanticCollapsiblesLimitation": "O BusyMark aceita as formas recolhíveis chapter, procedure, code-block e lista de definições, não todo o catálogo do Writerside.", "syntaxReferenceSemanticCodeBlocks": "Blocos de código semânticos para matemática e diagramas", "syntaxReferenceVideo": "Vídeo do Writerside", - "syntaxReferenceVideoLimitation": "Vídeo local usa uma imagem preview-src local; fontes hospedadas devem ser URLs HTTPS compatíveis do YouTube ou Vimeo." + "syntaxReferenceVideoLimitation": "Vídeo local usa uma imagem preview-src local; fontes hospedadas devem ser URLs HTTPS compatíveis do YouTube ou Vimeo.", + "exportAsHtml": "Exportar como HTML…", + "fileTypeHtml": "Documento HTML", + "exportingHtml": "A exportar HTML…", + "htmlExported": "Exportação HTML concluída", + "htmlExportFailed": "Falha na exportação HTML", + "htmlKeepAssetsTogether": "Ao copiar esta exportação, mantenha juntos o ficheiro HTML e a pasta de recursos associada.", + "htmlInstanceDescription": "Exporte uma instância como páginas ligadas offline. Escolha um nome para uma pasta de destino dedicada.", + "htmlInstance": "Instância", + "htmlOwnedDirectoryOnly": "Só é possível substituir uma pasta criada pela exportação HTML do BusyMark. Os ficheiros modificados ou alheios serão preservados.", + "showInFolder": "Mostrar na pasta", + "goToDeclaration": "Ir para a declaração", + "findUsages": "Encontrar utilizações", + "cannotRenameSymbol": "Não é possível mudar o nome do símbolo com segurança. Verifique o nome e atualize a referência antes de tentar novamente.", + "keyboardLayout": "Disposição do teclado", + "diagnosticWritersideUnsupported": "O conteúdo não suportado ou malformado é apresentado como código-fonte.", + "diagnosticWritersideSource": "Não é possível resolver a origem «{reference}»: {reason}", + "diagnosticWritersideLink": "O destino da ligação não está disponível nesta instância: {destination}", + "diagnosticWritersideSchema": "Marcação Writerside inválida: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Use true ou false; single-file deixou de ser suportado.", + "diagnosticWritersideReference": "Não é possível resolver {kind}: {reference}", + "sortTableColumn": "Ordenar {column}" } diff --git a/lib/l10n/app_pt_BR.arb b/lib/l10n/app_pt_BR.arb index 79b2d3fa..d5778725 100644 --- a/lib/l10n/app_pt_BR.arb +++ b/lib/l10n/app_pt_BR.arb @@ -3074,5 +3074,26 @@ "aiExplicitEditingDescription": "A edição com IA é iniciada apenas de forma explícita. O BusyMark envia somente o contexto exibido ao provedor selecionado e nunca aplica uma proposta sem revisão.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "Exportar como HTML…", + "fileTypeHtml": "Documento HTML", + "exportingHtml": "Exportando HTML…", + "htmlExported": "Exportação HTML concluída", + "htmlExportFailed": "Falha na exportação HTML", + "htmlKeepAssetsTogether": "Ao copiar esta exportação, mantenha juntos o arquivo HTML e a pasta de recursos associada.", + "htmlInstanceDescription": "Exporte uma instância como páginas vinculadas offline. Escolha um nome para uma pasta de destino exclusiva.", + "htmlInstance": "Instância", + "htmlOwnedDirectoryOnly": "Só é possível substituir uma pasta criada pela exportação HTML do BusyMark. Os arquivos modificados ou alheios serão preservados.", + "showInFolder": "Mostrar na pasta", + "goToDeclaration": "Ir para a declaração", + "findUsages": "Encontrar usos", + "cannotRenameSymbol": "Não é possível renomear o símbolo com segurança. Verifique o nome e atualize a referência antes de tentar novamente.", + "keyboardLayout": "Layout do teclado", + "diagnosticWritersideUnsupported": "O conteúdo não compatível ou malformado é exibido como código-fonte.", + "diagnosticWritersideSource": "Não é possível resolver a origem “{reference}”: {reason}", + "diagnosticWritersideLink": "O destino do link não está disponível nesta instância: {destination}", + "diagnosticWritersideSchema": "Marcação Writerside inválida: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Use true ou false; single-file não é mais compatível.", + "diagnosticWritersideReference": "Não é possível resolver {kind}: {reference}", + "sortTableColumn": "Ordenar {column}" } diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 0249f572..7098beb6 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -3100,5 +3100,26 @@ "aiExplicitEditingDescription": "Редактирование с помощью ИИ запускается только явно. BusyMark отправляет выбранному поставщику только показанный контекст и никогда не применяет предложение без проверки.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "Экспортировать в HTML…", + "fileTypeHtml": "Документ HTML", + "exportingHtml": "Экспорт HTML…", + "htmlExported": "Экспорт HTML завершён", + "htmlExportFailed": "Не удалось экспортировать HTML", + "htmlKeepAssetsTogether": "При копировании сохраняйте файл HTML вместе с папкой его ресурсов.", + "htmlInstanceDescription": "Экспортируйте один экземпляр как связанные автономные страницы. Выберите имя отдельной папки вывода.", + "htmlInstance": "Экземпляр", + "htmlOwnedDirectoryOnly": "Можно заменить только папку, созданную экспортом HTML BusyMark. Изменённые и посторонние файлы будут сохранены.", + "showInFolder": "Показать в папке", + "goToDeclaration": "Перейти к объявлению", + "findUsages": "Найти использования", + "cannotRenameSymbol": "Невозможно безопасно переименовать символ. Проверьте имя и обновите ссылку перед повторной попыткой.", + "keyboardLayout": "Раскладка клавиатуры", + "diagnosticWritersideUnsupported": "Неподдерживаемое или некорректное содержимое показано как исходный код.", + "diagnosticWritersideSource": "Не удалось разрешить источник «{reference}»: {reason}", + "diagnosticWritersideLink": "Цель ссылки недоступна в этом экземпляре: {destination}", + "diagnosticWritersideSchema": "Некорректная разметка Writerside: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Используйте true или false; single-file больше не поддерживается.", + "diagnosticWritersideReference": "Не удалось разрешить {kind}: {reference}", + "sortTableColumn": "Сортировать {column}" } diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 1ea7fab7..b6692855 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -4633,5 +4633,26 @@ "aiExplicitEditingDescription": "AI düzenleme açıkça kullanıcının isteğiyle başlatılır. BusyMark yalnızca seçili sağlayıcı için gösterilen bağlamı gönderir ve bir öneriyi hiçbiri onaylama olmadan uygulamaz.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "HTML olarak dışa aktar…", + "fileTypeHtml": "HTML belgesi", + "exportingHtml": "HTML dışa aktarılıyor…", + "htmlExported": "HTML dışa aktarımı tamamlandı", + "htmlExportFailed": "HTML dışa aktarılamadı", + "htmlKeepAssetsTogether": "Bu dışa aktarımı kopyalarken HTML dosyasını ve ilgili kaynak klasörünü bir arada tutun.", + "htmlInstanceDescription": "Bir örneği bağlantılı çevrimdışı sayfalar olarak dışa aktarın. Ayrı bir çıktı klasörü için ad seçin.", + "htmlInstance": "Örnek", + "htmlOwnedDirectoryOnly": "Yalnızca BusyMark HTML dışa aktarımıyla oluşturulan bir klasör değiştirilebilir. Değiştirilmiş veya ilgisiz dosyalar korunur.", + "showInFolder": "Klasörde Göster", + "goToDeclaration": "Bildirime git", + "findUsages": "Kullanımları bul", + "cannotRenameSymbol": "Simge güvenle yeniden adlandırılamıyor. Yeniden denemeden önce adı kontrol edin ve başvuruyu yenileyin.", + "keyboardLayout": "Klavye düzeni", + "diagnosticWritersideUnsupported": "Desteklenmeyen veya hatalı içerik kaynak olarak gösterilir.", + "diagnosticWritersideSource": "“{reference}” kaynağı çözümlenemiyor: {reason}", + "diagnosticWritersideLink": "Bağlantı hedefi bu örnekte kullanılamıyor: {destination}", + "diagnosticWritersideSchema": "Geçersiz Writerside işaretlemesi: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "true veya false kullanın; single-file artık desteklenmiyor.", + "diagnosticWritersideReference": "{kind} çözümlenemiyor: {reference}", + "sortTableColumn": "{column} sırala" } diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index a5aa3ea0..5cd78389 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -3100,5 +3100,26 @@ "aiExplicitEditingDescription": "Редагування за допомогою ШІ запускається лише явно. BusyMark надсилає вибраному постачальнику тільки показаний контекст і ніколи не застосовує пропозицію без перевірки.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "Експортувати в HTML…", + "fileTypeHtml": "Документ HTML", + "exportingHtml": "Експорт HTML…", + "htmlExported": "Експорт HTML завершено", + "htmlExportFailed": "Не вдалося експортувати HTML", + "htmlKeepAssetsTogether": "Під час копіювання зберігайте файл HTML разом із папкою його ресурсів.", + "htmlInstanceDescription": "Експортуйте один екземпляр як пов’язані автономні сторінки. Виберіть назву окремої вихідної папки.", + "htmlInstance": "Екземпляр", + "htmlOwnedDirectoryOnly": "Можна замінити лише папку, створену експортом HTML BusyMark. Змінені та сторонні файли буде збережено.", + "showInFolder": "Показати в папці", + "goToDeclaration": "Перейти до оголошення", + "findUsages": "Знайти використання", + "cannotRenameSymbol": "Неможливо безпечно перейменувати символ. Перевірте назву й оновіть посилання перед повторною спробою.", + "keyboardLayout": "Розкладка клавіатури", + "diagnosticWritersideUnsupported": "Непідтримуваний або некоректний вміст показано як джерело.", + "diagnosticWritersideSource": "Не вдалося знайти джерело «{reference}»: {reason}", + "diagnosticWritersideLink": "Ціль посилання недоступна в цьому екземплярі: {destination}", + "diagnosticWritersideSchema": "Некоректна розмітка Writerside: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Використовуйте true або false; single-file більше не підтримується.", + "diagnosticWritersideReference": "Не вдалося знайти {kind}: {reference}", + "sortTableColumn": "Сортувати {column}" } diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index e276b29d..aaafa4d1 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -4633,5 +4633,26 @@ "aiExplicitEditingDescription": "Chỉnh sửa bằng AI chỉ được thực hiện theo yêu cầu rõ ràng. BusyMark chỉ gửi ngữ cảnh được hiển thị cho nhà cung cấp đã chọn và không bao giờ áp dụng đề xuất khi chưa xem lại.", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "Xuất dưới dạng HTML…", + "fileTypeHtml": "Tài liệu HTML", + "exportingHtml": "Đang xuất HTML…", + "htmlExported": "Xuất HTML hoàn tất", + "htmlExportFailed": "Xuất HTML thất bại", + "htmlKeepAssetsTogether": "Khi sao chép bản xuất, hãy giữ tệp HTML và thư mục tài nguyên đi kèm ở cùng nhau.", + "htmlInstanceDescription": "Xuất một phiên bản thành các trang ngoại tuyến có liên kết. Chọn tên cho thư mục đầu ra riêng.", + "htmlInstance": "Phiên bản", + "htmlOwnedDirectoryOnly": "Chỉ có thể thay thế thư mục được tạo bởi chức năng xuất HTML của BusyMark. Các tệp đã sửa đổi hoặc không liên quan sẽ được giữ lại.", + "showInFolder": "Hiển thị trong thư mục", + "goToDeclaration": "Đi đến khai báo", + "findUsages": "Tìm nơi sử dụng", + "cannotRenameSymbol": "Không thể đổi tên ký hiệu một cách an toàn. Kiểm tra tên và làm mới tham chiếu trước khi thử lại.", + "keyboardLayout": "Bố cục bàn phím", + "diagnosticWritersideUnsupported": "Nội dung không được hỗ trợ hoặc sai định dạng được hiển thị dưới dạng mã nguồn.", + "diagnosticWritersideSource": "Không thể phân giải nguồn “{reference}”: {reason}", + "diagnosticWritersideLink": "Đích liên kết không khả dụng trong phiên bản này: {destination}", + "diagnosticWritersideSchema": "Đánh dấu Writerside không hợp lệ: {element}, {attribute}. {reason}", + "diagnosticWritersideLlmsTxt": "Dùng true hoặc false; single-file không còn được hỗ trợ.", + "diagnosticWritersideReference": "Không thể phân giải {kind}: {reference}", + "sortTableColumn": "Sắp xếp {column}" } diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index e6be94d7..12111228 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -75,5 +75,26 @@ "syntaxReferenceSemanticCollapsiblesLimitation": "BusyMark 支持可折叠的 chapter、procedure、code-block 和定义列表形式,但不支持完整的 Writerside 目录。", "syntaxReferenceSemanticCodeBlocks": "数学和图表的语义代码块", "syntaxReferenceVideo": "Writerside 视频", - "syntaxReferenceVideoLimitation": "本地视频使用本地 preview-src 图像;托管视频源必须是受支持的 YouTube 或 Vimeo HTTPS URL。" + "syntaxReferenceVideoLimitation": "本地视频使用本地 preview-src 图像;托管视频源必须是受支持的 YouTube 或 Vimeo HTTPS URL。", + "exportAsHtml": "导出为 HTML…", + "fileTypeHtml": "HTML 文档", + "exportingHtml": "正在导出 HTML…", + "htmlExported": "HTML 导出完成", + "htmlExportFailed": "HTML 导出失败", + "htmlKeepAssetsTogether": "复制导出结果时,请将 HTML 文件及其配套资源文件夹放在一起。", + "htmlInstanceDescription": "将一个实例导出为相互链接的离线页面。请选择专用输出文件夹的名称。", + "htmlInstance": "实例", + "htmlOwnedDirectoryOnly": "只能替换由 BusyMark HTML 导出创建的文件夹。已修改或无关的文件将被保留。", + "showInFolder": "在文件夹中显示", + "goToDeclaration": "转到声明", + "findUsages": "查找用法", + "cannotRenameSymbol": "无法安全地重命名此符号。请检查名称并刷新引用,然后重试。", + "keyboardLayout": "键盘布局", + "diagnosticWritersideUnsupported": "不支持或格式错误的内容将显示为源代码。", + "diagnosticWritersideSource": "无法解析源“{reference}”:{reason}", + "diagnosticWritersideLink": "此实例中无法使用链接目标:{destination}", + "diagnosticWritersideSchema": "无效的 Writerside 标记:{element},{attribute}。{reason}", + "diagnosticWritersideLlmsTxt": "请使用 true 或 false;不再支持 single-file。", + "diagnosticWritersideReference": "无法解析 {kind}:{reference}", + "sortTableColumn": "排序 {column}" } diff --git a/lib/l10n/app_zh_CN.arb b/lib/l10n/app_zh_CN.arb index 510e9638..0ffb25a7 100644 --- a/lib/l10n/app_zh_CN.arb +++ b/lib/l10n/app_zh_CN.arb @@ -4633,5 +4633,26 @@ "aiExplicitEditingDescription": "AI 编辑需要明确发起。BusyMark 只会将所选提供商对应的显示上下文发送出去,且不会在未经审核的情况下应用建议。", "@aiExplicitEditingDescription": { "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." - } + }, + "exportAsHtml": "导出为 HTML…", + "fileTypeHtml": "HTML 文档", + "exportingHtml": "正在导出 HTML…", + "htmlExported": "HTML 导出完成", + "htmlExportFailed": "HTML 导出失败", + "htmlKeepAssetsTogether": "复制导出结果时,请将 HTML 文件及其配套资源文件夹放在一起。", + "htmlInstanceDescription": "将一个实例导出为相互链接的离线页面。请选择专用输出文件夹的名称。", + "htmlInstance": "实例", + "htmlOwnedDirectoryOnly": "只能替换由 BusyMark HTML 导出创建的文件夹。已修改或无关的文件将被保留。", + "showInFolder": "在文件夹中显示", + "goToDeclaration": "转到声明", + "findUsages": "查找用法", + "cannotRenameSymbol": "无法安全地重命名此符号。请检查名称并刷新引用,然后重试。", + "keyboardLayout": "键盘布局", + "diagnosticWritersideUnsupported": "不支持或格式错误的内容将显示为源代码。", + "diagnosticWritersideSource": "无法解析源“{reference}”:{reason}", + "diagnosticWritersideLink": "此实例中无法使用链接目标:{destination}", + "diagnosticWritersideSchema": "无效的 Writerside 标记:{element},{attribute}。{reason}", + "diagnosticWritersideLlmsTxt": "请使用 true 或 false;不再支持 single-file。", + "diagnosticWritersideReference": "无法解析 {kind}:{reference}", + "sortTableColumn": "排序 {column}" } diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 893180bd..0879248d 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -6220,6 +6220,72 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Cannot resolve {kind}: {reference}'** String diagnosticWritersideReference(String kind, String reference); + + /// No description provided for @exportAsHtml. + /// + /// In en, this message translates to: + /// **'Export as HTML…'** + String get exportAsHtml; + + /// No description provided for @fileTypeHtml. + /// + /// In en, this message translates to: + /// **'HTML document'** + String get fileTypeHtml; + + /// No description provided for @exportingHtml. + /// + /// In en, this message translates to: + /// **'Exporting HTML…'** + String get exportingHtml; + + /// No description provided for @htmlExported. + /// + /// In en, this message translates to: + /// **'HTML export complete'** + String get htmlExported; + + /// No description provided for @htmlExportFailed. + /// + /// In en, this message translates to: + /// **'HTML export failed'** + String get htmlExportFailed; + + /// No description provided for @htmlKeepAssetsTogether. + /// + /// In en, this message translates to: + /// **'Keep the HTML file and its companion assets directory together when copying this export.'** + String get htmlKeepAssetsTogether; + + /// No description provided for @htmlInstanceDescription. + /// + /// In en, this message translates to: + /// **'Export one instance as linked offline pages. Choose a name for a dedicated output directory.'** + String get htmlInstanceDescription; + + /// No description provided for @htmlInstance. + /// + /// In en, this message translates to: + /// **'Instance'** + String get htmlInstance; + + /// No description provided for @htmlOwnedDirectoryOnly. + /// + /// In en, this message translates to: + /// **'Only a directory created by BusyMark HTML export can be replaced. Modified or unrelated files will be preserved.'** + String get htmlOwnedDirectoryOnly; + + /// No description provided for @showInFolder. + /// + /// In en, this message translates to: + /// **'Show in Folder'** + String get showInFolder; + + /// No description provided for @sortTableColumn. + /// + /// In en, this message translates to: + /// **'Sort {column}'** + String sortTableColumn(String column); } class _AppLocalizationsDelegate diff --git a/lib/l10n/generated/app_localizations_ar.dart b/lib/l10n/generated/app_localizations_ar.dart index addfe4d9..f521afef 100644 --- a/lib/l10n/generated/app_localizations_ar.dart +++ b/lib/l10n/generated/app_localizations_ar.dart @@ -3706,30 +3706,30 @@ class AppLocalizationsAr extends AppLocalizations { String get displayMath => 'رياضيات معروضة'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'الانتقال إلى التصريح'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'البحث عن الاستخدامات'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'لا يمكن إعادة تسمية الرمز بأمان. تحقق من الاسم وحدّث المرجع قبل المحاولة مجددًا.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'تخطيط لوحة المفاتيح'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'يُعرض المحتوى غير المدعوم أو المشوّه كنص مصدر.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'تعذّر حل المصدر «$reference»: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'هدف الرابط غير متاح في هذه النسخة: $destination'; } @override @@ -3738,15 +3738,53 @@ class AppLocalizationsAr extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'ترميز Writerside غير صالح: $element، $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'استخدم true أو false؛ لم يعد single-file مدعومًا.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return 'تعذّر حل $kind: $reference'; + } + + @override + String get exportAsHtml => 'تصدير بتنسيق HTML…'; + + @override + String get fileTypeHtml => 'مستند HTML'; + + @override + String get exportingHtml => 'جارٍ تصدير HTML…'; + + @override + String get htmlExported => 'اكتمل تصدير HTML'; + + @override + String get htmlExportFailed => 'فشل تصدير HTML'; + + @override + String get htmlKeepAssetsTogether => + 'عند نسخ التصدير، احتفظ بملف HTML ومجلد الموارد المرافق له معًا.'; + + @override + String get htmlInstanceDescription => + 'صدّر نسخة واحدة على هيئة صفحات مترابطة تعمل دون اتصال. اختر اسمًا لمجلد إخراج مخصص.'; + + @override + String get htmlInstance => 'النسخة'; + + @override + String get htmlOwnedDirectoryOnly => + 'يمكن استبدال مجلد أنشأه تصدير HTML في BusyMark فقط. ستُحفظ الملفات المعدّلة أو غير المرتبطة.'; + + @override + String get showInFolder => 'إظهار في المجلد'; + + @override + String sortTableColumn(String column) { + return 'فرز $column'; } } diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index b63f65b7..de970fab 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -3699,30 +3699,30 @@ class AppLocalizationsDe extends AppLocalizations { String get displayMath => 'Mathematische Formel als Block'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'Zur Deklaration wechseln'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'Verwendungen suchen'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'Das Symbol kann nicht sicher umbenannt werden. Prüfen Sie den Namen und aktualisieren Sie die Referenz, bevor Sie es erneut versuchen.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'Tastaturbelegung'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'Nicht unterstützter oder fehlerhafter Inhalt wird als Quelltext angezeigt.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'Quelle „$reference“ kann nicht aufgelöst werden: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'Das Linkziel ist in dieser Instanz nicht verfügbar: $destination'; } @override @@ -3731,15 +3731,53 @@ class AppLocalizationsDe extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'Ungültiges Writerside-Markup: $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'Verwenden Sie true oder false; single-file wird nicht mehr unterstützt.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return '$kind kann nicht aufgelöst werden: $reference'; + } + + @override + String get exportAsHtml => 'Als HTML exportieren…'; + + @override + String get fileTypeHtml => 'HTML-Dokument'; + + @override + String get exportingHtml => 'HTML wird exportiert…'; + + @override + String get htmlExported => 'HTML-Export abgeschlossen'; + + @override + String get htmlExportFailed => 'HTML-Export fehlgeschlagen'; + + @override + String get htmlKeepAssetsTogether => + 'Lassen Sie beim Kopieren die HTML-Datei und den zugehörigen Ressourcenordner zusammen.'; + + @override + String get htmlInstanceDescription => + 'Exportieren Sie eine Instanz als verknüpfte Offline-Seiten. Wählen Sie einen Namen für einen eigenen Ausgabeordner.'; + + @override + String get htmlInstance => 'Instanz'; + + @override + String get htmlOwnedDirectoryOnly => + 'Nur ein vom BusyMark-HTML-Export erstellter Ordner kann ersetzt werden. Geänderte oder fremde Dateien bleiben erhalten.'; + + @override + String get showInFolder => 'Im Ordner anzeigen'; + + @override + String sortTableColumn(String column) { + return '$column sortieren'; } } diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index cbc7eb2c..32dabc06 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -3737,4 +3737,42 @@ class AppLocalizationsEn extends AppLocalizations { String diagnosticWritersideReference(String kind, String reference) { return 'Cannot resolve $kind: $reference'; } + + @override + String get exportAsHtml => 'Export as HTML…'; + + @override + String get fileTypeHtml => 'HTML document'; + + @override + String get exportingHtml => 'Exporting HTML…'; + + @override + String get htmlExported => 'HTML export complete'; + + @override + String get htmlExportFailed => 'HTML export failed'; + + @override + String get htmlKeepAssetsTogether => + 'Keep the HTML file and its companion assets directory together when copying this export.'; + + @override + String get htmlInstanceDescription => + 'Export one instance as linked offline pages. Choose a name for a dedicated output directory.'; + + @override + String get htmlInstance => 'Instance'; + + @override + String get htmlOwnedDirectoryOnly => + 'Only a directory created by BusyMark HTML export can be replaced. Modified or unrelated files will be preserved.'; + + @override + String get showInFolder => 'Show in Folder'; + + @override + String sortTableColumn(String column) { + return 'Sort $column'; + } } diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart index 67c4547d..54a063a8 100644 --- a/lib/l10n/generated/app_localizations_es.dart +++ b/lib/l10n/generated/app_localizations_es.dart @@ -3703,30 +3703,30 @@ class AppLocalizationsEs extends AppLocalizations { String get displayMath => 'Matemáticas en bloque'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'Ir a la declaración'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'Buscar usos'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'No se puede cambiar el nombre del símbolo de forma segura. Compruebe el nombre y actualice la referencia antes de volver a intentarlo.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'Distribución del teclado'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'El contenido no compatible o mal formado se muestra como código fuente.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'No se puede resolver el origen «$reference»: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'El destino del enlace no está disponible en esta instancia: $destination'; } @override @@ -3735,15 +3735,53 @@ class AppLocalizationsEs extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'Marcado Writerside no válido: $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'Use true o false; single-file ya no es compatible.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return 'No se puede resolver $kind: $reference'; + } + + @override + String get exportAsHtml => 'Exportar como HTML…'; + + @override + String get fileTypeHtml => 'Documento HTML'; + + @override + String get exportingHtml => 'Exportando HTML…'; + + @override + String get htmlExported => 'Exportación HTML completada'; + + @override + String get htmlExportFailed => 'Error al exportar HTML'; + + @override + String get htmlKeepAssetsTogether => + 'Al copiar esta exportación, mantenga juntos el archivo HTML y su carpeta de recursos.'; + + @override + String get htmlInstanceDescription => + 'Exporte una instancia como páginas enlazadas sin conexión. Elija un nombre para una carpeta de salida exclusiva.'; + + @override + String get htmlInstance => 'Instancia'; + + @override + String get htmlOwnedDirectoryOnly => + 'Solo se puede reemplazar una carpeta creada por la exportación HTML de BusyMark. Se conservarán los archivos modificados o ajenos.'; + + @override + String get showInFolder => 'Mostrar en carpeta'; + + @override + String sortTableColumn(String column) { + return 'Ordenar $column'; } } diff --git a/lib/l10n/generated/app_localizations_et.dart b/lib/l10n/generated/app_localizations_et.dart index 44c88389..efe012a8 100644 --- a/lib/l10n/generated/app_localizations_et.dart +++ b/lib/l10n/generated/app_localizations_et.dart @@ -3666,30 +3666,30 @@ class AppLocalizationsEt extends AppLocalizations { String get displayMath => 'Plokina matemaatika'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'Mine deklaratsiooni juurde'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'Otsi kasutusi'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'Sümbolit ei saa turvaliselt ümber nimetada. Kontrolli nime ja värskenda viidet enne uuesti proovimist.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'Klaviatuuripaigutus'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'Toetamata või vigane sisu kuvatakse lähtekoodina.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'Allikat „$reference” ei saa lahendada: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'Lingi siht pole selles eksemplaris saadaval: $destination'; } @override @@ -3698,15 +3698,53 @@ class AppLocalizationsEt extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'Vigane Writerside’i märgistus: $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'Kasuta true või false; single-file ei ole enam toetatud.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return '$kind ei saa lahendada: $reference'; + } + + @override + String get exportAsHtml => 'Ekspordi HTML-ina…'; + + @override + String get fileTypeHtml => 'HTML-dokument'; + + @override + String get exportingHtml => 'HTML-i eksportimine…'; + + @override + String get htmlExported => 'HTML-i eksport on valmis'; + + @override + String get htmlExportFailed => 'HTML-i eksport ebaõnnestus'; + + @override + String get htmlKeepAssetsTogether => + 'Hoia eksporti kopeerides HTML-fail ja selle ressursikaust koos.'; + + @override + String get htmlInstanceDescription => + 'Ekspordi üks eksemplar lingitud võrguühenduseta lehtedena. Vali eraldi väljundkaustale nimi.'; + + @override + String get htmlInstance => 'Eksemplar'; + + @override + String get htmlOwnedDirectoryOnly => + 'Asendada saab ainult BusyMarki HTML-ekspordiga loodud kausta. Muudetud ja kõrvalised failid säilitatakse.'; + + @override + String get showInFolder => 'Näita kaustas'; + + @override + String sortTableColumn(String column) { + return 'Sordi $column'; } } diff --git a/lib/l10n/generated/app_localizations_fa.dart b/lib/l10n/generated/app_localizations_fa.dart index d409c519..be5b8d4f 100644 --- a/lib/l10n/generated/app_localizations_fa.dart +++ b/lib/l10n/generated/app_localizations_fa.dart @@ -3711,30 +3711,30 @@ class AppLocalizationsFa extends AppLocalizations { String get displayMath => 'ریاضی نمایشی'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'رفتن به اعلان'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'یافتن کاربردها'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'نمی‌توان نام نماد را با اطمینان تغییر داد. نام را بررسی و ارجاع را تازه‌سازی کنید، سپس دوباره تلاش کنید.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'چیدمان صفحه‌کلید'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'محتوای پشتیبانی‌نشده یا نامعتبر به‌صورت منبع نمایش داده می‌شود.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'منبع «$reference» قابل حل نیست: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'مقصد پیوند در این نمونه در دسترس نیست: $destination'; } @override @@ -3743,15 +3743,53 @@ class AppLocalizationsFa extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'نشانه‌گذاری نامعتبر Writerside: $element، $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'از true یا false استفاده کنید؛ single-file دیگر پشتیبانی نمی‌شود.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return '$kind قابل حل نیست: $reference'; + } + + @override + String get exportAsHtml => 'خروجی به‌صورت HTML…'; + + @override + String get fileTypeHtml => 'سند HTML'; + + @override + String get exportingHtml => 'در حال ایجاد خروجی HTML…'; + + @override + String get htmlExported => 'خروجی HTML کامل شد'; + + @override + String get htmlExportFailed => 'ایجاد خروجی HTML ناموفق بود'; + + @override + String get htmlKeepAssetsTogether => + 'هنگام کپی کردن خروجی، فایل HTML و پوشهٔ منابع همراه آن را کنار هم نگه دارید.'; + + @override + String get htmlInstanceDescription => + 'یک نمونه را به‌صورت صفحه‌های آفلاین پیوندخورده خروجی بگیرید. نامی برای پوشهٔ خروجی اختصاصی انتخاب کنید.'; + + @override + String get htmlInstance => 'نمونه'; + + @override + String get htmlOwnedDirectoryOnly => + 'فقط پوشه‌ای که با خروجی HTML در BusyMark ایجاد شده باشد قابل جایگزینی است. فایل‌های تغییریافته یا نامرتبط حفظ می‌شوند.'; + + @override + String get showInFolder => 'نمایش در پوشه'; + + @override + String sortTableColumn(String column) { + return 'مرتب‌سازی $column'; } } diff --git a/lib/l10n/generated/app_localizations_fr.dart b/lib/l10n/generated/app_localizations_fr.dart index 9e88f4ce..05de22f5 100644 --- a/lib/l10n/generated/app_localizations_fr.dart +++ b/lib/l10n/generated/app_localizations_fr.dart @@ -3698,30 +3698,30 @@ class AppLocalizationsFr extends AppLocalizations { String get displayMath => 'Formule en bloc'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'Aller à la déclaration'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'Rechercher les utilisations'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'Impossible de renommer ce symbole en toute sécurité. Vérifiez son nom et actualisez la référence avant de réessayer.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'Disposition du clavier'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'Le contenu non pris en charge ou mal formé est affiché sous forme de source.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'Impossible de résoudre la source « $reference » : $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'La cible du lien est indisponible dans cette instance : $destination'; } @override @@ -3730,15 +3730,53 @@ class AppLocalizationsFr extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'Balisage Writerside invalide : $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'Utilisez true ou false ; single-file n’est plus pris en charge.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return 'Impossible de résoudre $kind : $reference'; + } + + @override + String get exportAsHtml => 'Exporter au format HTML…'; + + @override + String get fileTypeHtml => 'Document HTML'; + + @override + String get exportingHtml => 'Exportation HTML…'; + + @override + String get htmlExported => 'Exportation HTML terminée'; + + @override + String get htmlExportFailed => 'Échec de l’exportation HTML'; + + @override + String get htmlKeepAssetsTogether => + 'Lors de la copie, conservez le fichier HTML et son dossier de ressources ensemble.'; + + @override + String get htmlInstanceDescription => + 'Exportez une instance sous forme de pages liées hors ligne. Choisissez un nom pour un dossier de sortie dédié.'; + + @override + String get htmlInstance => 'Instance'; + + @override + String get htmlOwnedDirectoryOnly => + 'Seul un dossier créé par l’exportation HTML de BusyMark peut être remplacé. Les fichiers modifiés ou étrangers seront conservés.'; + + @override + String get showInFolder => 'Afficher dans le dossier'; + + @override + String sortTableColumn(String column) { + return 'Trier $column'; } } diff --git a/lib/l10n/generated/app_localizations_hi.dart b/lib/l10n/generated/app_localizations_hi.dart index ef72233e..a8533ca3 100644 --- a/lib/l10n/generated/app_localizations_hi.dart +++ b/lib/l10n/generated/app_localizations_hi.dart @@ -3656,30 +3656,30 @@ class AppLocalizationsHi extends AppLocalizations { String get displayMath => 'डिस्प्ले गणित'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'घोषणा पर जाएँ'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'उपयोग खोजें'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'प्रतीक का नाम सुरक्षित रूप से नहीं बदला जा सकता। नाम जाँचें और दोबारा प्रयास करने से पहले संदर्भ रीफ़्रेश करें।'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'कीबोर्ड लेआउट'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'असमर्थित या गलत प्रारूप वाली सामग्री स्रोत के रूप में दिखाई जाती है।'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'स्रोत “$reference” हल नहीं किया जा सकता: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'इस इंस्टेंस में लिंक का लक्ष्य उपलब्ध नहीं है: $destination'; } @override @@ -3688,15 +3688,53 @@ class AppLocalizationsHi extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'अमान्य Writerside मार्कअप: $element, $attribute। $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'true या false का उपयोग करें; single-file अब समर्थित नहीं है।'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return '$kind हल नहीं किया जा सकता: $reference'; + } + + @override + String get exportAsHtml => 'HTML के रूप में निर्यात करें…'; + + @override + String get fileTypeHtml => 'HTML दस्तावेज़'; + + @override + String get exportingHtml => 'HTML निर्यात हो रहा है…'; + + @override + String get htmlExported => 'HTML निर्यात पूरा हुआ'; + + @override + String get htmlExportFailed => 'HTML निर्यात विफल हुआ'; + + @override + String get htmlKeepAssetsTogether => + 'इस निर्यात को कॉपी करते समय HTML फ़ाइल और उसके संसाधन फ़ोल्डर को साथ रखें।'; + + @override + String get htmlInstanceDescription => + 'एक इंस्टेंस को लिंक किए गए ऑफ़लाइन पृष्ठों के रूप में निर्यात करें। एक अलग आउटपुट फ़ोल्डर का नाम चुनें।'; + + @override + String get htmlInstance => 'इंस्टेंस'; + + @override + String get htmlOwnedDirectoryOnly => + 'केवल BusyMark HTML निर्यात द्वारा बनाया गया फ़ोल्डर बदला जा सकता है। बदली गई या असंबंधित फ़ाइलें सुरक्षित रहेंगी।'; + + @override + String get showInFolder => 'फ़ोल्डर में दिखाएँ'; + + @override + String sortTableColumn(String column) { + return '$column क्रमबद्ध करें'; } } diff --git a/lib/l10n/generated/app_localizations_id.dart b/lib/l10n/generated/app_localizations_id.dart index 2476c3c6..e7c165c9 100644 --- a/lib/l10n/generated/app_localizations_id.dart +++ b/lib/l10n/generated/app_localizations_id.dart @@ -3673,30 +3673,30 @@ class AppLocalizationsId extends AppLocalizations { String get displayMath => 'Matematika tampilan'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'Buka Deklarasi'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'Cari Penggunaan'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'Nama simbol tidak dapat diubah dengan aman. Periksa nama dan segarkan referensi sebelum mencoba lagi.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'Tata letak papan ketik'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'Konten yang tidak didukung atau salah format ditampilkan sebagai sumber.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'Tidak dapat menyelesaikan sumber “$reference”: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'Tujuan tautan tidak tersedia dalam instans ini: $destination'; } @override @@ -3705,15 +3705,53 @@ class AppLocalizationsId extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'Markup Writerside tidak valid: $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'Gunakan true atau false; single-file tidak lagi didukung.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return 'Tidak dapat menyelesaikan $kind: $reference'; + } + + @override + String get exportAsHtml => 'Ekspor sebagai HTML…'; + + @override + String get fileTypeHtml => 'Dokumen HTML'; + + @override + String get exportingHtml => 'Mengekspor HTML…'; + + @override + String get htmlExported => 'Ekspor HTML selesai'; + + @override + String get htmlExportFailed => 'Ekspor HTML gagal'; + + @override + String get htmlKeepAssetsTogether => + 'Saat menyalin hasil ekspor, simpan berkas HTML bersama folder aset pendampingnya.'; + + @override + String get htmlInstanceDescription => + 'Ekspor satu instans sebagai halaman luring yang saling tertaut. Pilih nama untuk folder keluaran khusus.'; + + @override + String get htmlInstance => 'Instans'; + + @override + String get htmlOwnedDirectoryOnly => + 'Hanya folder yang dibuat oleh ekspor HTML BusyMark yang dapat diganti. Berkas yang diubah atau tidak terkait akan dipertahankan.'; + + @override + String get showInFolder => 'Tampilkan dalam Folder'; + + @override + String sortTableColumn(String column) { + return 'Urutkan $column'; } } diff --git a/lib/l10n/generated/app_localizations_it.dart b/lib/l10n/generated/app_localizations_it.dart index 492e415d..5a407c49 100644 --- a/lib/l10n/generated/app_localizations_it.dart +++ b/lib/l10n/generated/app_localizations_it.dart @@ -3695,30 +3695,30 @@ class AppLocalizationsIt extends AppLocalizations { String get displayMath => 'Formula in blocco'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'Vai alla dichiarazione'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'Trova utilizzi'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'Impossibile rinominare il simbolo in sicurezza. Verifica il nome e aggiorna il riferimento prima di riprovare.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'Disposizione della tastiera'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'Il contenuto non supportato o malformato viene mostrato come sorgente.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'Impossibile risolvere la sorgente «$reference»: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'La destinazione del collegamento non è disponibile in questa istanza: $destination'; } @override @@ -3727,15 +3727,53 @@ class AppLocalizationsIt extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'Markup Writerside non valido: $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'Usa true o false; single-file non è più supportato.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return 'Impossibile risolvere $kind: $reference'; + } + + @override + String get exportAsHtml => 'Esporta come HTML…'; + + @override + String get fileTypeHtml => 'Documento HTML'; + + @override + String get exportingHtml => 'Esportazione HTML…'; + + @override + String get htmlExported => 'Esportazione HTML completata'; + + @override + String get htmlExportFailed => 'Esportazione HTML non riuscita'; + + @override + String get htmlKeepAssetsTogether => + 'Durante la copia, mantieni insieme il file HTML e la relativa cartella delle risorse.'; + + @override + String get htmlInstanceDescription => + 'Esporta un’istanza come pagine collegate offline. Scegli un nome per una cartella di destinazione dedicata.'; + + @override + String get htmlInstance => 'Istanza'; + + @override + String get htmlOwnedDirectoryOnly => + 'È possibile sostituire solo una cartella creata dall’esportazione HTML di BusyMark. I file modificati o estranei verranno conservati.'; + + @override + String get showInFolder => 'Mostra nella cartella'; + + @override + String sortTableColumn(String column) { + return 'Ordina $column'; } } diff --git a/lib/l10n/generated/app_localizations_ja.dart b/lib/l10n/generated/app_localizations_ja.dart index 2941ce97..a9434cab 100644 --- a/lib/l10n/generated/app_localizations_ja.dart +++ b/lib/l10n/generated/app_localizations_ja.dart @@ -3567,30 +3567,29 @@ class AppLocalizationsJa extends AppLocalizations { String get displayMath => 'ディスプレイ数式'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => '宣言へ移動'; @override - String get findUsages => 'Find Usages'; + String get findUsages => '使用箇所を検索'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'シンボル名を安全に変更できません。名前を確認し、参照を更新してから再試行してください。'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'キーボード配列'; @override - String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + String get diagnosticWritersideUnsupported => '未対応または不正な形式の内容はソースとして表示されます。'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'ソース「$reference」を解決できません: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'このインスタンスではリンク先を利用できません: $destination'; } @override @@ -3599,15 +3598,53 @@ class AppLocalizationsJa extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return '無効な Writerside マークアップ: $element、$attribute。$reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'true または false を使用してください。single-file はサポートされなくなりました。'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return '$kind を解決できません: $reference'; + } + + @override + String get exportAsHtml => 'HTML としてエクスポート…'; + + @override + String get fileTypeHtml => 'HTML ドキュメント'; + + @override + String get exportingHtml => 'HTML をエクスポート中…'; + + @override + String get htmlExported => 'HTML のエクスポートが完了しました'; + + @override + String get htmlExportFailed => 'HTML のエクスポートに失敗しました'; + + @override + String get htmlKeepAssetsTogether => + 'コピーするときは、HTML ファイルと付属のアセットフォルダーを一緒に移動してください。'; + + @override + String get htmlInstanceDescription => + '1 つのインスタンスを、リンクでつながるオフラインページとしてエクスポートします。専用の出力フォルダー名を選んでください。'; + + @override + String get htmlInstance => 'インスタンス'; + + @override + String get htmlOwnedDirectoryOnly => + 'BusyMark の HTML エクスポートで作成されたフォルダーのみ置き換えられます。変更されたファイルや無関係なファイルは保持されます。'; + + @override + String get showInFolder => 'フォルダーで表示'; + + @override + String sortTableColumn(String column) { + return '$column を並べ替え'; } } diff --git a/lib/l10n/generated/app_localizations_ko.dart b/lib/l10n/generated/app_localizations_ko.dart index 2705395c..2aa89230 100644 --- a/lib/l10n/generated/app_localizations_ko.dart +++ b/lib/l10n/generated/app_localizations_ko.dart @@ -3562,30 +3562,30 @@ class AppLocalizationsKo extends AppLocalizations { String get displayMath => '수학 표시'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => '선언으로 이동'; @override - String get findUsages => 'Find Usages'; + String get findUsages => '사용 위치 찾기'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + '기호 이름을 안전하게 바꿀 수 없습니다. 이름을 확인하고 참조를 새로 고친 후 다시 시도하세요.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => '키보드 배열'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + '지원하지 않거나 잘못된 형식의 내용은 소스로 표시됩니다.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return '소스 “$reference”를 확인할 수 없습니다: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return '이 인스턴스에서 링크 대상을 사용할 수 없습니다: $destination'; } @override @@ -3594,15 +3594,53 @@ class AppLocalizationsKo extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return '잘못된 Writerside 마크업: $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'true 또는 false를 사용하세요. single-file은 더 이상 지원되지 않습니다.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return '$kind을(를) 확인할 수 없습니다: $reference'; + } + + @override + String get exportAsHtml => 'HTML로 내보내기…'; + + @override + String get fileTypeHtml => 'HTML 문서'; + + @override + String get exportingHtml => 'HTML 내보내는 중…'; + + @override + String get htmlExported => 'HTML 내보내기 완료'; + + @override + String get htmlExportFailed => 'HTML 내보내기 실패'; + + @override + String get htmlKeepAssetsTogether => + '내보낸 결과를 복사할 때 HTML 파일과 관련 리소스 폴더를 함께 유지하세요.'; + + @override + String get htmlInstanceDescription => + '인스턴스 하나를 연결된 오프라인 페이지로 내보냅니다. 전용 출력 폴더의 이름을 선택하세요.'; + + @override + String get htmlInstance => '인스턴스'; + + @override + String get htmlOwnedDirectoryOnly => + 'BusyMark HTML 내보내기로 만든 폴더만 교체할 수 있습니다. 수정되거나 관련 없는 파일은 보존됩니다.'; + + @override + String get showInFolder => '폴더에서 보기'; + + @override + String sortTableColumn(String column) { + return '$column 정렬'; } } diff --git a/lib/l10n/generated/app_localizations_nb.dart b/lib/l10n/generated/app_localizations_nb.dart index 59685712..d78ec57f 100644 --- a/lib/l10n/generated/app_localizations_nb.dart +++ b/lib/l10n/generated/app_localizations_nb.dart @@ -3666,30 +3666,30 @@ class AppLocalizationsNb extends AppLocalizations { String get displayMath => 'Matematikkblokk'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'Gå til deklarasjon'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'Finn bruk'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'Symbolet kan ikke gis nytt navn trygt. Kontroller navnet og oppdater referansen før du prøver igjen.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'Tastaturoppsett'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'Innhold som ikke støttes eller er feilformet, vises som kildekode.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'Kan ikke løse kilden «$reference»: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'Lenkemålet er ikke tilgjengelig i denne instansen: $destination'; } @override @@ -3698,15 +3698,53 @@ class AppLocalizationsNb extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'Ugyldig Writerside-markering: $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'Bruk true eller false; single-file støttes ikke lenger.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return 'Kan ikke løse $kind: $reference'; + } + + @override + String get exportAsHtml => 'Eksporter som HTML…'; + + @override + String get fileTypeHtml => 'HTML-dokument'; + + @override + String get exportingHtml => 'Eksporterer HTML…'; + + @override + String get htmlExported => 'HTML-eksport fullført'; + + @override + String get htmlExportFailed => 'HTML-eksport mislyktes'; + + @override + String get htmlKeepAssetsTogether => + 'Hold HTML-filen og den tilhørende ressursmappen sammen når du kopierer eksporten.'; + + @override + String get htmlInstanceDescription => + 'Eksporter én instans som lenkede frakoblede sider. Velg et navn for en egen utdatamappe.'; + + @override + String get htmlInstance => 'Instans'; + + @override + String get htmlOwnedDirectoryOnly => + 'Bare en mappe opprettet av BusyMarks HTML-eksport kan erstattes. Endrede eller uvedkommende filer beholdes.'; + + @override + String get showInFolder => 'Vis i mappe'; + + @override + String sortTableColumn(String column) { + return 'Sorter $column'; } } diff --git a/lib/l10n/generated/app_localizations_nl.dart b/lib/l10n/generated/app_localizations_nl.dart index 0b02c3bb..cdda3937 100644 --- a/lib/l10n/generated/app_localizations_nl.dart +++ b/lib/l10n/generated/app_localizations_nl.dart @@ -3709,30 +3709,30 @@ class AppLocalizationsNl extends AppLocalizations { String get displayMath => 'Wiskunde weergeven'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'Ga naar declaratie'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'Gebruik zoeken'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'Het symbool kan niet veilig worden hernoemd. Controleer de naam en vernieuw de verwijzing voordat u het opnieuw probeert.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'Toetsenbordindeling'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'Niet-ondersteunde of ongeldige inhoud wordt als broncode getoond.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'Bron ‘$reference’ kan niet worden gevonden: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'Het linkdoel is niet beschikbaar in deze instantie: $destination'; } @override @@ -3741,15 +3741,53 @@ class AppLocalizationsNl extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'Ongeldige Writerside-opmaak: $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'Gebruik true of false; single-file wordt niet meer ondersteund.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return '$kind kan niet worden gevonden: $reference'; + } + + @override + String get exportAsHtml => 'Exporteren als HTML…'; + + @override + String get fileTypeHtml => 'HTML-document'; + + @override + String get exportingHtml => 'HTML exporteren…'; + + @override + String get htmlExported => 'HTML-export voltooid'; + + @override + String get htmlExportFailed => 'HTML-export mislukt'; + + @override + String get htmlKeepAssetsTogether => + 'Houd het HTML-bestand en de bijbehorende middelenmap bij elkaar wanneer u deze export kopieert.'; + + @override + String get htmlInstanceDescription => + 'Exporteer één instantie als gekoppelde offline pagina’s. Kies een naam voor een aparte uitvoermap.'; + + @override + String get htmlInstance => 'Instantie'; + + @override + String get htmlOwnedDirectoryOnly => + 'Alleen een map die door BusyMark HTML-export is gemaakt kan worden vervangen. Gewijzigde of andere bestanden blijven behouden.'; + + @override + String get showInFolder => 'Tonen in map'; + + @override + String sortTableColumn(String column) { + return '$column sorteren'; } } diff --git a/lib/l10n/generated/app_localizations_pl.dart b/lib/l10n/generated/app_localizations_pl.dart index 10b2144f..1ce07490 100644 --- a/lib/l10n/generated/app_localizations_pl.dart +++ b/lib/l10n/generated/app_localizations_pl.dart @@ -3718,30 +3718,30 @@ class AppLocalizationsPl extends AppLocalizations { String get displayMath => 'Matematyka blokowa'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'Przejdź do deklaracji'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'Znajdź użycia'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'Nie można bezpiecznie zmienić nazwy symbolu. Sprawdź nazwę i odśwież odwołanie przed ponowną próbą.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'Układ klawiatury'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'Nieobsługiwana lub nieprawidłowa treść jest wyświetlana jako źródło.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'Nie można rozwiązać źródła „$reference”: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'Cel odnośnika jest niedostępny w tej instancji: $destination'; } @override @@ -3750,15 +3750,53 @@ class AppLocalizationsPl extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'Nieprawidłowy znacznik Writerside: $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'Użyj true lub false; single-file nie jest już obsługiwane.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return 'Nie można rozwiązać $kind: $reference'; + } + + @override + String get exportAsHtml => 'Eksportuj jako HTML…'; + + @override + String get fileTypeHtml => 'Dokument HTML'; + + @override + String get exportingHtml => 'Eksportowanie HTML…'; + + @override + String get htmlExported => 'Eksport HTML zakończony'; + + @override + String get htmlExportFailed => 'Eksport HTML nie powiódł się'; + + @override + String get htmlKeepAssetsTogether => + 'Podczas kopiowania zachowaj razem plik HTML i towarzyszący mu katalog zasobów.'; + + @override + String get htmlInstanceDescription => + 'Wyeksportuj jedną instancję jako połączone strony offline. Wybierz nazwę osobnego katalogu wyjściowego.'; + + @override + String get htmlInstance => 'Instancja'; + + @override + String get htmlOwnedDirectoryOnly => + 'Można zastąpić tylko katalog utworzony przez eksport HTML BusyMark. Zmienione lub obce pliki zostaną zachowane.'; + + @override + String get showInFolder => 'Pokaż w folderze'; + + @override + String sortTableColumn(String column) { + return 'Sortuj $column'; } } diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart index 17ba9d9f..0ef6bd99 100644 --- a/lib/l10n/generated/app_localizations_pt.dart +++ b/lib/l10n/generated/app_localizations_pt.dart @@ -3697,30 +3697,30 @@ class AppLocalizationsPt extends AppLocalizations { String get displayMath => 'Display math'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'Ir para a declaração'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'Encontrar utilizações'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'Não é possível mudar o nome do símbolo com segurança. Verifique o nome e atualize a referência antes de tentar novamente.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'Disposição do teclado'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'O conteúdo não suportado ou malformado é apresentado como código-fonte.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'Não é possível resolver a origem «$reference»: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'O destino da ligação não está disponível nesta instância: $destination'; } @override @@ -3729,16 +3729,54 @@ class AppLocalizationsPt extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'Marcação Writerside inválida: $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'Use true ou false; single-file deixou de ser suportado.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return 'Não é possível resolver $kind: $reference'; + } + + @override + String get exportAsHtml => 'Exportar como HTML…'; + + @override + String get fileTypeHtml => 'Documento HTML'; + + @override + String get exportingHtml => 'A exportar HTML…'; + + @override + String get htmlExported => 'Exportação HTML concluída'; + + @override + String get htmlExportFailed => 'Falha na exportação HTML'; + + @override + String get htmlKeepAssetsTogether => + 'Ao copiar esta exportação, mantenha juntos o ficheiro HTML e a pasta de recursos associada.'; + + @override + String get htmlInstanceDescription => + 'Exporte uma instância como páginas ligadas offline. Escolha um nome para uma pasta de destino dedicada.'; + + @override + String get htmlInstance => 'Instância'; + + @override + String get htmlOwnedDirectoryOnly => + 'Só é possível substituir uma pasta criada pela exportação HTML do BusyMark. Os ficheiros modificados ou alheios serão preservados.'; + + @override + String get showInFolder => 'Mostrar na pasta'; + + @override + String sortTableColumn(String column) { + return 'Ordenar $column'; } } @@ -7434,4 +7472,87 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { @override String get displayMath => 'Matemática em bloco'; + + @override + String get goToDeclaration => 'Ir para a declaração'; + + @override + String get findUsages => 'Encontrar usos'; + + @override + String get cannotRenameSymbol => + 'Não é possível renomear o símbolo com segurança. Verifique o nome e atualize a referência antes de tentar novamente.'; + + @override + String get keyboardLayout => 'Layout do teclado'; + + @override + String get diagnosticWritersideUnsupported => + 'O conteúdo não compatível ou malformado é exibido como código-fonte.'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return 'Não é possível resolver a origem “$reference”: $reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return 'O destino do link não está disponível nesta instância: $destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return 'Marcação Writerside inválida: $element, $attribute. $reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + 'Use true ou false; single-file não é mais compatível.'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return 'Não é possível resolver $kind: $reference'; + } + + @override + String get exportAsHtml => 'Exportar como HTML…'; + + @override + String get fileTypeHtml => 'Documento HTML'; + + @override + String get exportingHtml => 'Exportando HTML…'; + + @override + String get htmlExported => 'Exportação HTML concluída'; + + @override + String get htmlExportFailed => 'Falha na exportação HTML'; + + @override + String get htmlKeepAssetsTogether => + 'Ao copiar esta exportação, mantenha juntos o arquivo HTML e a pasta de recursos associada.'; + + @override + String get htmlInstanceDescription => + 'Exporte uma instância como páginas vinculadas offline. Escolha um nome para uma pasta de destino exclusiva.'; + + @override + String get htmlInstance => 'Instância'; + + @override + String get htmlOwnedDirectoryOnly => + 'Só é possível substituir uma pasta criada pela exportação HTML do BusyMark. Os arquivos modificados ou alheios serão preservados.'; + + @override + String get showInFolder => 'Mostrar na pasta'; + + @override + String sortTableColumn(String column) { + return 'Ordenar $column'; + } } diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart index 1b21d3ae..d243ee2e 100644 --- a/lib/l10n/generated/app_localizations_ru.dart +++ b/lib/l10n/generated/app_localizations_ru.dart @@ -3717,30 +3717,30 @@ class AppLocalizationsRu extends AppLocalizations { String get displayMath => 'Формула отдельным блоком'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'Перейти к объявлению'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'Найти использования'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'Невозможно безопасно переименовать символ. Проверьте имя и обновите ссылку перед повторной попыткой.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'Раскладка клавиатуры'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'Неподдерживаемое или некорректное содержимое показано как исходный код.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'Не удалось разрешить источник «$reference»: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'Цель ссылки недоступна в этом экземпляре: $destination'; } @override @@ -3749,15 +3749,53 @@ class AppLocalizationsRu extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'Некорректная разметка Writerside: $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'Используйте true или false; single-file больше не поддерживается.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return 'Не удалось разрешить $kind: $reference'; + } + + @override + String get exportAsHtml => 'Экспортировать в HTML…'; + + @override + String get fileTypeHtml => 'Документ HTML'; + + @override + String get exportingHtml => 'Экспорт HTML…'; + + @override + String get htmlExported => 'Экспорт HTML завершён'; + + @override + String get htmlExportFailed => 'Не удалось экспортировать HTML'; + + @override + String get htmlKeepAssetsTogether => + 'При копировании сохраняйте файл HTML вместе с папкой его ресурсов.'; + + @override + String get htmlInstanceDescription => + 'Экспортируйте один экземпляр как связанные автономные страницы. Выберите имя отдельной папки вывода.'; + + @override + String get htmlInstance => 'Экземпляр'; + + @override + String get htmlOwnedDirectoryOnly => + 'Можно заменить только папку, созданную экспортом HTML BusyMark. Изменённые и посторонние файлы будут сохранены.'; + + @override + String get showInFolder => 'Показать в папке'; + + @override + String sortTableColumn(String column) { + return 'Сортировать $column'; } } diff --git a/lib/l10n/generated/app_localizations_tr.dart b/lib/l10n/generated/app_localizations_tr.dart index f821150f..dbebc93b 100644 --- a/lib/l10n/generated/app_localizations_tr.dart +++ b/lib/l10n/generated/app_localizations_tr.dart @@ -3668,30 +3668,30 @@ class AppLocalizationsTr extends AppLocalizations { String get displayMath => 'Blok matematik'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'Bildirime git'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'Kullanımları bul'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'Simge güvenle yeniden adlandırılamıyor. Yeniden denemeden önce adı kontrol edin ve başvuruyu yenileyin.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'Klavye düzeni'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'Desteklenmeyen veya hatalı içerik kaynak olarak gösterilir.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return '“$reference” kaynağı çözümlenemiyor: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'Bağlantı hedefi bu örnekte kullanılamıyor: $destination'; } @override @@ -3700,15 +3700,53 @@ class AppLocalizationsTr extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'Geçersiz Writerside işaretlemesi: $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'true veya false kullanın; single-file artık desteklenmiyor.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return '$kind çözümlenemiyor: $reference'; + } + + @override + String get exportAsHtml => 'HTML olarak dışa aktar…'; + + @override + String get fileTypeHtml => 'HTML belgesi'; + + @override + String get exportingHtml => 'HTML dışa aktarılıyor…'; + + @override + String get htmlExported => 'HTML dışa aktarımı tamamlandı'; + + @override + String get htmlExportFailed => 'HTML dışa aktarılamadı'; + + @override + String get htmlKeepAssetsTogether => + 'Bu dışa aktarımı kopyalarken HTML dosyasını ve ilgili kaynak klasörünü bir arada tutun.'; + + @override + String get htmlInstanceDescription => + 'Bir örneği bağlantılı çevrimdışı sayfalar olarak dışa aktarın. Ayrı bir çıktı klasörü için ad seçin.'; + + @override + String get htmlInstance => 'Örnek'; + + @override + String get htmlOwnedDirectoryOnly => + 'Yalnızca BusyMark HTML dışa aktarımıyla oluşturulan bir klasör değiştirilebilir. Değiştirilmiş veya ilgisiz dosyalar korunur.'; + + @override + String get showInFolder => 'Klasörde Göster'; + + @override + String sortTableColumn(String column) { + return '$column sırala'; } } diff --git a/lib/l10n/generated/app_localizations_uk.dart b/lib/l10n/generated/app_localizations_uk.dart index bb717697..83913d13 100644 --- a/lib/l10n/generated/app_localizations_uk.dart +++ b/lib/l10n/generated/app_localizations_uk.dart @@ -3725,30 +3725,30 @@ class AppLocalizationsUk extends AppLocalizations { String get displayMath => 'Формула окремим блоком'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'Перейти до оголошення'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'Знайти використання'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'Неможливо безпечно перейменувати символ. Перевірте назву й оновіть посилання перед повторною спробою.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'Розкладка клавіатури'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'Непідтримуваний або некоректний вміст показано як джерело.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'Не вдалося знайти джерело «$reference»: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'Ціль посилання недоступна в цьому екземплярі: $destination'; } @override @@ -3757,15 +3757,53 @@ class AppLocalizationsUk extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'Некоректна розмітка Writerside: $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'Використовуйте true або false; single-file більше не підтримується.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return 'Не вдалося знайти $kind: $reference'; + } + + @override + String get exportAsHtml => 'Експортувати в HTML…'; + + @override + String get fileTypeHtml => 'Документ HTML'; + + @override + String get exportingHtml => 'Експорт HTML…'; + + @override + String get htmlExported => 'Експорт HTML завершено'; + + @override + String get htmlExportFailed => 'Не вдалося експортувати HTML'; + + @override + String get htmlKeepAssetsTogether => + 'Під час копіювання зберігайте файл HTML разом із папкою його ресурсів.'; + + @override + String get htmlInstanceDescription => + 'Експортуйте один екземпляр як пов’язані автономні сторінки. Виберіть назву окремої вихідної папки.'; + + @override + String get htmlInstance => 'Екземпляр'; + + @override + String get htmlOwnedDirectoryOnly => + 'Можна замінити лише папку, створену експортом HTML BusyMark. Змінені та сторонні файли буде збережено.'; + + @override + String get showInFolder => 'Показати в папці'; + + @override + String sortTableColumn(String column) { + return 'Сортувати $column'; } } diff --git a/lib/l10n/generated/app_localizations_vi.dart b/lib/l10n/generated/app_localizations_vi.dart index 65254a87..57aa903a 100644 --- a/lib/l10n/generated/app_localizations_vi.dart +++ b/lib/l10n/generated/app_localizations_vi.dart @@ -3662,30 +3662,30 @@ class AppLocalizationsVi extends AppLocalizations { String get displayMath => 'Toán hiển thị'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => 'Đi đến khai báo'; @override - String get findUsages => 'Find Usages'; + String get findUsages => 'Tìm nơi sử dụng'; @override String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + 'Không thể đổi tên ký hiệu một cách an toàn. Kiểm tra tên và làm mới tham chiếu trước khi thử lại.'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => 'Bố cục bàn phím'; @override String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + 'Nội dung không được hỗ trợ hoặc sai định dạng được hiển thị dưới dạng mã nguồn.'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return 'Không thể phân giải nguồn “$reference”: $reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return 'Đích liên kết không khả dụng trong phiên bản này: $destination'; } @override @@ -3694,15 +3694,53 @@ class AppLocalizationsVi extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return 'Đánh dấu Writerside không hợp lệ: $element, $attribute. $reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + 'Dùng true hoặc false; single-file không còn được hỗ trợ.'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return 'Không thể phân giải $kind: $reference'; + } + + @override + String get exportAsHtml => 'Xuất dưới dạng HTML…'; + + @override + String get fileTypeHtml => 'Tài liệu HTML'; + + @override + String get exportingHtml => 'Đang xuất HTML…'; + + @override + String get htmlExported => 'Xuất HTML hoàn tất'; + + @override + String get htmlExportFailed => 'Xuất HTML thất bại'; + + @override + String get htmlKeepAssetsTogether => + 'Khi sao chép bản xuất, hãy giữ tệp HTML và thư mục tài nguyên đi kèm ở cùng nhau.'; + + @override + String get htmlInstanceDescription => + 'Xuất một phiên bản thành các trang ngoại tuyến có liên kết. Chọn tên cho thư mục đầu ra riêng.'; + + @override + String get htmlInstance => 'Phiên bản'; + + @override + String get htmlOwnedDirectoryOnly => + 'Chỉ có thể thay thế thư mục được tạo bởi chức năng xuất HTML của BusyMark. Các tệp đã sửa đổi hoặc không liên quan sẽ được giữ lại.'; + + @override + String get showInFolder => 'Hiển thị trong thư mục'; + + @override + String sortTableColumn(String column) { + return 'Sắp xếp $column'; } } diff --git a/lib/l10n/generated/app_localizations_zh.dart b/lib/l10n/generated/app_localizations_zh.dart index 6754b464..d7499877 100644 --- a/lib/l10n/generated/app_localizations_zh.dart +++ b/lib/l10n/generated/app_localizations_zh.dart @@ -3688,30 +3688,28 @@ class AppLocalizationsZh extends AppLocalizations { String get displayMath => 'Display math'; @override - String get goToDeclaration => 'Go to Declaration'; + String get goToDeclaration => '转到声明'; @override - String get findUsages => 'Find Usages'; + String get findUsages => '查找用法'; @override - String get cannotRenameSymbol => - 'The symbol cannot be renamed safely. Check the name and refresh the reference before trying again.'; + String get cannotRenameSymbol => '无法安全地重命名此符号。请检查名称并刷新引用,然后重试。'; @override - String get keyboardLayout => 'Keyboard layout'; + String get keyboardLayout => '键盘布局'; @override - String get diagnosticWritersideUnsupported => - 'Unsupported or malformed content is displayed as source.'; + String get diagnosticWritersideUnsupported => '不支持或格式错误的内容将显示为源代码。'; @override String diagnosticWritersideSource(String reference, String reason) { - return 'Cannot resolve source “$reference”: $reason'; + return '无法解析源“$reference”:$reason'; } @override String diagnosticWritersideLink(String destination) { - return 'Link target is unavailable in this instance: $destination'; + return '此实例中无法使用链接目标:$destination'; } @override @@ -3720,16 +3718,52 @@ class AppLocalizationsZh extends AppLocalizations { String attribute, String reason, ) { - return 'Invalid Writerside markup: $element, $attribute. $reason'; + return '无效的 Writerside 标记:$element,$attribute。$reason'; } @override String get diagnosticWritersideLlmsTxt => - 'Use true or false; single-file is no longer supported.'; + '请使用 true 或 false;不再支持 single-file。'; @override String diagnosticWritersideReference(String kind, String reference) { - return 'Cannot resolve $kind: $reference'; + return '无法解析 $kind:$reference'; + } + + @override + String get exportAsHtml => '导出为 HTML…'; + + @override + String get fileTypeHtml => 'HTML 文档'; + + @override + String get exportingHtml => '正在导出 HTML…'; + + @override + String get htmlExported => 'HTML 导出完成'; + + @override + String get htmlExportFailed => 'HTML 导出失败'; + + @override + String get htmlKeepAssetsTogether => '复制导出结果时,请将 HTML 文件及其配套资源文件夹放在一起。'; + + @override + String get htmlInstanceDescription => '将一个实例导出为相互链接的离线页面。请选择专用输出文件夹的名称。'; + + @override + String get htmlInstance => '实例'; + + @override + String get htmlOwnedDirectoryOnly => + '只能替换由 BusyMark HTML 导出创建的文件夹。已修改或无关的文件将被保留。'; + + @override + String get showInFolder => '在文件夹中显示'; + + @override + String sortTableColumn(String column) { + return '排序 $column'; } } @@ -7230,4 +7264,83 @@ class AppLocalizationsZhCn extends AppLocalizationsZh { @override String get displayMath => '显示数学'; + + @override + String get goToDeclaration => '转到声明'; + + @override + String get findUsages => '查找用法'; + + @override + String get cannotRenameSymbol => '无法安全地重命名此符号。请检查名称并刷新引用,然后重试。'; + + @override + String get keyboardLayout => '键盘布局'; + + @override + String get diagnosticWritersideUnsupported => '不支持或格式错误的内容将显示为源代码。'; + + @override + String diagnosticWritersideSource(String reference, String reason) { + return '无法解析源“$reference”:$reason'; + } + + @override + String diagnosticWritersideLink(String destination) { + return '此实例中无法使用链接目标:$destination'; + } + + @override + String diagnosticWritersideSchema( + String element, + String attribute, + String reason, + ) { + return '无效的 Writerside 标记:$element,$attribute。$reason'; + } + + @override + String get diagnosticWritersideLlmsTxt => + '请使用 true 或 false;不再支持 single-file。'; + + @override + String diagnosticWritersideReference(String kind, String reference) { + return '无法解析 $kind:$reference'; + } + + @override + String get exportAsHtml => '导出为 HTML…'; + + @override + String get fileTypeHtml => 'HTML 文档'; + + @override + String get exportingHtml => '正在导出 HTML…'; + + @override + String get htmlExported => 'HTML 导出完成'; + + @override + String get htmlExportFailed => 'HTML 导出失败'; + + @override + String get htmlKeepAssetsTogether => '复制导出结果时,请将 HTML 文件及其配套资源文件夹放在一起。'; + + @override + String get htmlInstanceDescription => '将一个实例导出为相互链接的离线页面。请选择专用输出文件夹的名称。'; + + @override + String get htmlInstance => '实例'; + + @override + String get htmlOwnedDirectoryOnly => + '只能替换由 BusyMark HTML 导出创建的文件夹。已修改或无关的文件将被保留。'; + + @override + String get showInFolder => '在文件夹中显示'; + + @override + String sortTableColumn(String column) { + return '排序 $column'; + } } diff --git a/lib/src/app/busymark_app.dart b/lib/src/app/busymark_app.dart index 2fa87433..e13fab3f 100644 --- a/lib/src/app/busymark_app.dart +++ b/lib/src/app/busymark_app.dart @@ -11,6 +11,7 @@ import 'package:ubuntu_localizations/ubuntu_localizations.dart'; import '../../l10n/generated/app_localizations.dart'; import '../export/markdown_pdf_export_ui.dart'; +import '../export/html_export_ui.dart'; import '../git/application/git_controller.dart'; import '../platform/linux_header_bar_service.dart'; import '../workspace/workspace_controller.dart'; @@ -40,6 +41,7 @@ final busyMarkCommandRegistryProvider = Provider(( BusyMarkCommandIds.open: const _OpenWorkspaceIntent(), BusyMarkCommandIds.save: const _SaveActiveIntent(), BusyMarkCommandIds.exportPdf: const _ExportPdfIntent(), + BusyMarkCommandIds.exportHtml: const _ExportHtmlIntent(), BusyMarkCommandIds.fullScreen: const _ToggleFullScreenIntent(), BusyMarkCommandIds.back: const _BackIntent(), BusyMarkCommandIds.search: const _OpenSearchIntent(), @@ -78,6 +80,8 @@ final busyMarkCommandRegistryProvider = Provider(( enabled: { BusyMarkCommandIds.save: () => ref.read(workspaceControllerProvider).workspace != null, + BusyMarkCommandIds.exportHtml: () => + canExportWorkspaceHtml(ref.read(workspaceControllerProvider)), BusyMarkCommandIds.exportPdf: () => canExportWorkspacePdf(ref.read(workspaceControllerProvider)), BusyMarkCommandIds.search: () => @@ -212,6 +216,17 @@ class BusyMarkApp extends ConsumerWidget { return null; }, ), + _ExportHtmlIntent: CallbackAction<_ExportHtmlIntent>( + onInvoke: (intent) { + final state = ref.read(workspaceControllerProvider); + final navigatorContext = rootNavigatorKey.currentContext; + if (navigatorContext != null && + canExportWorkspaceHtml(state)) { + unawaited(exportWorkspaceToHtml(navigatorContext, ref)); + } + return null; + }, + ), _ToggleFullScreenIntent: CallbackAction<_ToggleFullScreenIntent>( onInvoke: (intent) { @@ -818,6 +833,7 @@ class BusyMarkApp extends ConsumerWidget { backShortcut: shortcut(BusyMarkCommandIds.back), save: label(BusyMarkCommandIds.save), exportPdf: label(BusyMarkCommandIds.exportPdf), + exportHtml: label(BusyMarkCommandIds.exportHtml), exportPdfShortcut: shortcut(BusyMarkCommandIds.exportPdf), exportPdfGtkAccelerator: accelerator(BusyMarkCommandIds.exportPdf), fullScreen: label(BusyMarkCommandIds.fullScreen), @@ -1100,6 +1116,10 @@ class _SaveActiveIntent extends Intent { const _SaveActiveIntent(); } +class _ExportHtmlIntent extends Intent { + const _ExportHtmlIntent(); +} + class _ExportPdfIntent extends Intent { const _ExportPdfIntent(); } diff --git a/lib/src/app/busymark_main_menu.dart b/lib/src/app/busymark_main_menu.dart index ed1ca79c..177b5df1 100644 --- a/lib/src/app/busymark_main_menu.dart +++ b/lib/src/app/busymark_main_menu.dart @@ -11,6 +11,7 @@ import 'window_control_service.dart'; enum BusyMarkMainMenuAction { exportPdf, + exportHtml, generateMarkdownToc, fullScreen, settings, @@ -26,11 +27,13 @@ class BusyMarkMainMenuButton extends ConsumerWidget { super.key, required this.onSelected, this.canExportPdf = false, + this.canExportHtml = false, this.canGenerateMarkdownToc = false, }); final ValueChanged onSelected; final bool canExportPdf; + final bool canExportHtml; final bool canGenerateMarkdownToc; @override @@ -54,6 +57,13 @@ class BusyMarkMainMenuButton extends ConsumerWidget { shortcut: command(BusyMarkCommandIds.exportPdf).shortcut?.label, enabled: canExportPdf, ), + BusyMarkPopupMenuItem( + value: BusyMarkMainMenuAction.exportHtml, + label: command(BusyMarkCommandIds.exportHtml).label(context), + icon: BusyMarkGlyphs.exportPdf, + shortcut: command(BusyMarkCommandIds.exportHtml).shortcut?.label, + enabled: canExportHtml, + ), BusyMarkPopupMenuItem( value: BusyMarkMainMenuAction.generateMarkdownToc, label: l10n.generateOrUpdateMarkdownToc, @@ -109,6 +119,7 @@ class BusyMarkMainMenuButton extends ConsumerWidget { onSelected: (action) { final commandId = switch (action) { BusyMarkMainMenuAction.exportPdf => BusyMarkCommandIds.exportPdf, + BusyMarkMainMenuAction.exportHtml => BusyMarkCommandIds.exportHtml, BusyMarkMainMenuAction.fullScreen => BusyMarkCommandIds.fullScreen, BusyMarkMainMenuAction.settings => BusyMarkCommandIds.settings, BusyMarkMainMenuAction.keyboardShortcuts => diff --git a/lib/src/app/command_registry.dart b/lib/src/app/command_registry.dart index fde7f144..2bd874cb 100644 --- a/lib/src/app/command_registry.dart +++ b/lib/src/app/command_registry.dart @@ -245,6 +245,7 @@ abstract final class BusyMarkCommandIds { static const open = 'file.open'; static const save = 'file.save'; static const exportPdf = 'file.exportPdf'; + static const exportHtml = 'file.exportHtml'; static const fullScreen = 'view.fullScreen'; static const back = 'navigation.back'; static const search = 'search.find'; @@ -319,6 +320,12 @@ abstract final class BusyMarkCommandCatalog { } final commands = [ + command( + id: BusyMarkCommandIds.exportHtml, + label: (context) => context.l10n.exportAsHtml, + category: (context) => context.l10n.export, + scope: BusyMarkCommandScope.application, + ), for (final action in BusyMarkAppShortcutAction.values) command( id: _appId(action), diff --git a/lib/src/core/atomic_file_writer.dart b/lib/src/core/atomic_file_writer.dart index e228c155..6899b468 100644 --- a/lib/src/core/atomic_file_writer.dart +++ b/lib/src/core/atomic_file_writer.dart @@ -37,7 +37,7 @@ class AtomicFileWriter { } final stagingDirectory = await parent.createTemp('.busymark-export-'); - final stagedFile = File(p.join(stagingDirectory.path, 'document.pdf')); + final stagedFile = File(p.join(stagingDirectory.path, 'document.bin')); try { await stagedFile.writeAsBytes(bytes, flush: true); if (overwrite) { @@ -67,7 +67,7 @@ class AtomicFileWriter { throw AtomicFileAlreadyExistsException(absoluteTarget); } throw FileSystemException( - 'Failed to atomically publish the exported PDF', + 'Failed to atomically publish the exported file', absoluteTarget, OSError('no-replace publication failed', errorNumber), ); diff --git a/lib/src/core/linux_atomic_file_api.dart b/lib/src/core/linux_atomic_file_api.dart index ff3250c3..d44948dd 100644 --- a/lib/src/core/linux_atomic_file_api.dart +++ b/lib/src/core/linux_atomic_file_api.dart @@ -94,7 +94,11 @@ final class LinuxAtomicFileApi { /// Publishes [oldPath] at [newPath] without replacing an existing entity. /// /// Returns `null` on success, otherwise the Linux errno value. - int? publishNoReplace(String oldPath, String newPath) { + int? publishNoReplace( + String oldPath, + String newPath, { + bool directory = false, + }) { final errnoLocation = _errnoLocation; final link = _link; if (errnoLocation == null || link == null) { @@ -122,6 +126,7 @@ final class LinuxAtomicFileApi { return errorNumber; } } + if (directory) return _operationNotSupportedError; final result = link(nativeOldPath, nativeNewPath); return result == 0 ? null : errnoLocation().value; } finally { diff --git a/lib/src/export/html_document_writer.dart b/lib/src/export/html_document_writer.dart new file mode 100644 index 00000000..c5d55ab1 --- /dev/null +++ b/lib/src/export/html_document_writer.dart @@ -0,0 +1,1182 @@ +import 'dart:convert'; +import 'package:crypto/crypto.dart'; +import 'package:html/dom.dart' as dom; +import 'package:html/parser.dart' as parser; +import 'package:path/path.dart' as p; +import '../markdown/busymark_document.dart'; +import '../core/path_utils.dart'; +import '../markdown/raw_html_policy.dart'; +import '../visualization/visualization_models.dart'; +import '../writerside/writerside_document.dart'; +import 'html_export_links.dart'; +import 'html_export_models.dart'; +import 'html_publication_plan.dart'; +import 'html_rich_content.dart'; +import 'markdown_export_document.dart'; + +// Every string enters the DOM as text or a validated attribute. Source HTML +// takes the separate structural allowlist path below; it is never interpolated. +dom.Element _el( + String tag, { + String? text, + Map attrs = const {}, + Iterable children = const [], +}) { + final result = dom.Element.tag(tag)..attributes.addAll(attrs); + if (text != null) result.nodes.add(dom.Text(text)); + result.nodes.addAll(children); + return result; +} + +class HtmlDocumentWriter { + HtmlDocumentWriter({ + required this.page, + required this.plan, + required this.links, + required this.rich, + required this.stylesheet, + required this.warnings, + this.limits = const HtmlExportLimits(), + this.navigationLabel = 'Documentation', + this.outlineLabel = 'On this page', + this.workInProgressLabel = 'Work in progress', + this.contentLabel = 'Content', + this.disclosureLabel = 'Details', + }); + final HtmlPage page; + final HtmlPublicationPlan plan; + final HtmlExportLinks links; + final HtmlRichContent rich; + final String stylesheet; + final List warnings; + final HtmlExportLimits limits; + final String navigationLabel, + outlineLabel, + workInProgressLabel, + contentLabel, + disclosureLabel; + final List _rules = []; + final Set _emittedIds = {}; + int _rawNodes = 0; + + void _warn(String code, String message, BusyBlock? block) => warnings.add( + HtmlExportWarning( + code, + message, + sourcePath: block == null + ? page.sourcePath + : links.source(page, block.attributes), + line: block?.sourceSpan?.startLine ?? 1, + ), + ); + + Future write() async { + var contentId = 'busymark-content'; + while (page.ids.contains(contentId)) { + contentId = '$contentId-main'; + } + final content = await _blocks(page.document.blocks); + final article = _el('article', children: content); + if (page.topic?.document.rootElement?.attributes['id'] case final id? + when !_emittedIds.contains(id)) { + _attributes(article, {'id': id}); + } + if (page.workInProgress) { + article.nodes.insert( + 0, + _el('p', text: workInProgressLabel, attrs: {'class': 'status'}), + ); + } + if (article.querySelector('h1') == null) { + article.nodes.insert(0, _el('h1', text: page.title)); + } + final body = _el( + 'body', + children: [ + _el( + 'a', + text: contentLabel, + attrs: {'href': '#$contentId', 'class': 'skip-link'}, + ), + if (plan.navigation.isNotEmpty) + _el( + 'nav', + attrs: {'class': 'instance-nav', 'aria-label': navigationLabel}, + children: [ + _el( + 'details', + attrs: {'open': ''}, + children: [ + _el('summary', text: plan.title ?? navigationLabel), + await _navigation(plan.navigation), + ], + ), + ], + ), + _el( + 'main', + attrs: {'id': contentId, 'tabindex': '-1'}, + children: [ + if (page.outline.where((h) => h.level > 1).length > 1) + _el( + 'nav', + attrs: {'class': 'outline', 'aria-label': outlineLabel}, + children: [ + _el( + 'details', + children: [ + _el('summary', text: outlineLabel), + _el( + 'ul', + children: [ + for (final h in page.outline.where( + (h) => h.level > 1, + )) + _el( + 'li', + children: [ + _el( + 'a', + text: h.title, + attrs: { + 'href': '#${Uri.encodeComponent(h.id)}', + }, + ), + ], + ), + ], + ), + ], + ), + ], + ), + article, + ], + ), + ], + ); + final css = '$stylesheet\n${_rules.join('\n')}'; + // Meta CSP cannot enforce frame-ancestors or sandbox. All active source + // content has already been rejected. file: images need an explicit source + // in browsers that assign each local document an opaque origin. + final csp = + "default-src 'none'; script-src 'none'; connect-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'; frame-src 'none'; font-src 'none'; img-src 'self' file:; media-src 'self' file:; style-src 'sha256-${base64.encode(sha256.convert(utf8.encode(css)).bytes)}'"; + final metadata = page.document.frontMatter; + final lang = metadata['lang'] ?? metadata['language'] ?? 'und'; + final language = + RegExp(r'^[A-Za-z]{2,8}(?:-[A-Za-z0-9]{1,8})*$').hasMatch(lang) + ? lang + : 'und'; + final head = _el( + 'head', + children: [ + _el('meta', attrs: {'charset': 'utf-8'}), + _el( + 'meta', + attrs: {'http-equiv': 'Content-Security-Policy', 'content': csp}, + ), + _el( + 'meta', + attrs: { + 'name': 'viewport', + 'content': 'width=device-width, initial-scale=1', + }, + ), + _el('title', text: page.title), + for (final key in ['author', 'description', 'keywords']) + if (metadata[key] case final value?) + _el('meta', attrs: {'name': key, 'content': value}), + if (metadata['web-summary'] case final summary? + when !metadata.containsKey('description')) + _el('meta', attrs: {'name': 'description', 'content': summary}), + _el('style', text: css), + ], + ); + final root = _el( + 'html', + attrs: { + 'lang': language, + if ({'rtl', 'ltr', 'auto'}.contains(metadata['dir'])) + 'dir': metadata['dir']!, + }, + children: [head, body], + ); + _validateBoundary(root); + return '\n${root.outerHtml}\n'; + } + + Future _navigation(List entries) async { + final items = []; + for (final entry in entries) { + if (entry.hidden) continue; + final url = entry.page == null + ? HtmlExportLinks.external(entry.href ?? '') + : Uri.encodeComponent(entry.page!.filename); + final label = + '${entry.title}${entry.workInProgress ? ' — $workInProgressLabel' : ''}'; + final title = url == null + ? _el('span', text: label) + : _el( + 'a', + text: label, + attrs: { + 'href': url, + if (entry.page == page) 'aria-current': 'page', + }, + ); + final children = entry.children.where((e) => !e.hidden).toList(); + items.add( + _el( + 'li', + children: children.isEmpty + ? [title] + : [ + _el( + 'details', + attrs: {'open': ''}, + children: [ + _el('summary', children: [title]), + await _navigation(children), + ], + ), + ], + ), + ); + } + return _el('ul', children: items); + } + + String _style(dom.Element element, String declarations) { + final name = 's${_rules.length}'; + _rules.add('.$name{$declarations}'); + element.classes.add(name); + return name; + } + + void _attributes( + dom.Element element, + Map attributes, { + bool allowId = true, + }) { + final id = attributes['id']; + if (allowId && + id != null && + id.isNotEmpty && + !RegExp(r'\s|[\x00-\x1f]').hasMatch(id) && + _emittedIds.add(id)) { + element.id = id; + } + final direction = attributes['dir']; + if ({'rtl', 'ltr', 'auto'}.contains(direction)) { + element.attributes['dir'] = direction!; + } + if (attributes['title'] case final title?) { + element.attributes['title'] = title; + } + if (attributes['lang'] case final lang? + when RegExp(r'^[a-zA-Z0-9-]+$').hasMatch(lang)) { + element.attributes['lang'] = lang; + } + } + + bool _isList(BusyBlock b) => { + BusyBlockKind.orderedListItem, + BusyBlockKind.unorderedListItem, + BusyBlockKind.taskListItem, + }.contains(b.kind); + bool _ordered(BusyBlock b) => + b.kind == BusyBlockKind.orderedListItem || + b.attributes['ordered'] == 'true'; + Future> _blocks( + List blocks, [ + int depth = 0, + ]) async { + if (depth > limits.depth) { + throw const HtmlExportException( + 'Document nesting exceeds the HTML export limit.', + ); + } + final result = []; + for (var i = 0; i < blocks.length; i++) { + rich.token.check(); + final b = blocks[i]; + if (_isList(b)) { + final ordered = _ordered(b); + final list = _el(ordered ? 'ol' : 'ul'); + final start = + int.tryParse( + (b.attributes['marker'] ?? '').replaceAll(RegExp(r'[^0-9-]'), ''), + ) ?? + 1; + if (ordered && start != 1) list.attributes['start'] = '$start'; + while (i < blocks.length && + _isList(blocks[i]) && + _ordered(blocks[i]) == ordered) { + final item = blocks[i]; + final li = _el('li'); + _attributes(li, item.attributes); + if (item.kind == BusyBlockKind.taskListItem) { + li.classes.add('task'); + li.nodes.add( + _el( + 'input', + attrs: { + 'type': 'checkbox', + 'disabled': '', + 'aria-label': item.plainText, + if ((item.attributes['task'] ?? item.attributes['checked']) == + 'true') + 'checked': '', + }, + ), + ); + } + li.nodes.addAll(await _inlines(item.inlines, item)); + li.nodes.addAll(await _blocks(item.children, depth + 1)); + list.nodes.add(li); + i++; + } + i--; + result.add(list); + continue; + } + if (b.attributes['htmlTag'] == 'caption' && + i + 1 < blocks.length && + blocks[i + 1].kind == BusyBlockKind.table) { + result.add(await _table(blocks[++i], depth, caption: b)); + continue; + } + result.addAll(await _block(b, depth)); + } + return result; + } + + Future> _block( + BusyBlock b, + int depth, { + bool disclosure = true, + }) async { + if (b.kind == BusyBlockKind.frontMatter || b.isSourceOnly) return []; + if (disclosure && + b.attributes['element'] != 'deflist' && + busyMarkWritersideIsCollapsible(b.attributes)) { + final details = _el( + 'details', + attrs: { + if (busyMarkWritersideInitiallyExpanded(b.attributes)) 'open': '', + }, + ); + _attributes(details, b.attributes); + details.nodes.add( + _el( + 'summary', + text: + b.attributes['collapsed-title'] ?? + b.attributes['title'] ?? + (b.plainText.trim().isEmpty ? disclosureLabel : b.plainText), + ), + ); + // Strip only the wrapper ID to avoid a duplicate anchor on the heading. + final attributes = {...b.attributes}..remove('id'); + details.nodes.addAll( + await _block( + b.copyWith(attributes: attributes), + depth + 1, + disclosure: false, + ), + ); + return [details]; + } + if (b.attributes['html-footnotes'] case final source?) { + return _raw(source, b); + } + if (b.kind == BusyBlockKind.htmlBlock && b.rawSource != null) { + return _raw(b.rawSource!, b); + } + dom.Element element; + switch (b.kind) { + case BusyBlockKind.heading: + element = _el( + 'h${(int.tryParse(b.attributes['level'] ?? '') ?? 1).clamp(1, 6)}', + children: await _inlines(b.inlines, b), + ); + _attributes(element, b.attributes); + return [element, ...await _blocks(b.children, depth + 1)]; + case BusyBlockKind.paragraph: + element = _el('p', children: await _inlines(b.inlines, b)); + _attributes(element, b.attributes); + return [element, ...await _blocks(b.children, depth + 1)]; + case BusyBlockKind.codeBlock: + if (b.attributes['unsupported'] == 'true') { + _warn( + 'content.unsupported', + 'Unsupported content is shown as source.', + b, + ); + } + final descriptor = VisualizationDescriptor.maybeForFenceLanguage( + b.attributes['language'], + ); + if (descriptor != null) { + final source = links.source(page, b.attributes); + final result = await rich.diagram( + b, + source, + b.attributes[writersideSourceModuleRootAttribute] ?? + page.module?.rootPath ?? + p.dirname(source), + '${page.filename}:${b.id}', + ); + if (result?.reference case final reference?) { + return [await _reference(reference, b, depth)]; + } + if (result?.url case final url?) { + return [ + _el( + 'figure', + children: [ + _el( + 'img', + attrs: { + 'src': url, + 'alt': '${descriptor.kind.displayName} diagram', + }, + ), + ], + ), + ]; + } + } + final language = b.attributes['language'] ?? ''; + element = _el( + 'pre', + children: [ + _el( + 'code', + text: b.plainText, + attrs: { + if (RegExp(r'^[A-Za-z0-9_+-]{1,40}$').hasMatch(language)) + 'class': 'language-$language', + }, + ), + ], + ); + case BusyBlockKind.math: + element = _el( + 'div', + attrs: {'class': 'display-math'}, + children: [await _math(b.plainText, true, b)], + ); + case BusyBlockKind.table: + return [await _table(b, depth)]; + case BusyBlockKind.thematicBreak: + element = _el('hr'); + case BusyBlockKind.image: + element = _el('figure', children: await _inlines(b.inlines, b)); + if (b.attributes['src'] case final src? when b.inlines.isEmpty) { + element.nodes.add( + await _image(src, b.attributes['alt'] ?? '', b.attributes, b), + ); + } + if (b.attributes['caption'] case final caption?) { + element.nodes.add(_el('figcaption', text: caption)); + } + case BusyBlockKind.video: + final src = b.attributes['src'] ?? ''; + final external = HtmlExportLinks.external(src); + if (external != null) { + _warn('asset.remote', 'Remote video remains an external link.', b); + element = _el( + 'p', + children: [ + _el( + 'a', + text: b.attributes['title'] ?? external, + attrs: {'href': external}, + ), + ], + ); + } else { + final url = await links.assets.local( + src, + sourcePath: links.source(page, b.attributes), + searchRoots: links.roots(page, b.attributes), + line: b.sourceSpan?.startLine ?? 1, + ); + if (url == null) { + element = _el( + 'p', + text: b.attributes['title'] ?? 'Video unavailable', + ); + } else { + element = _el( + 'video', + attrs: {'src': url, 'controls': '', 'preload': 'metadata'}, + children: [ + _el( + 'a', + text: b.attributes['title'] ?? p.basename(src), + attrs: {'href': url}, + ), + ], + ); + } + } + case BusyBlockKind.writersideAdmonition: + case BusyBlockKind.blockquote: + final style = + b.attributes['style'] ?? + (b.kind == BusyBlockKind.blockquote ? 'quote' : 'note'); + element = _el( + style == 'quote' ? 'blockquote' : 'aside', + attrs: { + 'class': + 'admonition ${const {'tip', 'note', 'warning', 'quote'}.contains(style) ? style : 'note'}', + }, + children: [ + if (style != 'quote') + _el( + 'p', + attrs: {'class': 'admonition-title'}, + text: b.attributes['title'] ?? style, + ), + ...await _inlines(b.inlines, b), + ...await _blocks(b.children, depth + 1), + ], + ); + case BusyBlockKind.writersideProcedure: + element = _el( + 'section', + attrs: {'class': 'procedure'}, + children: [ + if (b.plainText.isNotEmpty) + _el('h3', children: await _inlines(b.inlines, b)), + ...await _blocks(b.children, depth + 1), + ], + ); + case BusyBlockKind.writersideTabs: + if (b.attributes['topic-switcher'] == 'true') return []; + element = _el( + 'section', + attrs: { + 'class': b.attributes['element'] == 'tab' ? 'tab-panel' : 'tabs', + }, + children: [ + if (b.plainText.trim().isNotEmpty || b.attributes['title'] != null) + _el('h3', text: b.attributes['title'] ?? b.plainText), + ...await _blocks(b.children, depth + 1), + ], + ); + case BusyBlockKind.writersideRawXml: + final kind = b.attributes['element']; + if (kind == 'deflist') { + element = _el('dl'); + for (final child in b.children) { + element.nodes.add( + _el('dt', children: await _inlines(child.inlines, child)), + ); + final definition = _el('dd'); + final content = await _blocks(child.children, depth + 1); + if (busyMarkWritersideIsCollapsible(child.attributes)) { + definition.nodes.add( + _el( + 'details', + attrs: { + if (busyMarkWritersideInitiallyExpanded(child.attributes)) + 'open': '', + }, + children: [ + _el( + 'summary', + text: + child.attributes['collapsed-title'] ?? + disclosureLabel, + ), + ...content, + ], + ), + ); + } else { + definition.nodes.addAll(content); + } + _attributes(definition, child.attributes); + element.nodes.add(definition); + } + } else if (b.children.isNotEmpty) { + element = _el( + 'section', + children: [ + ...await _inlines(b.inlines, b), + ...await _blocks(b.children, depth + 1), + ], + ); + } else { + _warn( + 'content.unsupported', + 'Unsupported content is shown as source.', + b, + ); + element = _el('pre', text: b.rawSource ?? b.plainText); + } + case BusyBlockKind.htmlBlock: + element = _el( + b.attributes['htmlTag'] == 'figure' ? 'figure' : 'section', + attrs: { + if (b.attributes['writerside-card'] == 'true') 'class': 'card', + }, + children: [ + ...await _inlines(b.inlines, b), + ...await _blocks(b.children, depth + 1), + ], + ); + case BusyBlockKind.unknown: + _warn( + 'content.unsupported', + 'Unsupported content is shown as source.', + b, + ); + element = _el( + 'pre', + attrs: {'class': 'unsupported'}, + text: b.rawSource ?? b.plainText, + ); + element.nodes.addAll(await _blocks(b.children, depth + 1)); + case BusyBlockKind.unorderedListItem: + case BusyBlockKind.orderedListItem: + case BusyBlockKind.taskListItem: + return _blocks([b], depth); + case BusyBlockKind.frontMatter: + return []; + } + _attributes(element, b.attributes); + if (b.attributes['switcher-key'] case final key?) { + return [ + _el( + 'section', + attrs: {'class': 'switcher-section'}, + children: [ + _el('p', text: key, attrs: {'class': 'variant-label'}), + element, + ], + ), + ]; + } + return [element]; + } + + Future _table( + BusyBlock b, + int depth, { + BusyBlock? caption, + }) async { + final table = _el('table'); + _attributes(table, b.attributes); + if (caption != null) { + table.nodes.add( + _el('caption', children: await _inlines(caption.inlines, caption)), + ); + } + final head = _el('thead'), body = _el('tbody'); + for (final row in b.children) { + final tr = _el('tr'); + final header = row.attributes['header'] == 'true'; + for (final cell in row.children) { + final isHeader = + cell.attributes['cell'] == 'th' || + cell.attributes['header'] == 'true' || + (header && cell.attributes['header'] != 'false'); + final td = _el( + isHeader ? 'th' : 'td', + attrs: {if (isHeader) 'scope': header ? 'col' : 'row'}, + children: [ + ...await _inlines(cell.inlines, cell), + ...await _blocks(cell.children, depth + 1), + ], + ); + _attributes(td, cell.attributes); + for (final name in ['rowspan', 'colspan']) { + final n = int.tryParse(cell.attributes[name] ?? ''); + if (n != null && n > 0 && n <= 1000) td.attributes[name] = '$n'; + } + final align = cell.attributes['align']; + if ({'left', 'center', 'right'}.contains(align)) { + td.classes.add('align-$align'); + } + _dimension( + td, + cell.attributes['width'] ?? cell.attributes['column-width'], + 'width', + ); + tr.nodes.add(td); + } + (header && body.nodes.isEmpty ? head : body).nodes.add(tr); + } + if (head.nodes.isNotEmpty) table.nodes.add(head); + table.nodes.add(body); + return _el( + 'div', + attrs: {'class': 'table-scroll', 'tabindex': '0'}, + children: [table], + ); + } + + void _dimension(dom.Element element, String? value, String name) { + if (value == null || + !RegExp(r'^\d{1,5}(?:\.\d{1,3})?(?:px|%)?$').hasMatch(value)) { + return; + } + final number = double.tryParse(value.replaceAll(RegExp(r'px|%'), '')); + if (number == null || + number <= 0 || + number > (value.endsWith('%') ? 100 : 20000)) { + return; + } + _style( + element, + '$name:${value.endsWith('%') || value.endsWith('px') ? value : '${value}px'};', + ); + } + + Future> _inlines( + List values, + BusyBlock block, [ + int depth = 0, + Map inherited = const {}, + ]) async { + if (depth > limits.depth) { + throw const HtmlExportException( + 'Inline nesting exceeds the export limit.', + ); + } + final out = []; + for (final value in values) { + final a = {...block.attributes, ...inherited, ...value.attributes}; + final nodes = value.children.isEmpty + ? [dom.Text(value.text)] + : await _inlines(value.children, block, depth + 1, a); + dom.Node node; + switch (value.kind) { + case BusyInlineKind.text: + node = dom.Text(value.text); + case BusyInlineKind.strong: + node = _el('strong', children: nodes); + case BusyInlineKind.emphasis: + node = _el('em', children: nodes); + case BusyInlineKind.underline: + final description = + a['tooltip-description'] ?? + a['resolved-description'] ?? + (a['element'] == 'tooltip' ? a['summary'] : null); + node = _el( + description == null ? 'u' : 'abbr', + children: nodes, + attrs: {if (description != null) 'title': description}, + ); + case BusyInlineKind.strikethrough: + node = _el('del', children: nodes); + case BusyInlineKind.code: + var text = value.text; + if (a['shortcut-layouts'] case final layouts?) { + try { + final map = jsonDecode(layouts) as Map; + if (map.length > 1) { + text = map.entries + .map((e) => '${e.key}: ${e.value}') + .join('; '); + } + } on Object { + /* Resolved primary label remains. */ + } + } + node = _el(a['element'] == 'shortcut' ? 'kbd' : 'code', text: text); + case BusyInlineKind.softBreak: + node = dom.Text('\n'); + case BusyInlineKind.hardBreak: + node = _el('br'); + case BusyInlineKind.image: + node = await _image(value.destination ?? '', value.text, a, block); + case BusyInlineKind.link: + final url = await links.resolve( + value.destination, + page, + a, + line: block.sourceSpan?.startLine ?? 1, + ); + if (url == null) { + node = _el('span', children: nodes); + } else { + node = _el( + 'a', + children: nodes, + attrs: { + 'href': url, + if (a['element'] == 'resource') + 'download': p.basename(value.text), + if (a['summary'] case final summary?) 'title': summary, + }, + ); + } + if (node is dom.Element) _attributes(node, value.attributes); + if (value.attributes['id']?.startsWith('fnref') == true) { + node = _el('sup', children: [node]); + } + case BusyInlineKind.math: + node = await _math(value.text, false, block); + case BusyInlineKind.html: + out.addAll(await _raw(value.text, block)); + continue; + case BusyInlineKind.writersideVariable: + case BusyInlineKind.unknown: + _warn( + 'content.unsupported', + 'Unresolved inline content is shown as source.', + block, + ); + node = _el('code', text: value.text); + } + if (node is dom.Element && value.kind != BusyInlineKind.link) { + _attributes(node, value.attributes); + } + if (value.attributes['switcher-key'] case final key?) { + node = _el('span', children: [dom.Text('[$key] '), node]); + } + out.add(node); + } + return out; + } + + Future _image( + String src, + String alt, + Map a, + BusyBlock block, + ) async { + final url = await links.assets.local( + src, + sourcePath: links.source(page, a), + searchRoots: links.roots(page, a), + line: block.sourceSpan?.startLine ?? 1, + ); + if (url == null) { + final external = HtmlExportLinks.external(src); + return _el( + 'span', + attrs: {'class': 'unavailable-image'}, + children: [ + if (external != null) + _el( + 'a', + text: alt.isEmpty ? external : alt, + attrs: {'href': external}, + ) + else + dom.Text( + alt.isEmpty ? 'Image unavailable: ${p.basename(src)}' : alt, + ), + ], + ); + } + final image = _el('img', attrs: {'src': url, 'alt': alt}); + if (a['title'] case final title?) image.attributes['title'] = title; + _dimension(image, a['width'], 'width'); + _dimension(image, a['height'], 'height'); + return image; + } + + Future _math( + String expression, + bool display, + BusyBlock block, + ) async { + final fontSize = block.kind == BusyBlockKind.heading + ? switch (block.attributes['level']) { + '1' => 39.1, + '2' => 29.75, + '3' => 22.1, + _ => 17.0, + } + : 17.0; + final image = await rich.formula( + expression, + display, + links.source(page, block.attributes), + block.sourceSpan?.startLine ?? 1, + fontSize: fontSize, + ); + if (image == null) { + return _el('code', text: expression, attrs: {'class': 'math-fallback'}); + } + final element = _el( + 'img', + attrs: { + 'src': image.url, + 'alt': expression, + 'class': display ? 'math-display' : 'math-inline', + }, + ); + if ([ + image.width, + image.height, + image.depth, + ].every((v) => v.isFinite && v.abs() < 20000)) { + _style( + element, + 'width:${image.width / fontSize}em;height:${image.height / fontSize}em;${display ? '' : 'vertical-align:-${image.depth / fontSize}em;'}', + ); + } + return element; + } + + /// Narrow HTML adapter: supported structure survives, attributes never pass + /// through unchecked. Rejected elements remain visible as escaped source. + Future> _raw(String source, BusyBlock block) async { + final fragment = parser.parseFragment(source); + Future> nodes(Iterable values, int depth) async { + if (depth > limits.depth) { + throw const HtmlExportException( + 'Raw HTML nesting exceeds the export limit.', + ); + } + final out = []; + for (final value in values) { + if (++_rawNodes > 50000) { + throw const HtmlExportException('Raw HTML exceeds the node limit.'); + } + if (value is dom.Text) { + out.add(dom.Text(value.data)); + continue; + } + if (value is! dom.Element) continue; + final tag = value.localName!; + if (!safeHtmlTags.contains(tag)) { + _warn( + 'html.unsupported', + 'Unsafe or unsupported HTML is shown as source.', + block, + ); + out.add(_el('code', text: value.outerHtml)); + continue; + } + final attrs = value.attributes.map((k, v) => MapEntry(k.toString(), v)); + if (attrs.keys.any( + (name) => + name.startsWith('on') || + {'style', 'srcdoc', 'srcset'}.contains(name), + )) { + _warn( + 'html.attributes', + 'Active HTML attributes were omitted.', + block, + ); + } + if (tag == 'img') { + out.add( + await _image(attrs['src'] ?? '', attrs['alt'] ?? '', { + ...block.attributes, + ...attrs, + }, block), + ); + continue; + } + final element = _el(tag, children: await nodes(value.nodes, depth + 1)); + _attributes(element, attrs); + if (tag == 'a') { + final url = await links.resolve(attrs['href'], page, { + ...block.attributes, + ...attrs, + }, line: block.sourceSpan?.startLine ?? 1); + if (url != null) element.attributes['href'] = url; + } + if (tag == 'details') { + if (attrs.containsKey('open')) element.attributes['open'] = ''; + if (!element.children.any((e) => e.localName == 'summary')) { + element.nodes.insert(0, _el('summary', text: disclosureLabel)); + } + } + for (final name in switch (tag) { + 'ol' => ['start'], + 'li' => ['value'], + 'td' || 'th' => ['rowspan', 'colspan'], + _ => [], + }) { + final n = int.tryParse(attrs[name] ?? ''); + if (n != null && + n.abs() <= 10000 && + (!name.endsWith('span') || n > 0)) { + element.attributes[name] = '$n'; + } + } + if (tag == 'th' && + {'row', 'col', 'rowgroup', 'colgroup'}.contains(attrs['scope'])) { + element.attributes['scope'] = attrs['scope']!; + } + if (tag == 'code' && + RegExp( + r'^language-[A-Za-z0-9_+-]{1,40}$', + ).hasMatch(attrs['class'] ?? '')) { + element.attributes['class'] = attrs['class']!; + } + if (attrs['class'] == 'footnotes') { + element.classes.add('footnotes'); + element.attributes['role'] = 'doc-endnotes'; + } + if ({'left', 'center', 'right'}.contains(attrs['align'])) { + element.classes.add('align-${attrs['align']}'); + } + _dimension(element, attrs['width'], 'width'); + out.add(element); + } + return out; + } + + return nodes(fragment.nodes, 0); + } + + /// OpenAPI already has a structured static representation. Only that output + /// uses this adapter; ordinary Markdown and Writerside never use the PDF mapper. + Future _reference( + MarkdownExportBlock block, + BusyBlock owner, + int depth, + ) async { + if (depth > limits.depth) { + throw const HtmlExportException( + 'API reference nesting exceeds the export limit.', + ); + } + Future> inline(List values) async => + _inlines([for (final i in values) _apiInline(i)], owner); + final tag = switch (block.kind) { + MarkdownExportBlockKind.heading => + 'h${((block.attributes['level'] as int?) ?? 2).clamp(1, 6)}', + MarkdownExportBlockKind.paragraph => 'p', + MarkdownExportBlockKind.code => 'pre', + MarkdownExportBlockKind.table => 'table', + MarkdownExportBlockKind.tableRow => 'tr', + MarkdownExportBlockKind.tableCell => + block.attributes['header'] == true ? 'th' : 'td', + MarkdownExportBlockKind.list => + block.attributes['ordered'] == true ? 'ol' : 'ul', + MarkdownExportBlockKind.listItem => 'li', + MarkdownExportBlockKind.thematicBreak => 'hr', + MarkdownExportBlockKind.blockquote => 'blockquote', + _ => 'section', + }; + final element = _el( + tag, + children: [ + if (block.text.isNotEmpty) dom.Text(block.text), + ...await inline(block.inlines), + ], + ); + if (block.kind == MarkdownExportBlockKind.code) { + final contents = element.nodes.toList(); + element.nodes.clear(); + final language = block.attributes['language']?.toString() ?? ''; + element.nodes.add( + _el( + 'code', + children: contents, + attrs: { + if (RegExp(r'^[a-zA-Z0-9_+-]{1,32}$').hasMatch(language)) + 'class': 'language-$language', + }, + ), + ); + } + if (block.kind == MarkdownExportBlockKind.heading) { + final base = slugForHeading(element.text).isEmpty + ? 'api-section' + : slugForHeading(element.text); + var id = base; + var suffix = 2; + while (page.ids.contains(id)) { + id = '$base-${suffix++}'; + } + page.ids.add(id); + _attributes(element, {'id': id}); + page.outline.add(( + id: id, + title: element.text, + level: int.parse(tag.substring(1)), + )); + } + final children = [ + for (final child in block.children) + await _reference(child, owner, depth + 1), + ]; + if (tag == 'table') { + final head = _el('thead'); + final body = _el('tbody'); + for (final row in children) { + (body.nodes.isEmpty && row.querySelector('th') != null ? head : body) + .nodes + .add(row); + } + if (head.nodes.isNotEmpty) element.nodes.add(head); + element.nodes.add(body); + } else { + element.nodes.addAll(children); + } + if (tag == 'table') { + return _el( + 'div', + attrs: {'class': 'table-scroll', 'tabindex': '0'}, + children: [element], + ); + } + return element; + } + + BusyInline _apiInline(MarkdownExportInline value) => BusyInline( + kind: BusyInlineKind.values.byName(value.kind.name), + text: value.text, + destination: value.destination, + attributes: value.attributes, + children: value.children.map(_apiInline).toList(), + ); + + void _validateBoundary(dom.Element root) { + for (final element in [root, ...root.querySelectorAll('*')]) { + if ({ + 'script', + 'iframe', + 'object', + 'embed', + 'form', + 'base', + 'link', + }.contains(element.localName)) { + throw const HtmlExportException( + 'Unsafe element at the HTML output boundary.', + ); + } + for (final entry in element.attributes.entries) { + final key = entry.key.toString(); + if (key.startsWith('on') || + key == 'style' || + key.startsWith('busymark-source')) { + throw const HtmlExportException( + 'Unsafe attribute at the HTML output boundary.', + ); + } + if (key == 'href' || key == 'src') { + final value = entry.value; + if (HtmlExportLinks.external(value) != null && key == 'href') { + continue; + } + final uri = Uri.tryParse(value); + if (uri == null || + uri.hasScheme || + uri.hasAuthority || + uri.path.startsWith('/') || + uri.path.split('/').contains('..')) { + throw const HtmlExportException( + 'Non-portable URL at the HTML output boundary.', + ); + } + } + } + } + } +} diff --git a/lib/src/export/html_export_assets.dart b/lib/src/export/html_export_assets.dart new file mode 100644 index 00000000..d8d3caad --- /dev/null +++ b/lib/src/export/html_export_assets.dart @@ -0,0 +1,277 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:crypto/crypto.dart'; +import 'package:path/path.dart' as p; +import 'package:xml/xml.dart'; +import '../visualization/generated_svg_normalizer.dart'; +import 'markdown_export_assets.dart'; +import 'html_export_models.dart'; + +/// One export's immutable, validated asset snapshot, keyed by content. +class HtmlExportAssets { + HtmlExportAssets({ + required this.directory, + required this.urlDirectory, + required this.allowedRoots, + required this.token, + required this.warnings, + this.limits = const HtmlExportLimits(), + }); + final Directory directory; + final String urlDirectory; + final List allowedRoots; + final HtmlExportCancellationToken token; + final List warnings; + final HtmlExportLimits limits; + final Map _references = {}; + final Set filenames = {}; + int _total = 0; + + Future local( + String reference, { + required String sourcePath, + List searchRoots = const [], + int line = 1, + bool download = false, + }) async { + token.check(); + final key = + '$sourcePath\u0000${searchRoots.join('\u0000')}\u0000$download\u0000$reference'; + if (_references.containsKey(key)) return _references[key]; + String? result; + try { + final uri = Uri.tryParse(reference); + if (uri == null || + (uri.hasScheme && uri.scheme != 'file') || + uri.hasAuthority) { + throw const HtmlExportException( + 'Remote or unsupported resource was not packaged.', + ); + } + final path = uri.scheme == 'file' + ? uri.toFilePath() + : Uri.decodeComponent(uri.path); + final candidates = p.isAbsolute(path) + ? [path] + : [ + p.join(p.dirname(sourcePath), path), + for (final root in searchRoots) p.join(root, path), + ]; + File? found; + for (final candidate in candidates) { + try { + final canonical = await File(candidate).resolveSymbolicLinks(); + if (!allowedRoots.any((root) => p.isWithin(root, canonical))) { + continue; + } + if (await FileSystemEntity.type(canonical, followLinks: false) == + FileSystemEntityType.file) { + found = File(canonical); + break; + } + } on FileSystemException { + /* Try the next configured root. */ + } + } + if (found == null) { + throw const HtmlExportException( + 'Resource is missing or outside the allowed source roots.', + ); + } + if (await found.length() > limits.assetBytes) { + throw const HtmlExportException( + 'Resource exceeds the asset size limit.', + ); + } + final bytes = await found.readAsBytes(); + result = await bytesAsset( + bytes, + p.extension(found.path).toLowerCase(), + download: download, + ); + } on Object catch (error) { + token.check(); + warnings.add( + HtmlExportWarning( + 'asset.unavailable', + '${p.basename(reference)}: ${error is HtmlExportException ? error.message : 'Resource could not be read.'}', + sourcePath: sourcePath, + line: line, + ), + ); + } + _references[key] = result; + return result; + } + + Future bytesAsset( + List input, + String extension, { + bool download = false, + }) async { + token.check(); + if (extension == '.jpeg') extension = '.jpg'; + var bytes = input; + if (extension == '.svg') bytes = utf8.encode(safeSvg(utf8.decode(input))); + final signature = const MarkdownExportAssetStager().hasExpectedFormat( + bytes, + extension, + ); + final media = + (extension == '.webp' && + bytes.length > 12 && + ascii.decode(bytes.sublist(0, 4), allowInvalid: true) == 'RIFF' && + ascii.decode(bytes.sublist(8, 12), allowInvalid: true) == 'WEBP') || + (extension == '.mp4' && + bytes.length > 12 && + ascii.decode(bytes.sublist(4, 8), allowInvalid: true) == 'ftyp') || + (extension == '.webm' && + bytes.length > 4 && + bytes[0] == 0x1a && + bytes[1] == 0x45 && + bytes[2] == 0xdf && + bytes[3] == 0xa3); + final attachment = + download && + const { + '.pdf', + '.zip', + '.txt', + '.csv', + '.json', + '.yaml', + '.yml', + }.contains(extension); + if (!signature && !media && !attachment) { + throw const HtmlExportException( + 'Unsupported or invalid resource format.', + ); + } + if (bytes.length > limits.assetBytes) { + throw const HtmlExportException('Resource exceeds the asset size limit.'); + } + final name = '${sha256.convert(bytes)}$extension'; + if (!filenames.contains(name)) { + if (filenames.length >= limits.assets || + _total + bytes.length > limits.totalAssetBytes) { + throw const HtmlExportException('The export asset limit was reached.'); + } + await directory.create(recursive: true); + await File(p.join(directory.path, name)).writeAsBytes(bytes, flush: true); + filenames.add(name); + _total += bytes.length; + } + return '${Uri.encodeComponent(urlDirectory)}/${Uri.encodeComponent(name)}'; + } + + static String safeSvg(String source) { + // Reject active SVG before normalizing. Never silently accept a stripped script. + if (RegExp( + r'(), + ]; + if (elements.length > 50000) { + throw const HtmlExportException('SVG is too complex.'); + } + for (final el in elements) { + if (!tags.contains(el.name.local)) { + throw const HtmlExportException('Unsafe or unsupported SVG element.'); + } + for (final a in el.attributes) { + final name = a.name.local.toLowerCase(); + if (name.startsWith('on') || + name == 'base' || + ((name == 'href' || name == 'src') && !a.value.startsWith('#'))) { + throw const HtmlExportException( + 'SVG contains an active or external reference.', + ); + } + if ({ + 'style', + 'fill', + 'stroke', + 'filter', + 'clip-path', + 'mask', + 'cursor', + 'font-family', + 'marker-start', + 'marker-mid', + 'marker-end', + }.contains(name)) { + _safeCss(a.value); + } + } + if (el.name.local == 'style') _safeCss(el.innerText); + } + final normalized = const GeneratedSvgNormalizer().normalize(source); + final safe = normalized.vectorSafeSvg; + if (safe == null || normalized.hasForeignObject) { + throw const HtmlExportException( + 'SVG cannot be packaged as a standalone image.', + ); + } + return safe; + } + + static void _safeCss(String value) { + if (value.contains('\\') || + RegExp( + r'@|expression\s*\(|-moz-binding|javascript:', + caseSensitive: false, + ).hasMatch(value)) { + throw const HtmlExportException('Unsafe SVG CSS.'); + } + for (final match in RegExp( + r'''url\(\s*['"]?([^)'"\s]+)''', + caseSensitive: false, + ).allMatches(value)) { + if (!match.group(1)!.startsWith('#')) { + throw const HtmlExportException('SVG references an external resource.'); + } + } + } +} diff --git a/lib/src/export/html_export_links.dart b/lib/src/export/html_export_links.dart new file mode 100644 index 00000000..acee34b1 --- /dev/null +++ b/lib/src/export/html_export_links.dart @@ -0,0 +1,158 @@ +import 'package:path/path.dart' as p; +import '../writerside/writerside_document.dart'; +import '../writerside/writerside_model.dart'; +import 'html_export_assets.dart'; +import 'html_export_models.dart'; +import 'html_publication_plan.dart'; + +class HtmlExportLinks { + HtmlExportLinks({ + required this.plan, + required this.assets, + required this.warnings, + this.modules = const [], + }); + final HtmlPublicationPlan plan; + final HtmlExportAssets assets; + final List warnings; + final List modules; + + String source(HtmlPage page, Map attributes) => + attributes[writersideSourceTopicPathAttribute] ?? page.sourcePath; + List roots(HtmlPage page, Map attributes) { + final root = attributes[writersideSourceModuleRootAttribute]; + final module = + modules + .where((m) => root != null && p.equals(m.rootPath, root)) + .firstOrNull ?? + page.module; + return module == null + ? [] + : [ + p.join(module.rootPath, module.effectiveImagesDir), + if (module.config.resourcesDir case final dir?) + p.join(module.rootPath, dir), + module.rootPath, + ]; + } + + static String? external(String value) { + if (RegExp(r'[\x00-\x20\x7f\\]').hasMatch(value)) return null; + final uri = Uri.tryParse(value); + if (uri == null || + !{ + 'https', + 'http', + 'mailto', + 'tel', + }.contains(uri.scheme.toLowerCase())) { + return null; + } + if ((uri.scheme == 'https' || uri.scheme == 'http') && uri.host.isEmpty) { + return null; + } + return uri.toString(); + } + + Future resolve( + String? value, + HtmlPage page, + Map attributes, { + int line = 1, + }) async { + if (value == null || value.trim().isEmpty) return null; + final destination = value.trim(); + if (external(destination) case final url?) return url; + final origin = source(page, attributes); + void warn(String message) => warnings.add( + HtmlExportWarning( + 'link.unresolved', + message, + sourcePath: origin, + line: line, + ), + ); + if (attributes['nullable'] == 'true' && + attributes['resolved-available'] == 'false') { + return null; + } + if (attributes['element'] == 'resource') { + return assets.local( + destination, + sourcePath: origin, + searchRoots: roots(page, attributes), + line: line, + download: true, + ); + } + final uri = Uri.tryParse(destination); + if (uri == null || + uri.hasScheme || + uri.hasAuthority || + RegExp(r'[\x00-\x1f\\]').hasMatch(destination)) { + warn('Unsafe or unsupported link destination was omitted.'); + return null; + } + var fragment = Uri.decodeComponent(uri.fragment); + final path = uri.path; + HtmlPage? target; + if (path.isEmpty) { + target = page; + if (!page.ids.contains(fragment) && origin != page.sourcePath) { + target = plan.pageForSource(origin); + } + } else { + final absolute = p.normalize( + p.isAbsolute(path) + ? path + : p.join(p.dirname(origin), Uri.decodeComponent(path)), + ); + target = plan.pageForSource(absolute); + if (target == null && page.module != null) { + final module = + modules + .where( + (m) => + m.rootPath == + attributes[writersideSourceModuleRootAttribute], + ) + .firstOrNull ?? + page.module!; + final topic = module.topicByReference(Uri.decodeComponent(path)); + if (topic != null) target = plan.pageForSource(topic.filePath); + } + } + if (target != null) { + if (!target.ids.contains(fragment) && target.ids.contains(uri.fragment)) { + fragment = uri.fragment; + } + if (fragment.isNotEmpty && !target.ids.contains(fragment)) { + warn('Missing anchor "$fragment" in ${p.basename(target.sourcePath)}.'); + return null; + } + return '${target == page ? (fragment.isEmpty ? Uri.encodeComponent(target.filename) : '') : Uri.encodeComponent(target.filename)}${fragment.isEmpty ? '' : '#${Uri.encodeComponent(fragment)}'}'; + } + if (attributes['nullable'] == 'true') return null; + if (const { + '.md', + '.markdown', + '.topic', + '.html', + '.htm', + }.contains(p.extension(path).toLowerCase())) { + warn('Linked document ${p.basename(path)} is outside this export.'); + return null; + } + final asset = await assets.local( + destination, + sourcePath: origin, + searchRoots: roots(page, attributes), + line: line, + download: true, + ); + if (asset == null) { + warn('Link target ${p.basename(path)} could not be resolved.'); + } + return asset; + } +} diff --git a/lib/src/export/html_export_models.dart b/lib/src/export/html_export_models.dart new file mode 100644 index 00000000..b48d2078 --- /dev/null +++ b/lib/src/export/html_export_models.dart @@ -0,0 +1,105 @@ +import '../markdown/markdown_model.dart'; +import '../markdown/busymark_document.dart'; + +class HtmlExportWarning { + const HtmlExportWarning( + this.code, + this.message, { + this.sourcePath = '', + this.line = 1, + }); + final String code; + final String message; + final String sourcePath; + final int line; + @override + String toString() => + '${sourcePath.isEmpty ? '' : '$sourcePath:$line: '}$message'; +} + +class HtmlExportException implements Exception { + const HtmlExportException(this.message, {this.cancelled = false}); + final String message; + final bool cancelled; + @override + String toString() => message; +} + +class HtmlExportCancellationToken { + bool _cancelled = false; + final Set _listeners = {}; + bool get isCancelled => _cancelled; + void cancel() { + _cancelled = true; + for (final listener in _listeners.toList()) { + listener(); + } + } + + void attach(void Function() listener) { + _listeners.add(listener); + if (_cancelled) listener(); + } + + void detach(void Function() listener) => _listeners.remove(listener); + void check() { + if (_cancelled) { + throw const HtmlExportException( + 'HTML export cancelled.', + cancelled: true, + ); + } + } +} + +class HtmlExportLimits { + const HtmlExportLimits({ + this.topics = 2000, + this.sourceBytes = 64 * 1024 * 1024, + this.assetBytes = 16 * 1024 * 1024, + this.totalAssetBytes = 128 * 1024 * 1024, + this.assets = 2048, + this.graphics = 512, + this.depth = 64, + this.renderTimeout = const Duration(seconds: 45), + }); + final int topics, + sourceBytes, + assetBytes, + totalAssetBytes, + assets, + graphics, + depth; + final Duration renderTimeout; +} + +class MarkdownHtmlExportRequest { + const MarkdownHtmlExportRequest({ + required this.source, + required this.filePath, + required this.workspaceRoot, + required this.destinationPath, + this.overwrite = false, + this.mode = MarkdownMode.commonMark, + this.document, + }); + final String source, filePath, workspaceRoot, destinationPath; + final bool overwrite; + final MarkdownMode mode; + final BusyDocument? document; +} + +class HtmlExportResult { + const HtmlExportResult({ + required this.entryPointPath, + required this.warnings, + this.assetsPath, + this.pageCount = 1, + }); + final String entryPointPath; + final String? assetsPath; + final int pageCount; + final List warnings; +} + +typedef HtmlExportProgress = void Function(int completed, int total); diff --git a/lib/src/export/html_export_publisher.dart b/lib/src/export/html_export_publisher.dart new file mode 100644 index 00000000..1add12ca --- /dev/null +++ b/lib/src/export/html_export_publisher.dart @@ -0,0 +1,254 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:crypto/crypto.dart'; +import 'package:path/path.dart' as p; +import '../core/atomic_file_writer.dart'; +import '../core/linux_atomic_file_api.dart'; +import 'html_export_models.dart'; + +const htmlExportManifest = '.busymark-html-export.json'; + +class HtmlExportPublisher { + const HtmlExportPublisher({this.fileWriter = const AtomicFileWriter()}); + final AtomicFileWriter fileWriter; + + Future staging(String destination) async { + final parent = Directory(p.dirname(p.absolute(destination))); + if (!await parent.exists()) { + throw const HtmlExportException( + 'The destination parent directory does not exist.', + ); + } + return parent.createTemp('.busymark-html-'); + } + + Future publishDocument({ + required Directory stage, + required String destination, + required String html, + required String assetsName, + required bool overwrite, + required HtmlExportCancellationToken token, + }) async { + token.check(); + final type = await FileSystemEntity.type(destination, followLinks: false); + if (type != FileSystemEntityType.notFound && !overwrite) { + throw const HtmlExportException( + 'The destination already exists. Confirm overwrite to replace it.', + ); + } + if (type != FileSystemEntityType.notFound && + type != FileSystemEntityType.file) { + throw const HtmlExportException( + 'The HTML destination must be a regular file.', + ); + } + final stagedAssets = Directory(p.join(stage.path, assetsName)); + if (await stagedAssets.exists()) { + final target = Directory(p.join(p.dirname(destination), assetsName)); + final targetType = await FileSystemEntity.type( + target.path, + followLinks: false, + ); + if (targetType == FileSystemEntityType.notFound) { + await _manifest(stagedAssets, 'assets'); + _publishDirectory(stagedAssets.path, target.path); + } else { + await _verifyOwned(target, 'assets'); + // Immutable names ensure an old entry point remains valid throughout. + await for (final entity in stagedAssets.list(followLinks: false)) { + token.check(); + if (entity is! File) { + throw const HtmlExportException('Invalid staged asset.'); + } + final targetPath = p.join(target.path, p.basename(entity.path)); + if (!await File(targetPath).exists()) { + await fileWriter.writeBytes( + targetPath, + await entity.readAsBytes(), + overwrite: false, + ); + } + } + // Assets are append-only; the ownership marker is stable and no previous + // files are removed. Each filename is verified against its content hash. + } + } + token.check(); + await fileWriter.writeBytes( + destination, + utf8.encode(html), + overwrite: overwrite, + ); + } + + Future publishSite({ + required Directory stage, + required String destination, + required bool overwrite, + required HtmlExportCancellationToken token, + }) async { + await _manifest(stage, 'site'); + token.check(); + final type = await FileSystemEntity.type(destination, followLinks: false); + if (type == FileSystemEntityType.notFound) { + _publishDirectory(stage.path, destination); + return; + } + if (!overwrite) { + throw const HtmlExportException( + 'The destination already exists. Confirm overwrite to replace it.', + ); + } + final previous = Directory(destination); + final identity = await _verifyOwned(previous, 'site'); + token.check(); + final api = LinuxAtomicFileApi.instance; + if (!api.isAvailable) { + throw const HtmlExportException( + 'Atomic directory replacement is unavailable on this system. Choose a new destination.', + ); + } + final error = api.exchange(stage.path, destination); + if (error != null) { + throw HtmlExportException( + 'Could not atomically replace the HTML export (system error $error).', + ); + } + // Verify the exchanged directory too, protecting a concurrently changed target. + try { + if (await _verifyOwned(stage, 'site') != identity) { + throw const HtmlExportException( + 'The destination changed during export.', + ); + } + } on Object { + final rollback = api.exchange(stage.path, destination); + if (rollback != null) { + throw HtmlExportRecoveryException(stage.path); + } + rethrow; + } + } + + void _publishDirectory(String source, String target) { + final api = LinuxAtomicFileApi.instance; + if (!api.isAvailable) { + throw const HtmlExportException( + 'Atomic directory publication is unavailable.', + ); + } + final error = api.publishNoReplace(source, target, directory: true); + if (error != null) { + throw HtmlExportException( + 'Could not publish the export directory (system error $error).', + ); + } + } + + Future _manifest(Directory directory, String kind) async { + final files = {}; + await for (final entity in directory.list( + recursive: true, + followLinks: false, + )) { + if (entity is Link) { + throw const HtmlExportException( + 'Export output must not contain symlinks.', + ); + } + if (entity is File) { + files[p.relative(entity.path, from: directory.path)] = sha256 + .convert(await entity.readAsBytes()) + .toString(); + } + } + await File(p.join(directory.path, htmlExportManifest)).writeAsString( + jsonEncode({ + 'owner': 'BusyMark HTML export', + 'version': 1, + 'kind': kind, + 'files': files, + }), + flush: true, + ); + } + + Future _verifyOwned(Directory directory, String kind) async { + if (await FileSystemEntity.type(directory.path, followLinks: false) != + FileSystemEntityType.directory) { + throw const HtmlExportException( + 'The destination is not an exporter-owned directory.', + ); + } + final marker = File(p.join(directory.path, htmlExportManifest)); + if (await FileSystemEntity.type(marker.path, followLinks: false) != + FileSystemEntityType.file || + await marker.length() > 1024 * 1024) { + throw const HtmlExportException( + 'The destination is not an exporter-owned directory. Choose a dedicated export directory.', + ); + } + final source = await marker.readAsString(); + final manifest = jsonDecode(source); + if (manifest is! Map || + manifest['owner'] != 'BusyMark HTML export' || + manifest['kind'] != kind || + manifest['version'] != 1 || + manifest['files'] is! Map) { + throw const HtmlExportException('Invalid export ownership marker.'); + } + final expected = Map.from(manifest['files'] as Map); + var count = 0; + var bytes = 0; + await for (final entity in directory.list( + recursive: true, + followLinks: false, + )) { + if (++count > 10000 || entity is Link) { + throw const HtmlExportException( + 'The destination contains unsupported user files.', + ); + } + if (entity is Directory) { + if (kind != 'site' || + p.relative(entity.path, from: directory.path) != 'assets') { + throw const HtmlExportException( + 'The destination contains an unexpected directory.', + ); + } + } + if (entity is! File || entity.path == marker.path) continue; + final name = p.relative(entity.path, from: directory.path); + final length = await entity.length(); + bytes += length; + if (length > 256 * 1024 * 1024 || bytes > 1024 * 1024 * 1024) { + throw const HtmlExportException( + 'The previous directory exceeds ownership verification limits. Choose a new destination.', + ); + } + final digest = sha256.convert(await entity.readAsBytes()).toString(); + if (kind == 'assets' + ? !RegExp('^$digest\\.[a-z0-9]+\$').hasMatch(name) + : expected.remove(name) != digest) { + throw const HtmlExportException( + 'The previous export contains changed or unowned files. Choose a new destination to preserve them.', + ); + } + } + if (kind == 'site' && expected.isNotEmpty) { + throw const HtmlExportException( + 'The previous export is incomplete. Choose a new destination.', + ); + } + return sha256.convert(utf8.encode(source)).toString(); + } +} + +/// Cleanup must retain the displaced directory if even rollback is unavailable. +class HtmlExportRecoveryException extends HtmlExportException { + HtmlExportRecoveryException(String stagePath) + : super( + 'Directory replacement could not be rolled back. The previous output is retained at $stagePath.', + ); +} diff --git a/lib/src/export/html_export_service.dart b/lib/src/export/html_export_service.dart new file mode 100644 index 00000000..158dbda6 --- /dev/null +++ b/lib/src/export/html_export_service.dart @@ -0,0 +1,418 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:flutter/services.dart'; +import 'package:html/parser.dart' as html; +import 'package:path/path.dart' as p; +import '../markdown/busymark_document.dart'; +import '../markdown/markdown_parser.dart'; +import '../math/math_coordinator.dart'; +import '../visualization/visualization_coordinator.dart'; +import '../visualization/visualization_models.dart'; +import '../writerside/writerside_project.dart'; +import '../writerside/writerside_module_service.dart'; +import '../writerside/writerside_parsers.dart'; +import '../writerside/writerside_model.dart'; +import 'html_export_assets.dart'; +import 'html_export_links.dart'; +import 'html_export_models.dart'; +import 'html_export_publisher.dart'; +import 'html_publication_plan.dart'; +import 'html_document_writer.dart'; +import 'html_rich_content.dart'; + +class HtmlExportService { + const HtmlExportService({ + this.parser = const MarkdownParser(preserveHtmlSemantics: true), + this.publisher = const HtmlExportPublisher(), + this.limits = const HtmlExportLimits(), + this.math, + this.visualization, + this.stylesheetLoader = _stylesheet, + }); + final MarkdownParser parser; + final HtmlExportPublisher publisher; + final HtmlExportLimits limits; + final MathCoordinator? math; + final VisualizationCoordinator? visualization; + final Future Function() stylesheetLoader; + static Future _stylesheet() => + rootBundle.loadString('assets/export/html.css'); + + Future exportMarkdown( + MarkdownHtmlExportRequest request, { + HtmlExportCancellationToken? cancellationToken, + HtmlExportProgress? onProgress, + }) async { + final token = cancellationToken ?? HtmlExportCancellationToken(); + token.check(); + if (utf8.encode(request.source).length > limits.sourceBytes) { + throw const HtmlExportException( + 'The document exceeds the source byte limit.', + ); + } + final destination = p.normalize(p.absolute(request.destinationPath)); + if (!HtmlPublicationPlan.validFilename(p.basename(destination))) { + throw const HtmlExportException('Choose a valid .html filename.'); + } + final sourcePath = request.filePath.isEmpty + ? p.join( + request.workspaceRoot.isEmpty + ? p.dirname(destination) + : request.workspaceRoot, + 'untitled.md', + ) + : request.filePath; + final document = + request.document ?? + (await parser.parseAsync( + filePath: sourcePath, + source: request.source, + mode: request.mode, + workspaceRoot: request.workspaceRoot.isEmpty + ? null + : request.workspaceRoot, + validateLocalReferences: false, + )).busyDocument; + final warnings = []; + final page = HtmlPage( + document: document, + filename: p.basename(destination), + title: document.title ?? p.basenameWithoutExtension(sourcePath), + ); + prepareHtmlPage(page, warnings, limits); + final plan = HtmlPublicationPlan(pages: [page], startPage: page); + return _export( + plan, + destination, + site: false, + overwrite: request.overwrite, + roots: [ + if (request.filePath.isNotEmpty) p.dirname(request.filePath), + if (request.workspaceRoot.isNotEmpty) request.workspaceRoot, + ], + warnings: warnings, + token: token, + onProgress: onProgress, + ); + } + + /// Capture all modules and source trees before preparing any output. Callers + /// may pass a captured project when testing or exporting an already loaded snapshot. + Future exportWriterside({ + required String projectRoot, + required String moduleRoot, + required String instanceId, + required String destinationPath, + bool overwrite = false, + WritersideProject? capturedProject, + HtmlExportCancellationToken? cancellationToken, + HtmlExportProgress? onProgress, + }) async { + final token = cancellationToken ?? HtmlExportCancellationToken(); + token.check(); + final project = + capturedProject ?? + await const WritersideProjectService( + moduleService: WritersideModuleService( + topicParser: WritersideTopicParser( + markdownParser: MarkdownParser(preserveHtmlSemantics: true), + ), + ), + ).load(projectRoot, preferredModuleRoot: moduleRoot); + token.check(); + final module = project.modules + .where((m) => p.equals(m.rootPath, moduleRoot)) + .firstOrNull; + final instance = module?.instances + .where((i) => i.id == instanceId && !i.isLibrary) + .firstOrNull; + if (module == null || instance == null) { + throw const HtmlExportException( + 'Select a non-library Writerside instance.', + ); + } + final warnings = []; + final plan = HtmlPublicationPlan.writerside( + module: module, + instance: instance, + modulesByOrigin: project.modulesByOrigin, + warnings: warnings, + limits: limits, + ); + return _export( + plan, + p.normalize(p.absolute(destinationPath)), + site: true, + overwrite: overwrite, + roots: project.modules.map((m) => m.rootPath).toList(), + modules: project.modules, + warnings: warnings, + token: token, + onProgress: onProgress, + ); + } + + Future _export( + HtmlPublicationPlan plan, + String destination, { + required bool site, + required bool overwrite, + required List roots, + List modules = const [], + required List warnings, + required HtmlExportCancellationToken token, + HtmlExportProgress? onProgress, + }) async { + final stage = await publisher.staging(destination); + var retainStage = false; + try { + final canonicalRoots = []; + for (final root in roots.toSet()) { + try { + canonicalRoots.add(await Directory(root).resolveSymbolicLinks()); + } on FileSystemException { + /* Missing roots cannot authorize assets. */ + } + } + final assetName = site + ? 'assets' + : '${p.basenameWithoutExtension(destination)}.assets'; + final assets = HtmlExportAssets( + directory: Directory(p.join(stage.path, assetName)), + urlDirectory: assetName, + allowedRoots: canonicalRoots, + token: token, + warnings: warnings, + limits: limits, + ); + final links = HtmlExportLinks( + plan: plan, + assets: assets, + warnings: warnings, + modules: modules, + ); + // Snapshot all local media before the first potentially long render job. + for (final page in plan.pages) { + await _captureAssets(page, links, page.document.blocks, token); + } + final css = await stylesheetLoader(); + token.check(); + final rich = HtmlRichContent( + assets: assets, + token: token, + warnings: warnings, + exportId: p.basename(stage.path), + math: math, + visualization: visualization, + limits: limits, + ); + Future captureGraphics( + HtmlPage page, + List blocks, + ) async { + for (final block in blocks) { + if (block.kind == BusyBlockKind.codeBlock && + VisualizationDescriptor.maybeForFenceLanguage( + block.attributes['language'], + ) != + null) { + final source = links.source(page, block.attributes); + final roots = links.roots(page, block.attributes); + await rich.captureDiagram( + block, + source, + roots.isEmpty + ? (canonicalRoots.isEmpty + ? p.dirname(source) + : canonicalRoots.last) + : roots.last, + '${page.filename}:${block.id}', + ); + } + await captureGraphics(page, block.children); + } + } + + for (final page in plan.pages) { + await captureGraphics(page, page.document.blocks); + } + final outputs = {}; + for (final (index, page) in plan.pages.indexed) { + token.check(); + onProgress?.call(index, plan.pages.length); + outputs[page.filename] = await HtmlDocumentWriter( + page: page, + plan: plan, + links: links, + rich: rich, + stylesheet: css, + warnings: warnings, + limits: limits, + ).write(); + } + if (site) outputs['index.html'] = outputs[plan.startPage.filename]!; + _validateOutputs(outputs, assets); + token.check(); + if (site) { + for (final entry in outputs.entries) { + await File( + p.join(stage.path, entry.key), + ).writeAsString(entry.value, flush: true); + } + await publisher.publishSite( + stage: stage, + destination: destination, + overwrite: overwrite, + token: token, + ); + } else { + await publisher.publishDocument( + stage: stage, + destination: destination, + html: outputs.values.single, + assetsName: assetName, + overwrite: overwrite, + token: token, + ); + } + onProgress?.call(plan.pages.length, plan.pages.length); + return HtmlExportResult( + entryPointPath: site ? p.join(destination, 'index.html') : destination, + assetsPath: assets.filenames.isEmpty + ? null + : p.join(site ? destination : p.dirname(destination), assetName), + pageCount: plan.pages.length, + warnings: List.unmodifiable( + { + for (final warning in warnings) + '${warning.code}\u0000${warning.sourcePath}\u0000${warning.line}\u0000${warning.message}': + warning, + }.values, + ), + ); + } on HtmlExportRecoveryException { + retainStage = true; + rethrow; + } finally { + if (!retainStage && await stage.exists()) { + await stage.delete(recursive: true); + } + } + } + + Future _captureAssets( + HtmlPage page, + HtmlExportLinks links, + List blocks, + HtmlExportCancellationToken token, + ) async { + Future capture( + String? value, + Map attributes, + int line, { + bool download = false, + }) async { + if (value != null) { + await links.assets.local( + value, + sourcePath: links.source(page, attributes), + searchRoots: links.roots(page, attributes), + line: line, + download: download, + ); + } + } + + Future inlines( + List values, + Map inherited, + int line, + ) async { + for (final value in values) { + final attrs = {...inherited, ...value.attributes}; + if (value.kind == BusyInlineKind.image) { + await capture(value.destination, attrs, line); + } + if (value.kind == BusyInlineKind.link) { + await links.resolve(value.destination, page, attrs, line: line); + } + await inlines(value.children, attrs, line); + } + } + + for (final block in blocks) { + token.check(); + final line = block.sourceSpan?.startLine ?? 1; + await inlines(block.inlines, block.attributes, line); + if ({BusyBlockKind.video, BusyBlockKind.image}.contains(block.kind)) { + await capture(block.attributes['src'], block.attributes, line); + } + final raw = + block.attributes['html-footnotes'] ?? + (block.kind == BusyBlockKind.htmlBlock ? block.rawSource : null); + if (raw != null) { + for (final element + in html.parseFragment(raw).querySelectorAll('img,a')) { + final attrs = { + ...block.attributes, + ...element.attributes.map((k, v) => MapEntry(k.toString(), v)), + }; + if (element.localName == 'img') { + await capture(element.attributes['src'], attrs, line); + } else { + await links.resolve( + element.attributes['href'], + page, + attrs, + line: line, + ); + } + } + } + await _captureAssets(page, links, block.children, token); + } + } + + void _validateOutputs(Map outputs, HtmlExportAssets assets) { + final ids = { + for (final entry in outputs.entries) + entry.key: html + .parse(entry.value) + .querySelectorAll('[id]') + .map((e) => e.id) + .toSet(), + }; + var bytes = 0; + for (final entry in outputs.entries) { + bytes += utf8.encode(entry.value).length; + if (bytes > limits.sourceBytes * 4) { + throw const HtmlExportException( + 'Generated HTML exceeds the output byte limit.', + ); + } + final doc = html.parse(entry.value); + for (final element in doc.querySelectorAll('[href],[src]')) { + final value = element.attributes['href'] ?? element.attributes['src']!; + if (HtmlExportLinks.external(value) != null) continue; + final uri = Uri.parse(value); + final path = Uri.decodeComponent(uri.path); + if (path.startsWith('${assets.urlDirectory}/')) { + if (!assets.filenames.contains(p.posix.basename(path))) { + throw const HtmlExportException( + 'An output resource was not packaged.', + ); + } + } else { + final target = path.isEmpty ? entry.key : path; + if (!ids.containsKey(target) || + (uri.fragment.isNotEmpty && + !ids[target]!.contains(Uri.decodeComponent(uri.fragment)))) { + throw HtmlExportException( + 'An output link does not resolve: $value.', + ); + } + } + } + } + } +} diff --git a/lib/src/export/html_export_ui.dart b/lib/src/export/html_export_ui.dart new file mode 100644 index 00000000..00a604ae --- /dev/null +++ b/lib/src/export/html_export_ui.dart @@ -0,0 +1,308 @@ +import 'dart:async'; +import 'dart:io'; +import 'package:file_selector/file_selector.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:path/path.dart' as p; +import 'package:url_launcher/url_launcher.dart'; +import '../app/app_settings.dart'; +import '../app/busymark_design.dart'; +import '../app/busymark_dialogs.dart'; +import '../app/localization.dart'; +import '../math/math_providers.dart'; +import '../markdown/markdown_model.dart'; +import '../platform/linux_header_bar_service.dart'; +import '../visualization/visualization_providers.dart'; +import '../workspace/workspace_controller.dart'; +import '../workspace/workspace_model.dart'; +import '../workspace/workspace_safety.dart'; +import '../writerside/writerside_model.dart'; +import 'markdown_pdf_export_ui.dart' show canExportActiveMarkdown; +import 'writerside_pdf_export_ui.dart' show canExportWritersidePdf; +import 'html_export_models.dart'; +import 'html_export_service.dart'; + +final htmlExportServiceProvider = Provider( + (ref) => HtmlExportService( + math: ref.watch(mathCoordinatorProvider), + visualization: ref.watch(visualizationCoordinatorProvider), + ), +); + +bool canExportWorkspaceHtml(WorkspaceState state) => + canExportActiveMarkdown(state) || canExportWritersidePdf(state); + +Future exportWorkspaceToHtml(BuildContext context, WidgetRef ref) async { + var snapshot = ref.read(workspaceControllerProvider); + if (!canExportWorkspaceHtml(snapshot)) return; + final site = snapshot.workspace?.kind == WorkspaceKind.writersideModule; + if (site) { + if (!await confirmSafeToContinue(context, ref) || !context.mounted) return; + snapshot = ref.read(workspaceControllerProvider); + } + final workspace = snapshot.workspace!; + final headerBar = ref.read(linuxHeaderBarServiceProvider); + WritersideInstance? instance; + if (site) { + final instances = workspace.writersideModule!.instances + .where((i) => !i.isLibrary) + .toList(); + final stored = ref + .read(appSettingsControllerProvider) + .selectedWritersideInstanceId(workspace.rootPath); + var selected = + instances.where((i) => i.id == stored).firstOrNull ?? instances.first; + instance = await showBusyMarkModalDialog( + context, + headerBarService: headerBar.isAvailable ? headerBar : null, + builder: (context) => StatefulBuilder( + builder: (context, setState) => BusyMarkDialogShell( + title: context.l10n.exportAsHtml, + actions: [ + BusyMarkDialogButton( + label: context.l10n.cancel, + onPressed: () => Navigator.pop(context), + ), + BusyMarkDialogButton( + label: context.l10n.export, + suggested: true, + onPressed: () => Navigator.pop(context, selected), + ), + ], + children: [ + Text(context.l10n.htmlInstanceDescription), + BusyMarkComboRow( + title: context.l10n.htmlInstance, + values: instances, + selected: selected, + labelFor: (i) => i.name, + onSelected: (i) => setState(() => selected = i), + ), + ], + ), + ), + ); + if (instance == null || !context.mounted) return; + } + final path = workspace.activeFilePath ?? workspace.markdown?.filePath ?? ''; + final name = path.isEmpty + ? context.l10n.untitledMarkdownFileName + : p.basename(path); + final location = await getSaveLocation( + suggestedName: site + ? '${instance!.id}-html' + : '${p.basenameWithoutExtension(name)}.html', + initialDirectory: workspace.rootPath.isEmpty ? null : workspace.rootPath, + acceptedTypeGroups: site + ? const [] + : [ + XTypeGroup( + label: context.l10n.fileTypeHtml, + extensions: const ['html'], + mimeTypes: const ['text/html'], + ), + ], + confirmButtonText: context.l10n.export, + ); + if (location == null || !context.mounted) return; + final destination = + !site && p.extension(location.path).toLowerCase() != '.html' + ? '${location.path}.html' + : location.path; + var overwrite = false; + if (await FileSystemEntity.type(destination, followLinks: false) != + FileSystemEntityType.notFound) { + if (!context.mounted) return; + overwrite = + await showBusyMarkModalDialog( + context, + headerBarService: headerBar.isAvailable ? headerBar : null, + builder: (context) => BusyMarkDialogShell( + title: context.l10n.warning, + actions: [ + BusyMarkDialogButton( + label: context.l10n.cancel, + onPressed: () => Navigator.pop(context, false), + ), + BusyMarkDialogButton( + label: context.l10n.overwrite, + destructive: true, + onPressed: () => Navigator.pop(context, true), + ), + ], + children: [ + Text(context.l10n.errorPathAlreadyExists(destination)), + if (site) Text(context.l10n.htmlOwnedDirectoryOnly), + ], + ), + ) ?? + false; + if (!overwrite || !context.mounted) return; + } + if (!context.mounted) return; + // Capture text and service before starting the modal operation. Subsequent + // workspace notifications cannot replace these inputs. + final service = ref.read(htmlExportServiceProvider); + final request = MarkdownHtmlExportRequest( + source: snapshot.activeText, + filePath: path, + workspaceRoot: workspace.rootPath, + destinationPath: destination, + overwrite: overwrite, + mode: workspace.markdown?.mode ?? MarkdownMode.commonMark, + ); + final selected = instance; + final token = HtmlExportCancellationToken(); + final outcome = await showBusyMarkModalDialog<_Outcome>( + context, + barrierDismissible: false, + headerBarService: headerBar.isAvailable ? headerBar : null, + builder: (context) => _Progress( + token: token, + operation: (progress) => site + ? service.exportWriterside( + projectRoot: workspace.rootPath, + moduleRoot: workspace.writersideModule!.rootPath, + instanceId: selected!.id, + destinationPath: destination, + overwrite: overwrite, + cancellationToken: token, + onProgress: progress, + ) + : service.exportMarkdown( + request, + cancellationToken: token, + onProgress: progress, + ), + ), + ); + if (outcome == null || !context.mounted || outcome.cancelled) return; + final result = outcome.result; + await showBusyMarkModalDialog( + context, + headerBarService: headerBar.isAvailable ? headerBar : null, + builder: (context) => BusyMarkDialogShell( + title: result == null + ? context.l10n.htmlExportFailed + : context.l10n.htmlExported, + maxWidth: 640, + actions: [ + if (result != null) + BusyMarkDialogButton( + label: context.l10n.open, + onPressed: () => unawaited( + launchUrl( + Uri.file(result.entryPointPath), + mode: LaunchMode.externalApplication, + ), + ), + ), + if (result != null) + BusyMarkDialogButton( + label: context.l10n.showInFolder, + onPressed: () => unawaited( + launchUrl( + Uri.directory(p.dirname(result.entryPointPath)), + mode: LaunchMode.externalApplication, + ), + ), + ), + BusyMarkDialogButton( + label: MaterialLocalizations.of(context).closeButtonLabel, + onPressed: () => Navigator.pop(context), + ), + ], + children: [ + if (result == null) + SelectableText(outcome.error ?? context.l10n.htmlExportFailed) + else ...[ + SelectableText(result.entryPointPath), + if (!site && result.assetsPath != null) + Text(context.l10n.htmlKeepAssetsTogether), + if (result.warnings.isNotEmpty) + ConstrainedBox( + constraints: const BoxConstraints(maxHeight: 280), + child: SingleChildScrollView( + child: SelectionArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + for (final warning in result.warnings) + Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: Text(warning.toString()), + ), + ], + ), + ), + ), + ), + ], + ], + ), + ); +} + +class _Outcome { + const _Outcome({this.result, this.error, this.cancelled = false}); + final HtmlExportResult? result; + final String? error; + final bool cancelled; +} + +class _Progress extends StatefulWidget { + const _Progress({required this.token, required this.operation}); + final HtmlExportCancellationToken token; + final Future Function(HtmlExportProgress progress) + operation; + @override + State<_Progress> createState() => _ProgressState(); +} + +class _ProgressState extends State<_Progress> { + double? progress; + @override + void initState() { + super.initState(); + WidgetsBinding.instance.addPostFrameCallback((_) => run()); + } + + Future run() async { + _Outcome outcome; + try { + outcome = _Outcome( + result: await widget.operation((done, total) { + if (mounted) { + setState(() => progress = total == 0 ? null : done / total); + } + }), + ); + } on HtmlExportException catch (error) { + outcome = _Outcome(error: error.message, cancelled: error.cancelled); + } on Object catch (error) { + outcome = _Outcome(error: error.toString()); + } + if (mounted) Navigator.pop(context, outcome); + } + + @override + Widget build(BuildContext context) => PopScope( + canPop: false, + child: BusyMarkDialogShell( + title: context.l10n.exportingHtml, + closable: false, + actions: [ + BusyMarkDialogButton( + label: context.l10n.cancel, + onPressed: widget.token.isCancelled + ? null + : () => setState(widget.token.cancel), + ), + ], + children: [ + LinearProgressIndicator(value: progress), + const SizedBox(height: 20), + ], + ), + ); +} diff --git a/lib/src/export/html_publication_plan.dart b/lib/src/export/html_publication_plan.dart new file mode 100644 index 00000000..d1a757b4 --- /dev/null +++ b/lib/src/export/html_publication_plan.dart @@ -0,0 +1,376 @@ +import 'dart:convert'; +import 'package:path/path.dart' as p; +import 'package:html/parser.dart' as html; +import '../core/path_utils.dart'; +import '../markdown/busymark_document.dart'; +import '../writerside/writerside_model.dart'; +import '../writerside/writerside_document_resolver.dart'; +import '../writerside/writerside_document_renderer.dart'; +import 'html_export_models.dart'; + +class HtmlPage { + HtmlPage({ + required this.document, + required this.filename, + required this.title, + this.module, + this.topic, + this.workInProgress = false, + }); + BusyDocument document; + final String filename, title; + final WritersideModule? module; + final WritersideTopic? topic; + bool workInProgress; + final Set ids = {}; + final List<({String id, String title, int level})> outline = []; + String get sourcePath => document.filePath; +} + +class HtmlNavigationEntry { + const HtmlNavigationEntry({ + required this.title, + this.page, + this.href, + this.hidden = false, + this.workInProgress = false, + this.children = const [], + }); + final String title; + final HtmlPage? page; + final String? href; + final bool hidden, workInProgress; + final List children; +} + +class HtmlPublicationPlan { + HtmlPublicationPlan({ + required this.pages, + required this.startPage, + this.navigation = const [], + this.title, + }); + final List pages; + final HtmlPage startPage; + final List navigation; + final String? title; + + static HtmlPublicationPlan writerside({ + required WritersideModule module, + required WritersideInstance instance, + required Map modulesByOrigin, + required List warnings, + HtmlExportLimits limits = const HtmlExportLimits(), + }) { + if (instance.isLibrary) { + throw const HtmlExportException('Library instances cannot be exported.'); + } + final byIdentity = {}; + final filenames = {}; + var bytes = 0; + HtmlPage? add(String? reference, WritersideModule origin) { + if (reference == null) return null; + final topic = origin.topicByReference(reference); + if (topic == null) { + throw HtmlExportException( + 'Missing TOC topic: $reference (${origin.rootPath}).', + ); + } + final identity = '${origin.rootPath}\u0000${topic.filePath}'; + if (byIdentity[identity] case final existing?) return existing; + if (byIdentity.length >= limits.topics) { + throw const HtmlExportException( + 'The instance exceeds the topic limit.', + ); + } + bytes += utf8.encode(topic.document.source).length; + if (bytes > limits.sourceBytes) { + throw const HtmlExportException( + 'The instance exceeds the source byte limit.', + ); + } + final resolved = const WritersideDocumentResolver().resolve( + topic.document, + WritersideResolveContext( + module: origin, + topic: topic, + instance: instance, + modulesByOrigin: modulesByOrigin, + ), + ); + warnings.addAll( + resolved.diagnostics.map( + (d) => HtmlExportWarning( + d.code, + '${d.code}: ${d.args.values.join(', ')}', + sourcePath: d.filePath, + line: d.line ?? 1, + ), + ), + ); + final title = resolved.title ?? topic.title ?? topic.id; + final customName = + resolved.document.elements + .where((e) => e.name == 'web-file-name') + .firstOrNull + ?.plainText + .trim() ?? + topic.webFileName; + final filename = + customName ?? + '${p.basenameWithoutExtension(topic.fileName).toLowerCase().replaceAll(RegExp(r'[^\p{L}\p{N}-]', unicode: true), '-')}.html'; + if (!validFilename(filename)) { + throw HtmlExportException( + 'Invalid web filename "$filename" in ${topic.filePath}.', + ); + } + var document = const WritersideDocumentRenderer().toBusyDocument( + resolved.document, + title: title, + includeTitleHeading: topic.format == WritersideTopicFormat.xml, + ); + // Markdown already supplies its H1. Apply a resolved instance title there. + if (topic.format == WritersideTopicFormat.markdown) { + var replaced = false; + document = document.copyWith( + blocks: [ + for (final b in document.blocks) + if (!replaced && + b.kind == BusyBlockKind.heading && + b.attributes['level'] == '1') + (() { + replaced = true; + return b.plainText == title + ? b + : b.copyWith( + inlines: [ + BusyInline(kind: BusyInlineKind.text, text: title), + ], + ); + })() + else + b, + ], + ); + } + document = document.copyWith( + frontMatter: { + ...?topic.markdown?.busyDocument.frontMatter, + ...document.frontMatter, + ...{ + for (final key in ['lang', 'dir']) + if (resolved.document.rootElement?.attributes[key] + case final value?) + key: value, + }, + }, + ); + final page = HtmlPage( + document: document, + filename: filename, + title: title, + module: origin, + topic: topic, + ); + final collision = filenames[filename.toLowerCase()]; + if (collision != null) { + throw HtmlExportException( + 'Web filename collision "$filename": ${collision.sourcePath} and ${topic.filePath}.', + ); + } + filenames[filename.toLowerCase()] = page; + byIdentity[identity] = page; + return page; + } + + final requestedStart = add(instance.startPage, module); + HtmlNavigationEntry entry(TocNode node, WritersideModule inherited) { + final origin = node.origin == null + ? inherited + : modulesByOrigin[node.origin]; + if (origin == null) { + throw HtmlExportException('Unknown TOC module origin: ${node.origin}.'); + } + // References to another instance remain explicit navigation links, without + // implicitly publishing that instance. + final page = + node.referenceInstanceId != null && + node.referenceInstanceId != instance.id + ? null + : add(node.topicReference, origin); + if (page != null && node.workInProgress) page.workInProgress = true; + if (node.includeResolutionError != null) { + throw HtmlExportException( + 'TOC include failed: ${node.includeResolutionError}.', + ); + } + return HtmlNavigationEntry( + title: node.tocTitle ?? page?.title ?? node.href ?? node.id ?? '', + page: page, + href: node.href, + hidden: node.hidden, + workInProgress: node.workInProgress, + children: node.children.map((child) => entry(child, origin)).toList(), + ); + } + + final navigation = instance.navigationTocRoots + .map((node) => entry(node, module)) + .toList(); + if (byIdentity.isEmpty) { + throw const HtmlExportException('The instance has no topics to export.'); + } + final start = requestedStart ?? byIdentity.values.first; + final index = filenames['index.html']; + if (index != null && index != start) { + throw HtmlExportException( + 'index.html is reserved for the start page, but is declared by ${index.sourcePath}.', + ); + } + final plan = HtmlPublicationPlan( + pages: byIdentity.values.toList(), + startPage: start, + navigation: navigation, + title: instance.name, + ); + for (final page in plan.pages) { + prepareHtmlPage(page, warnings, limits); + } + return plan; + } + + static bool validFilename(String name) => + name.isNotEmpty && + utf8.encode(name).length <= 240 && + name.toLowerCase().endsWith('.html') && + !name.startsWith('.') && + !RegExp(r'[/\\\x00-\x1f\x7f?#:%]').hasMatch(name) && + p.basename(name) == name; + + HtmlPage? pageForSource(String source) => + pages.where((page) => p.equals(page.sourcePath, source)).firstOrNull; +} + +void prepareHtmlPage( + HtmlPage page, + List warnings, + HtmlExportLimits limits, +) { + final explicit = {}; + void collect(Iterable blocks, int depth) { + if (depth > limits.depth) { + throw const HtmlExportException( + 'Document nesting exceeds the export limit.', + ); + } + for (final b in blocks) { + final id = b.attributes['id']; + if (id != null && b.attributes['generatedId'] != 'true') { + if (!explicit.add(id)) { + warnings.add( + HtmlExportWarning( + 'anchor.duplicate', + 'Duplicate explicit ID "$id".', + sourcePath: page.sourcePath, + line: b.sourceSpan?.startLine ?? 1, + ), + ); + } + } + collect(b.children, depth + 1); + } + } + + collect(page.document.blocks, 0); + final used = {}; + var occurrence = 0; + BusyBlock block(BusyBlock b) { + var attributes = {...b.attributes}; + var id = attributes['id']; + if (b.kind == BusyBlockKind.heading && + (id == null || attributes['generatedId'] == 'true')) { + final slug = slugForHeading(b.plainText); + final base = slug.isEmpty ? 'section' : slug; + id = base; + for ( + var suffix = 1; + used.contains(id) || explicit.contains(id); + suffix++ + ) { + id = '$base-$suffix'; + } + } + if (id != null) { + if (id.isEmpty || + RegExp(r'\s|[\x00-\x1f]').hasMatch(id) || + !used.add(id)) { + warnings.add( + HtmlExportWarning( + 'anchor.ambiguous', + 'Invalid or repeated ID "$id"; its duplicate anchor was omitted.', + sourcePath: page.sourcePath, + line: b.sourceSpan?.startLine ?? 1, + ), + ); + attributes.remove('id'); + } else { + attributes['id'] = id; + page.ids.add(id); + if (b.kind == BusyBlockKind.heading) { + page.outline.add(( + id: id, + title: b.plainText, + level: int.tryParse(attributes['level'] ?? '') ?? 1, + )); + } + } + } + // IDs for render jobs describe occurrences, since included blocks may share IDs. + final key = 'html-${occurrence++}'; + return b.copyWith( + id: key, + attributes: attributes, + children: b.children.map(block).toList(), + ); + } + + page.document = page.document.copyWith( + blocks: page.document.blocks.map(block).toList(), + ); + void rawIds(Iterable blocks) { + for (final b in blocks) { + final source = + b.attributes['html-footnotes'] ?? + (b.kind == BusyBlockKind.htmlBlock ? b.rawSource : null); + if (source != null) { + for (final element + in html.parseFragment(source).querySelectorAll('[id]')) { + final id = element.id; + if (!page.ids.add(id)) { + warnings.add( + HtmlExportWarning( + 'anchor.duplicate', + 'Duplicate explicit ID "$id".', + sourcePath: page.sourcePath, + ), + ); + } + } + } + void inlineIds(Iterable values) { + for (final value in values) { + if (value.attributes['id'] case final id?) page.ids.add(id); + inlineIds(value.children); + } + } + + inlineIds(b.inlines); + rawIds(b.children); + } + } + + rawIds(page.document.blocks); + if (page.topic?.document.rootElement?.attributes['id'] case final id?) { + page.ids.add(id); + } +} diff --git a/lib/src/export/html_release_smoke.dart b/lib/src/export/html_release_smoke.dart new file mode 100644 index 00000000..1ebd45df --- /dev/null +++ b/lib/src/export/html_release_smoke.dart @@ -0,0 +1,151 @@ +import 'dart:io'; +import 'package:path/path.dart' as p; +import '../markdown/markdown_model.dart'; +import '../math/math_coordinator.dart'; +import '../visualization/visualization_coordinator.dart'; +import 'html_export_models.dart'; +import 'html_export_service.dart'; + +/// Product-path smoke coverage, invoked by the existing guarded release check. +Future> runHtmlReleaseSmoke({ + required Directory sourceRoot, + required Directory outputRoot, + required MathCoordinator math, + required VisualizationCoordinator visualization, +}) async { + final exporter = HtmlExportService(math: math, visualization: visualization); + const markdown = r'''--- +lang: en +description: An offline BusyMark HTML export +--- +# Offline document + +This is **semantic HTML**, with $x^2 + y^2 = z^2$ inline mathematics. + +## 日本語 + +[Jump to tables](#tables). Footnote[^one]. + +3. First item + - A nested item +4. Second item + +- [x] Completed task +- [ ] Remaining task + +## Tables + +| Name | Value | +| :--- | ---: | +| Example | 12 | + +
Printable disclosure

Disclosure body must print.

Term
Definition
+ +![Local image](logo.svg "A local asset") + +## Mathematics + +$$ +\int_0^1 x^2\,dx = \frac{1}{3} +$$ + +## Diagrams + +```mermaid +flowchart LR + A[Source] --> B[Offline HTML] +``` + +```plantuml +@startuml +Alice -> Bob: Offline export +@enduml +``` + +```d2 +source -> html: export +``` + +## API + +```openapi +openapi: 3.1.0 +info: + title: Offline API + version: 1.0.0 +paths: + /items: + get: + summary: List items + responses: + '200': + description: A list of items +``` + +[^one]: A **structured footnote** with a return link. +'''; + await File(p.join(sourceRoot.path, 'logo.svg')).writeAsString( + 'BusyMark', + ); + final documentPath = p.join(sourceRoot.path, 'offline.md'); + await File(documentPath).writeAsString(markdown); + final document = await exporter.exportMarkdown( + MarkdownHtmlExportRequest( + source: markdown, + filePath: documentPath, + workspaceRoot: sourceRoot.path, + destinationPath: p.join(outputRoot.path, 'offline.html'), + mode: MarkdownMode.gfm, + overwrite: true, + ), + ); + if (document.warnings.isNotEmpty) { + throw StateError('HTML smoke diagnostics: ${document.warnings.join('; ')}'); + } + final module = Directory(p.join(sourceRoot.path, 'writerside')); + Future put(String path, String source) async { + final file = File(p.join(module.path, path)); + await file.parent.create(recursive: true); + await file.writeAsString(source); + } + + await put( + 'writerside.cfg', + '', + ); + await put( + 'guide.tree', + '', + ); + await put( + 'topics/Start.topic', + '''Offline GuideWelcome.html

Portable documentation.

All Linux instructions.

All Windows instructions.

Select HTML.

Open the output.

''', + ); + await put( + 'topics/Reference.topic', + '''

Welcome to %product%.

Both columns
OneTwo

All details are printable.

''', + ); + await put('topics/Hidden.md', '# Hidden topic\n\nLink-accessible content.'); + await put( + 'snippets/flow.mmd', + 'flowchart LR\n A[Topic] --> B[Shared assets]', + ); + final site = await exporter.exportWriterside( + projectRoot: module.path, + moduleRoot: module.path, + instanceId: 'guide', + destinationPath: p.join(outputRoot.path, 'writerside'), + overwrite: true, + ); + if (site.warnings.isNotEmpty) { + throw StateError( + 'Writerside HTML smoke diagnostics: ${site.warnings.join('; ')}', + ); + } + return { + 'markdownHtml': document.entryPointPath, + 'writersideHtml': site.entryPointPath, + 'htmlPages': site.pageCount + 1, + 'htmlWarnings': 0, + }; +} diff --git a/lib/src/export/html_rich_content.dart b/lib/src/export/html_rich_content.dart new file mode 100644 index 00000000..0747a64d --- /dev/null +++ b/lib/src/export/html_rich_content.dart @@ -0,0 +1,220 @@ +import 'dart:async'; +import 'dart:convert'; +import '../math/math_coordinator.dart'; +import '../math/math_models.dart'; +import '../math/math_svg_preprocessor.dart'; +import '../visualization/visualization_coordinator.dart'; +import '../visualization/visualization_models.dart'; +import '../visualization/visualization_renderer.dart'; +import '../writerside/writerside_diagram_source_loader.dart'; +import '../writerside/writerside_source_loader.dart'; +import '../markdown/busymark_document.dart'; +import 'html_export_assets.dart'; +import 'html_export_models.dart'; +import 'markdown_export_document.dart'; +import 'openapi_static_export_mapper.dart'; + +class HtmlMathImage { + const HtmlMathImage(this.url, this.width, this.height, this.depth); + final String url; + final double width, height, depth; +} + +class HtmlGraphic { + const HtmlGraphic({this.url, this.reference}); + final String? url; + final MarkdownExportBlock? reference; +} + +/// Uses BusyMark's native/offline coordinators with HTML sizing and job identity. +class HtmlRichContent { + HtmlRichContent({ + required this.assets, + required this.token, + required this.warnings, + required this.exportId, + this.math, + this.visualization, + this.limits = const HtmlExportLimits(), + }); + final HtmlExportAssets assets; + final HtmlExportCancellationToken token; + final List warnings; + final MathCoordinator? math; + final VisualizationCoordinator? visualization; + final String exportId; + final HtmlExportLimits limits; + int _occurrence = 0; + final Map _captured = {}; + final Map _captureErrors = {}; + + Future captureDiagram( + BusyBlock block, + String sourcePath, + String root, + String occurrenceId, + ) async { + if (_captured.length >= limits.graphics) return; + token.check(); + final cancellation = VisualizationCancellationToken(); + token.attach(cancellation.cancel); + try { + final descriptor = VisualizationDescriptor.forFenceLanguage( + block.attributes['language'], + ); + var source = block.plainText; + if (block.attributes['src'] case final reference? + when !block.attributes.containsKey( + writersideResolvedSourceAttribute, + )) { + source = await const WritersideDiagramSourceLoader().load( + reference: reference, + documentPath: sourcePath, + workspaceRoot: root, + ); + } + final request = VisualizationRenderRequest( + blockKey: 'html:$exportId:$occurrenceId', + kind: descriptor.kind, + source: source, + sourceStartLine: block.sourceSpan?.startLine ?? 1, + documentPath: sourcePath, + workspaceRoot: root, + theme: VisualizationTheme.light, + profile: VisualizationRenderProfile.html, + engineVersion: descriptor.kind.engineVersion, + editRevision: 0, + priority: VisualizationRenderPriority.export, + ); + _captured[occurrenceId] = await visualization + ?.capture(request, cancellation) + .timeout(limits.renderTimeout); + } on Object catch (error) { + token.check(); + _captureErrors[occurrenceId] = error.toString(); + _captured[occurrenceId] = null; + } finally { + cancellation.cancel(); + token.detach(cancellation.cancel); + } + } + + Future _render( + String sourcePath, + int line, + String kind, + Future Function(String key) action, + void Function(String key) cancel, + ) async { + token.check(); + final key = 'html:$exportId:$sourcePath:${_occurrence++}'; + if (_occurrence > limits.graphics) { + warnings.add( + HtmlExportWarning( + 'render.limit', + 'Generated graphics limit reached; $kind source is shown.', + sourcePath: sourcePath, + line: line, + ), + ); + return null; + } + void stop() => cancel(key); + token.attach(stop); + try { + return await action(key).timeout(limits.renderTimeout); + } on Object catch (error) { + token.check(); + warnings.add( + HtmlExportWarning( + 'render.failed', + '$kind could not be rendered; its source is shown. ${error is HtmlExportException ? error.message : error.toString()}', + sourcePath: sourcePath, + line: line, + ), + ); + return null; + } finally { + token.detach(stop); + stop(); + } + } + + Future formula( + String expression, + bool display, + String sourcePath, + int line, { + double fontSize = 17, + }) => _render(sourcePath, line, 'Mathematics', (key) async { + if (math == null) throw StateError('Math renderer unavailable'); + final results = await math!.renderAll([ + MathRenderRequest( + expressionId: key, + expression: expression, + display: display, + blockKey: key, + editRevision: 0, + em: fontSize, + ex: fontSize / 2, + containerWidth: 800, + renderProfile: 'html', + ), + ]); + final result = results.single; + if (result is! RenderedMathResult) { + throw StateError('Math rendering failed'); + } + final svg = const MathSvgPreprocessor().resolveCurrentColor( + result.vectorSvg, + '#20242b', + ); + final url = await assets.bytesAsset(utf8.encode(svg), '.svg'); + return HtmlMathImage(url, result.width, result.height, result.depth); + }, (key) => math?.cancel(key)); + + Future diagram( + BusyBlock block, + String sourcePath, + String root, + String occurrenceId, + ) => _render( + sourcePath, + block.sourceSpan?.startLine ?? 1, + block.attributes['language'] ?? 'Diagram', + (key) async { + final captured = _captured[occurrenceId]; + if (captured == null || visualization == null) { + throw HtmlExportException( + _captureErrors[occurrenceId] ?? + 'The diagram renderer or prepared source is unavailable.', + ); + } + final result = await visualization!.renderCaptured(captured); + if (result is OpenApiVisualizationResult) { + return HtmlGraphic( + reference: const OpenApiStaticExportMapper().map(result.reference), + ); + } + if (result is SvgVisualizationResult) { + return HtmlGraphic( + url: await assets.bytesAsset(utf8.encode(result.svg), '.svg'), + ); + } + if (result is RasterVisualizationResult) { + return HtmlGraphic( + url: await assets.bytesAsset(result.pngBytes, '.png'), + ); + } + throw HtmlExportException( + result is FailedVisualizationResult + ? result.message + : 'The diagram renderer returned unsupported output.', + ); + }, + (_) { + final captured = _captured[occurrenceId]; + if (captured != null) visualization?.cancel(captured.request.blockKey); + }, + ); +} diff --git a/lib/src/export/markdown_export_assets.dart b/lib/src/export/markdown_export_assets.dart index 5bc875a8..5857bcab 100644 --- a/lib/src/export/markdown_export_assets.dart +++ b/lib/src/export/markdown_export_assets.dart @@ -123,7 +123,7 @@ class MarkdownExportAssetStager { } final bytes = await File(resolved).readAsBytes(); cancellationToken.throwIfCancelled(); - if (!_hasExpectedFormat(bytes, extension)) { + if (!hasExpectedFormat(bytes, extension)) { warnings.add( MarkdownPdfWarning( MarkdownPdfWarningCode.imageUnsupported, @@ -163,7 +163,8 @@ class MarkdownExportAssetStager { } } - bool _hasExpectedFormat(List bytes, String extension) { + /// Shared signature validation for offline export backends. + bool hasExpectedFormat(List bytes, String extension) { bool startsWith(List signature) { if (bytes.length < signature.length) { return false; diff --git a/lib/src/markdown/markdown_ast_adapter.dart b/lib/src/markdown/markdown_ast_adapter.dart index 7abe7000..b961f7f7 100644 --- a/lib/src/markdown/markdown_ast_adapter.dart +++ b/lib/src/markdown/markdown_ast_adapter.dart @@ -35,6 +35,7 @@ class MarkdownAstAdapter { required String source, required MarkdownMode mode, String? title, + bool preserveHtmlSemantics = false, }) { final frontMatter = _extractFrontMatter(source); final imageAttributes = _imageAttributeBlocks(source); @@ -51,7 +52,7 @@ class MarkdownAstAdapter { preserveRaw: true, attributes: frontMatter.values, ), - ..._blocksFromMarkdownSource( + ...(preserveHtmlSemantics ? _blocksForHtml : _blocksFromMarkdownSource)( markdownSource, nextId: () => 'b${blockIndex++}', mode: mode, @@ -68,6 +69,97 @@ class MarkdownAstAdapter { ); } + /// Use the existing grammar in two phases so definitions on either side of + /// a raw HTML block share one reference context. No source text is changed. + List _blocksForHtml( + String source, { + required String Function() nextId, + required MarkdownMode mode, + }) { + final document = busyMarkMarkdownDocument(mode); + final nodes = []; + for (final segment in _rawHtmlAwareSegments(source, mode)) { + if (segment.rawHtml) { + nodes.add( + md.Element.empty('busymark-export-raw') + ..attributes['source'] = segment.text, + ); + } else { + final text = _protectProseHyphenLines( + _protectImageDestinationsWithSpaces(segment.text), + ); + nodes.addAll( + md.BlockParser( + text.split('\n').map(md.Line.new).toList(), + document, + ).parseLines(), + ); + } + } + void parseInlines(List children) { + for (var i = 0; i < children.length; i++) { + final node = children[i]; + if (node is md.UnparsedContent) { + final parsed = document.parseInline(node.textContent); + children.replaceRange(i, i + 1, parsed); + i += parsed.length - 1; + } else if (node is md.Element && node.children != null) { + parseInlines(node.children!); + } + } + } + + parseInlines(nodes); + final footnotes = []; + final body = []; + for (final node in nodes) { + if (node is md.Element && node.footnoteLabel != null) { + final label = node.footnoteLabel!; + final count = document.footnoteReferences[label] ?? 0; + if (count == 0) continue; + final returns = md.Element('p', [ + for (var i = 0; i < count; i++) + md.Element.text('a', i == 0 ? '↩' : '↩${i + 1}') + ..attributes['href'] = + '#fnref-${Uri.encodeComponent(label)}${i == 0 ? '' : '-${i + 1}'}', + ]); + node.children?.add(returns); + footnotes.add(node); + } else { + body.add(node); + } + } + footnotes.sort( + (a, b) => document.footnoteLabels + .indexOf(a.footnoteLabel!.toLowerCase()) + .compareTo( + document.footnoteLabels.indexOf(b.footnoteLabel!.toLowerCase()), + ), + ); + if (footnotes.isNotEmpty) { + body.add( + md.Element('section', [md.Element('ol', footnotes)]) + ..attributes['class'] = 'footnotes', + ); + } + final blocks = [ + for (final node in body) + if (node is md.Element && node.tag == 'busymark-export-raw') + BusyBlock( + id: nextId(), + kind: BusyBlockKind.htmlBlock, + rawSource: node.attributes['source'], + preserveRaw: true, + attributes: const {'sourceFormat': 'html'}, + ) + else + ..._blocksFromNode(node, nextId: nextId, mode: mode), + ]; + return mode == MarkdownMode.writersideMarkdown + ? _attachWritersideCodeAttributes(blocks) + : blocks; + } + List _blocksFromMarkdownSource( String source, { required String Function() nextId, @@ -411,6 +503,11 @@ class MarkdownAstAdapter { kind: BusyBlockKind.unknown, inlines: _inlinesFromNodes(children), rawSource: node.textContent, + // Retain the parser-generated structure for semantic HTML export. + // Source serialization and preview continue to use the existing fields. + attributes: { + 'html-footnotes': md.renderToHtml([node]), + }, preserveRaw: true, isGenerated: true, ), diff --git a/lib/src/markdown/markdown_parser.dart b/lib/src/markdown/markdown_parser.dart index 8f2c4e45..6f890c62 100644 --- a/lib/src/markdown/markdown_parser.dart +++ b/lib/src/markdown/markdown_parser.dart @@ -24,7 +24,11 @@ const int _maxLocalReferenceTargetBytes = 2 * 1024 * 1024; const int _backgroundParseThresholdBytes = 64 * 1024; class MarkdownParser { - const MarkdownParser(); + const MarkdownParser({this.preserveHtmlSemantics = false}); + + /// Keeps cross-block reference context for the HTML export projection. The + /// editor and source serializer retain their existing projection by default. + final bool preserveHtmlSemantics; List parseInlineFragment({ required String source, @@ -266,6 +270,7 @@ class MarkdownParser { source: source, mode: mode, title: title, + preserveHtmlSemantics: preserveHtmlSemantics, ); var busyDocument = _withScannedSourceMetadata( renderedDocument, diff --git a/lib/src/platform/header_bar_configuration.dart b/lib/src/platform/header_bar_configuration.dart index 196ddc97..7a527af0 100644 --- a/lib/src/platform/header_bar_configuration.dart +++ b/lib/src/platform/header_bar_configuration.dart @@ -33,6 +33,7 @@ class HeaderBarLabels { required this.backShortcut, required this.save, required this.exportPdf, + this.exportHtml = '', required this.exportPdfShortcut, required this.exportPdfGtkAccelerator, required this.fullScreen, @@ -74,6 +75,7 @@ class HeaderBarLabels { final String backShortcut; final String save; final String exportPdf; + final String exportHtml; final String exportPdfShortcut; final String exportPdfGtkAccelerator; final String fullScreen; @@ -115,6 +117,7 @@ class HeaderBarLabels { 'backShortcut': backShortcut, 'save': save, 'exportPdf': exportPdf, + 'exportHtml': exportHtml, 'exportPdfShortcut': exportPdfShortcut, 'exportPdfGtkAccelerator': exportPdfGtkAccelerator, 'fullScreen': fullScreen, @@ -295,6 +298,7 @@ class HeaderBarConfiguration { required this.textDirection, required this.canRefresh, this.canExportPdf = false, + this.canExportHtml = false, required this.documentControlsVisible, required this.searchActive, required this.searchVisible, @@ -316,6 +320,7 @@ class HeaderBarConfiguration { final TextDirection textDirection; final bool canRefresh; final bool canExportPdf; + final bool canExportHtml; final bool documentControlsVisible; final bool searchActive; final bool searchVisible; @@ -338,6 +343,7 @@ class HeaderBarConfiguration { TextDirection? textDirection, bool? canRefresh, bool? canExportPdf, + bool? canExportHtml, bool? documentControlsVisible, bool? searchActive, bool? searchVisible, @@ -358,6 +364,7 @@ class HeaderBarConfiguration { textDirection: textDirection ?? this.textDirection, canRefresh: canRefresh ?? this.canRefresh, canExportPdf: canExportPdf ?? this.canExportPdf, + canExportHtml: canExportHtml ?? this.canExportHtml, documentControlsVisible: documentControlsVisible ?? this.documentControlsVisible, searchActive: searchActive ?? this.searchActive, @@ -381,6 +388,7 @@ class HeaderBarConfiguration { 'textDirection': textDirection == TextDirection.rtl ? 'rtl' : 'ltr', 'canRefresh': canRefresh, 'canExportPdf': canExportPdf, + 'canExportHtml': canExportHtml, 'documentControlsVisible': documentControlsVisible, 'searchActive': searchActive, 'searchVisible': searchVisible, @@ -402,6 +410,7 @@ class HeaderBarConfiguration { textDirection == other.textDirection && canRefresh == other.canRefresh && canExportPdf == other.canExportPdf && + canExportHtml == other.canExportHtml && documentControlsVisible == other.documentControlsVisible && searchActive == other.searchActive && searchVisible == other.searchVisible && @@ -432,6 +441,7 @@ class HeaderBarConfiguration { textDirection, canRefresh, canExportPdf, + canExportHtml, documentControlsVisible, searchActive, searchVisible, diff --git a/lib/src/platform/linux_header_bar_service.dart b/lib/src/platform/linux_header_bar_service.dart index 0757e37e..1ae96164 100644 --- a/lib/src/platform/linux_header_bar_service.dart +++ b/lib/src/platform/linux_header_bar_service.dart @@ -17,6 +17,7 @@ enum HeaderBarAction { refresh, save, exportPdf, + exportHtml, fullScreen, menu, settings, @@ -291,6 +292,7 @@ class LinuxHeaderBarService extends ChangeNotifier { ('setViewMode', configuration.viewMode.name), ('setCanRefresh', configuration.canRefresh), ('setCanExportPdf', configuration.canExportPdf), + ('setCanExportHtml', configuration.canExportHtml), ('setDocumentControlsVisible', configuration.documentControlsVisible), ('setSearchVisible', configuration.searchVisible), ('setSidebarVisible', configuration.sidebarVisible), @@ -391,6 +393,7 @@ class LinuxHeaderBarService extends ChangeNotifier { 'refresh' => HeaderBarAction.refresh, 'save' => HeaderBarAction.save, 'exportPdf' => HeaderBarAction.exportPdf, + 'exportHtml' => HeaderBarAction.exportHtml, 'fullScreen' => HeaderBarAction.fullScreen, 'menu' => HeaderBarAction.menu, 'settings' => HeaderBarAction.settings, diff --git a/lib/src/visualization/visualization_coordinator.dart b/lib/src/visualization/visualization_coordinator.dart index 10368ef2..f09e198b 100644 --- a/lib/src/visualization/visualization_coordinator.dart +++ b/lib/src/visualization/visualization_coordinator.dart @@ -56,9 +56,43 @@ class VisualizationCoordinator { return result; } - Future render( + /// Freeze renderer dependencies before a long-running export starts. The + /// opaque result can only be rendered by this coordinator. + Future capture( VisualizationRenderRequest request, + VisualizationCancellationToken token, ) async { + if (_disposed) { + throw StateError('VisualizationCoordinator has been disposed.'); + } + final renderer = _renderers[request.kind]; + if (renderer == null) { + throw StateError('The visualization renderer is unavailable.'); + } + final prepared = await renderer.prepare(request, token); + token.throwIfCancelled(); + return CapturedVisualizationRequest._(this, prepared); + } + + Future renderCaptured( + CapturedVisualizationRequest captured, + ) { + if (!identical(captured._owner, this)) { + throw ArgumentError( + 'The captured request belongs to another coordinator.', + ); + } + return _render(captured.request, captured: true); + } + + Future render( + VisualizationRenderRequest request, + ) => _render(request); + + Future _render( + VisualizationRenderRequest request, { + bool captured = false, + }) async { if (_disposed) { throw StateError('VisualizationCoordinator has been disposed.'); } @@ -84,7 +118,9 @@ class VisualizationCoordinator { } try { - final prepared = await renderer.prepare(request, token); + final prepared = captured + ? request + : await renderer.prepare(request, token); _throwIfSuperseded(prepared, token); final cached = await cache.get(prepared.cacheKey); _throwIfSuperseded(prepared, token); @@ -254,3 +290,10 @@ int _priority(VisualizationRenderPriority priority) => switch (priority) { VisualizationRenderPriority.nearVisible => 1, VisualizationRenderPriority.background => 2, }; + +/// An in-memory snapshot of validated renderer inputs and local dependencies. +class CapturedVisualizationRequest { + const CapturedVisualizationRequest._(this._owner, this.request); + final VisualizationCoordinator _owner; + final VisualizationRenderRequest request; +} diff --git a/lib/src/visualization/visualization_models.dart b/lib/src/visualization/visualization_models.dart index 0b9883a8..8f4042aa 100644 --- a/lib/src/visualization/visualization_models.dart +++ b/lib/src/visualization/visualization_models.dart @@ -85,7 +85,7 @@ class VisualizationDescriptor { enum VisualizationTheme { light, dark } -enum VisualizationRenderProfile { preview, pdf } +enum VisualizationRenderProfile { preview, pdf, html } enum VisualizationRenderPriority { visible, nearVisible, background, export } diff --git a/lib/src/visualization/visualization_raster_sizing.dart b/lib/src/visualization/visualization_raster_sizing.dart index 11762afe..f4aa6d95 100644 --- a/lib/src/visualization/visualization_raster_sizing.dart +++ b/lib/src/visualization/visualization_raster_sizing.dart @@ -23,12 +23,14 @@ class VisualizationRasterSizingPolicy { const VisualizationRasterSizingPolicy({ this.previewScale = 2, this.pdfScale = 3, + this.htmlScale = 2, this.maximumDimension = 8192, this.maximumPixels = 64000000, }); final double previewScale; final double pdfScale; + final double htmlScale; final int maximumDimension; final int maximumPixels; @@ -48,6 +50,7 @@ class VisualizationRasterSizingPolicy { final preferredScale = switch (profile) { VisualizationRenderProfile.preview => previewScale, VisualizationRenderProfile.pdf => pdfScale, + VisualizationRenderProfile.html => htmlScale, }; if (!preferredScale.isFinite || preferredScale <= 0) { throw ArgumentError.value( diff --git a/lib/src/visualization/visualization_release_smoke.dart b/lib/src/visualization/visualization_release_smoke.dart index b61eb893..22231cbf 100644 --- a/lib/src/visualization/visualization_release_smoke.dart +++ b/lib/src/visualization/visualization_release_smoke.dart @@ -6,6 +6,7 @@ import 'dart:ui' as ui; import 'package:path/path.dart' as p; import '../export/markdown_pdf_export_service.dart'; +import '../export/html_release_smoke.dart'; import '../export/markdown_pdf_models.dart'; import '../export/markdown_math_export.dart'; import '../export/markdown_visualization_export.dart'; @@ -290,6 +291,16 @@ Future runVisualizationReleaseSmoke(String reportPath) async { checks['pdfEmbeddedImages'] = embeddedImages; checks['pdfPath'] = pdfPath; + await checkpoint('exporting offline HTML documents'); + checks.addAll( + await runHtmlReleaseSmoke( + sourceRoot: workingDirectory, + outputRoot: reportFile.parent, + math: mathCoordinator, + visualization: coordinator, + ), + ); + await _writeReport(reportFile, {'ok': true, 'checks': checks}); return 0; } on Object catch (error, stackTrace) { diff --git a/lib/src/workspace/presentation/settings_screen.dart b/lib/src/workspace/presentation/settings_screen.dart index d26c3700..6e373bc1 100644 --- a/lib/src/workspace/presentation/settings_screen.dart +++ b/lib/src/workspace/presentation/settings_screen.dart @@ -318,6 +318,7 @@ class _SettingsScreenState extends ConsumerState { case HeaderBarAction.search: case HeaderBarAction.refresh: case HeaderBarAction.save: + case HeaderBarAction.exportHtml: case HeaderBarAction.exportPdf: case HeaderBarAction.fullScreen: case HeaderBarAction.menu: @@ -339,6 +340,7 @@ class _SettingsScreenState extends ConsumerState { BusyMarkMainMenuAction action, ) { switch (action) { + case BusyMarkMainMenuAction.exportHtml: case BusyMarkMainMenuAction.exportPdf: case BusyMarkMainMenuAction.generateMarkdownToc: break; diff --git a/lib/src/workspace/presentation/welcome_screen.dart b/lib/src/workspace/presentation/welcome_screen.dart index d3bf5b2b..063b0276 100644 --- a/lib/src/workspace/presentation/welcome_screen.dart +++ b/lib/src/workspace/presentation/welcome_screen.dart @@ -255,6 +255,7 @@ class _WelcomeScreenState extends ConsumerState { case HeaderBarAction.search: case HeaderBarAction.refresh: case HeaderBarAction.save: + case HeaderBarAction.exportHtml: case HeaderBarAction.exportPdf: case HeaderBarAction.fullScreen: case HeaderBarAction.menu: @@ -285,6 +286,7 @@ class _WelcomeScreenState extends ConsumerState { BusyMarkMainMenuAction action, ) { switch (action) { + case BusyMarkMainMenuAction.exportHtml: case BusyMarkMainMenuAction.exportPdf: case BusyMarkMainMenuAction.generateMarkdownToc: break; diff --git a/lib/src/workspace/presentation/workspace_screen.dart b/lib/src/workspace/presentation/workspace_screen.dart index a89bebac..aa51ba59 100644 --- a/lib/src/workspace/presentation/workspace_screen.dart +++ b/lib/src/workspace/presentation/workspace_screen.dart @@ -58,6 +58,7 @@ import '../../editor/wysiwyg/wysiwyg_session_state.dart'; import '../../editor/writerside_video_view.dart'; import '../../feedback/presentation/feedback_dialog.dart'; import '../../export/markdown_pdf_export_ui.dart'; +import '../../export/html_export_ui.dart'; import '../../git/application/git_controller.dart'; import '../../git/domain/git_models.dart'; import '../../git/presentation/git_diff_viewer.dart'; @@ -661,6 +662,7 @@ class WorkspaceScreen extends ConsumerWidget { : _activeFileName(context, workspace); final hasSidebar = _hasWorkspaceSidebar(workspace); final canExportPdf = canExportWorkspacePdf(state); + final canExportHtml = canExportWorkspaceHtml(state); final canGenerateMarkdownToc = _activeWorkspaceDocumentKind(workspace)?.supportsAiMarkdownEditing ?? false; @@ -671,6 +673,7 @@ class WorkspaceScreen extends ConsumerWidget { searchQuery: searchState.query, canRefresh: true, canExportPdf: canExportPdf, + canExportHtml: canExportHtml, documentControlsVisible: true, searchActive: searchState.active, searchVisible: true, @@ -844,6 +847,7 @@ class WorkspaceScreen extends ConsumerWidget { ), BusyMarkMainMenuButton( canExportPdf: canExportPdf, + canExportHtml: canExportHtml, canGenerateMarkdownToc: canGenerateMarkdownToc, onSelected: (action) => _handleMainMenuAction(context, ref, action), @@ -974,6 +978,8 @@ class WorkspaceScreen extends ConsumerWidget { unawaited(_validateActiveAndShowProblems(context, ref)); case HeaderBarAction.save: execute(BusyMarkCommandIds.save); + case HeaderBarAction.exportHtml: + execute(BusyMarkCommandIds.exportHtml); case HeaderBarAction.exportPdf: execute(BusyMarkCommandIds.exportPdf); case HeaderBarAction.fullScreen: @@ -1021,6 +1027,8 @@ class WorkspaceScreen extends ConsumerWidget { BusyMarkMainMenuAction action, ) { switch (action) { + case BusyMarkMainMenuAction.exportHtml: + unawaited(exportWorkspaceToHtml(context, ref)); case BusyMarkMainMenuAction.exportPdf: unawaited(exportWorkspaceToPdf(context, ref)); case BusyMarkMainMenuAction.generateMarkdownToc: diff --git a/lib/src/writerside/writerside_document_resolver.dart b/lib/src/writerside/writerside_document_resolver.dart index 23e58343..e5a6e5a9 100644 --- a/lib/src/writerside/writerside_document_resolver.dart +++ b/lib/src/writerside/writerside_document_resolver.dart @@ -529,6 +529,37 @@ class _ResolveState { if (variable.attributes['name'] != null) variable.attributes['name']!: variable.attributes['value'] ?? '', }; + Map variablesFor(WritersideDocumentNode? target) { + if (target == null || targetTopic == null) return targetVariables; + final scoped = {...targetVariables}; + // Link metadata inherits the same lexical defaults as the target text, + // including a paragraph nested inside a reusable snippet. + final ancestors = + targetTopic.document.elements + .where( + (element) => + element.span.startOffset <= target.span.startOffset && + element.span.endOffset >= target.span.endOffset, + ) + .toList() + ..sort((a, b) => a.span.startOffset.compareTo(b.span.startOffset)); + for (final ancestor in ancestors) { + for (final variable + in ancestor.children.whereType()) { + if (variable.semanticKind == WritersideSemanticKind.variable && + _matchesInstance( + variable.attributes['instance'], + targetModule!, + ) && + variable.attributes['name'] != null) { + scoped[variable.attributes['name']!] = + variable.attributes['value'] ?? ''; + } + } + } + return scoped; + } + String? summaryFor(String name) { final element = targetTopic?.document.elements .where( @@ -554,7 +585,7 @@ class _ResolveState { ? null : _interpolate( summaryNode.plainText, - targetVariables, + variablesFor(summaryNode), summaryNode, ignore: false, ).trim(); @@ -579,7 +610,7 @@ class _ResolveState { return { 'resolved-label': _interpolate( label, - targetVariables, + variablesFor(target), node, ignore: false, ), diff --git a/lib/src/writerside/writerside_table_view.dart b/lib/src/writerside/writerside_table_view.dart index 68246902..404fffb2 100644 --- a/lib/src/writerside/writerside_table_view.dart +++ b/lib/src/writerside/writerside_table_view.dart @@ -3,6 +3,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import '../markdown/preview_model.dart'; +import '../app/localization.dart'; +import '../app/busymark_glyphs.dart'; import '../markdown/table_grid.dart'; class WritersideTableView extends StatefulWidget { @@ -109,14 +111,16 @@ class _WritersideTableViewState extends State { }), child: Semantics( button: true, - label: 'Sort ${cell.value.text}', + label: context.l10n.sortTableColumn( + cell.value.text, + ), child: Row( children: [ Expanded(child: content), Icon( sortColumn == cell.column && !ascending - ? Icons.arrow_downward - : Icons.arrow_upward, + ? BusyMarkGlyphs.downArrow + : BusyMarkGlyphs.upArrow, size: 16, ), ], diff --git a/linux/runner/my_application.cc b/linux/runner/my_application.cc index f711ca10..4c2437f6 100644 --- a/linux/runner/my_application.cc +++ b/linux/runner/my_application.cc @@ -154,6 +154,7 @@ struct HeaderBarConfiguration { const gchar* view_mode; gboolean can_refresh; gboolean can_export_pdf; + gboolean can_export_html; gboolean document_controls_visible; gboolean search_active; gboolean search_visible; @@ -1322,7 +1323,7 @@ static GtkWidget* create_header_toggle_button(const gchar* icon_name) { } static const gchar* main_menu_icon_name(const gchar* action) { - if (g_strcmp0(action, "exportPdf") == 0) { + if (g_strcmp0(action, "exportPdf") == 0 || g_strcmp0(action, "exportHtml") == 0) { return "document-save-as-symbolic"; } if (g_strcmp0(action, "settings") == 0) { @@ -1381,6 +1382,11 @@ static void rebuild_main_menu_model(MyApplication* self, FlValue* labels) { localized_label_or(labels, "exportPdf", ""), "header.export-pdf", main_menu_icon_name("exportPdf"), fl_lookup_string_arg(labels, "exportPdfGtkAccelerator")); + append_action_menu_item( + self->main_menu_model, + localized_label_or(labels, "exportHtml", ""), "header.export-html", + main_menu_icon_name("exportHtml"), + nullptr); append_action_menu_item( self->main_menu_model, localized_label_or(labels, "fullScreen", ""), "header.full-screen", @@ -1553,6 +1559,8 @@ static void set_header_action_enabled(MyApplication* self, static void setup_header_actions(MyApplication* self) { self->header_action_group = g_simple_action_group_new(); add_header_gaction(self, "export-pdf", "exportPdf"); + add_header_gaction(self, "export-html", "exportHtml"); + set_header_action_enabled(self, "export-html", FALSE); set_header_action_enabled(self, "export-pdf", FALSE); add_header_gaction(self, "settings", "settings"); add_header_gaction(self, "keyboard-shortcuts", "keyboardShortcuts"); @@ -1870,6 +1878,7 @@ static gboolean decode_header_bar_configuration( configuration->sidebar_width <= 0 || !fl_lookup_optional_bool_arg(args, "canRefresh", &configuration->can_refresh) || + !fl_lookup_optional_bool_arg(args, "canExportHtml", &configuration->can_export_html) || !fl_lookup_optional_bool_arg(args, "canExportPdf", &configuration->can_export_pdf) || !fl_lookup_optional_bool_arg( @@ -1918,6 +1927,7 @@ static void apply_header_bar_configuration( set_widget_sensitive(self->refresh_button, configuration.can_refresh); set_header_action_enabled(self, "export-pdf", configuration.can_export_pdf); + set_header_action_enabled(self, "export-html", configuration.can_export_html); set_sidebar_width(self, configuration.sidebar_width); set_text_direction(self, configuration.text_direction); set_sidebar_visible(self, configuration.sidebar_visible); @@ -2157,6 +2167,9 @@ static void header_bar_method_call_cb(FlMethodChannel* channel, } else if (strcmp(method, "setCanRefresh") == 0) { set_widget_sensitive(self->refresh_button, fl_method_bool_arg(args)); respond_success(method_call); + } else if (strcmp(method, "setCanExportHtml") == 0) { + set_header_action_enabled(self, "export-html", fl_method_bool_arg(args)); + respond_success(method_call); } else if (strcmp(method, "setCanExportPdf") == 0) { set_header_action_enabled(self, "export-pdf", fl_method_bool_arg(args)); respond_success(method_call); diff --git a/pubspec.yaml b/pubspec.yaml index 05923db1..32c71490 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -45,4 +45,5 @@ flutter: uses-material-design: true assets: - assets/branding/busymark_logo.svg + - assets/export/html.css - assets/export/markdown.typ diff --git a/test/src/header_bar_configuration_test.dart b/test/src/header_bar_configuration_test.dart index fd9751e2..7b997ebe 100644 --- a/test/src/header_bar_configuration_test.dart +++ b/test/src/header_bar_configuration_test.dart @@ -95,6 +95,7 @@ void main() { 'textDirection': 'ltr', 'canRefresh': false, 'canExportPdf': false, + 'canExportHtml': false, 'documentControlsVisible': false, 'searchActive': false, 'searchVisible': false, diff --git a/test/src/html_export_test.dart b/test/src/html_export_test.dart new file mode 100644 index 00000000..a405b846 --- /dev/null +++ b/test/src/html_export_test.dart @@ -0,0 +1,412 @@ +import 'dart:io'; +import 'package:busymark/src/export/html_export_models.dart'; +import 'package:busymark/src/export/html_export_service.dart'; +import 'package:busymark/src/export/html_export_assets.dart'; +import 'package:busymark/src/markdown/markdown_model.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:html/parser.dart' as html; +import 'package:path/path.dart' as p; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + late Directory root; + late HtmlExportService service; + setUp(() async { + root = await Directory.systemTemp.createTemp('busymark-html-test-'); + service = HtmlExportService( + stylesheetLoader: () => File('assets/export/html.css').readAsString(), + ); + }); + tearDown(() async { + if (await root.exists()) await root.delete(recursive: true); + }); + Future export( + String source, { + String name = 'document', + bool overwrite = false, + HtmlExportCancellationToken? token, + HtmlExportService? exporter, + }) => (exporter ?? service).exportMarkdown( + MarkdownHtmlExportRequest( + source: source, + filePath: p.join(root.path, 'source.md'), + workspaceRoot: root.path, + destinationPath: p.join(root.path, '$name.html'), + mode: MarkdownMode.gfm, + overwrite: overwrite, + ), + cancellationToken: token, + ); + + test( + 'unsaved Markdown is a complete styled document with stable semantic anchors', + () async { + await File( + p.join(root.path, 'source.md'), + ).writeAsString('# Old disk text'); + const source = '''# Current title + +## 日本語 + +[Jump](#日本語) + +## Repeat + +## Repeat + +3. Outer + - Nested **strong** and *emphasis* +4. Next + +- [x] Done +- [ ] Pending + +| Header | Number | +| :--- | ---: | +| Value | 10 | + +```dart + + preserved +``` + +Footnote[^note] and again[^note]. + +
Between notes

Body

+ +[^note]: **Nested** note text. + +[Outside](other.md) +'''; + final result = await export(source); + final text = await File(result.entryPointPath).readAsString(); + final doc = html.parse(text); + expect(text, startsWith('')); + expect( + doc.querySelector('meta[charset]')!.attributes['charset'], + 'utf-8', + ); + expect(doc.querySelectorAll('h1').length, 1); + expect(doc.querySelector('title')!.text, 'Current title'); + expect( + doc.querySelector('ol[start="3"] ul li')!.text, + contains('Nested'), + ); + expect(doc.querySelectorAll('input[disabled]').length, 2); + expect(doc.querySelectorAll('input[checked]').length, 1); + expect(doc.querySelectorAll('table thead th').length, 2); + expect( + doc.querySelector('pre code')!.text, + contains('\n preserved'), + ); + expect(doc.querySelectorAll('script'), isEmpty); + expect(doc.getElementById('日本語'), isNotNull); + expect(doc.getElementById('repeat-1'), isNotNull); + expect(doc.querySelector('.footnotes strong')!.text, 'Nested'); + for (final a in doc.querySelectorAll('a[href^="#"]')) { + expect( + doc.getElementById( + Uri.decodeComponent(a.attributes['href']!.substring(1)), + ), + isNotNull, + reason: a.outerHtml, + ); + } + expect( + result.warnings.any((w) => w.message.contains('outside this export')), + isTrue, + ); + expect(text, isNot(contains(root.path))); + expect(result.assetsPath, isNull); + expect( + await File(p.join(root.path, 'source.md')).readAsString(), + '# Old disk text', + ); + }, + ); + + test( + 'raw disclosures, definitions and spans survive with structural sanitization', + () async { + final result = await export('''# HTML + +
More & less

Body bold

Term

Description

+ +
Values
Group
AB
C
+ + + +

Unsafe

+'''); + final doc = html.parse(await File(result.entryPointPath).readAsString()); + expect( + doc.querySelector('article details[open] > summary')!.text, + 'More & less', + ); + expect(doc.querySelector('dl dd p')!.text, 'Description'); + expect(doc.querySelector('th[colspan="2"]'), isNotNull); + expect(doc.querySelector('td[rowspan="2"]'), isNotNull); + expect(doc.querySelector('script'), isNull); + expect(doc.querySelector('[onclick]'), isNull); + expect(doc.querySelector('a[href^="javascript"]'), isNull); + expect(doc.body!.text, contains('window.evil')); + expect(result.warnings, isNotEmpty); + }, + ); + + test( + 'content-addressed assets relocate, deduplicate and reject symlink escapes', + () async { + const svg = + ''; + await File(p.join(root.path, 'one.svg')).writeAsString(svg); + await File(p.join(root.path, 'two.svg')).writeAsString(svg); + final outside = await Directory.systemTemp.createTemp( + 'busymark-html-outside-', + ); + addTearDown(() => outside.delete(recursive: true)); + await File(p.join(outside.path, 'secret.svg')).writeAsString(svg); + await Link( + p.join(root.path, 'escape.svg'), + ).create(p.join(outside.path, 'secret.svg')); + final result = await export( + '# Assets\n\n![One](one.svg) ![Two](two.svg) ![Escape](escape.svg) ![Remote](https://example.com/x.png)', + ); + final doc = html.parse(await File(result.entryPointPath).readAsString()); + final images = doc.querySelectorAll('img'); + expect(images.length, 2); + expect(images[0].attributes['src'], images[1].attributes['src']); + expect( + result.warnings.where((w) => w.code == 'asset.unavailable').length, + 2, + ); + expect( + await Directory( + result.assetsPath!, + ).list().where((f) => f.path.endsWith('.svg')).length, + 1, + ); + final relocated = await Directory.systemTemp.createTemp( + 'busymark-html-relocated-', + ); + addTearDown(() => relocated.delete(recursive: true)); + await File( + result.entryPointPath, + ).rename(p.join(relocated.path, 'document.html')); + await Directory( + result.assetsPath!, + ).rename(p.join(relocated.path, 'document.assets')); + expect( + await File( + p.join( + relocated.path, + Uri.decodeComponent(images.first.attributes['src']!), + ), + ).exists(), + isTrue, + ); + }, + ); + + test('untrusted metadata and data URLs cannot create active HTML', () async { + final result = await export('''--- +title: +lang: en-US +dir: rtl +head: +css: https://evil.invalid/style.css +--- +# Safe heading + +[Unsafe](javascript:alert(1)) + + + +
+'''); + final text = await File(result.entryPointPath).readAsString(); + final doc = html.parse(text); + expect(doc.querySelector('title')!.text, ''); + expect(doc.documentElement!.attributes['dir'], 'rtl'); + expect( + doc.querySelectorAll('script,form,input,head img,head link,[onerror]'), + isEmpty, + ); + expect( + doc + .querySelectorAll('[href],[src]') + .any( + (e) => (e.attributes['href'] ?? e.attributes['src']!).startsWith( + 'data:', + ), + ), + isFalse, + ); + expect(doc.querySelector('style')!.text, isNot(contains('evil.invalid'))); + expect( + doc.querySelector('meta[http-equiv]')!.attributes['content'], + contains("script-src 'none'"), + ); + expect(result.warnings, isNotEmpty); + }); + + test('unsafe SVG and CSS never reach exported assets', () { + for (final inner in [ + '', + '', + '', + '', + '', + ]) { + expect( + () => HtmlExportAssets.safeSvg( + '$inner', + ), + throwsA(isA()), + ); + } + }); + + test( + 'overwrite refusal, cancellation and rendering failure preserve previous HTML', + () async { + final result = await export('# Previous'); + final previous = await File(result.entryPointPath).readAsBytes(); + await expectLater( + export('# Replacement'), + throwsA(isA()), + ); + final token = HtmlExportCancellationToken()..cancel(); + await expectLater( + export('# Replacement', overwrite: true, token: token), + throwsA(isA()), + ); + expect(await File(result.entryPointPath).readAsBytes(), previous); + final failed = await export( + '# Fallback\n\n```mermaid\ngraph LR; A-->B\n```\n\n\$x^2\$', + name: 'failed', + ); + expect(failed.warnings.any((w) => w.code == 'render.failed'), isTrue); + final doc = html.parse(await File(failed.entryPointPath).readAsString()); + expect(doc.querySelector('pre code')!.text, contains('graph LR')); + expect( + await root + .list() + .where((f) => p.basename(f.path).startsWith('.busymark-html-')) + .length, + 0, + ); + }, + ); + + test( + 'metadata title remains separate from a formatted Markdown title heading', + () async { + final result = await export( + '---\ntitle: Page metadata\n---\n# Visible *heading*', + ); + final doc = html.parse(await File(result.entryPointPath).readAsString()); + expect(doc.querySelector('title')!.text, 'Page metadata'); + expect(doc.querySelectorAll('h1').length, 1); + expect(doc.querySelector('h1 em')!.text, 'heading'); + }, + ); + + test('UTF-8 byte limits are enforced', () async { + final limited = HtmlExportService( + limits: const HtmlExportLimits(sourceBytes: 8), + ); + await expectLater( + export('日本語', exporter: limited), + throwsA(isA()), + ); + }); + + test('Writerside produces linked pages, hidden topics, WIP and start copy', () async { + Future put(String name, String source) async { + final f = File(p.join(root.path, name)); + await f.parent.create(recursive: true); + await f.writeAsString(source); + } + + await put( + 'writerside.cfg', + '', + ); + await put( + 'guide.tree', + '', + ); + await put( + 'topics/Start.topic', + 'Selected titleStart Here.html

Welcome

Alpha

Beta

Own anchor

', + ); + await put( + 'topics/Hidden.topic', + '

Secret content

', + ); + await put( + 'topics/Draft.topic', + '

Draft content

', + ); + final destination = p.join(root.path, 'site'); + final result = await service.exportWriterside( + projectRoot: root.path, + moduleRoot: root.path, + instanceId: 'guide', + destinationPath: destination, + ); + expect(result.pageCount, 3); + final index = await File(result.entryPointPath).readAsString(); + expect( + index, + await File(p.join(destination, 'Start Here.html')).readAsString(), + ); + final doc = html.parse(index); + expect(doc.querySelector('h1')!.text, 'Selected title'); + expect(doc.querySelector('a[href="hidden.html#same"]'), isNotNull); + expect( + doc.querySelectorAll('.instance-nav a').map((a) => a.text).join(' '), + isNot(contains('Hidden')), + ); + expect(doc.querySelectorAll('.tab-panel').length, 2); + expect( + await File(p.join(destination, 'draft.html')).readAsString(), + contains('Work in progress'), + ); + await service.exportWriterside( + projectRoot: root.path, + moduleRoot: root.path, + instanceId: 'guide', + destinationPath: destination, + overwrite: true, + ); + await File(p.join(destination, 'mine.txt')).writeAsString('keep'); + await expectLater( + service.exportWriterside( + projectRoot: root.path, + moduleRoot: root.path, + instanceId: 'guide', + destinationPath: destination, + overwrite: true, + ), + throwsA(isA()), + ); + expect(await File(p.join(destination, 'mine.txt')).readAsString(), 'keep'); + expect(await File(result.entryPointPath).readAsString(), index); + }); + + test('official conformance fixture exports as individual pages', () async { + final source = p.absolute('test/fixtures/writerside/conformance_project'); + final cfg = await File(p.join(source, 'conformance.tree')).exists(); + expect(cfg, isTrue); + final result = await service.exportWriterside( + projectRoot: source, + moduleRoot: source, + instanceId: 'conformance', + destinationPath: p.join(root.path, 'official'), + ); + expect(result.pageCount, greaterThan(1)); + expect(await File(result.entryPointPath).exists(), isTrue); + }); +} diff --git a/test/src/html_export_ui_test.dart b/test/src/html_export_ui_test.dart new file mode 100644 index 00000000..8a4c104e --- /dev/null +++ b/test/src/html_export_ui_test.dart @@ -0,0 +1,303 @@ +import 'dart:async'; +import 'dart:io'; +import 'package:busymark/l10n/generated/app_localizations.dart'; +import 'package:busymark/src/app/app_settings.dart'; +import 'package:busymark/src/app/app_theme.dart'; +import 'package:busymark/src/app/busymark_main_menu.dart'; +import 'package:busymark/src/app/command_registry.dart'; +import 'package:busymark/src/export/html_export_models.dart'; +import 'package:busymark/src/export/html_export_service.dart'; +import 'package:busymark/src/export/html_export_ui.dart'; +import 'package:busymark/src/platform/linux_header_bar_service.dart'; +import 'package:busymark/src/workspace/workspace_controller.dart'; +import 'package:busymark/src/writerside/writerside_project.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart' as p; + +void main() { + test( + 'HTML command has no default shortcut and PDF retains Ctrl+Shift+E', + () async { + var calls = 0; + var enabled = false; + final registry = BusyMarkCommandCatalog.create( + executions: {BusyMarkCommandIds.exportHtml: () => calls++}, + enabled: {BusyMarkCommandIds.exportHtml: () => enabled}, + ); + expect(registry[BusyMarkCommandIds.exportHtml]!.shortcut, isNull); + expect( + registry[BusyMarkCommandIds.exportPdf]!.shortcut!.label, + 'Ctrl+Shift+E', + ); + expect(await registry.execute(BusyMarkCommandIds.exportHtml), isFalse); + enabled = true; + expect(await registry.execute(BusyMarkCommandIds.exportHtml), isTrue); + expect(calls, 1); + final native = File('linux/runner/my_application.cc').readAsStringSync(); + expect(native, contains('"header.export-html"')); + expect(native, contains('configuration.can_export_html')); + expect(native, contains('"setCanExportHtml"')); + }, + ); + + testWidgets('Flutter HTML menu preserves enablement and dispatch', ( + tester, + ) async { + var selected = false; + Future menu(bool enabled) => tester.pumpWidget( + ProviderScope( + child: MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: BusyMarkMainMenuButton( + canExportHtml: enabled, + onSelected: (action) => + selected = action == BusyMarkMainMenuAction.exportHtml, + ), + ), + ), + ), + ); + await menu(false); + await tester.tap(find.byType(BusyMarkMainMenuButton)); + await tester.pumpAndSettle(); + final item = find.byWidgetPredicate( + (widget) => + widget is PopupMenuItem && + widget.value == BusyMarkMainMenuAction.exportHtml, + ); + expect( + tester.widget>(item).enabled, + isFalse, + ); + await tester.sendKeyEvent(LogicalKeyboardKey.escape); + await tester.pumpAndSettle(); + await menu(true); + await tester.tap(find.byType(BusyMarkMainMenuButton)); + await tester.pumpAndSettle(); + expect( + tester.widget>(item).enabled, + isTrue, + ); + await tester.tap(find.text('Export as HTML…')); + await tester.pumpAndSettle(); + expect(selected, isTrue); + }); + + testWidgets( + 'untitled active text stays captured while destination picker is open', + (tester) async { + final root = Directory.systemTemp.createTempSync('html-ui-'); + addTearDown(() => root.deleteSync(recursive: true)); + final service = _RecordingExporter(); + final picker = Completer(); + const channel = MethodChannel('plugins.flutter.io/file_selector'); + String? suggestion; + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, ( + call, + ) async { + suggestion = (call.arguments as Map)['suggestedName'] as String?; + return picker.future; + }); + addTearDown( + () => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + channel, + null, + ), + ); + late WidgetRef ref; + await tester.pumpWidget(_harness(service, (value) => ref = value)); + await tester.runAsync( + () => + ref.read(workspaceControllerProvider.notifier).createMarkdownFile(), + ); + ref + .read(workspaceControllerProvider.notifier) + .updateActiveText('# Captured unsaved'); + await tester.tap(find.text('Run HTML')); + await tester.pumpAndSettle(); + expect(suggestion, endsWith('.html')); + ref + .read(workspaceControllerProvider.notifier) + .updateActiveText('# Later edit'); + picker.complete(p.join(root.path, 'untitled.html')); + for (var i = 0; i < 15; i++) { + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 50)), + ); + await tester.pump(const Duration(milliseconds: 100)); + } + expect(service.markdown?.source, '# Captured unsaved'); + expect(ref.read(workspaceControllerProvider).activeText, '# Later edit'); + expect(find.text('Open'), findsOneWidget); + expect(find.text('Show in Folder'), findsOneWidget); + await tester.tap(find.text('Close')); + await tester.pumpAndSettle(); + await tester.pumpWidget(const SizedBox()); + }, + ); + + for (final action in ['Cancel', 'Discard', 'Save']) { + testWidgets( + 'Writerside HTML follows $action handling before instance selection', + (tester) async { + final root = Directory.systemTemp.createTempSync('html-ws-ui-'); + addTearDown(() => root.deleteSync(recursive: true)); + void put(String name, String source) { + final file = File(p.join(root.path, name)); + file.parent.createSync(recursive: true); + file.writeAsStringSync(source); + } + + put( + 'writerside.cfg', + '', + ); + put( + 'guide.tree', + '', + ); + put('topics/a.topic', '

Disk

'); + final service = _RecordingExporter(); + late WidgetRef ref; + await tester.pumpWidget(_harness(service, (value) => ref = value)); + await tester.runAsync( + () => ref + .read(workspaceControllerProvider.notifier) + .openPath(root.path), + ); + await tester.runAsync( + () => ref + .read(workspaceControllerProvider.notifier) + .openActiveFile(p.join(root.path, 'topics/a.topic')), + ); + ref + .read(workspaceControllerProvider.notifier) + .updateActiveText( + '

New

', + ); + await tester.pumpAndSettle(); + await tester.tap(find.text('Run HTML')); + await tester.pumpAndSettle(); + expect(find.text('Unsaved changes'), findsOneWidget); + await tester.tap(find.text(action)); + for ( + var i = 0; + i < 60 && find.text('Instance').evaluate().isEmpty; + i++ + ) { + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 50)), + ); + await tester.pump(const Duration(milliseconds: 100)); + } + if (action == 'Cancel') { + expect(find.text('Instance'), findsNothing); + expect( + ref.read(workspaceControllerProvider).hasUnsavedChanges, + isTrue, + ); + } else { + expect(find.text('Instance'), findsOneWidget); + expect( + File(p.join(root.path, 'topics/a.topic')).readAsStringSync(), + contains(action == 'Save' ? 'Edited' : 'Old'), + ); + await tester.tap(find.text('Cancel')); + await tester.pumpAndSettle(); + } + expect(service.markdown, isNull); + expect(service.siteCalls, 0); + await tester.pumpWidget(const SizedBox()); + }, + ); + } +} + +Widget _harness( + HtmlExportService service, + void Function(WidgetRef) ready, +) => ProviderScope( + overrides: [ + htmlExportServiceProvider.overrideWithValue(service), + localSettingsStoreProvider.overrideWithValue(_Settings()), + linuxHeaderBarServiceProvider.overrideWithValue( + LinuxHeaderBarService(channel: const MethodChannel('html-test-header')), + ), + ], + child: MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: buildBusyMarkTheme( + brightness: Brightness.light, + accentColor: Colors.blue, + ), + home: Scaffold( + body: Consumer( + builder: (context, ref, child) { + ready(ref); + return Column( + children: [ + TextButton( + onPressed: () => exportWorkspaceToHtml(context, ref), + child: const Text('Run HTML'), + ), + BusyMarkMainMenuButton(canExportHtml: true, onSelected: (_) {}), + ], + ); + }, + ), + ), + ), +); + +class _Settings implements LocalSettingsStore { + Map data = AppSettings.defaults() + .copyWith(autoSave: false) + .toJson(); + @override + Future> load() async => data; + @override + Future save(Map json) async { + data = json; + } +} + +class _RecordingExporter extends HtmlExportService { + MarkdownHtmlExportRequest? markdown; + int siteCalls = 0; + @override + Future exportMarkdown( + MarkdownHtmlExportRequest request, { + HtmlExportCancellationToken? cancellationToken, + HtmlExportProgress? onProgress, + }) async { + markdown = request; + return HtmlExportResult( + entryPointPath: request.destinationPath, + warnings: const [], + ); + } + + @override + Future exportWriterside({ + required String projectRoot, + required String moduleRoot, + required String instanceId, + required String destinationPath, + bool overwrite = false, + WritersideProject? capturedProject, + HtmlExportCancellationToken? cancellationToken, + HtmlExportProgress? onProgress, + }) async { + siteCalls++; + return HtmlExportResult( + entryPointPath: p.join(destinationPath, 'index.html'), + warnings: const [], + ); + } +} diff --git a/test/src/html_publication_test.dart b/test/src/html_publication_test.dart new file mode 100644 index 00000000..29c1ddb7 --- /dev/null +++ b/test/src/html_publication_test.dart @@ -0,0 +1,307 @@ +import 'dart:io'; +import 'dart:convert'; +import 'package:busymark/src/core/atomic_file_writer.dart'; +import 'package:busymark/src/export/html_export_models.dart'; +import 'package:busymark/src/export/html_export_publisher.dart'; +import 'package:busymark/src/export/html_export_service.dart'; +import 'package:busymark/src/markdown/markdown_model.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:html/parser.dart' as html; +import 'package:path/path.dart' as p; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + late Directory root; + setUp(() async { + root = await Directory.systemTemp.createTemp('html-publication-'); + }); + tearDown(() async { + await root.delete(recursive: true); + }); + Future put(String name, String source) async { + final f = File(p.join(root.path, name)); + await f.parent.create(recursive: true); + await f.writeAsString(source); + } + + Future module(String dir, String name, String tree) async { + await put( + '$dir/writerside.cfg', + '', + ); + await put('$dir/guide.tree', tree); + await put( + '$dir/v.list', + '', + ); + } + + Future site({ + String dir = 'module', + String output = 'site', + bool overwrite = false, + }) => const HtmlExportService().exportWriterside( + projectRoot: root.path, + moduleRoot: p.join(root.path, dir), + instanceId: 'guide', + destinationPath: p.join(root.path, output), + overwrite: overwrite, + ); + test( + 'Writerside module origins preserve includes, variables, file identity and nullable links', + () async { + await module( + 'main', + 'main', + '', + ); + await module( + 'shared', + 'shared', + '', + ); + await put( + 'main/topics/Start.topic', + '

Selected content

Excluded content

OptionalRequired', + ); + await put( + 'shared/topics/Shared.topic', + '

%label%

Text

', + ); + await put( + 'main/images/logo.svg', + '', + ); + await put( + 'shared/images/logo.svg', + '', + ); + final result = await site(dir: 'main'); + final doc = html.parse(await File(result.entryPointPath).readAsString()); + expect(doc.querySelector('h1')!.text, 'BusyMark'); + expect(doc.body!.text, contains('Caller')); + expect(doc.body!.text, isNot(contains('Excluded content'))); + final images = doc.querySelectorAll('img'); + expect(images.length, 2); + expect(images[0].attributes['src'], isNot(images[1].attributes['src'])); + expect( + doc.querySelector('a[href="shared.html#same"]')!.text, + 'Shared section', + ); + expect( + doc.querySelectorAll('a').where((a) => a.text == 'Optional'), + isEmpty, + ); + expect(doc.body!.text, contains('Optional')); + expect( + result.warnings.any((w) => w.code == 'writerside.link.unavailable'), + isTrue, + ); + expect( + doc.querySelectorAll('a').where((a) => a.text == 'Required'), + isEmpty, + ); + expect( + result.warnings.any((w) => w.code == 'writerside.variable.unresolved'), + isFalse, + ); + }, + ); + test('definition lists preserve individual disclosure states and IDs', () async { + await module( + 'module', + 'docs', + '', + ); + await put( + 'module/topics/Start.topic', + '

First definition

Second definition

Term
', + ); + final result = await site(); + final doc = html.parse(await File(result.entryPointPath).readAsString()); + expect(result.warnings, isEmpty); + expect(doc.querySelectorAll('dl dt').map((e) => e.text), [ + 'First term', + 'Second term', + ]); + expect( + doc.querySelector('dd#first details')!.attributes.containsKey('open'), + isFalse, + ); + expect( + doc.querySelector('dd#second details')!.attributes.containsKey('open'), + isTrue, + ); + expect(doc.querySelector('details dl'), isNull); + }); + test( + 'web filename and index collisions identify both topics before publication', + () async { + await module( + 'module', + 'docs', + '', + ); + await put( + 'module/topics/Guide_A.topic', + '

One

', + ); + await put( + 'module/topics/Guide-A.topic', + '

Two

', + ); + await expectLater( + site(), + throwsA( + isA().having( + (e) => e.message, + 'conflicts', + allOf(contains('Guide_A.topic'), contains('Guide-A.topic')), + ), + ), + ); + expect(await Directory(p.join(root.path, 'site')).exists(), isFalse); + await put( + 'module/topics/Guide-A.topic', + 'index.html', + ); + await expectLater( + site(), + throwsA( + isA().having( + (e) => e.message, + 'reserved', + contains('reserved'), + ), + ), + ); + await put( + 'module/topics/Guide-A.topic', + '../escape.html', + ); + await expectLater( + site(), + throwsA( + isA().having( + (e) => e.message, + 'invalid', + contains('Invalid web filename'), + ), + ), + ); + }, + ); + test( + 'source and media are captured before progress or later editor changes', + () async { + const svg = + ''; + await put('logo.svg', svg); + await put('source.md', '# Disk'); + final request = MarkdownHtmlExportRequest( + source: '# Unsaved\n\n![Logo](logo.svg)', + filePath: p.join(root.path, 'source.md'), + workspaceRoot: root.path, + destinationPath: p.join(root.path, 'out.html'), + ); + final result = await const HtmlExportService().exportMarkdown( + request, + onProgress: (done, total) { + File(p.join(root.path, 'source.md')).writeAsStringSync('# Later'); + File( + p.join(root.path, 'logo.svg'), + ).writeAsStringSync(svg.replaceAll('red', 'blue')); + }, + ); + final doc = html.parse(await File(result.entryPointPath).readAsString()); + expect(doc.querySelector('h1')!.text, 'Unsaved'); + expect( + await File( + p.join(root.path, doc.querySelector('img')!.attributes['src']!), + ).readAsString(), + contains('red'), + ); + }, + ); + test( + 'publication failure retains previous HTML and referenced immutable assets', + () async { + await put( + 'logo.svg', + '', + ); + MarkdownHtmlExportRequest request(String source) => + MarkdownHtmlExportRequest( + source: source, + filePath: p.join(root.path, 'source.md'), + workspaceRoot: root.path, + destinationPath: p.join(root.path, 'out.html'), + overwrite: true, + ); + final original = await const HtmlExportService().exportMarkdown( + request('# Old\n\n![Logo](logo.svg)'), + ); + final bytes = await File(original.entryPointPath).readAsBytes(); + await put( + 'logo.svg', + '', + ); + final service = HtmlExportService( + publisher: HtmlExportPublisher(fileWriter: _FailHtmlWrite()), + ); + await expectLater( + service.exportMarkdown(request('# New\n\n![Logo](logo.svg)')), + throwsA(isA()), + ); + expect(await File(original.entryPointPath).readAsBytes(), bytes); + final url = html + .parse(utf8.decode(bytes)) + .querySelector('img')! + .attributes['src']!; + expect( + await File(p.join(root.path, url)).readAsString(), + contains('red'), + ); + expect( + await root + .list() + .where((f) => p.basename(f.path).startsWith('.busymark-html-')) + .length, + 0, + ); + }, + ); + test( + 'duplicate explicit IDs warn, non-Latin footnotes and document IDs resolve', + () async { + final result = await const HtmlExportService().exportMarkdown( + MarkdownHtmlExportRequest( + source: + '# Ids\n\nNote[^日本語].\n\n[^日本語]: Return.\n\n
Reserved source ID
\n\n

One

\n\n

Two

', + filePath: p.join(root.path, 'source.md'), + workspaceRoot: root.path, + destinationPath: p.join(root.path, 'out.html'), + mode: MarkdownMode.gfm, + ), + ); + final doc = html.parse(await File(result.entryPointPath).readAsString()); + expect(doc.querySelectorAll('[id="twice"]').length, 1); + expect(doc.querySelectorAll('[id="busymark-content"]').length, 1); + expect(result.warnings.any((w) => w.code == 'anchor.duplicate'), isTrue); + }, + ); +} + +class _FailHtmlWrite extends AtomicFileWriter { + @override + Future writeBytes( + String targetPath, + List bytes, { + required bool overwrite, + }) async { + if (targetPath.endsWith('.html')) { + throw const FileSystemException('Simulated permission failure'); + } + return super.writeBytes(targetPath, bytes, overwrite: overwrite); + } +} diff --git a/test/src/html_rich_export_test.dart b/test/src/html_rich_export_test.dart new file mode 100644 index 00000000..36dc703b --- /dev/null +++ b/test/src/html_rich_export_test.dart @@ -0,0 +1,325 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; +import 'dart:convert'; +import 'package:busymark/src/export/html_export_models.dart'; +import 'package:busymark/src/export/html_export_service.dart'; +import 'package:busymark/src/math/math_coordinator.dart'; +import 'package:busymark/src/math/math_renderer.dart'; +import 'package:busymark/src/visualization/visualization_cache.dart'; +import 'package:busymark/src/visualization/visualization_coordinator.dart'; +import 'package:busymark/src/visualization/visualization_models.dart'; +import 'package:busymark/src/visualization/visualization_renderer.dart'; +import 'package:busymark/src/visualization/web_render_host.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:html/parser.dart' as html; +import 'package:path/path.dart' as p; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + test( + 'HTML uses unique occurrence jobs, standalone math and diagram/static API engines', + () async { + final root = await Directory.systemTemp.createTemp('html-rich-'); + addTearDown(() => root.delete(recursive: true)); + final host = _MathHost(); + final math = MathCoordinator(renderer: MathRenderer(host: host)); + addTearDown(math.dispose); + final renderer = _Diagrams(); + final visualization = VisualizationCoordinator( + renderers: [renderer], + cache: VisualizationCache( + diskRoot: Directory(p.join(root.path, 'cache')), + ), + ); + addTearDown(visualization.dispose); + final service = HtmlExportService( + math: math, + visualization: visualization, + ); + final result = await service.exportMarkdown( + MarkdownHtmlExportRequest( + source: r'''# Rich $H$ + +Inline $x^2$ and $\alpha$. + +$$ +\int_0^1 x dx +$$ + +```mermaid +graph LR; A-->B +``` + +```plantuml +@startuml +A -> B +@enduml +``` + +```d2 +a -> b +``` + +```openapi +openapi: 3.1.0 +``` +''', + filePath: p.join(root.path, 'source.md'), + workspaceRoot: root.path, + destinationPath: p.join(root.path, 'out.html'), + ), + ); + expect(result.warnings, isEmpty); + final doc = html.parse(await File(result.entryPointPath).readAsString()); + expect(doc.querySelectorAll('.math-inline').length, 3); + expect(doc.querySelectorAll('.math-display').length, 1); + expect(doc.querySelectorAll('img').length, 7); + expect(doc.body!.text, contains('Test API')); + expect( + renderer.requests.map((r) => r.profile), + everyElement(VisualizationRenderProfile.html), + ); + expect(renderer.requests.map((r) => r.blockKey).toSet().length, 4); + expect( + host.requests.map((r) => r['renderProfile']), + everyElement('html'), + ); + expect(host.requests.first['em'], 39.1); + expect(host.requests.skip(1).map((r) => r['em']), everyElement(17.0)); + for (final file in await Directory( + result.assetsPath!, + ).list().where((f) => f.path.endsWith('.svg')).toList()) { + final svg = await File(file.path).readAsString(); + expect(svg, isNot(contains('currentColor'))); + expect(svg, isNot(contains('http://localhost'))); + } + }, + ); + + test('all diagram dependencies are captured before rendering begins', () async { + final root = await Directory.systemTemp.createTemp('html-dependencies-'); + addTearDown(() => root.delete(recursive: true)); + final dependency = File(p.join(root.path, 'schema.json')); + await dependency.writeAsString('original dependency'); + final renderer = _Diagrams(dependency: dependency); + final coordinator = VisualizationCoordinator( + renderers: [renderer], + cache: VisualizationCache( + diskRoot: Directory(p.join(root.path, 'cache')), + ), + ); + addTearDown(coordinator.dispose); + final result = await HtmlExportService(visualization: coordinator) + .exportMarkdown( + MarkdownHtmlExportRequest( + source: + '```mermaid\ngraph LR; A-->B\n```\n\n```openapi\nopenapi: 3.1.0\n```', + filePath: p.join(root.path, 'source.md'), + workspaceRoot: root.path, + destinationPath: p.join(root.path, 'out.html'), + ), + onProgress: (_, _) => + dependency.writeAsStringSync('later dependency'), + ); + expect(result.warnings, isEmpty); + expect(renderer.preparations, 2); + expect( + renderer.requests.map((r) => r.options.values['captured']), + everyElement('original dependency'), + ); + }); + + test( + 'cancelling an active render retains existing output and removes staging', + () async { + final root = await Directory.systemTemp.createTemp('html-render-cancel-'); + addTearDown(() => root.delete(recursive: true)); + final destination = File(p.join(root.path, 'out.html')); + await destination.writeAsString('Previous usable output'); + final renderer = _Diagrams(hang: true); + final coordinator = VisualizationCoordinator( + renderers: [renderer], + cache: VisualizationCache( + diskRoot: Directory(p.join(root.path, 'cache')), + ), + ); + addTearDown(coordinator.dispose); + final token = HtmlExportCancellationToken(); + final pending = HtmlExportService(visualization: coordinator) + .exportMarkdown( + MarkdownHtmlExportRequest( + source: '```d2\na -> b\n```', + filePath: p.join(root.path, 'source.md'), + workspaceRoot: root.path, + destinationPath: destination.path, + overwrite: true, + ), + cancellationToken: token, + ); + final expectation = expectLater( + pending, + throwsA( + isA().having( + (e) => e.cancelled, + 'cancelled', + isTrue, + ), + ), + ); + for (var i = 0; i < 200 && renderer.requests.isEmpty; i++) { + await Future.delayed(const Duration(milliseconds: 5)); + } + expect(renderer.requests, isNotEmpty); + token.cancel(); + await expectation; + expect(await destination.readAsString(), 'Previous usable output'); + expect( + await root + .list() + .where((f) => p.basename(f.path).startsWith('.busymark-html-')) + .length, + 0, + ); + }, + ); + + test( + 'render timeout is bounded and cancellation interrupts a pending job', + () async { + final root = await Directory.systemTemp.createTemp('html-timeout-'); + addTearDown(() => root.delete(recursive: true)); + final renderer = _Diagrams(hang: true); + final coordinator = VisualizationCoordinator( + renderers: [renderer], + cache: VisualizationCache( + diskRoot: Directory(p.join(root.path, 'cache')), + ), + ); + addTearDown(coordinator.dispose); + final service = HtmlExportService( + visualization: coordinator, + limits: const HtmlExportLimits( + renderTimeout: Duration(milliseconds: 50), + ), + ); + final result = await service.exportMarkdown( + MarkdownHtmlExportRequest( + source: '```d2\na -> b\n```', + filePath: p.join(root.path, 'source.md'), + workspaceRoot: root.path, + destinationPath: p.join(root.path, 'out.html'), + ), + ); + expect(result.warnings.single.code, 'render.failed'); + expect( + await File(result.entryPointPath).readAsString(), + contains('a -> b'), + ); + }, + ); +} + +class _MathHost implements WebRenderHost { + final requests = >[]; + @override + Future> renderMathBatch({ + required List> expressions, + required VisualizationCancellationToken cancellationToken, + }) async { + requests.addAll(expressions); + return { + 'results': [ + for (final e in expressions) + { + 'id': e['id'], + 'svg': + r'', + 'width': 30, + 'height': 14, + 'depth': 2, + }, + ], + }; + } + + @override + dynamic noSuchMethod(Invocation i) => super.noSuchMethod(i); +} + +class _Diagrams implements VisualizationRenderer { + _Diagrams({this.hang = false, this.dependency}); + final File? dependency; + int preparations = 0; + final bool hang; + final requests = []; + @override + Set get supportedKinds => + VisualizationRendererKind.values.toSet(); + @override + Future prepare( + VisualizationRenderRequest r, + VisualizationCancellationToken t, + ) async { + preparations++; + return dependency == null + ? r + : r.copyWith( + options: VisualizationRendererOptions({ + 'captured': await dependency!.readAsString(), + }), + ); + } + + @override + Future render( + VisualizationRenderRequest r, + VisualizationCancellationToken t, + ) async { + requests.add(r); + if (hang) { + final c = Completer(); + t.onCancel( + () => c.completeError(const VisualizationCancelledException()), + ); + return c.future; + } + if (r.kind == VisualizationRendererKind.openApi) { + return const OpenApiVisualizationResult( + content: 'openapi: 3.1.0', + reference: OpenApiReferenceModel( + title: 'Test API', + apiVersion: '1', + specificationVersion: '3.1.0', + valid: true, + serverCount: 0, + pathCount: 0, + operations: [], + tags: [], + document: { + 'openapi': '3.1.0', + 'info': {'title': 'Test API', 'version': '1'}, + 'paths': {}, + }, + ), + ); + } + if (r.kind == VisualizationRendererKind.d2) { + return RasterVisualizationResult( + pngBytes: Uint8List.fromList( + base64Decode( + 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=', + ), + ), + width: 1, + height: 1, + ); + } + return const SvgVisualizationResult( + svg: + '', + width: 40, + height: 20, + ); + } +} diff --git a/test/src/localization_audit_test.dart b/test/src/localization_audit_test.dart index 13bc040f..f52de488 100644 --- a/test/src/localization_audit_test.dart +++ b/test/src/localization_audit_test.dart @@ -715,6 +715,7 @@ const _localeSpecificEnglishMatches = >{ 'shortcutGroupGeneral', }, 'fr': { + 'htmlInstance', // Instance is also the French technical term. 'actions', 'source', 'validation', diff --git a/test/src/workspace_controller_test.dart b/test/src/workspace_controller_test.dart index d568e321..99687eb6 100644 --- a/test/src/workspace_controller_test.dart +++ b/test/src/workspace_controller_test.dart @@ -14,7 +14,6 @@ import 'package:busymark/src/workspace/workspace_message.dart'; import 'package:busymark/src/workspace/workspace_model.dart'; import 'package:busymark/src/workspace/workspace_service.dart'; import 'package:busymark/src/writerside/writerside_project_creator.dart'; -import 'package:busymark/src/writerside/writerside_project.dart'; import 'package:busymark/src/writerside/writerside_topic_creator.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/test/src/writerside_semantic_widgets_test.dart b/test/src/writerside_semantic_widgets_test.dart index 5ccdf823..404c6c45 100644 --- a/test/src/writerside_semantic_widgets_test.dart +++ b/test/src/writerside_semantic_widgets_test.dart @@ -1,3 +1,4 @@ +import 'package:busymark/l10n/generated/app_localizations.dart'; import 'package:busymark/src/markdown/preview_model.dart'; import 'package:busymark/src/writerside/writerside_tabs_view.dart'; import 'package:busymark/src/writerside/writerside_table_view.dart'; @@ -32,6 +33,8 @@ void main() { ) async { await tester.pumpWidget( MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: WritersidePreviewScope( child: Column( @@ -107,6 +110,8 @@ void main() { ); await tester.pumpWidget( MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: SingleChildScrollView( child: WritersideTableView( @@ -197,6 +202,8 @@ void main() { addTearDown(controller.dispose); await tester.pumpWidget( MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, home: Scaffold( body: SizedBox( height: 300, diff --git a/tools/verify_html_export_browser.py b/tools/verify_html_export_browser.py new file mode 100644 index 00000000..c8118883 --- /dev/null +++ b/tools/verify_html_export_browser.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +"""Verify relocated release-smoke exports in current installed browser engines. + +Requires Selenium 4.48+, Firefox/geckodriver, and Chrome/chromedriver. The browser +uses a dead outbound proxy and BiDi observation; only the local HTTP server is +allowed. No script is added to the exported files. +""" +import argparse +import base64 +import functools +import http.server +import json +import shutil +import subprocess +import tempfile +import threading +from pathlib import Path +from urllib.parse import urlparse +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.common.print_page_options import PrintOptions +from selenium.webdriver.firefox.service import Service as FirefoxService + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('export_root', type=Path) + parser.add_argument('--output', type=Path, required=True) + parser.add_argument('--firefox', default='/snap/firefox/current/usr/lib/firefox/firefox') + parser.add_argument('--geckodriver', default='/snap/firefox/current/usr/lib/firefox/geckodriver') + parser.add_argument('--chrome', default='/usr/bin/google-chrome') + args = parser.parse_args() + args.output.mkdir(parents=True, exist_ok=True) + relocated = Path(tempfile.mkdtemp(prefix='busymark-relocated-html-')) + for name in ['offline.html', 'offline.assets', 'writerside']: + source = args.export_root / name + if source.is_dir(): shutil.copytree(source, relocated / name) + else: shutil.copy2(source, relocated / name) + handler = functools.partial(http.server.SimpleHTTPRequestHandler, directory=relocated) + server = http.server.ThreadingHTTPServer(('127.0.0.1', 0), handler) + threading.Thread(target=server.serve_forever, daemon=True).start() + report = {'relocated_root': str(relocated), 'checks': []} + try: + for engine in ['chromium', 'firefox']: + if engine == 'chromium': + options = webdriver.ChromeOptions() + options.binary_location = args.chrome + for flag in ['--headless=new', '--disable-background-networking', '--no-first-run', + '--proxy-server=http://127.0.0.1:9', '--proxy-bypass-list=127.0.0.1;localhost']: + options.add_argument(flag) + options.enable_bidi = True + browser = webdriver.Chrome(options=options) + else: + options = webdriver.FirefoxOptions() + options.binary_location = args.firefox + options.add_argument('-headless') + options.enable_bidi = True + for key, value in {'network.proxy.type': 1, 'network.proxy.http': '127.0.0.1', + 'network.proxy.http_port': 9, 'network.proxy.ssl': '127.0.0.1', + 'network.proxy.ssl_port': 9, 'network.proxy.no_proxies_on': '127.0.0.1,localhost', + 'network.captive-portal-service.enabled': False, + 'network.connectivity-service.enabled': False}.items(): + options.set_preference(key, value) + browser = webdriver.Firefox(options=options, service=FirefoxService(executable_path=args.geckodriver)) + print(engine, 'launched', flush=True) + browser.set_page_load_timeout(20) + browser.set_window_size(1280, 950) + requests, blocked = [], [] + def observe(event): + data = event if isinstance(event, dict) else vars(event) + request = data.get('request') or {} + url = request.get('url', '') if isinstance(request, dict) else request.url + requests.append(url) + parsed = urlparse(url) + if parsed.scheme in ('http', 'https') and parsed.hostname not in ('127.0.0.1', 'localhost'): + blocked.append(url) + browser.network.add_event_handler('before_request', observe) + try: + for mode in ['file', 'http']: + for relative in ['offline.html', 'writerside/index.html', 'writerside/Welcome.html', 'writerside/reference.html', 'writerside/hidden.html']: + url = (relocated / relative).as_uri() if mode == 'file' else f'http://127.0.0.1:{server.server_port}/{relative}' + requests.clear(); blocked.clear() + browser.get(url) + values = browser.execute_script('''return {title:document.title, + scripts:document.scripts.length, + images:[...document.images].map(i=>({src:i.getAttribute('src'),ok:i.complete&&i.naturalWidth>0})), + css:[...document.styleSheets].reduce((n,s)=>n+s.cssRules.length,0), + font:getComputedStyle(document.documentElement).fontSize, + width:document.documentElement.scrollWidth,viewport:innerWidth, + anchors:[...document.querySelectorAll('a[href^="#"]')].every(a=>!!document.getElementById(decodeURIComponent(a.hash.slice(1))))};''') + assert values['scripts'] == 0, values + assert values['css'] > 20 and values['font'] == '17px', values + assert all(image['ok'] for image in values['images']), values + assert values['anchors'] and values['width'] <= values['viewport'], values + assert not blocked, blocked + browser.find_element(By.TAG_NAME, 'body').send_keys(Keys.TAB) + assert browser.execute_script('return document.activeElement.tagName') == 'A' + details = browser.find_elements(By.CSS_SELECTOR, 'article details > summary') + if details: + summary = details[0] + summary.click() + before = browser.execute_script('return arguments[0].parentElement.open', summary) + summary.send_keys(Keys.SPACE) + assert browser.execute_script('return arguments[0].parentElement.open', summary) != before + browser.execute_script('arguments[0].parentElement.open=false', summary) + if relative == 'offline.html': + assert browser.find_elements(By.CSS_SELECTOR, 'sup a[href="#fn-one"]') + assert browser.find_elements(By.CSS_SELECTOR, '.footnotes #fn-one a[href="#fnref-one"]') + assert 'Footnote[^one]' not in browser.find_element(By.TAG_NAME, 'article').text + browser.find_element(By.CSS_SELECTOR, 'article a[href="#tables"]').click() + assert browser.execute_script('return decodeURIComponent(location.hash)') == '#tables' + browser.execute_script('scrollTo(0,0)') + if relative.startswith('writerside/'): + assert browser.find_elements(By.CSS_SELECTOR, '.instance-nav a[aria-current="page"]') or relative.endswith('hidden.html') + stem = f'{engine}-{mode}-{relative.replace("/", "-")}' + browser.save_screenshot(str(args.output / f'{stem}.png')) + options = PrintOptions(); options.background = True + pdf = args.output / f'{stem}.pdf' + pdf.write_bytes(base64.b64decode(browser.print_page(options))) + printed = subprocess.check_output(['pdftotext', '-layout', str(pdf), '-'], text=True) + if relative == 'offline.html': assert 'Disclosure body must print.' in printed, printed + if relative.endswith('reference.html'): assert 'All details are printable.' in printed, printed + if relative.endswith(('index.html','Welcome.html')): + assert 'All Linux instructions.' in printed and 'All Windows instructions.' in printed + # WebDriver may evaluate code, but source-injected scripts + # must still be blocked by the document CSP. + browser.execute_script("const s=document.createElement('script');s.textContent='window.__htmlProbe=1';document.body.append(s)") + assert browser.execute_script('return window.__htmlProbe || 0') == 0 + assert not blocked, blocked + report['checks'].append({'engine':engine,'version':browser.capabilities['browserVersion'], + 'mode':mode,'page':relative,'images':len(values['images']), + 'requests':list(requests),'print_bytes':pdf.stat().st_size}) + print(engine, mode, relative, 'PASS', flush=True) + finally: + browser.quit() + report['ok'] = True + finally: + server.shutdown() + (args.output / 'browser-report.json').write_text(json.dumps(report, indent=2)) + print(json.dumps({'ok':True,'checks':len(report['checks']),'relocated_root':str(relocated)})) + +if __name__ == '__main__': main() From ae4469da688c02b2ffb99565786b72016191bcc2 Mon Sep 17 00:00:00 2001 From: albert Date: Sat, 5 Sep 2026 13:30:00 -0700 Subject: [PATCH 07/37] Defer monitor refresh during foreground loading --- lib/src/workspace/workspace_controller.dart | 24 ++++++-- test/src/workspace_controller_test.dart | 65 +++++++++++++++++++++ 2 files changed, 84 insertions(+), 5 deletions(-) diff --git a/lib/src/workspace/workspace_controller.dart b/lib/src/workspace/workspace_controller.dart index b2c09a27..b8d6534b 100644 --- a/lib/src/workspace/workspace_controller.dart +++ b/lib/src/workspace/workspace_controller.dart @@ -596,6 +596,7 @@ class WorkspaceController extends Notifier { } Future _handleFileMonitorEvent(WorkspaceFileMonitorEvent event) async { + if (!ref.mounted) return; final matching = state.documentBuffers.where((buffer) { final path = buffer.filePath; return path != null && @@ -605,6 +606,7 @@ class WorkspaceController extends Notifier { }).toList(); for (final buffer in matching) { await _applyExternalFileState(buffer, event); + if (!ref.mounted) return; } final workspaceRoot = state.workspace?.rootPath; if (workspaceRoot == null || @@ -612,11 +614,21 @@ class WorkspaceController extends Notifier { !p.isWithin(workspaceRoot, event.path))) { return; } + _scheduleMonitoredWorkspaceRefresh(); + } + + void _scheduleMonitoredWorkspaceRefresh() { _workspaceRefreshDebounce?.cancel(); - _workspaceRefreshDebounce = Timer( - const Duration(milliseconds: 250), - () => unawaited(refreshWorkspaceFromDiskPreservingOpenTabs()), - ); + _workspaceRefreshDebounce = Timer(const Duration(milliseconds: 250), () { + if (!ref.mounted) return; + // Our own filesystem writes also emit notifications. A background + // refresh must not invalidate an operation already loading its result. + if (state.isLoading) { + _scheduleMonitoredWorkspaceRefresh(); + return; + } + unawaited(refreshWorkspaceFromDiskPreservingOpenTabs()); + }); } Future _applyExternalFileState( @@ -2928,6 +2940,7 @@ class WorkspaceController extends Notifier { ? workspace.activeFilePath ?? workspace.rootPath : workspace.rootPath; final refreshed = await _service.openPath(openTarget); + if (!_isCurrentActiveDocumentOperation(operationRevision)) return false; final refreshedWorkspace = workspace.kind == WorkspaceKind.singleMarkdown ? workspace.copyWith( files: _mergedDocumentFiles(workspace.files, refreshed.files), @@ -2973,6 +2986,7 @@ class WorkspaceController extends Notifier { ), ); } + if (!_isCurrentActiveDocumentOperation(operationRevision)) return false; var activeBuffer = buffers .where((buffer) => buffer.id == state.activeBufferId) .firstOrNull; @@ -3353,7 +3367,7 @@ class WorkspaceController extends Notifier { } bool _isCurrentActiveDocumentOperation(int operationRevision) { - return operationRevision == _activeDocumentRevision; + return ref.mounted && operationRevision == _activeDocumentRevision; } bool _isCurrentActiveDocument( diff --git a/test/src/workspace_controller_test.dart b/test/src/workspace_controller_test.dart index 99687eb6..8c1dee21 100644 --- a/test/src/workspace_controller_test.dart +++ b/test/src/workspace_controller_test.dart @@ -1618,6 +1618,36 @@ void main() { }, ); + test('monitor refresh waits for an active foreground refresh', () async { + final directory = await Directory.systemTemp.createTemp( + 'busymark-refresh-', + ); + addTearDown(() => directory.delete(recursive: true)); + File(p.join(directory.path, 'a.md')).writeAsStringSync('# Original\n'); + final monitor = _ControlledFileMonitor(); + addTearDown(monitor.dispose); + final service = _GatedRefreshWorkspaceService(); + final harness = await _createControllerHarness( + service: service, + fileMonitor: monitor, + ); + await harness.controller.openPath(directory.path); + service.gate = Completer(); + final refresh = harness.controller.refreshWorkspaceFromDisk(); + await _waitFor(() => service.refreshStarts == 1); + monitor.emit(directory.path); + // Cross the controller's debounce while the foreground operation is held. + await Future.delayed(const Duration(milliseconds: 350)); + final startsWhileLoading = service.refreshStarts; + service.gate!.complete(); + service.gate = null; + final succeeded = await refresh; + await _waitFor(() => !harness.controller.state.isLoading); + expect(startsWhileLoading, 1); + expect(succeeded, isTrue); + expect(harness.controller.state.activeText, '# Original\n'); + }); + test('external file moves remap the open document buffer', () async { final directory = await Directory.systemTemp.createTemp( 'busymark-external-move-', @@ -2542,3 +2572,38 @@ WorkspaceFileSnapshot _delayedSnapshot(String text, [int revision = 0]) { final _autosaveInitialModifiedAt = DateTime(2026); final _delayedInitialModifiedAt = DateTime(2026, 2); + +class _ControlledFileMonitor extends WorkspaceFileMonitor { + final _events = StreamController.broadcast(); + @override + Stream get events => _events.stream; + void emit(String path) => _events.add( + WorkspaceFileMonitorEvent( + kind: WorkspaceFileEventKind.workspaceChanged, + path: path, + ), + ); + @override + Future start({ + required String rootPath, + required Iterable openFilePaths, + }) async {} + @override + void updateOpenFilePaths(Iterable paths) {} + @override + Future dispose() => _events.close(); +} + +class _GatedRefreshWorkspaceService extends WorkspaceService { + Completer? gate; + var refreshStarts = 0; + @override + Future openPath(String path) async { + final pending = gate; + if (pending != null) { + refreshStarts++; + await pending.future; + } + return super.openPath(path); + } +} From 620c2f993b30c8eb5cdde577e3addb5bc215be1a Mon Sep 17 00:00:00 2001 From: albert Date: Sat, 5 Sep 2026 13:33:00 -0700 Subject: [PATCH 08/37] Customize PDF and HTML exports --- .github/workflows/flutter-linux.yml | 2 + README.md | 9 +- assets/export/html.css | 8 +- assets/export/markdown.typ | 56 +- docs/html-export-verification.md | 165 +++-- docs/html-export.md | 261 +++----- docs/pdf-export.md | 52 ++ docs/writerside-pdf-export.md | 36 +- lib/l10n/app_ar.arb | 45 +- lib/l10n/app_de.arb | 45 +- lib/l10n/app_en.arb | 57 ++ lib/l10n/app_es.arb | 45 +- lib/l10n/app_et.arb | 45 +- lib/l10n/app_fa.arb | 45 +- lib/l10n/app_fr.arb | 45 +- lib/l10n/app_hi.arb | 45 +- lib/l10n/app_id.arb | 45 +- lib/l10n/app_it.arb | 45 +- lib/l10n/app_ja.arb | 45 +- lib/l10n/app_ko.arb | 45 +- lib/l10n/app_nb.arb | 45 +- lib/l10n/app_nl.arb | 45 +- lib/l10n/app_pl.arb | 45 +- lib/l10n/app_pt.arb | 45 +- lib/l10n/app_pt_BR.arb | 45 +- lib/l10n/app_ru.arb | 45 +- lib/l10n/app_tr.arb | 45 +- lib/l10n/app_uk.arb | 45 +- lib/l10n/app_vi.arb | 45 +- lib/l10n/app_zh.arb | 45 +- lib/l10n/app_zh_CN.arb | 45 +- lib/l10n/generated/app_localizations.dart | 258 ++++++++ lib/l10n/generated/app_localizations_ar.dart | 135 ++++ lib/l10n/generated/app_localizations_de.dart | 136 ++++ lib/l10n/generated/app_localizations_en.dart | 135 ++++ lib/l10n/generated/app_localizations_es.dart | 135 ++++ lib/l10n/generated/app_localizations_et.dart | 135 ++++ lib/l10n/generated/app_localizations_fa.dart | 135 ++++ lib/l10n/generated/app_localizations_fr.dart | 136 ++++ lib/l10n/generated/app_localizations_hi.dart | 135 ++++ lib/l10n/generated/app_localizations_id.dart | 136 ++++ lib/l10n/generated/app_localizations_it.dart | 136 ++++ lib/l10n/generated/app_localizations_ja.dart | 134 ++++ lib/l10n/generated/app_localizations_ko.dart | 134 ++++ lib/l10n/generated/app_localizations_nb.dart | 135 ++++ lib/l10n/generated/app_localizations_nl.dart | 135 ++++ lib/l10n/generated/app_localizations_pl.dart | 135 ++++ lib/l10n/generated/app_localizations_pt.dart | 270 ++++++++ lib/l10n/generated/app_localizations_ru.dart | 135 ++++ lib/l10n/generated/app_localizations_tr.dart | 135 ++++ lib/l10n/generated/app_localizations_uk.dart | 135 ++++ lib/l10n/generated/app_localizations_vi.dart | 135 ++++ lib/l10n/generated/app_localizations_zh.dart | 268 ++++++++ lib/src/app/app_settings.dart | 23 + lib/src/app/busymark_design.dart | 9 + lib/src/export/export_metadata_mapper.dart | 70 ++ lib/src/export/export_options.dart | 481 ++++++++++++++ lib/src/export/export_options_editor.dart | 618 ++++++++++++++++++ lib/src/export/html_document_writer.dart | 192 ++++-- lib/src/export/html_export_assets.dart | 36 +- lib/src/export/html_export_models.dart | 4 + lib/src/export/html_export_service.dart | 32 +- lib/src/export/html_export_styles.dart | 94 +++ lib/src/export/html_export_ui.dart | 61 +- lib/src/export/html_release_smoke.dart | 64 +- lib/src/export/html_rich_content.dart | 4 +- lib/src/export/markdown_export_mapper.dart | 97 +-- lib/src/export/markdown_math_export.dart | 29 +- .../export/markdown_pdf_export_service.dart | 24 +- lib/src/export/markdown_pdf_export_ui.dart | 112 +--- lib/src/export/markdown_pdf_models.dart | 53 +- lib/src/export/typst_compiler.dart | 13 +- lib/src/export/typst_payload_builder.dart | 25 +- lib/src/export/writerside_pdf_export_ui.dart | 166 +---- lib/src/export/writerside_pdf_models.dart | 4 +- lib/src/math/math_models.dart | 7 +- lib/src/math/math_renderer.dart | 2 +- .../visualization_release_smoke.dart | 51 +- linux/CMakeLists.txt | 23 + snap/snapcraft.yaml | 3 + test/src/export_options_editor_test.dart | 301 +++++++++ test/src/export_options_test.dart | 243 +++++++ test/src/html_export_options_test.dart | 279 ++++++++ test/src/html_export_ui_test.dart | 6 + test/src/html_publication_test.dart | 55 ++ test/src/html_rich_export_test.dart | 69 +- test/src/localization_audit_test.dart | 3 + test/src/markdown_export_mapper_test.dart | 6 +- test/src/markdown_math_export_test.dart | 61 +- .../src/markdown_pdf_export_service_test.dart | 6 +- test/src/markdown_pdf_export_test.dart | 2 +- .../markdown_visualization_export_test.dart | 2 +- test/src/pdf_export_options_render_test.dart | 265 ++++++++ test/src/writerside_pdf_export_test.dart | 37 +- tools/verify_html_export_browser.py | 49 +- 95 files changed, 7809 insertions(+), 871 deletions(-) create mode 100644 docs/pdf-export.md create mode 100644 lib/src/export/export_metadata_mapper.dart create mode 100644 lib/src/export/export_options.dart create mode 100644 lib/src/export/export_options_editor.dart create mode 100644 lib/src/export/html_export_styles.dart create mode 100644 test/src/export_options_editor_test.dart create mode 100644 test/src/export_options_test.dart create mode 100644 test/src/html_export_options_test.dart create mode 100644 test/src/pdf_export_options_render_test.dart diff --git a/.github/workflows/flutter-linux.yml b/.github/workflows/flutter-linux.yml index 1b1766ee..7c4388e5 100644 --- a/.github/workflows/flutter-linux.yml +++ b/.github/workflows/flutter-linux.yml @@ -32,6 +32,8 @@ jobs: bubblewrap \ clang \ cmake \ + fonts-noto-core \ + fonts-noto-mono \ ninja-build \ pkg-config \ libgtk-3-dev \ diff --git a/README.md b/README.md index dc607599..a047dca3 100644 --- a/README.md +++ b/README.md @@ -110,8 +110,11 @@ disabled in the text editor. Version-control metadata directories such as Use **Main menu → Export as PDF** or Ctrl+Shift+E to export either the active Markdown document or the opened Writerside module. Markdown export uses the current editor contents, including unsaved changes, -and offers A4 or Letter paper, portrait or landscape orientation, three margin -sizes, and optional page numbers. +and offers A4, Letter, Legal or custom paper, orientation and independent margins, +Noto typography, accent colors, title headers/footers, positioned page numbers, +and optional TOC and heading numbering. Settings are remembered separately for +PDF and HTML; **Reset to defaults** restores each format’s defaults. See +[PDF export settings](docs/pdf-export.md). Markdown PDF generation is local and offline. BusyMark bundles the pinned Typst compiler; users do not install or configure a separate program. Local PNG, @@ -302,7 +305,7 @@ component with BusyMark and do not install development packages, Node.js, Java, or Chromium. ```bash -sudo apt-get install curl libhandy-1-dev xz-utils libwebkit2gtk-4.1-dev +sudo apt-get install curl libhandy-1-dev xz-utils libwebkit2gtk-4.1-dev fonts-noto-core fonts-noto-mono # Install Node.js 22 or newer from https://nodejs.org/en/download node --version npm --version diff --git a/assets/export/html.css b/assets/export/html.css index 82058e60..6ba885bb 100644 --- a/assets/export/html.css +++ b/assets/export/html.css @@ -1,5 +1,7 @@ -:root{color-scheme:light;font-family:system-ui,sans-serif;font-size:17px;line-height:1.65;color:#20242b;background:#fff} -*{box-sizing:border-box}body{margin:0}main{max-width:54rem;margin:auto;padding:2rem 3rem 5rem;min-width:0}article{overflow-wrap:anywhere}h1,h2,h3,h4,h5,h6{line-height:1.25;color:#111827;scroll-margin-top:1rem}h1{font-size:2.3rem;margin:0 0 1.2rem}h2{font-size:1.75rem;margin-top:2.1rem}h3{font-size:1.3rem;margin-top:1.8rem}p{margin:1rem 0}a{color:#1559aa;text-underline-offset:.16em}a:hover{text-decoration-thickness:2px}a:focus-visible,summary:focus-visible,[tabindex]:focus-visible{outline:3px solid #a34200;outline-offset:4px;border-radius:2px}img,video{max-width:100%;height:auto}figure{margin:1.5rem 0}figcaption,caption{font-size:.9rem;color:#4b5563;text-align:start}pre{overflow:auto;white-space:pre;max-width:100%;padding:1rem;border:1px solid #d8dee6;border-radius:.35rem;background:#f6f8fa;font-size:.86rem;line-height:1.55;overflow-wrap:normal}code,kbd,samp{font-family:ui-monospace,monospace;font-size:.9em}p code,li code{background:#f1f3f5;padding:.1rem .25rem;border-radius:.2rem}kbd{border:1px solid #cbd2da;padding:.1rem .3rem;border-radius:.2rem}ul,ol{padding-inline-start:1.6rem}li{margin:.35rem 0}.task{list-style:none}.task input{margin-inline-start:-1.5rem;margin-inline-end:.5rem}blockquote,.admonition{margin:1.4rem 0;padding:.25rem 1.2rem;border-inline-start:4px solid #6b7280;background:#f5f6f8}.warning{border-color:#a34200;background:#fff6e9}.tip{border-color:#247550;background:#f0faf4}.note{border-color:#2366aa;background:#f1f7fd}.admonition-title{font-weight:650;text-transform:capitalize}details{border:1px solid #d8dee6;border-radius:.35rem;padding:.7rem 1rem;margin:1rem 0}summary{cursor:pointer;font-weight:600}details>summary+*{margin-top:1rem}dl{margin:1rem 0}dt{font-weight:650;margin-top:1rem}dd{margin-inline-start:1.5rem}.table-scroll{overflow-x:auto;max-width:100%;margin:1.5rem 0}table{border-collapse:collapse;min-width:60%;font-size:.94rem}th,td{padding:.6rem .8rem;border:1px solid #ccd4dd;vertical-align:top;text-align:start}th{background:#eef2f6;font-weight:650}td>:first-child,th>:first-child{margin-top:0}td>:last-child,th>:last-child{margin-bottom:0}.align-left{text-align:left}.align-center{text-align:center}.align-right{text-align:right}.math-inline{max-width:none}.display-math{overflow-x:auto;text-align:center;margin:1.5rem 0}.math-display{display:inline-block}.unavailable-image,.unsupported,.math-fallback{color:#713b12}.tab-panel,.card,.switcher-section{border:1px solid #d8dee6;padding:1rem;margin:1rem 0;border-radius:.4rem}.tab-panel>h3:first-child{margin-top:0}.variant-label,.status{font-size:.85rem;font-weight:600;color:#713b12}.outline{font-size:.9rem;margin-bottom:2rem}.outline ul{columns:2}.instance-nav{padding:1rem 1.5rem;background:#f5f7fa;border-bottom:1px solid #d8dee6}.instance-nav ul{list-style:none;padding-inline-start:1rem}.instance-nav details{border:none;padding:.2rem;margin:.2rem 0}.instance-nav a[aria-current=page]{font-weight:700;color:#111827;text-decoration-thickness:2px}.skip-link{position:absolute;inset-inline-start:1rem;top:-10rem;background:white;padding:.5rem;z-index:2}.skip-link:focus{top:.5rem}.footnotes{font-size:.9rem;border-top:1px solid #ccd4dd;margin-top:3rem;padding-top:1rem}hr{border:0;border-top:1px solid #ccd4dd;margin:2rem 0} -@media(min-width:78rem){body:has(.instance-nav){display:grid;grid-template-columns:19rem minmax(0,1fr)}.instance-nav{height:100vh;position:sticky;top:0;overflow:auto;border-bottom:0;border-inline-end:1px solid #d8dee6}main{width:100%}} +:root{font-family:var(--body-font,system-ui,sans-serif);font-size:var(--body-size,17px);line-height:1.65;color:var(--fg);background:var(--bg)} +*{box-sizing:border-box}body{margin:0}main{max-width:var(--content-width,918px);margin:auto;padding:2rem 3rem 5rem;min-width:0}article{overflow-wrap:anywhere}h1,h2,h3,h4,h5,h6{line-height:1.25;color:var(--heading);scroll-margin-top:1rem}h1{font-size:2.3rem;margin:0 0 1.2rem}h2{font-size:1.75rem;margin-top:2.1rem}h3{font-size:1.3rem;margin-top:1.8rem}p{margin:1rem 0}a{color:var(--link);text-underline-offset:.16em}a:hover{text-decoration-thickness:2px}a:focus-visible,summary:focus-visible,[tabindex]:focus-visible{outline:3px solid var(--focus);outline-offset:4px;border-radius:2px}img,video{max-width:100%;height:auto}figure{margin:1.5rem 0}figcaption,caption{font-size:.9rem;color:var(--muted);text-align:start}pre{overflow:auto;white-space:pre;max-width:100%;padding:1rem;border:1px solid var(--border);border-radius:.35rem;background:var(--code);font-size:.86rem;line-height:1.55;overflow-wrap:normal}code,kbd,samp{font-family:ui-monospace,monospace;font-size:.9em}p code,li code{background:var(--inline-code);padding:.1rem .25rem;border-radius:.2rem}kbd{border:1px solid var(--border);padding:.1rem .3rem;border-radius:.2rem}ul,ol{padding-inline-start:1.6rem}li{margin:.35rem 0}.task{list-style:none}.task input{margin-inline-start:-1.5rem;margin-inline-end:.5rem}blockquote,.admonition{margin:1.4rem 0;padding:.25rem 1.2rem;border-inline-start:4px solid var(--muted);background:var(--surface)}.warning{border-color:var(--focus);background:var(--warning)}.tip{border-color:#247550;background:var(--tip)}.note{border-color:#2366aa;background:var(--note)}.admonition-title{font-weight:650;text-transform:capitalize}details{border:1px solid var(--border);border-radius:.35rem;padding:.7rem 1rem;margin:1rem 0}summary{cursor:pointer;font-weight:600}details>summary+*{margin-top:1rem}dl{margin:1rem 0}dt{font-weight:650;margin-top:1rem}dd{margin-inline-start:1.5rem}.table-scroll{overflow-x:auto;max-width:100%;margin:1.5rem 0}table{border-collapse:collapse;min-width:60%;font-size:.94rem}th,td{padding:.6rem .8rem;border:1px solid var(--border);vertical-align:top;text-align:start}th{background:var(--table);font-weight:650}td>:first-child,th>:first-child{margin-top:0}td>:last-child,th>:last-child{margin-bottom:0}.align-left{text-align:left}.align-center{text-align:center}.align-right{text-align:right}.math-inline{max-width:none}.display-math{overflow-x:auto;text-align:center;margin:1.5rem 0}.math-display{display:inline-block}.unavailable-image,.unsupported,.math-fallback{color:var(--status)}.tab-panel,.card,.switcher-section{border:1px solid var(--border);padding:1rem;margin:1rem 0;border-radius:.4rem}.tab-panel>h3:first-child{margin-top:0}.variant-label,.status{font-size:.85rem;font-weight:600;color:var(--status)}.outline{font-size:.9rem;margin-bottom:2rem}.outline>details>ul{columns:2}.outline ul ul{columns:1}.instance-nav{padding:1rem 1.5rem;background:var(--surface);border-bottom:1px solid var(--border)}.instance-nav ul{list-style:none;padding-inline-start:1rem}.instance-nav details{border:none;padding:.2rem;margin:.2rem 0}.instance-nav a[aria-current=page]{font-weight:700;color:var(--heading);text-decoration-thickness:2px}.skip-link{position:absolute;inset-inline-start:1rem;top:-10rem;background:var(--bg);padding:.5rem;z-index:2}.skip-link:focus{top:.5rem}.footnotes{font-size:.9rem;border-top:1px solid var(--border);margin-top:3rem;padding-top:1rem}hr{border:0;border-top:1px solid var(--border);margin:2rem 0} +@media(min-width:78rem){body:has(.instance-nav){display:grid;grid-template-columns:19rem minmax(0,1fr)}.instance-nav{height:100vh;position:sticky;top:0;overflow:auto;border-bottom:0;border-inline-end:1px solid var(--border)}main{width:100%}} @media(max-width:40rem){main{padding:1.5rem 1rem}.outline ul{columns:1}h1{font-size:1.9rem}} @media print{.instance-nav,.outline,.skip-link{display:none!important}body{display:block!important}main{max-width:none;padding:0}details{border:0}details::details-content{display:block!important;content-visibility:visible!important}details>*{display:block!important}summary{font-weight:bold}pre{white-space:pre-wrap;overflow:visible;font-size:9pt}.table-scroll{overflow:visible}table{width:100%;font-size:9pt}thead{display:table-header-group}tr,img,figure{break-inside:avoid}a{color:inherit}img,video{max-width:100%}.math-inline{max-width:none}.tab-panel,.card{break-inside:avoid}h1,h2,h3{break-after:avoid}} + +.math-inline,.math-display{filter:var(--math-filter)}.heading-number{font-variant-numeric:tabular-nums}h4,h5,h6{font-size:1rem} diff --git a/assets/export/markdown.typ b/assets/export/markdown.typ index 1f38aa93..f3077dc9 100644 --- a/assets/export/markdown.typ +++ b/assets/export/markdown.typ @@ -10,30 +10,45 @@ description: document-metadata.description, keywords: document-metadata.keywords, ) +#assert(data.schemaVersion == 2, message: "Unsupported export payload") +#let typography = options.typography +#let geometry = options.page +#let margins = geometry.marginsPt +#let running-visible() = options.showHeaderFooterOnFirstPage or counter(page).get().first() > 1 +#let number-position = if options.pageNumbers == "bottomLeft" { left } else if options.pageNumbers == "bottomRight" { right } else { center } #set page( - paper: options.paper, - flipped: options.landscape, - margin: ( - x: options.marginHorizontalPt * 1pt, - y: options.marginVerticalPt * 1pt, - ), - numbering: if options.pageNumbers { "1" } else { none }, - number-align: center + bottom, + width: geometry.widthPt * 1pt, + height: geometry.heightPt * 1pt, + margin: (top: margins.top * 1pt, right: margins.right * 1pt, bottom: margins.bottom * 1pt, left: margins.left * 1pt), + // Logical page numbering also supplies native outline page references. + // First-page visibility belongs to the running footer, never the numbering + // function: an outline on that page must still show its destination numbers. + numbering: "1", + number-align: number-position + bottom, + header: if options.header == "none" { none } else { context { if running-visible() { text(document-metadata.title) } } }, + footer: if options.footer == "none" and options.pageNumbers == "off" { none } else { context { + if running-visible() { + // Native page footer content combines title and counter without overlap. + if options.footer == "documentTitle" { align(center, text(document-metadata.title)) } + if options.pageNumbers != "off" { align(number-position, counter(page).display("1")) } + } + } }, ) #set text( + font: typography.bodyFont, fallback: true, - size: 10.5pt, - lang: document-metadata.language, + size: typography.bodySizePt * 1pt, + lang: document-metadata.language.split("-").first(), + region: if document-metadata.language.split("-").len() == 2 and document-metadata.language.split("-").last().len() == 2 { document-metadata.language.split("-").last() } else { none }, ) #set par(leading: 0.68em) -#set heading(numbering: none) -#show heading.where(level: 1): set text(size: 22pt, weight: "bold") -#show heading.where(level: 2): set text(size: 17pt, weight: "bold") -#show heading.where(level: 3): set text(size: 13.5pt, weight: "bold") -#show heading.where(level: 4): set text(size: 11.5pt, weight: "bold") -#show heading.where(level: 5): set text(size: 10.5pt, weight: "bold") -#show heading.where(level: 6): set text(size: 10.5pt, weight: "bold") -#show link: set text(fill: rgb("2563a5")) +#set heading(numbering: if options.content.numberHeadings { "1.1" } else { none }) +#show heading: it => { + set text(size: typography.headingSizesPt.at(calc.min(it.level, 6) - 1) * 1pt, weight: "bold") + it +} +#show raw: set text(font: typography.codeFont, size: typography.codeSizePt * 1pt) +#show link: set text(fill: rgb(options.accentColor)) #let value-or(item, key, default) = item.at(key, default: default) @@ -376,4 +391,9 @@ } } +#if options.content.includeToc { + outline(depth: options.content.tocDepth) + v(1em) +} + #for block-data in data.blocks { render-block(block-data) } diff --git a/docs/html-export-verification.md b/docs/html-export-verification.md index ee78f396..57e031fa 100644 --- a/docs/html-export-verification.md +++ b/docs/html-export-verification.md @@ -1,65 +1,108 @@ -# HTML export verification — September 5, 2026 +# PDF and HTML export verification — September 5, 2026 -The implementation and reproduction commands are described in -[HTML export](html-export.md). Validation used Flutter 3.47.0 on Linux and the -application's bundled rendering executables; no dependency was added to the -application for HTML serialization or browser-side rendering. +Validation used Flutter 3.47.0 on Linux, bundled Typst 0.15.1, the bundled Noto +fonts, and BusyMark’s existing local math and visualization engines. User-facing +settings are documented in [PDF export](pdf-export.md), [HTML export](html-export.md), +and [Writerside PDF export](writerside-pdf-export.md). -| Check | Executed result | +## Implementation areas + +- `lib/src/export/export_options.dart` supplies shared content options and one + validated, serializable option model per format. `app_settings.dart` persists + the last confirmed values through the existing settings store. +- `export_options_editor.dart` supplies the reusable modal editors for Markdown + and Writerside. Existing PDF and HTML export UI entry points use those editors; + Writerside retains its workspace-specific instance and Save/Discard/Cancel flow. +- `typst_payload_builder.dart`, `markdown_math_export.dart`, `typst_compiler.dart`, + and `assets/export/markdown.typ` carry PDF geometry, typography, native TOC, + numbering, accent, and running text through payload schema 2. The semantic + `markdown_export_mapper.dart` no longer sets PDF math metrics. +- `html_document_writer.dart`, `html_export_styles.dart`, `html_export_assets.dart`, + and the HTML service/rich-content preparation apply themes, typography, semantic + TOCs, numbering, bounded custom CSS, and both resource packaging modes. + `export_metadata_mapper.dart` provides common resolved metadata. +- Linux and Snap build configuration stages Noto Sans, Serif, Mono and available + Noto script fallbacks. Localization sources and generated output cover all new + settings. Focused model, widget, payload, native PDF, HTML, math and Writerside + tests sit beside the existing export tests. + +## Executed checks + +| Check | Result | | --- | --- | -| Dart formatting of changed handwritten sources | Passed; no formatting changes required | +| Changed Dart sources formatted; `git diff --check`; Python browser script syntax | Passed | | Repository-wide `flutter analyze --no-pub` | Passed; no issues | -| `flutter gen-l10n` | Passed; new HTML and missing Writerside messages supplied for all shipped regional locales | -| Full `flutter test --no-pub`, with `BUSYMARK_TYPST_PATH` and `BUSYMARK_D2_PATH` pointing to the release bundle | **1,438 passed, no skips** | -| Focused rich-export checks after improving renderer failure messages | Passed; profiles, snapshots, timeout fallback, active cancellation and output preservation | -| `flutter build linux --release --no-pub` | Passed | -| Native release smoke under Xvfb | Passed; real MathJax 4.1.3, Mermaid, PlantUML, D2, static OpenAPI and existing PDF smoke; zero HTML warnings | -| Relocated browser checks | **20 passed**: five pages × two URL modes × two browsers | -| `git diff --check` and Python browser-check syntax compilation | Passed | - -The full suite includes the existing PDF exports and native configuration, -localization, source preservation, and editor regression tests. Base `pt` and -`zh` localization templates remain partial as before; the shipped `pt_BR` and -`zh_CN` locales have complete messages and pass the localization audit. - -Browser verification used **Chromium/Chrome 151.0.7922.137** and **Firefox -154.0.1**. Each opened the relocated Markdown page and all four Writerside HTML -files directly through `file:` URLs and through a local static HTTP server. -Outbound proxy connections were unavailable, and BiDi observation recorded no -unexpected external request. HTTP-only favicon probes were local 404s and are -not export dependencies. - -Checks covered stylesheet/CSP hashing, image loading, internal anchors, -footnote references and return links, current navigation, keyboard focus, -disclosure interaction, horizontal overflow, script blocking, and printing. -PDF text extraction confirmed that collapsed disclosure content and every tab -were printed. Representative Chromium and Firefox screenshots were also -visually inspected. The footnote case crosses a raw HTML disclosure block, -exercising the corrected shared reference context. - -Representative outputs from the real release binary: - -- `/tmp/busymark-html-final/offline.html` and `offline.assets/`: unsaved-source - export path, Unicode headings, nested/task lists, tables, disclosure, a local - SVG, inline/display math, three diagram engines, static API reference, and a - structured footnote. -- `/tmp/busymark-html-final/writerside/index.html`: selected-instance entry point, - also preserved as `Welcome.html`; includes with caller variable overrides, - all tabs, procedure steps, custom filename, hidden-page links and WIP status. -- `/tmp/busymark-html-final/writerside/reference.html`: spanning table, - collapsible chapter, and a diagram loaded from the configured snippets folder. -- `/tmp/busymark-html-final/writerside/hidden.html`: link-accessible hidden topic. -- `/tmp/busymark-html-final/visualization-smoke.pdf`: existing PDF verification. - -Native results are recorded in `/tmp/busymark-html-final/report.json`. Browser -results, screenshots, and printed PDFs are under -`/tmp/busymark-html-browser-final/`; its `browser-report.json` identifies the -separate relocated root. Sources and engine temporary directories were removed -before the relocated copies were opened. These paths are verification artifacts, -not dependencies of the exported documents, and may be removed by temporary-file -cleanup. The committed scripts reproduce them. - -No requested automated check remains unavailable. Browser interaction and print -verification ran headlessly; physical-printer output and assistive-technology -certification were not tested. This is behavioral validation of BusyMark's native -export, not an assertion of pixel parity with JetBrains' website builder. +| `flutter gen-l10n` and localization audit | Passed | +| Full `flutter test --no-pub` with bundled Typst and D2 paths | **1,469 passed; no skips** | +| Native PDF customization tests | Six profiles compiled; page geometry, embedded Noto families, body/code sizes, native outline entries/page references, heading numbering, running titles and counter placement verified | +| Workspace refresh regression | Reproduced before the fix; all 63 controller tests pass after the fix | +| `flutter build linux --release --no-pub` | Passed; final release bundle includes Noto fonts and licenses | +| Release application smoke under Xvfb | Passed; MathJax 4.1.3, Mermaid, PlantUML, D2, static OpenAPI, default/custom PDFs and Markdown/Writerside HTML; zero HTML warnings | +| Relocated browser verification | **46 passed** in Chrome 151.0.7922.137 and Firefox 154.0.1 | + +The new tests cover absent/malformed persisted settings, validation and geometry, +all four dialogs’ reuse of remembered format options, dependent controls, Reset, +cancellation, CSS validation and ordering, embedded and external assets, output +bounds, existing-output preservation, metadata, TOC hierarchy/depth, numbering, +custom math metrics, and unchanged Writerside resolution and publication order. +Existing PDF, HTML, native menu, source-preservation and editor tests remain part +of the complete suite. + +Full-suite verification exposed an existing filesystem-monitor race: a background +refresh could invalidate a foreground Writerside operation. A controlled regression +test reproduced that failure. Monitor refreshes now wait for active loading to +finish, and stale/disposed refreshes stop before changing controller state. + +Base `pt` and `zh` localization templates remain partial as before. The shipped +`pt_BR` and `zh_CN` locales have complete messages and pass the localization audit. + +## Browser and output verification + +Browser checks open relocated Markdown and Writerside pages through both `file:` +URLs and a local static HTTP server, with external networking unavailable. They +verify image loading, CSP/style hashing, metadata, custom CSS overrides, typography, +automatic light/dark preference, embedded resources, anchors, footnotes, navigation, +keyboard focus, disclosure, overflow, script blocking and printing. Request +observation recorded no unexpected external resources; local favicon 404 probes +are not document dependencies. Representative screenshots were visually inspected. +Print checks include disclosure bodies and every Writerside tab. + +Representative outputs generated by the release application: + +- `/tmp/busymark-custom-output/offline.html` and `offline.assets/`: default + Markdown output with Unicode headings, nested/task lists, tables, disclosure, + local SVG, inline/display math, three diagram engines, static API and footnotes. +- `/tmp/busymark-custom-output/automatic-single.html`: automatic theme, embedded + resources, 20 px serif text, customized width/accent, numbered headings and CSS. +- `/tmp/busymark-custom-output/dark-assets.html`: dark appearance with companion + resources using relative URLs. +- `/tmp/busymark-custom-output/writerside/index.html`: default multipage instance + with includes, variables, all tabs, procedures, custom filenames, hidden topics + and work-in-progress status. +- `/tmp/busymark-custom-output/writerside-embedded/index.html`: the same instance + with shared customization and embedded resources in each topic page. +- `/tmp/busymark-custom-output/visualization-smoke.pdf`: default PDF rich content. +- `/tmp/busymark-custom-output/customized.pdf`: 240 × 320 mm pages, independent + margins, 14 pt Noto Sans, 11 pt code, purple accent, numbered native TOC, + title headers/footers, right-aligned page numbers and first-page suppression. + +Native results are in `/tmp/busymark-custom-output/report.json`. Browser results, +screenshots and printed PDFs are under `/tmp/busymark-custom-browser-final/`; +`browser-report.json` identifies the separate relocated root. The source fixtures +and renderer temporary directories were removed before opening relocated copies. +These temporary artifact paths are not export dependencies and may be cleaned up. + +To reproduce with a release bundle and the browser-check dependencies installed: + +```sh +BUSYMARK_RELEASE_SMOKE=1 xvfb-run -a build/linux/x64/release/bundle/busymark \ + --visualization-release-smoke=/tmp/busymark-custom-output/report.json +python3 tools/verify_html_export_browser.py /tmp/busymark-custom-output \ + --output /tmp/busymark-custom-browser-final +``` + +Browser and print verification ran headlessly. Physical-printer output, assistive +technology certification, and a complete Snap package build were not performed; +the Linux bundle and its staged Noto fonts/licenses were verified. The existing +HTML exporter has no client-side syntax highlighter, so this change retains its +code rendering and supplies a theme-aware code palette without another dependency. diff --git a/docs/html-export.md b/docs/html-export.md index b8bbe11b..5f809383 100644 --- a/docs/html-export.md +++ b/docs/html-export.md @@ -1,174 +1,91 @@ # HTML export -Use **Main menu → Export as HTML…** or the command palette's **Export as HTML…** -command. The GTK header menu and Flutter menu have the same availability. PDF's -Ctrl+Shift+E shortcut is unchanged; HTML has no default shortcut. - -An active Markdown document exports its current editor text, including unsaved -and untitled content, to a complete UTF-8 `.html` document. Text-only documents -need just that file. Local images, media, downloadable resources, and generated -graphics use a companion `.assets` directory. Keep that directory beside -the HTML file when copying the export. - -For Writerside, resolve unsaved project changes using Save/Discard/Cancel, select -one non-library instance, and choose a dedicated output directory. The export -contains separate topic pages, ordinary navigation links, shared `assets`, and -an `index.html` entry point. Hidden topics retain pages but no navigation entry; -work-in-progress entries retain their status. Repeated TOC references share a -page. Topic titles, TOC labels, module origins, instance title overrides, and -custom web filenames remain distinct. Filename collisions stop publication. -The start page retains its declared filename and also supplies `index.html`. - -The result dialog offers **Open**, **Show in Folder**, and individual diagnostics -with source paths and line numbers. Missing required links are diagnostics with -visible labels, rather than fabricated destinations; missing nullable links -become ordinary text. Single-document Markdown export does not export other -linked documents. Unavailable visual content retains alternative text, a safe -link, or escaped source, with a diagnostic. - -## Semantic output and offline rendering - -The HTML writer consumes BusyDocument and the existing selected Markdown mode. -Writerside first passes through the shared project loader, document resolver, -and document renderer. It does not use Typst, Pandoc, screenshots, or a second -Markdown dialect. Ordinary HTML export does not require a Typst executable. - -Headings and explicit IDs, nested lists and task states, tables and cell spans, -code whitespace, footnotes and return links, procedures, definition lists, -admonitions, and supported raw HTML structure remain semantic HTML. Disclosures -use native `details`/`summary`. Every Writerside tab and topic variant is included -as a labeled section. Page-local generated IDs use BusyMark's Unicode-aware slug -rules and disambiguate repeated headings. Duplicate explicit IDs are diagnosed. - -An HTML-only projection in the existing Markdown AST adapter preserves raw HTML -structure and cross-block footnote/reference context. Default editor and PDF -projections, original source text, and source serialization are unchanged. - -Math uses MathCoordinator with a separate HTML profile and standalone SVG glyphs. -Mermaid, PlantUML, and D2 use VisualizationCoordinator's HTML profile, normalized -SVG, or the existing raster fallback. OpenAPI uses the existing local dependency -resolver and static reference mapper, producing headings, tables and examples. -Renderer dependencies are captured before rendering starts. Jobs use export, -page, and occurrence identity, including repeated includes. No browser-side -renderer, webfont, JavaScript, runtime fetch, or live API client is needed. - -The light stylesheet is independent of the editor theme. It includes responsive -media, table/code overflow, focus outlines, navigation landmarks, heading -outlines, language/direction metadata, and print rules that expose disclosure -bodies and every tab. - -## Ownership, confinement, and failure handling - -Source attributes are never copied wholesale into output. DOM text/attribute -escaping, URL validation, structural raw HTML allowlists, and final output checks -are separate controls. Unsupported or active source markup is shown as escaped -source with a diagnostic. SVG validation rejects active content, unsafe CSS, -and external references before normalization; SVGs are loaded as images. - -Local assets must canonicalize inside the document/workspace or configured -Writerside module/resource roots. Symlink escapes, unsupported formats, missing -files, and remote assets produce diagnostics. Remote resources are not fetched. -Validated asset content determines immutable hashed filenames, so identically -named files from different topics do not collide. Internal origin paths remain -available during resolution but are not serialized as HTML attributes or URLs. - -The generated meta CSP disables scripts, connections, objects, frames, forms, -base-URL changes, and fonts. Its style hash authorizes only exporter-owned CSS. -Image/media policies allow the generated relative resources over HTTP and -`file:` origins; final URL validation and asset confinement provide the narrower -resource boundary. The meta policy does not claim unsupported `frame-ancestors` -or sandbox protection. CSP complements sanitization. - -Assets are staged before a document entry point is atomically replaced. Existing -companion assets are append-only and content-verified; replacing HTML never -removes files used by the previous HTML. A `.busymark-html-export.json` ownership -marker identifies exporter directories. Unowned or modified output directories -are refused. Writerside stages a complete sibling directory and uses Linux atomic -rename/exchange only when supported; the file hard-link fallback is never used -for directories. Publication checks the displaced output too and rolls back a -concurrent change. If rollback itself fails, the retained recovery directory is -reported instead of deleted. - -Cancellation and ordinary publication failures clean temporary staging files -and retain an existing export. Default processing limits are 2,000 topics, -64 MiB UTF-8 source, 16 MiB per asset, 128 MiB total assets, 2,048 assets, -512 generated graphics, 64 nesting levels, and 45 seconds per render/preparation. -Generated HTML is bounded to four times the source-byte limit. Oversized output -fails before publication. Unused immutable companion assets can accumulate across -replacements; automatic deletion would risk older HTML copies. - -## Implementation map - -| Responsibility | Files under `lib/src/export/` | -| --- | --- | -| Requests, results, limits, cancellation | `html_export_models.dart` | -| Input capture and orchestration | `html_export_service.dart`, `html_export_ui.dart` | -| Writerside publication identities and navigation | `html_publication_plan.dart` | -| Link and anchor resolution | `html_export_links.dart` | -| Semantic DOM writer and final safety boundary | `html_document_writer.dart` | -| Confined, validated, content-addressed resources | `html_export_assets.dart` | -| Existing math, diagram, and static API engines | `html_rich_content.dart` | -| Atomic publication and ownership checks | `html_export_publisher.dart` | -| Real-engine release fixture | `html_release_smoke.dart` | - -Other integration changes are in `assets/export/html.css`, `pubspec.yaml`, the -Markdown AST adapter/parser, visualization profiles/coordinator, atomic-file -helpers, application command/menu dispatch, the Linux header-bar bridge and GTK -runner, and ARBs/generated localization output. Verification also corrected -Writerside link-summary variable scopes and completed missing Writerside UI -translations and table-sort glyph/localization integration. - -## Verification - -Structural, asset, publication, renderer, and widget coverage lives in -`test/src/html_export_test.dart`, `html_publication_test.dart`, -`html_rich_export_test.dart`, and `html_export_ui_test.dart`. Header-bar and -localization/source audits cover shared integration. Tests include unsafe URLs, -raw HTML and SVG, metadata injection, duplicate/non-Latin IDs, module-relative -assets, hidden/WIP pages, collisions, dependency snapshots, timeout fallback, -permission failure, overwrite refusal, ownership checks, and staging cleanup. - -The existing Linux visualization release smoke also writes a representative -Markdown export (`offline.html` plus assets) and a Writerside instance -(`writerside/index.html`, `Welcome.html`, `reference.html`, and `hidden.html`). It -uses real packaged MathJax, Mermaid, PlantUML, D2, OpenAPI, and the existing PDF -smoke. Run after a release build: - -```bash -BUSYMARK_RELEASE_SMOKE=1 xvfb-run -a build/linux/x64/release/bundle/busymark \ - --visualization-release-smoke=/tmp/busymark-html-verification/report.json -``` - -`tools/verify_html_export_browser.py` copies those exports to a new location, -starts a local static server, and checks both direct file opening and HTTP in -installed Chromium and Firefox. It uses an unavailable outbound proxy and BiDi -request observation, verifies assets, anchors, footnotes, responsive layout, -keyboard disclosure controls and navigation, probes CSP script blocking, saves -screenshots, prints every page, and checks printed disclosure/tab text. It needs -Selenium 4.48+, matching browser drivers, and `pdftotext`: - -```bash -python3 tools/verify_html_export_browser.py /tmp/busymark-html-verification \ - --output /tmp/busymark-html-browser-verification -``` - -The test does not require internet access to render exports. Install browsers, -drivers and Selenium beforehand; explicit browser/driver paths are configurable. -Printed PDF text checks complement screenshot inspection; they do not establish -accessibility conformance or pixel equality with the Writerside website builder. - -## Documentation decisions - -Separate topic filenames, titles, and start-page behavior follow JetBrains' -[topics documentation](https://www.jetbrains.com/help/writerside/topics.html). -Hidden/WIP handling follows the -[instance documentation](https://www.jetbrains.com/help/writerside/instances.html), -and missing/nullable link behavior follows -[links and references](https://www.jetbrains.com/help/writerside/links-and-references.html). -Native disclosure behavior follows -[MDN details](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/details). -Standalone math reuses the approach described by -[MathJax conversion documentation](https://docs.mathjax.org/en/v4.1/web/convert.html). -The final boundary combines controls described in -[OWASP XSS prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html) -and [OWASP CSP guidance](https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html). +Choose **Main menu → Export as HTML…** or use the command palette. HTML has no +default shortcut; **Ctrl+Shift+E** continues to export PDF. + +Markdown exports the active document’s current editor text, including unsaved +and untitled content. Writerside first offers Save, Discard, or Cancel for +project changes, then lets you choose a non-library instance and a dedicated +output directory. + +## Export settings + +Markdown and Writerside share the same HTML settings, independently of your +editor and preview theme: + +- **Content:** include a heading-based table of contents, choose a depth from + 1–6, and number headings. The TOC links to the existing heading anchors. + Numbering changes the export only. The heading outline remains enabled by + default; heading numbering is off. +- **Appearance:** light, dark, or automatic theme; serif or sans-serif body + text; a base size from 12–28 px; and an accent/link color. Automatic follows + the browser’s light/dark preference. Code uses the export’s theme without + requiring a browser highlighting library. +- **Layout:** a maximum content width from 320–1920 px. Pages still adapt to + smaller screens; wide code blocks and tables scroll within the page. +- **Output:** a single HTML file or HTML with an assets directory, plus an + optional custom stylesheet. + +Defaults are a light theme, 17 px sans-serif text, a maximum width of 918 px, +blue links, an assets directory when needed, and no custom stylesheet. + +BusyMark remembers the last confirmed HTML settings globally, including across +Markdown and Writerside exports. PDF settings are remembered separately. +**Reset to defaults** restores the default values in the dialog. Cancelling +the settings dialog leaves the remembered values unchanged. + +## Packaging + +**Single HTML file** embeds the local and generated resources needed by a +Markdown document, so you can copy the `.html` file on its own. Remote resources +are not downloaded or embedded. + +**HTML + assets directory** places images, media, downloads, and generated +graphics in a companion `.assets` directory using relative links. Keep +the HTML file and that directory together when copying the export. A text-only +document needs just the HTML file. + +Writerside always retains separate linked topic pages and an `index.html` +entry point. With an assets directory, pages share `assets/`. In single-file +mode, each topic page embeds its resources; copy the entire instance directory +to preserve navigation. Hidden topics retain pages without navigation entries, +and work-in-progress entries retain their status. Repeated TOC references share +one page. Existing topic filenames and resolved instance order are preserved. + +Both modes work offline when opened directly in a browser or served by a static +web server. No BusyMark installation, preview server, or original source folder +is required to read them. + +## Custom CSS + +Select **Custom stylesheet…** to choose a local UTF-8 `.css` file of up to +256 KiB. Its rules follow BusyMark’s generated stylesheet, allowing intentional +overrides. **Remove custom stylesheet** returns to the built-in appearance. + +BusyMark reads CSS directly, without running a preprocessor. Imports, resource +URLs, escaped CSS, HTML, and executable CSS are rejected. No remote fonts or +other resources are fetched. A missing, oversized, or invalid stylesheet must +be corrected or removed before exporting. Browser scripts and template code +are not supported customization mechanisms. + +Custom CSS is optional. The generated document already has semantic headings, +links, lists, tables, code, metadata, and accessible navigation. Built-in print +styles hide navigation and expose disclosure bodies and every Writerside tab. +Custom rules can override presentation, including print styling. + +## Resources and existing exports + +Supported local images, media, equations, diagrams, and static API documentation +are prepared during export. Remote video remains a link. Missing or unsupported +content produces an actionable diagnostic and readable fallback where possible. +HTML does not automatically export other linked Markdown documents or crawl +other Writerside instances. + +Choose the destination after confirming settings. BusyMark asks before replacing +existing output. A Writerside destination can replace only an unmodified export +created by BusyMark, protecting unrelated files. Cancellation and ordinary +export failures preserve the previous output. + +The result offers **Open**, **Show in Folder**, and source-associated diagnostics. +When replacing an HTML document with an assets directory, old resources may be +retained so earlier copies of that HTML remain usable. diff --git a/docs/pdf-export.md b/docs/pdf-export.md new file mode 100644 index 00000000..39b77dca --- /dev/null +++ b/docs/pdf-export.md @@ -0,0 +1,52 @@ +# PDF export + +Choose **Main menu → Export as PDF…**, use the command palette, or press +**Ctrl+Shift+E**. Markdown exports the active editor text, including unsaved and +untitled documents. Writerside first offers Save, Discard, or Cancel for project +changes, then lets you select a non-library instance. + +The export settings are independent of the editor and preview appearance. +Markdown and Writerside offer the same PDF controls: + +- **Content:** include a table of contents, choose its heading depth from 1–6, + and number headings. Numbering does not modify your source. The table of + contents uses the document’s headings and page numbers. +- **Page:** A4, US Letter, US Legal, or custom dimensions in millimetres; + portrait or landscape; narrow, normal, wide, or four independent custom + margins. Custom dimensions are 50–1200 mm. Margins must leave at least 20 mm + of content width and height. +- **Typography:** serif or sans-serif body text, body size from 8–24 pt, and + code size from 6–20 pt. BusyMark includes Noto fonts for consistent PDF + typography. Heading sizes scale with the body size, and equations use the + selected typography and available page width. +- **Header & Footer:** no text or the resolved document title in either area; + page numbers off, bottom left, bottom center, or bottom right; and whether + headers, footers, and page numbers appear on the first page. +- **Appearance:** an accent/link color, chosen from the palette or entered as + `#RRGGBB`. + +After you confirm the settings, BusyMark remembers them globally for the next +PDF export, including exports from other documents and Writerside modules. +**Reset to defaults** restores the default values in the dialog. Cancel leaves +your remembered settings unchanged. PDF and HTML remember separate settings. + +Defaults are A4 portrait, normal margins, 10.5 pt serif body text, 8.4 pt code, +blue links, and centered page numbers on all pages. Generated TOC and heading +numbering are off. Custom page dimensions describe the portrait geometry; +landscape swaps the width and height. + +Choose the destination after confirming settings. BusyMark asks before +replacing an existing file. Export can be cancelled, and a failed export keeps +the previous PDF usable. + +## Offline content + +PDF export works locally with BusyMark’s included PDF, math, and diagram tools. +It does not download remote images, fonts, or other resources. Supported local +images, equations, diagrams, tables, links, and static API documentation remain +part of the exported document. When supported content cannot be rendered, +BusyMark reports a warning and keeps readable alternative text or source where +possible. + +For instance ordering and Writerside content behavior, see +[Writerside PDF export](writerside-pdf-export.md). diff --git a/docs/writerside-pdf-export.md b/docs/writerside-pdf-export.md index 9f9f5814..c35ad0ea 100644 --- a/docs/writerside-pdf-export.md +++ b/docs/writerside-pdf-export.md @@ -11,10 +11,22 @@ Open a Writerside module and select **Main menu → Export as PDF** or press discard unsaved project changes, then lets you select: - one non-library Writerside instance; -- A4 or US Letter page size; -- portrait or landscape orientation; -- narrow, normal, or wide margins; and -- whether to include page numbers. +- a generated table of contents with heading depth 1–6 and optional heading numbering; +- A4, US Letter, US Legal, or custom page dimensions in millimetres; +- portrait or landscape and preset or four independent custom margins; +- serif or sans-serif Noto typography, body size, and code size; +- document-title headers and footers, page-number position, and first-page visibility; and +- an accent/link color. + +These are the same controls used for Markdown PDF export. Confirmed PDF settings +are remembered globally; instance selection remains specific to the workspace. +**Reset to defaults** restores the default settings in the dialog. Cancelling +keeps the previously remembered settings. The editor theme does not affect PDF +appearance. See [PDF export settings](pdf-export.md) for ranges and defaults. + +Generated TOC and heading numbering use the exported heading structure without +changing topic source. Custom typography also controls heading and equation +sizing; custom dimensions and margins determine the available content width. The instance's resolved TOC determines topic order. Hidden and work-in-progress TOC entries are omitted unless a work-in-progress topic is the configured start @@ -61,19 +73,3 @@ BusyMark is not the JetBrains Writerside publication builder. The native export targets a reliable offline PDF of the syntax BusyMark understands; teams that need byte-for-byte parity with JetBrains website artifacts can still run JetBrains' separate CI tooling outside BusyMark. - -## Verification - -Focused tests cover instance selection, TOC ordering, variables, Markdown and -`.topic` XML composition, local asset rebasing, cancellation, failure mapping, -and the repository's Writerside demo through a test compiler runner. A separate -integration test compiles semantic content using the real bundled Typst binary -when available. See [Writerside support](writerside-support.md) for the official -builder fixture comparison and the limits of that evidence. - -Run: - -```bash -flutter test test/src/writerside_pdf_export_test.dart -flutter test test/src/markdown_pdf_export_test.dart -``` diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index 03d30278..fa97665b 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -3095,5 +3095,48 @@ "diagnosticWritersideSchema": "ترميز Writerside غير صالح: {element}، {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "استخدم true أو false؛ لم يعد single-file مدعومًا.", "diagnosticWritersideReference": "تعذّر حل {kind}: {reference}", - "sortTableColumn": "فرز {column}" + "sortTableColumn": "فرز {column}", + "exportReset": "استعادة الإعدادات الافتراضية", + "exportToc": "تضمين جدول المحتويات", + "exportTocDepth": "عمق جدول المحتويات", + "exportNumberHeadings": "ترقيم العناوين", + "exportLegal": "US Legal", + "exportCustom": "مخصص", + "exportPageWidth": "عرض الصفحة (مم)", + "exportPageHeight": "ارتفاع الصفحة (مم)", + "exportMarginTop": "الهامش العلوي (مم)", + "exportMarginRight": "الهامش الأيمن (مم)", + "exportMarginBottom": "الهامش السفلي (مم)", + "exportMarginLeft": "الهامش الأيسر (مم)", + "exportTypography": "الخطوط", + "exportSans": "بلا زوائد", + "exportSerif": "بزوائد", + "exportBodySize": "حجم خط النص", + "exportCodeSize": "حجم خط الشيفرة", + "exportRunningText": "رأس الصفحة وتذييلها", + "exportHeader": "رأس الصفحة", + "exportFooter": "تذييل الصفحة", + "exportNone": "بلا", + "exportDocumentTitle": "عنوان المستند", + "exportBottomLeft": "أسفل اليسار", + "exportBottomCenter": "أسفل الوسط", + "exportBottomRight": "أسفل اليمين", + "exportFirstPage": "إظهار الرأس والتذييل في الصفحة الأولى", + "exportAccent": "لون التمييز / الروابط", + "exportTheme": "المظهر", + "exportAutomatic": "تلقائي", + "exportLayout": "التخطيط", + "exportContentWidth": "العرض الأقصى للمحتوى", + "exportOutput": "الإخراج", + "exportPackaging": "التجميع", + "exportSingleFile": "ملف HTML واحد", + "exportAssetsDirectory": "HTML + مجلد موارد", + "exportCustomCss": "ورقة أنماط مخصصة…", + "exportRemoveCss": "إزالة ورقة الأنماط المخصصة", + "exportCssNote": "اختر ملف CSS اختياريًا بترميز UTF-8 (حتى 256 KiB). تُرفض عمليات الاستيراد وعناوين الموارد وCSS القابل للتنفيذ أو المحتوي على محارف هروب. تُطبق الأنماط بعد أنماط BusyMark. لا تُجلب موارد بعيدة.", + "exportSitePackagingNote": "يحتفظ Writerside بصفحات مواضيع منفصلة ومترابطة. يضمّن وضع الملف الواحد الموارد في كل صفحة.", + "exportInvalidGeometry": "اترك عرضًا وارتفاعًا للمحتوى لا يقلان عن 20 مم بعد الهوامش.", + "exportInvalidColor": "أدخل لونًا بصيغة #RRGGBB.", + "exportInvalidCss": "اختر ملف .css مقروءًا بترميز UTF-8 حتى 256 KiB، دون استيراد أو عناوين موارد أو HTML أو CSS قابل للتنفيذ أو يحتوي على محارف هروب.", + "exportInvalidRange": "{field}: أدخل رقمًا بين {minimum} و{maximum}." } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 18f71484..4fdb355d 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -3095,5 +3095,48 @@ "diagnosticWritersideSchema": "Ungültiges Writerside-Markup: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "Verwenden Sie true oder false; single-file wird nicht mehr unterstützt.", "diagnosticWritersideReference": "{kind} kann nicht aufgelöst werden: {reference}", - "sortTableColumn": "{column} sortieren" + "sortTableColumn": "{column} sortieren", + "exportReset": "Auf Standardwerte zurücksetzen", + "exportToc": "Inhaltsverzeichnis einfügen", + "exportTocDepth": "Gliederungstiefe", + "exportNumberHeadings": "Überschriften nummerieren", + "exportLegal": "US Legal", + "exportCustom": "Benutzerdefiniert", + "exportPageWidth": "Seitenbreite (mm)", + "exportPageHeight": "Seitenhöhe (mm)", + "exportMarginTop": "Oberer Rand (mm)", + "exportMarginRight": "Rechter Rand (mm)", + "exportMarginBottom": "Unterer Rand (mm)", + "exportMarginLeft": "Linker Rand (mm)", + "exportTypography": "Typografie", + "exportSans": "Serifenlos", + "exportSerif": "Mit Serifen", + "exportBodySize": "Schriftgröße des Texts", + "exportCodeSize": "Schriftgröße für Code", + "exportRunningText": "Kopf- und Fußzeile", + "exportHeader": "Kopfzeile", + "exportFooter": "Fußzeile", + "exportNone": "Keine", + "exportDocumentTitle": "Dokumenttitel", + "exportBottomLeft": "Unten links", + "exportBottomCenter": "Unten mittig", + "exportBottomRight": "Unten rechts", + "exportFirstPage": "Kopf- und Fußzeile auf der ersten Seite anzeigen", + "exportAccent": "Akzent-/Linkfarbe", + "exportTheme": "Design", + "exportAutomatic": "Automatisch", + "exportLayout": "Layout", + "exportContentWidth": "Maximale Inhaltsbreite", + "exportOutput": "Ausgabe", + "exportPackaging": "Verpackung", + "exportSingleFile": "Einzelne HTML-Datei", + "exportAssetsDirectory": "HTML + Ressourcenordner", + "exportCustomCss": "Eigenes Stylesheet…", + "exportRemoveCss": "Eigenes Stylesheet entfernen", + "exportCssNote": "Wählen Sie eine optionale UTF-8-CSS-Datei (bis 256 KiB). Importe, Ressourcen-URLs sowie ausführbares oder maskiertes CSS werden abgelehnt. Die Regeln folgen dem BusyMark-Stylesheet. Entfernte Ressourcen werden nie abgerufen.", + "exportSitePackagingNote": "Writerside behält getrennte, verknüpfte Themenseiten. Der Einzeldateimodus bettet Ressourcen in jede Seite ein.", + "exportInvalidGeometry": "Nach Abzug der Ränder müssen mindestens 20 mm Inhaltsbreite und -höhe bleiben.", + "exportInvalidColor": "Geben Sie eine Farbe als #RRGGBB ein.", + "exportInvalidCss": "Wählen Sie eine lesbare UTF-8-CSS-Datei bis 256 KiB ohne Importe, Ressourcen-URLs, HTML sowie ausführbares oder maskiertes CSS.", + "exportInvalidRange": "{field}: Geben Sie eine Zahl zwischen {minimum} und {maximum} ein." } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 8bb27012..9dbf1a73 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -2396,5 +2396,62 @@ "type": "String" } } + }, + "exportReset": "Reset to defaults", + "exportToc": "Include table of contents", + "exportTocDepth": "TOC depth", + "exportNumberHeadings": "Number headings", + "exportLegal": "US Legal", + "exportCustom": "Custom", + "exportPageWidth": "Page width (mm)", + "exportPageHeight": "Page height (mm)", + "exportMarginTop": "Top margin (mm)", + "exportMarginRight": "Right margin (mm)", + "exportMarginBottom": "Bottom margin (mm)", + "exportMarginLeft": "Left margin (mm)", + "exportTypography": "Typography", + "exportSans": "Sans-serif", + "exportSerif": "Serif", + "exportBodySize": "Body font size", + "exportCodeSize": "Code font size", + "exportRunningText": "Header & Footer", + "exportHeader": "Header", + "exportFooter": "Footer", + "exportNone": "None", + "exportDocumentTitle": "Document title", + "exportBottomLeft": "Bottom left", + "exportBottomCenter": "Bottom center", + "exportBottomRight": "Bottom right", + "exportFirstPage": "Show header and footer on first page", + "exportAccent": "Accent / link color", + "exportTheme": "Theme", + "exportAutomatic": "Automatic", + "exportLayout": "Layout", + "exportContentWidth": "Maximum content width", + "exportOutput": "Output", + "exportPackaging": "Packaging", + "exportSingleFile": "Single HTML file", + "exportAssetsDirectory": "HTML + assets directory", + "exportCustomCss": "Custom stylesheet…", + "exportRemoveCss": "Remove custom stylesheet", + "exportCssNote": "Select an optional UTF-8 CSS file (up to 256 KiB). Imports, resource URLs, and executable or escaped CSS are not accepted. Styles are applied after BusyMark’s stylesheet. Remote resources are never fetched.", + "exportSitePackagingNote": "Writerside keeps separate linked topic pages. Single-file mode embeds resources in each page.", + "exportInvalidGeometry": "Leave at least 20 mm of content width and height after margins.", + "exportInvalidColor": "Enter a color as #RRGGBB.", + "exportInvalidCss": "Choose a readable UTF-8 .css file up to 256 KiB, without imports, resource URLs, HTML, or executable or escaped CSS.", + "exportInvalidRange": "{field}: enter a number between {minimum} and {maximum}.", + "@exportInvalidRange": { + "description": "Invalid numeric export setting.", + "placeholders": { + "field": { + "type": "String" + }, + "minimum": { + "type": "String" + }, + "maximum": { + "type": "String" + } + } } } diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index ead71529..48230a98 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -3095,5 +3095,48 @@ "diagnosticWritersideSchema": "Marcado Writerside no válido: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "Use true o false; single-file ya no es compatible.", "diagnosticWritersideReference": "No se puede resolver {kind}: {reference}", - "sortTableColumn": "Ordenar {column}" + "sortTableColumn": "Ordenar {column}", + "exportReset": "Restablecer valores predeterminados", + "exportToc": "Incluir índice", + "exportTocDepth": "Profundidad del índice", + "exportNumberHeadings": "Numerar encabezados", + "exportLegal": "US Legal", + "exportCustom": "Personalizado", + "exportPageWidth": "Ancho de página (mm)", + "exportPageHeight": "Alto de página (mm)", + "exportMarginTop": "Margen superior (mm)", + "exportMarginRight": "Margen derecho (mm)", + "exportMarginBottom": "Margen inferior (mm)", + "exportMarginLeft": "Margen izquierdo (mm)", + "exportTypography": "Tipografía", + "exportSans": "Sin serifas", + "exportSerif": "Con serifas", + "exportBodySize": "Tamaño del texto", + "exportCodeSize": "Tamaño del código", + "exportRunningText": "Encabezado y pie de página", + "exportHeader": "Encabezado", + "exportFooter": "Pie de página", + "exportNone": "Ninguno", + "exportDocumentTitle": "Título del documento", + "exportBottomLeft": "Abajo a la izquierda", + "exportBottomCenter": "Abajo en el centro", + "exportBottomRight": "Abajo a la derecha", + "exportFirstPage": "Mostrar encabezado y pie en la primera página", + "exportAccent": "Color de acento / enlaces", + "exportTheme": "Tema", + "exportAutomatic": "Automático", + "exportLayout": "Diseño", + "exportContentWidth": "Ancho máximo del contenido", + "exportOutput": "Salida", + "exportPackaging": "Empaquetado", + "exportSingleFile": "Un solo archivo HTML", + "exportAssetsDirectory": "HTML + carpeta de recursos", + "exportCustomCss": "Hoja de estilo personalizada…", + "exportRemoveCss": "Quitar hoja de estilo", + "exportCssNote": "Seleccione un archivo CSS UTF-8 opcional (hasta 256 KiB). Se rechazan importaciones, URL de recursos y CSS ejecutable o escapado. Los estilos se aplican después de los de BusyMark. Nunca se descargan recursos remotos.", + "exportSitePackagingNote": "Writerside conserva páginas de temas separadas y enlazadas. El modo de archivo único incorpora los recursos en cada página.", + "exportInvalidGeometry": "Deje al menos 20 mm de ancho y alto de contenido después de los márgenes.", + "exportInvalidColor": "Introduzca un color como #RRGGBB.", + "exportInvalidCss": "Elija un archivo .css UTF-8 legible de hasta 256 KiB, sin importaciones, URL de recursos, HTML ni CSS ejecutable o escapado.", + "exportInvalidRange": "{field}: introduzca un número entre {minimum} y {maximum}." } diff --git a/lib/l10n/app_et.arb b/lib/l10n/app_et.arb index 5df05efd..32b5a9aa 100644 --- a/lib/l10n/app_et.arb +++ b/lib/l10n/app_et.arb @@ -3555,5 +3555,48 @@ "diagnosticWritersideSchema": "Vigane Writerside’i märgistus: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "Kasuta true või false; single-file ei ole enam toetatud.", "diagnosticWritersideReference": "{kind} ei saa lahendada: {reference}", - "sortTableColumn": "Sordi {column}" + "sortTableColumn": "Sordi {column}", + "exportReset": "Taasta vaikeväärtused", + "exportToc": "Lisa sisukord", + "exportTocDepth": "Sisukorra sügavus", + "exportNumberHeadings": "Nummerda pealkirjad", + "exportLegal": "US Legal", + "exportCustom": "Kohandatud", + "exportPageWidth": "Lehe laius (mm)", + "exportPageHeight": "Lehe kõrgus (mm)", + "exportMarginTop": "Ülaveeris (mm)", + "exportMarginRight": "Paremveeris (mm)", + "exportMarginBottom": "Alaveeris (mm)", + "exportMarginLeft": "Vasakveeris (mm)", + "exportTypography": "Tüpograafia", + "exportSans": "Seriifideta", + "exportSerif": "Seriifidega", + "exportBodySize": "Põhiteksti suurus", + "exportCodeSize": "Koodi suurus", + "exportRunningText": "Päis ja jalus", + "exportHeader": "Päis", + "exportFooter": "Jalus", + "exportNone": "Puudub", + "exportDocumentTitle": "Dokumendi pealkiri", + "exportBottomLeft": "All vasakul", + "exportBottomCenter": "All keskel", + "exportBottomRight": "All paremal", + "exportFirstPage": "Näita päist ja jalust esimesel lehel", + "exportAccent": "Rõhu-/lingivärv", + "exportTheme": "Teema", + "exportAutomatic": "Automaatne", + "exportLayout": "Paigutus", + "exportContentWidth": "Sisu suurim laius", + "exportOutput": "Väljund", + "exportPackaging": "Pakendamine", + "exportSingleFile": "Üks HTML-fail", + "exportAssetsDirectory": "HTML + ressursikaust", + "exportCustomCss": "Kohandatud laadileht…", + "exportRemoveCss": "Eemalda kohandatud laadileht", + "exportCssNote": "Vali soovi korral UTF-8 CSS-fail (kuni 256 KiB). Importimine, ressursside URL-id ning käivitatav või paojadadega CSS pole lubatud. Laadid järgnevad BusyMarki laadidele. Võrguressursse ei laadita.", + "exportSitePackagingNote": "Writerside säilitab eraldi lingitud teemalehed. Ühe faili režiim manustab ressursid igale lehele.", + "exportInvalidGeometry": "Jäta pärast veeriseid sisule vähemalt 20 mm laiust ja kõrgust.", + "exportInvalidColor": "Sisesta värv kujul #RRGGBB.", + "exportInvalidCss": "Vali loetav UTF-8 .css-fail kuni 256 KiB, ilma importide, ressursside URL-ide, HTML-i ning käivitatava või paojadadega CSS-ita.", + "exportInvalidRange": "{field}: sisesta arv vahemikus {minimum} kuni {maximum}." } diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index f6f4086d..258b7c73 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -3137,5 +3137,48 @@ "diagnosticWritersideSchema": "نشانه‌گذاری نامعتبر Writerside: {element}، {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "از true یا false استفاده کنید؛ single-file دیگر پشتیبانی نمی‌شود.", "diagnosticWritersideReference": "{kind} قابل حل نیست: {reference}", - "sortTableColumn": "مرتب‌سازی {column}" + "sortTableColumn": "مرتب‌سازی {column}", + "exportReset": "بازنشانی به پیش‌فرض‌ها", + "exportToc": "افزودن فهرست مطالب", + "exportTocDepth": "عمق فهرست مطالب", + "exportNumberHeadings": "شماره‌گذاری عنوان‌ها", + "exportLegal": "US Legal", + "exportCustom": "سفارشی", + "exportPageWidth": "عرض صفحه (میلی‌متر)", + "exportPageHeight": "ارتفاع صفحه (میلی‌متر)", + "exportMarginTop": "حاشیهٔ بالا (میلی‌متر)", + "exportMarginRight": "حاشیهٔ راست (میلی‌متر)", + "exportMarginBottom": "حاشیهٔ پایین (میلی‌متر)", + "exportMarginLeft": "حاشیهٔ چپ (میلی‌متر)", + "exportTypography": "حروف‌چینی", + "exportSans": "بدون سریف", + "exportSerif": "سریف", + "exportBodySize": "اندازهٔ قلم متن", + "exportCodeSize": "اندازهٔ قلم کد", + "exportRunningText": "سرصفحه و پاصفحه", + "exportHeader": "سرصفحه", + "exportFooter": "پاصفحه", + "exportNone": "هیچ‌کدام", + "exportDocumentTitle": "عنوان سند", + "exportBottomLeft": "پایین چپ", + "exportBottomCenter": "پایین وسط", + "exportBottomRight": "پایین راست", + "exportFirstPage": "نمایش سرصفحه و پاصفحه در صفحهٔ نخست", + "exportAccent": "رنگ تأکید / پیوند", + "exportTheme": "پوسته", + "exportAutomatic": "خودکار", + "exportLayout": "چیدمان", + "exportContentWidth": "بیشترین عرض محتوا", + "exportOutput": "خروجی", + "exportPackaging": "بسته‌بندی", + "exportSingleFile": "یک فایل HTML", + "exportAssetsDirectory": "HTML + پوشهٔ منابع", + "exportCustomCss": "شیوه‌نامهٔ سفارشی…", + "exportRemoveCss": "حذف شیوه‌نامهٔ سفارشی", + "exportCssNote": "یک فایل CSS اختیاری با UTF-8 انتخاب کنید (تا ۲۵۶ KiB). واردسازی، نشانی منابع و CSS اجرایی یا دارای نویسهٔ گریز پذیرفته نمی‌شود. سبک‌ها پس از CSS برنامه اعمال می‌شوند. منابع راه دور دریافت نمی‌شوند.", + "exportSitePackagingNote": "Writerside صفحه‌های موضوعی جدا و پیوندخورده را نگه می‌دارد. حالت تک‌فایلی منابع را در هر صفحه جاسازی می‌کند.", + "exportInvalidGeometry": "پس از حاشیه‌ها دست‌کم ۲۰ میلی‌متر عرض و ارتفاع برای محتوا باقی بگذارید.", + "exportInvalidColor": "رنگ را به‌صورت #RRGGBB وارد کنید.", + "exportInvalidCss": "یک فایل .css خوانا با UTF-8 تا ۲۵۶ KiB انتخاب کنید، بدون واردسازی، نشانی منابع، HTML یا CSS اجرایی یا دارای نویسهٔ گریز.", + "exportInvalidRange": "{field}: عددی بین {minimum} و {maximum} وارد کنید." } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 1c155693..86498b4e 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -3095,5 +3095,48 @@ "diagnosticWritersideSchema": "Balisage Writerside invalide : {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "Utilisez true ou false ; single-file n’est plus pris en charge.", "diagnosticWritersideReference": "Impossible de résoudre {kind} : {reference}", - "sortTableColumn": "Trier {column}" + "sortTableColumn": "Trier {column}", + "exportReset": "Rétablir les valeurs par défaut", + "exportToc": "Inclure une table des matières", + "exportTocDepth": "Profondeur de la table", + "exportNumberHeadings": "Numéroter les titres", + "exportLegal": "US Legal", + "exportCustom": "Personnalisé", + "exportPageWidth": "Largeur de page (mm)", + "exportPageHeight": "Hauteur de page (mm)", + "exportMarginTop": "Marge supérieure (mm)", + "exportMarginRight": "Marge droite (mm)", + "exportMarginBottom": "Marge inférieure (mm)", + "exportMarginLeft": "Marge gauche (mm)", + "exportTypography": "Typographie", + "exportSans": "Sans empattement", + "exportSerif": "Avec empattement", + "exportBodySize": "Taille du texte", + "exportCodeSize": "Taille du code", + "exportRunningText": "En-tête et pied de page", + "exportHeader": "En-tête", + "exportFooter": "Pied de page", + "exportNone": "Aucun", + "exportDocumentTitle": "Titre du document", + "exportBottomLeft": "En bas à gauche", + "exportBottomCenter": "En bas au centre", + "exportBottomRight": "En bas à droite", + "exportFirstPage": "Afficher l’en-tête et le pied sur la première page", + "exportAccent": "Couleur d’accent / des liens", + "exportTheme": "Thème", + "exportAutomatic": "Automatique", + "exportLayout": "Mise en page", + "exportContentWidth": "Largeur maximale du contenu", + "exportOutput": "Sortie", + "exportPackaging": "Conditionnement", + "exportSingleFile": "Fichier HTML unique", + "exportAssetsDirectory": "HTML + dossier de ressources", + "exportCustomCss": "Feuille de style personnalisée…", + "exportRemoveCss": "Retirer la feuille de style", + "exportCssNote": "Choisissez un fichier CSS UTF-8 facultatif (256 KiB maximum). Les imports, URL de ressources et CSS exécutable ou échappé sont refusés. Les styles suivent ceux de BusyMark. Aucune ressource distante n’est téléchargée.", + "exportSitePackagingNote": "Writerside conserve des pages liées distinctes. Le mode fichier unique intègre les ressources dans chaque page.", + "exportInvalidGeometry": "Laissez au moins 20 mm de largeur et de hauteur de contenu après les marges.", + "exportInvalidColor": "Saisissez une couleur au format #RRGGBB.", + "exportInvalidCss": "Choisissez un fichier .css UTF-8 lisible de 256 KiB maximum, sans imports, URL de ressources, HTML ni CSS exécutable ou échappé.", + "exportInvalidRange": "{field} : saisissez un nombre entre {minimum} et {maximum}." } diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index 47c60dc3..c8c5c68c 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -3095,5 +3095,48 @@ "diagnosticWritersideSchema": "अमान्य Writerside मार्कअप: {element}, {attribute}। {reason}", "diagnosticWritersideLlmsTxt": "true या false का उपयोग करें; single-file अब समर्थित नहीं है।", "diagnosticWritersideReference": "{kind} हल नहीं किया जा सकता: {reference}", - "sortTableColumn": "{column} क्रमबद्ध करें" + "sortTableColumn": "{column} क्रमबद्ध करें", + "exportReset": "डिफ़ॉल्ट पर रीसेट करें", + "exportToc": "विषय-सूची शामिल करें", + "exportTocDepth": "विषय-सूची की गहराई", + "exportNumberHeadings": "शीर्षकों को क्रमांक दें", + "exportLegal": "US Legal", + "exportCustom": "कस्टम", + "exportPageWidth": "पृष्ठ की चौड़ाई (mm)", + "exportPageHeight": "पृष्ठ की ऊँचाई (mm)", + "exportMarginTop": "ऊपरी मार्जिन (mm)", + "exportMarginRight": "दायाँ मार्जिन (mm)", + "exportMarginBottom": "निचला मार्जिन (mm)", + "exportMarginLeft": "बायाँ मार्जिन (mm)", + "exportTypography": "टाइपोग्राफ़ी", + "exportSans": "बिना सेरिफ़", + "exportSerif": "सेरिफ़", + "exportBodySize": "मुख्य पाठ का फ़ॉन्ट आकार", + "exportCodeSize": "कोड का फ़ॉन्ट आकार", + "exportRunningText": "शीर्षलेख और पादलेख", + "exportHeader": "शीर्षलेख", + "exportFooter": "पादलेख", + "exportNone": "कोई नहीं", + "exportDocumentTitle": "दस्तावेज़ का शीर्षक", + "exportBottomLeft": "नीचे बाएँ", + "exportBottomCenter": "नीचे बीच में", + "exportBottomRight": "नीचे दाएँ", + "exportFirstPage": "पहले पृष्ठ पर शीर्षलेख और पादलेख दिखाएँ", + "exportAccent": "हाइलाइट / लिंक का रंग", + "exportTheme": "थीम", + "exportAutomatic": "स्वचालित", + "exportLayout": "लेआउट", + "exportContentWidth": "सामग्री की अधिकतम चौड़ाई", + "exportOutput": "आउटपुट", + "exportPackaging": "पैकेजिंग", + "exportSingleFile": "एक HTML फ़ाइल", + "exportAssetsDirectory": "HTML + संसाधन फ़ोल्डर", + "exportCustomCss": "कस्टम स्टाइलशीट…", + "exportRemoveCss": "कस्टम स्टाइलशीट हटाएँ", + "exportCssNote": "वैकल्पिक UTF-8 CSS फ़ाइल चुनें (256 KiB तक)। इंपोर्ट, संसाधन URL और निष्पादन योग्य या एस्केप वाला CSS स्वीकार नहीं किया जाता। शैलियाँ BusyMark CSS के बाद लागू होती हैं। दूरस्थ संसाधन डाउनलोड नहीं किए जाते।", + "exportSitePackagingNote": "Writerside अलग-अलग लिंक किए गए विषय पृष्ठ रखता है। एकल फ़ाइल मोड हर पृष्ठ में संसाधन एम्बेड करता है।", + "exportInvalidGeometry": "मार्जिन के बाद सामग्री के लिए कम से कम 20 mm चौड़ाई और ऊँचाई छोड़ें।", + "exportInvalidColor": "रंग #RRGGBB के रूप में दर्ज करें।", + "exportInvalidCss": "256 KiB तक की पढ़ने योग्य UTF-8 .css फ़ाइल चुनें, जिसमें इंपोर्ट, संसाधन URL, HTML और निष्पादन योग्य या एस्केप वाला CSS न हो।", + "exportInvalidRange": "{field}: {minimum} से {maximum} के बीच संख्या दर्ज करें।" } diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index f4c379c1..288e3632 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -4654,5 +4654,48 @@ "diagnosticWritersideSchema": "Markup Writerside tidak valid: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "Gunakan true atau false; single-file tidak lagi didukung.", "diagnosticWritersideReference": "Tidak dapat menyelesaikan {kind}: {reference}", - "sortTableColumn": "Urutkan {column}" + "sortTableColumn": "Urutkan {column}", + "exportReset": "Pulihkan nilai bawaan", + "exportToc": "Sertakan daftar isi", + "exportTocDepth": "Kedalaman daftar isi", + "exportNumberHeadings": "Nomori judul", + "exportLegal": "US Legal", + "exportCustom": "Khusus", + "exportPageWidth": "Lebar halaman (mm)", + "exportPageHeight": "Tinggi halaman (mm)", + "exportMarginTop": "Margin atas (mm)", + "exportMarginRight": "Margin kanan (mm)", + "exportMarginBottom": "Margin bawah (mm)", + "exportMarginLeft": "Margin kiri (mm)", + "exportTypography": "Tipografi", + "exportSans": "Tanpa serif", + "exportSerif": "Berserif", + "exportBodySize": "Ukuran huruf isi", + "exportCodeSize": "Ukuran huruf kode", + "exportRunningText": "Kepala dan kaki halaman", + "exportHeader": "Kepala halaman", + "exportFooter": "Kaki halaman", + "exportNone": "Tidak ada", + "exportDocumentTitle": "Judul dokumen", + "exportBottomLeft": "Kiri bawah", + "exportBottomCenter": "Tengah bawah", + "exportBottomRight": "Kanan bawah", + "exportFirstPage": "Tampilkan kepala dan kaki pada halaman pertama", + "exportAccent": "Warna aksen / tautan", + "exportTheme": "Tema", + "exportAutomatic": "Otomatis", + "exportLayout": "Tata letak", + "exportContentWidth": "Lebar isi maksimum", + "exportOutput": "Keluaran", + "exportPackaging": "Pengemasan", + "exportSingleFile": "Satu berkas HTML", + "exportAssetsDirectory": "HTML + folder aset", + "exportCustomCss": "Lembar gaya khusus…", + "exportRemoveCss": "Hapus lembar gaya khusus", + "exportCssNote": "Pilih berkas CSS UTF-8 opsional (hingga 256 KiB). Impor, URL sumber daya, serta CSS yang dapat dieksekusi atau memakai escape ditolak. Gaya diterapkan setelah CSS BusyMark. Sumber daya jarak jauh tidak diunduh.", + "exportSitePackagingNote": "Writerside mempertahankan halaman topik terpisah yang saling tertaut. Mode berkas tunggal menyematkan sumber daya di setiap halaman.", + "exportInvalidGeometry": "Sisakan lebar dan tinggi isi minimal 20 mm setelah margin.", + "exportInvalidColor": "Masukkan warna sebagai #RRGGBB.", + "exportInvalidCss": "Pilih berkas .css UTF-8 yang dapat dibaca hingga 256 KiB, tanpa impor, URL sumber daya, HTML, atau CSS yang dapat dieksekusi atau memakai escape.", + "exportInvalidRange": "{field}: masukkan angka antara {minimum} dan {maximum}." } diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 3cb7c4fb..13bfa692 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -3095,5 +3095,48 @@ "diagnosticWritersideSchema": "Markup Writerside non valido: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "Usa true o false; single-file non è più supportato.", "diagnosticWritersideReference": "Impossibile risolvere {kind}: {reference}", - "sortTableColumn": "Ordina {column}" + "sortTableColumn": "Ordina {column}", + "exportReset": "Ripristina i valori predefiniti", + "exportToc": "Includi indice", + "exportTocDepth": "Profondità dell’indice", + "exportNumberHeadings": "Numera i titoli", + "exportLegal": "US Legal", + "exportCustom": "Personalizzato", + "exportPageWidth": "Larghezza pagina (mm)", + "exportPageHeight": "Altezza pagina (mm)", + "exportMarginTop": "Margine superiore (mm)", + "exportMarginRight": "Margine destro (mm)", + "exportMarginBottom": "Margine inferiore (mm)", + "exportMarginLeft": "Margine sinistro (mm)", + "exportTypography": "Tipografia", + "exportSans": "Senza grazie", + "exportSerif": "Con grazie", + "exportBodySize": "Dimensione del testo", + "exportCodeSize": "Dimensione del codice", + "exportRunningText": "Intestazione e piè di pagina", + "exportHeader": "Intestazione", + "exportFooter": "Piè di pagina", + "exportNone": "Nessuno", + "exportDocumentTitle": "Titolo del documento", + "exportBottomLeft": "In basso a sinistra", + "exportBottomCenter": "In basso al centro", + "exportBottomRight": "In basso a destra", + "exportFirstPage": "Mostra intestazione e piè di pagina sulla prima pagina", + "exportAccent": "Colore accento / collegamenti", + "exportTheme": "Tema", + "exportAutomatic": "Automatico", + "exportLayout": "Impaginazione", + "exportContentWidth": "Larghezza massima del contenuto", + "exportOutput": "Uscita", + "exportPackaging": "Pacchetto", + "exportSingleFile": "Un solo file HTML", + "exportAssetsDirectory": "HTML + cartella risorse", + "exportCustomCss": "Foglio di stile personalizzato…", + "exportRemoveCss": "Rimuovi il foglio di stile", + "exportCssNote": "Scegli un file CSS UTF-8 facoltativo (fino a 256 KiB). Importazioni, URL di risorse e CSS eseguibile o con escape non sono ammessi. Gli stili seguono quelli di BusyMark. Le risorse remote non vengono scaricate.", + "exportSitePackagingNote": "Writerside mantiene pagine separate e collegate. La modalità file singolo incorpora le risorse in ogni pagina.", + "exportInvalidGeometry": "Lascia almeno 20 mm di larghezza e altezza del contenuto dopo i margini.", + "exportInvalidColor": "Inserisci un colore come #RRGGBB.", + "exportInvalidCss": "Scegli un file .css UTF-8 leggibile fino a 256 KiB, senza importazioni, URL di risorse, HTML o CSS eseguibile o con escape.", + "exportInvalidRange": "{field}: inserisci un numero tra {minimum} e {maximum}." } diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index dd5a037a..997cdc4c 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -4654,5 +4654,48 @@ "diagnosticWritersideSchema": "無効な Writerside マークアップ: {element}、{attribute}。{reason}", "diagnosticWritersideLlmsTxt": "true または false を使用してください。single-file はサポートされなくなりました。", "diagnosticWritersideReference": "{kind} を解決できません: {reference}", - "sortTableColumn": "{column} を並べ替え" + "sortTableColumn": "{column} を並べ替え", + "exportReset": "既定値に戻す", + "exportToc": "目次を含める", + "exportTocDepth": "目次の深さ", + "exportNumberHeadings": "見出しに番号を付ける", + "exportLegal": "US Legal", + "exportCustom": "カスタム", + "exportPageWidth": "ページ幅 (mm)", + "exportPageHeight": "ページ高さ (mm)", + "exportMarginTop": "上余白 (mm)", + "exportMarginRight": "右余白 (mm)", + "exportMarginBottom": "下余白 (mm)", + "exportMarginLeft": "左余白 (mm)", + "exportTypography": "書体", + "exportSans": "サンセリフ", + "exportSerif": "セリフ", + "exportBodySize": "本文の文字サイズ", + "exportCodeSize": "コードの文字サイズ", + "exportRunningText": "ヘッダーとフッター", + "exportHeader": "ヘッダー", + "exportFooter": "フッター", + "exportNone": "なし", + "exportDocumentTitle": "文書タイトル", + "exportBottomLeft": "左下", + "exportBottomCenter": "中央下", + "exportBottomRight": "右下", + "exportFirstPage": "最初のページにもヘッダーとフッターを表示", + "exportAccent": "アクセント/リンクの色", + "exportTheme": "テーマ", + "exportAutomatic": "自動", + "exportLayout": "レイアウト", + "exportContentWidth": "コンテンツの最大幅", + "exportOutput": "出力", + "exportPackaging": "パッケージ形式", + "exportSingleFile": "単一の HTML ファイル", + "exportAssetsDirectory": "HTML + アセットフォルダー", + "exportCustomCss": "カスタムスタイルシート…", + "exportRemoveCss": "カスタムスタイルシートを削除", + "exportCssNote": "任意の UTF-8 CSS ファイルを選択できます(最大 256 KiB)。インポート、リソース URL、実行可能な CSS、エスケープを含む CSS は拒否されます。BusyMark のスタイルの後に適用されます。外部リソースは取得しません。", + "exportSitePackagingNote": "Writerside はリンクされた個別のトピックページを保持します。単一ファイルモードでは各ページにリソースを埋め込みます。", + "exportInvalidGeometry": "余白を除いたコンテンツの幅と高さをそれぞれ 20 mm 以上にしてください。", + "exportInvalidColor": "色を #RRGGBB 形式で入力してください。", + "exportInvalidCss": "読み取り可能な UTF-8 .css ファイル(最大 256 KiB)を選択してください。インポート、リソース URL、HTML、実行可能な CSS、エスケープを含む CSS は使用できません。", + "exportInvalidRange": "{field}: {minimum} から {maximum} の数値を入力してください。" } diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index 75f90d8e..3edae17f 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -4654,5 +4654,48 @@ "diagnosticWritersideSchema": "잘못된 Writerside 마크업: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "true 또는 false를 사용하세요. single-file은 더 이상 지원되지 않습니다.", "diagnosticWritersideReference": "{kind}을(를) 확인할 수 없습니다: {reference}", - "sortTableColumn": "{column} 정렬" + "sortTableColumn": "{column} 정렬", + "exportReset": "기본값으로 재설정", + "exportToc": "목차 포함", + "exportTocDepth": "목차 깊이", + "exportNumberHeadings": "제목 번호 매기기", + "exportLegal": "US Legal", + "exportCustom": "사용자 지정", + "exportPageWidth": "페이지 너비 (mm)", + "exportPageHeight": "페이지 높이 (mm)", + "exportMarginTop": "위쪽 여백 (mm)", + "exportMarginRight": "오른쪽 여백 (mm)", + "exportMarginBottom": "아래쪽 여백 (mm)", + "exportMarginLeft": "왼쪽 여백 (mm)", + "exportTypography": "글꼴", + "exportSans": "고딕체", + "exportSerif": "명조체", + "exportBodySize": "본문 글꼴 크기", + "exportCodeSize": "코드 글꼴 크기", + "exportRunningText": "머리글 및 바닥글", + "exportHeader": "머리글", + "exportFooter": "바닥글", + "exportNone": "없음", + "exportDocumentTitle": "문서 제목", + "exportBottomLeft": "왼쪽 아래", + "exportBottomCenter": "가운데 아래", + "exportBottomRight": "오른쪽 아래", + "exportFirstPage": "첫 페이지에 머리글과 바닥글 표시", + "exportAccent": "강조 / 링크 색상", + "exportTheme": "테마", + "exportAutomatic": "자동", + "exportLayout": "레이아웃", + "exportContentWidth": "최대 콘텐츠 너비", + "exportOutput": "출력", + "exportPackaging": "패키징", + "exportSingleFile": "단일 HTML 파일", + "exportAssetsDirectory": "HTML + 리소스 폴더", + "exportCustomCss": "사용자 지정 스타일시트…", + "exportRemoveCss": "사용자 지정 스타일시트 제거", + "exportCssNote": "선택적으로 UTF-8 CSS 파일을 지정하세요(최대 256 KiB). 가져오기, 리소스 URL, 실행 가능하거나 이스케이프된 CSS는 허용되지 않습니다. BusyMark 스타일 뒤에 적용됩니다. 원격 리소스를 가져오지 않습니다.", + "exportSitePackagingNote": "Writerside는 별도로 연결된 주제 페이지를 유지합니다. 단일 파일 모드는 각 페이지에 리소스를 포함합니다.", + "exportInvalidGeometry": "여백을 제외한 콘텐츠 너비와 높이를 각각 20 mm 이상 확보하세요.", + "exportInvalidColor": "#RRGGBB 형식으로 색상을 입력하세요.", + "exportInvalidCss": "가져오기, 리소스 URL, HTML, 실행 가능하거나 이스케이프된 CSS가 없는 읽기 가능한 UTF-8 .css 파일(최대 256 KiB)을 선택하세요.", + "exportInvalidRange": "{field}: {minimum}에서 {maximum} 사이의 숫자를 입력하세요." } diff --git a/lib/l10n/app_nb.arb b/lib/l10n/app_nb.arb index c65572b4..5b14d8e1 100644 --- a/lib/l10n/app_nb.arb +++ b/lib/l10n/app_nb.arb @@ -3095,5 +3095,48 @@ "diagnosticWritersideSchema": "Ugyldig Writerside-markering: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "Bruk true eller false; single-file støttes ikke lenger.", "diagnosticWritersideReference": "Kan ikke løse {kind}: {reference}", - "sortTableColumn": "Sorter {column}" + "sortTableColumn": "Sorter {column}", + "exportReset": "Tilbakestill til standard", + "exportToc": "Ta med innholdsfortegnelse", + "exportTocDepth": "Dybde på innholdsfortegnelse", + "exportNumberHeadings": "Nummerer overskrifter", + "exportLegal": "US Legal", + "exportCustom": "Egendefinert", + "exportPageWidth": "Sidebredde (mm)", + "exportPageHeight": "Sidehøyde (mm)", + "exportMarginTop": "Toppmarg (mm)", + "exportMarginRight": "Høyremarg (mm)", + "exportMarginBottom": "Bunnmarg (mm)", + "exportMarginLeft": "Venstremarg (mm)", + "exportTypography": "Typografi", + "exportSans": "Uten seriffer", + "exportSerif": "Med seriffer", + "exportBodySize": "Tekststørrelse", + "exportCodeSize": "Kodestørrelse", + "exportRunningText": "Topp- og bunntekst", + "exportHeader": "Topptekst", + "exportFooter": "Bunntekst", + "exportNone": "Ingen", + "exportDocumentTitle": "Dokumenttittel", + "exportBottomLeft": "Nederst til venstre", + "exportBottomCenter": "Nederst i midten", + "exportBottomRight": "Nederst til høyre", + "exportFirstPage": "Vis topp- og bunntekst på første side", + "exportAccent": "Aksent-/lenkefarge", + "exportTheme": "Tema", + "exportAutomatic": "Automatisk", + "exportLayout": "Oppsett", + "exportContentWidth": "Maksimal innholdsbredde", + "exportOutput": "Utdata", + "exportPackaging": "Pakking", + "exportSingleFile": "Én HTML-fil", + "exportAssetsDirectory": "HTML + ressursmappe", + "exportCustomCss": "Egendefinert stilark…", + "exportRemoveCss": "Fjern egendefinert stilark", + "exportCssNote": "Velg en valgfri UTF-8-CSS-fil (opptil 256 KiB). Importer, ressurs-URL-er og kjørbar eller escaped CSS avvises. Stilene følger BusyMarks stilark. Eksterne ressurser hentes aldri.", + "exportSitePackagingNote": "Writerside beholder separate, lenkede emnesider. Enkeltfilmodus bygger ressursene inn i hver side.", + "exportInvalidGeometry": "La minst 20 mm innholdsbredde og -høyde stå igjen etter margene.", + "exportInvalidColor": "Skriv inn en farge som #RRGGBB.", + "exportInvalidCss": "Velg en lesbar UTF-8 .css-fil opptil 256 KiB uten importer, ressurs-URL-er, HTML eller kjørbar eller escaped CSS.", + "exportInvalidRange": "{field}: skriv inn et tall mellom {minimum} og {maximum}." } diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 483fa604..d673b813 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -4654,5 +4654,48 @@ "diagnosticWritersideSchema": "Ongeldige Writerside-opmaak: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "Gebruik true of false; single-file wordt niet meer ondersteund.", "diagnosticWritersideReference": "{kind} kan niet worden gevonden: {reference}", - "sortTableColumn": "{column} sorteren" + "sortTableColumn": "{column} sorteren", + "exportReset": "Standaardwaarden herstellen", + "exportToc": "Inhoudsopgave opnemen", + "exportTocDepth": "Diepte inhoudsopgave", + "exportNumberHeadings": "Koppen nummeren", + "exportLegal": "US Legal", + "exportCustom": "Aangepast", + "exportPageWidth": "Paginabreedte (mm)", + "exportPageHeight": "Paginahoogte (mm)", + "exportMarginTop": "Bovenmarge (mm)", + "exportMarginRight": "Rechtermarge (mm)", + "exportMarginBottom": "Ondermarge (mm)", + "exportMarginLeft": "Linkermarge (mm)", + "exportTypography": "Typografie", + "exportSans": "Schreefloos", + "exportSerif": "Met schreef", + "exportBodySize": "Tekstgrootte", + "exportCodeSize": "Codegrootte", + "exportRunningText": "Kop- en voettekst", + "exportHeader": "Koptekst", + "exportFooter": "Voettekst", + "exportNone": "Geen", + "exportDocumentTitle": "Documenttitel", + "exportBottomLeft": "Linksonder", + "exportBottomCenter": "Middenonder", + "exportBottomRight": "Rechtsonder", + "exportFirstPage": "Kop- en voettekst op de eerste pagina tonen", + "exportAccent": "Accent-/linkkleur", + "exportTheme": "Thema", + "exportAutomatic": "Automatisch", + "exportLayout": "Indeling", + "exportContentWidth": "Maximale inhoudsbreedte", + "exportOutput": "Uitvoer", + "exportPackaging": "Verpakking", + "exportSingleFile": "Eén HTML-bestand", + "exportAssetsDirectory": "HTML + middelenmap", + "exportCustomCss": "Aangepast stijlblad…", + "exportRemoveCss": "Aangepast stijlblad verwijderen", + "exportCssNote": "Kies een optioneel UTF-8-CSS-bestand (maximaal 256 KiB). Imports, bron-URL’s en uitvoerbare of ontsnapte CSS worden geweigerd. De stijlen volgen die van BusyMark. Externe bronnen worden nooit opgehaald.", + "exportSitePackagingNote": "Writerside behoudt aparte gekoppelde onderwerppagina’s. De enkelbestandsmodus sluit bronnen in elke pagina in.", + "exportInvalidGeometry": "Laat na de marges minimaal 20 mm inhoudsbreedte en -hoogte over.", + "exportInvalidColor": "Voer een kleur in als #RRGGBB.", + "exportInvalidCss": "Kies een leesbaar UTF-8 .css-bestand tot 256 KiB zonder imports, bron-URL’s, HTML of uitvoerbare of ontsnapte CSS.", + "exportInvalidRange": "{field}: voer een getal tussen {minimum} en {maximum} in." } diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index e1e8ec89..5eb6b2fb 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -3121,5 +3121,48 @@ "diagnosticWritersideSchema": "Nieprawidłowy znacznik Writerside: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "Użyj true lub false; single-file nie jest już obsługiwane.", "diagnosticWritersideReference": "Nie można rozwiązać {kind}: {reference}", - "sortTableColumn": "Sortuj {column}" + "sortTableColumn": "Sortuj {column}", + "exportReset": "Przywróć domyślne", + "exportToc": "Dołącz spis treści", + "exportTocDepth": "Głębokość spisu treści", + "exportNumberHeadings": "Numeruj nagłówki", + "exportLegal": "US Legal", + "exportCustom": "Niestandardowy", + "exportPageWidth": "Szerokość strony (mm)", + "exportPageHeight": "Wysokość strony (mm)", + "exportMarginTop": "Margines górny (mm)", + "exportMarginRight": "Margines prawy (mm)", + "exportMarginBottom": "Margines dolny (mm)", + "exportMarginLeft": "Margines lewy (mm)", + "exportTypography": "Typografia", + "exportSans": "Bezszeryfowa", + "exportSerif": "Szeryfowa", + "exportBodySize": "Rozmiar tekstu", + "exportCodeSize": "Rozmiar kodu", + "exportRunningText": "Nagłówek i stopka", + "exportHeader": "Nagłówek", + "exportFooter": "Stopka", + "exportNone": "Brak", + "exportDocumentTitle": "Tytuł dokumentu", + "exportBottomLeft": "Na dole po lewej", + "exportBottomCenter": "Na dole na środku", + "exportBottomRight": "Na dole po prawej", + "exportFirstPage": "Pokaż nagłówek i stopkę na pierwszej stronie", + "exportAccent": "Kolor akcentu / łączy", + "exportTheme": "Motyw", + "exportAutomatic": "Automatyczny", + "exportLayout": "Układ", + "exportContentWidth": "Maksymalna szerokość treści", + "exportOutput": "Wyjście", + "exportPackaging": "Pakowanie", + "exportSingleFile": "Jeden plik HTML", + "exportAssetsDirectory": "HTML + katalog zasobów", + "exportCustomCss": "Własny arkusz stylów…", + "exportRemoveCss": "Usuń własny arkusz stylów", + "exportCssNote": "Wybierz opcjonalny plik CSS UTF-8 (do 256 KiB). Importy, adresy zasobów oraz wykonywalny CSS lub sekwencje ucieczki są odrzucane. Style następują po arkuszu BusyMark. Zdalne zasoby nie są pobierane.", + "exportSitePackagingNote": "Writerside zachowuje osobne połączone strony tematów. Tryb jednego pliku osadza zasoby w każdej stronie.", + "exportInvalidGeometry": "Po odjęciu marginesów pozostaw co najmniej 20 mm szerokości i wysokości treści.", + "exportInvalidColor": "Wpisz kolor w formacie #RRGGBB.", + "exportInvalidCss": "Wybierz czytelny plik .css UTF-8 do 256 KiB, bez importów, adresów zasobów, HTML oraz wykonywalnego CSS i sekwencji ucieczki.", + "exportInvalidRange": "{field}: wpisz liczbę między {minimum} a {maximum}." } diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 220ec7e8..c28e12b6 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -96,5 +96,48 @@ "diagnosticWritersideSchema": "Marcação Writerside inválida: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "Use true ou false; single-file deixou de ser suportado.", "diagnosticWritersideReference": "Não é possível resolver {kind}: {reference}", - "sortTableColumn": "Ordenar {column}" + "sortTableColumn": "Ordenar {column}", + "exportReset": "Restaurar predefinições", + "exportToc": "Incluir índice", + "exportTocDepth": "Profundidade do índice", + "exportNumberHeadings": "Numerar títulos", + "exportLegal": "US Legal", + "exportCustom": "Personalizado", + "exportPageWidth": "Largura da página (mm)", + "exportPageHeight": "Altura da página (mm)", + "exportMarginTop": "Margem superior (mm)", + "exportMarginRight": "Margem direita (mm)", + "exportMarginBottom": "Margem inferior (mm)", + "exportMarginLeft": "Margem esquerda (mm)", + "exportTypography": "Tipografia", + "exportSans": "Sem serifas", + "exportSerif": "Com serifas", + "exportBodySize": "Tamanho do texto", + "exportCodeSize": "Tamanho do código", + "exportRunningText": "Cabeçalho e rodapé", + "exportHeader": "Cabeçalho", + "exportFooter": "Rodapé", + "exportNone": "Nenhum", + "exportDocumentTitle": "Título do documento", + "exportBottomLeft": "Em baixo à esquerda", + "exportBottomCenter": "Em baixo ao centro", + "exportBottomRight": "Em baixo à direita", + "exportFirstPage": "Mostrar cabeçalho e rodapé na primeira página", + "exportAccent": "Cor de destaque / ligações", + "exportTheme": "Tema", + "exportAutomatic": "Automático", + "exportLayout": "Disposição", + "exportContentWidth": "Largura máxima do conteúdo", + "exportOutput": "Saída", + "exportPackaging": "Empacotamento", + "exportSingleFile": "Um único ficheiro HTML", + "exportAssetsDirectory": "HTML + pasta de recursos", + "exportCustomCss": "Folha de estilo personalizada…", + "exportRemoveCss": "Remover folha de estilo", + "exportCssNote": "Escolha um ficheiro CSS UTF-8 opcional (até 256 KiB). Importações, URL de recursos e CSS executável ou com escapes são rejeitados. Os estilos seguem os do BusyMark. Nunca são transferidos recursos remotos.", + "exportSitePackagingNote": "O Writerside mantém páginas de tópicos separadas e ligadas. O modo de ficheiro único incorpora os recursos em cada página.", + "exportInvalidGeometry": "Deixe pelo menos 20 mm de largura e altura de conteúdo após as margens.", + "exportInvalidColor": "Introduza uma cor como #RRGGBB.", + "exportInvalidCss": "Escolha um ficheiro .css UTF-8 legível até 256 KiB, sem importações, URL de recursos, HTML ou CSS executável ou com escapes.", + "exportInvalidRange": "{field}: introduza um número entre {minimum} e {maximum}." } diff --git a/lib/l10n/app_pt_BR.arb b/lib/l10n/app_pt_BR.arb index d5778725..168a2064 100644 --- a/lib/l10n/app_pt_BR.arb +++ b/lib/l10n/app_pt_BR.arb @@ -3095,5 +3095,48 @@ "diagnosticWritersideSchema": "Marcação Writerside inválida: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "Use true ou false; single-file não é mais compatível.", "diagnosticWritersideReference": "Não é possível resolver {kind}: {reference}", - "sortTableColumn": "Ordenar {column}" + "sortTableColumn": "Ordenar {column}", + "exportReset": "Restaurar padrões", + "exportToc": "Incluir índice", + "exportTocDepth": "Profundidade do índice", + "exportNumberHeadings": "Numerar títulos", + "exportLegal": "US Legal", + "exportCustom": "Personalizado", + "exportPageWidth": "Largura da página (mm)", + "exportPageHeight": "Altura da página (mm)", + "exportMarginTop": "Margem superior (mm)", + "exportMarginRight": "Margem direita (mm)", + "exportMarginBottom": "Margem inferior (mm)", + "exportMarginLeft": "Margem esquerda (mm)", + "exportTypography": "Tipografia", + "exportSans": "Sem serifas", + "exportSerif": "Com serifas", + "exportBodySize": "Tamanho do texto", + "exportCodeSize": "Tamanho do código", + "exportRunningText": "Cabeçalho e rodapé", + "exportHeader": "Cabeçalho", + "exportFooter": "Rodapé", + "exportNone": "Nenhum", + "exportDocumentTitle": "Título do documento", + "exportBottomLeft": "Embaixo à esquerda", + "exportBottomCenter": "Embaixo ao centro", + "exportBottomRight": "Embaixo à direita", + "exportFirstPage": "Mostrar cabeçalho e rodapé na primeira página", + "exportAccent": "Cor de destaque / links", + "exportTheme": "Tema", + "exportAutomatic": "Automático", + "exportLayout": "Layout", + "exportContentWidth": "Largura máxima do conteúdo", + "exportOutput": "Saída", + "exportPackaging": "Empacotamento", + "exportSingleFile": "Um único arquivo HTML", + "exportAssetsDirectory": "HTML + pasta de recursos", + "exportCustomCss": "Folha de estilo personalizada…", + "exportRemoveCss": "Remover folha de estilo", + "exportCssNote": "Escolha um arquivo CSS UTF-8 opcional (até 256 KiB). Importações, URL de recursos e CSS executável ou com escapes são rejeitados. Os estilos seguem os do BusyMark. Nunca são baixados recursos remotos.", + "exportSitePackagingNote": "O Writerside mantém páginas de tópicos separadas e vinculadas. O modo de arquivo único incorpora os recursos em cada página.", + "exportInvalidGeometry": "Deixe pelo menos 20 mm de largura e altura de conteúdo após as margens.", + "exportInvalidColor": "Insira uma cor como #RRGGBB.", + "exportInvalidCss": "Escolha um arquivo .css UTF-8 legível até 256 KiB, sem importações, URL de recursos, HTML ou CSS executável ou com escapes.", + "exportInvalidRange": "{field}: insira um número entre {minimum} e {maximum}." } diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 7098beb6..de81f71c 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -3121,5 +3121,48 @@ "diagnosticWritersideSchema": "Некорректная разметка Writerside: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "Используйте true или false; single-file больше не поддерживается.", "diagnosticWritersideReference": "Не удалось разрешить {kind}: {reference}", - "sortTableColumn": "Сортировать {column}" + "sortTableColumn": "Сортировать {column}", + "exportReset": "Восстановить значения по умолчанию", + "exportToc": "Добавить оглавление", + "exportTocDepth": "Глубина оглавления", + "exportNumberHeadings": "Нумеровать заголовки", + "exportLegal": "US Legal", + "exportCustom": "Другой", + "exportPageWidth": "Ширина страницы (мм)", + "exportPageHeight": "Высота страницы (мм)", + "exportMarginTop": "Верхнее поле (мм)", + "exportMarginRight": "Правое поле (мм)", + "exportMarginBottom": "Нижнее поле (мм)", + "exportMarginLeft": "Левое поле (мм)", + "exportTypography": "Типографика", + "exportSans": "Без засечек", + "exportSerif": "С засечками", + "exportBodySize": "Размер основного шрифта", + "exportCodeSize": "Размер шрифта кода", + "exportRunningText": "Колонтитулы", + "exportHeader": "Верхний колонтитул", + "exportFooter": "Нижний колонтитул", + "exportNone": "Нет", + "exportDocumentTitle": "Название документа", + "exportBottomLeft": "Снизу слева", + "exportBottomCenter": "Снизу по центру", + "exportBottomRight": "Снизу справа", + "exportFirstPage": "Показывать колонтитулы на первой странице", + "exportAccent": "Цвет акцента / ссылок", + "exportTheme": "Тема", + "exportAutomatic": "Автоматически", + "exportLayout": "Макет", + "exportContentWidth": "Максимальная ширина содержимого", + "exportOutput": "Вывод", + "exportPackaging": "Упаковка", + "exportSingleFile": "Один файл HTML", + "exportAssetsDirectory": "HTML + папка ресурсов", + "exportCustomCss": "Свой файл стилей…", + "exportRemoveCss": "Удалить свой файл стилей", + "exportCssNote": "Выберите необязательный файл CSS в UTF-8 (до 256 КиБ). Импорты, URL ресурсов, исполняемый CSS и escape-последовательности запрещены. Стили применяются после стилей BusyMark. Удалённые ресурсы не загружаются.", + "exportSitePackagingNote": "Writerside сохраняет отдельные связанные страницы тем. Режим одного файла встраивает ресурсы в каждую страницу.", + "exportInvalidGeometry": "После вычета полей оставьте не менее 20 мм ширины и высоты содержимого.", + "exportInvalidColor": "Введите цвет в формате #RRGGBB.", + "exportInvalidCss": "Выберите читаемый файл .css в UTF-8 до 256 КиБ без импортов, URL ресурсов, HTML, исполняемого CSS и escape-последовательностей.", + "exportInvalidRange": "{field}: введите число от {minimum} до {maximum}." } diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index b6692855..96b14eaf 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -4654,5 +4654,48 @@ "diagnosticWritersideSchema": "Geçersiz Writerside işaretlemesi: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "true veya false kullanın; single-file artık desteklenmiyor.", "diagnosticWritersideReference": "{kind} çözümlenemiyor: {reference}", - "sortTableColumn": "{column} sırala" + "sortTableColumn": "{column} sırala", + "exportReset": "Varsayılanlara sıfırla", + "exportToc": "İçindekiler tablosunu ekle", + "exportTocDepth": "İçindekiler derinliği", + "exportNumberHeadings": "Başlıkları numaralandır", + "exportLegal": "US Legal", + "exportCustom": "Özel", + "exportPageWidth": "Sayfa genişliği (mm)", + "exportPageHeight": "Sayfa yüksekliği (mm)", + "exportMarginTop": "Üst kenar boşluğu (mm)", + "exportMarginRight": "Sağ kenar boşluğu (mm)", + "exportMarginBottom": "Alt kenar boşluğu (mm)", + "exportMarginLeft": "Sol kenar boşluğu (mm)", + "exportTypography": "Tipografi", + "exportSans": "Serifsiz", + "exportSerif": "Serifli", + "exportBodySize": "Gövde yazı tipi boyutu", + "exportCodeSize": "Kod yazı tipi boyutu", + "exportRunningText": "Üst bilgi ve alt bilgi", + "exportHeader": "Üst bilgi", + "exportFooter": "Alt bilgi", + "exportNone": "Yok", + "exportDocumentTitle": "Belge başlığı", + "exportBottomLeft": "Sol alt", + "exportBottomCenter": "Alt orta", + "exportBottomRight": "Sağ alt", + "exportFirstPage": "İlk sayfada üst ve alt bilgiyi göster", + "exportAccent": "Vurgu / bağlantı rengi", + "exportTheme": "Tema", + "exportAutomatic": "Otomatik", + "exportLayout": "Düzen", + "exportContentWidth": "En fazla içerik genişliği", + "exportOutput": "Çıktı", + "exportPackaging": "Paketleme", + "exportSingleFile": "Tek HTML dosyası", + "exportAssetsDirectory": "HTML + kaynak klasörü", + "exportCustomCss": "Özel stil sayfası…", + "exportRemoveCss": "Özel stil sayfasını kaldır", + "exportCssNote": "İsteğe bağlı UTF-8 CSS dosyası seçin (en fazla 256 KiB). İçe aktarımlar, kaynak URL’leri ve çalıştırılabilir veya kaçışlı CSS reddedilir. Stiller BusyMark CSS’inden sonra uygulanır. Uzak kaynaklar indirilmez.", + "exportSitePackagingNote": "Writerside ayrı bağlantılı konu sayfalarını korur. Tek dosya modu kaynakları her sayfaya gömer.", + "exportInvalidGeometry": "Kenar boşluklarından sonra en az 20 mm içerik genişliği ve yüksekliği bırakın.", + "exportInvalidColor": "#RRGGBB biçiminde bir renk girin.", + "exportInvalidCss": "İçe aktarım, kaynak URL’si, HTML, çalıştırılabilir veya kaçışlı CSS içermeyen, okunabilir UTF-8 .css dosyası seçin (en fazla 256 KiB).", + "exportInvalidRange": "{field}: {minimum} ile {maximum} arasında bir sayı girin." } diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 5cd78389..458944a5 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -3121,5 +3121,48 @@ "diagnosticWritersideSchema": "Некоректна розмітка Writerside: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "Використовуйте true або false; single-file більше не підтримується.", "diagnosticWritersideReference": "Не вдалося знайти {kind}: {reference}", - "sortTableColumn": "Сортувати {column}" + "sortTableColumn": "Сортувати {column}", + "exportReset": "Відновити типові значення", + "exportToc": "Додати зміст", + "exportTocDepth": "Глибина змісту", + "exportNumberHeadings": "Нумерувати заголовки", + "exportLegal": "US Legal", + "exportCustom": "Власний", + "exportPageWidth": "Ширина сторінки (мм)", + "exportPageHeight": "Висота сторінки (мм)", + "exportMarginTop": "Верхнє поле (мм)", + "exportMarginRight": "Праве поле (мм)", + "exportMarginBottom": "Нижнє поле (мм)", + "exportMarginLeft": "Ліве поле (мм)", + "exportTypography": "Типографіка", + "exportSans": "Без зарубок", + "exportSerif": "Із зарубками", + "exportBodySize": "Розмір основного шрифту", + "exportCodeSize": "Розмір шрифту коду", + "exportRunningText": "Колонтитули", + "exportHeader": "Верхній колонтитул", + "exportFooter": "Нижній колонтитул", + "exportNone": "Немає", + "exportDocumentTitle": "Назва документа", + "exportBottomLeft": "Знизу ліворуч", + "exportBottomCenter": "Знизу по центру", + "exportBottomRight": "Знизу праворуч", + "exportFirstPage": "Показувати колонтитули на першій сторінці", + "exportAccent": "Колір акценту / посилань", + "exportTheme": "Тема", + "exportAutomatic": "Автоматично", + "exportLayout": "Макет", + "exportContentWidth": "Максимальна ширина вмісту", + "exportOutput": "Вивід", + "exportPackaging": "Пакування", + "exportSingleFile": "Один файл HTML", + "exportAssetsDirectory": "HTML + папка ресурсів", + "exportCustomCss": "Власний файл стилів…", + "exportRemoveCss": "Вилучити власний файл стилів", + "exportCssNote": "Виберіть необов’язковий файл CSS у UTF-8 (до 256 КіБ). Імпорти, URL ресурсів, виконуваний CSS і escape-послідовності заборонені. Стилі застосовуються після стилів BusyMark. Віддалені ресурси не завантажуються.", + "exportSitePackagingNote": "Writerside зберігає окремі пов’язані сторінки тем. Режим одного файлу вбудовує ресурси в кожну сторінку.", + "exportInvalidGeometry": "Після віднімання полів залиште щонайменше 20 мм ширини й висоти вмісту.", + "exportInvalidColor": "Введіть колір у форматі #RRGGBB.", + "exportInvalidCss": "Виберіть читабельний файл .css у UTF-8 до 256 КіБ без імпортів, URL ресурсів, HTML, виконуваного CSS і escape-послідовностей.", + "exportInvalidRange": "{field}: введіть число від {minimum} до {maximum}." } diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index aaafa4d1..1f1b5709 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -4654,5 +4654,48 @@ "diagnosticWritersideSchema": "Đánh dấu Writerside không hợp lệ: {element}, {attribute}. {reason}", "diagnosticWritersideLlmsTxt": "Dùng true hoặc false; single-file không còn được hỗ trợ.", "diagnosticWritersideReference": "Không thể phân giải {kind}: {reference}", - "sortTableColumn": "Sắp xếp {column}" + "sortTableColumn": "Sắp xếp {column}", + "exportReset": "Khôi phục mặc định", + "exportToc": "Bao gồm mục lục", + "exportTocDepth": "Độ sâu mục lục", + "exportNumberHeadings": "Đánh số tiêu đề", + "exportLegal": "US Legal", + "exportCustom": "Tùy chỉnh", + "exportPageWidth": "Chiều rộng trang (mm)", + "exportPageHeight": "Chiều cao trang (mm)", + "exportMarginTop": "Lề trên (mm)", + "exportMarginRight": "Lề phải (mm)", + "exportMarginBottom": "Lề dưới (mm)", + "exportMarginLeft": "Lề trái (mm)", + "exportTypography": "Kiểu chữ", + "exportSans": "Không chân", + "exportSerif": "Có chân", + "exportBodySize": "Cỡ chữ nội dung", + "exportCodeSize": "Cỡ chữ mã", + "exportRunningText": "Đầu trang và chân trang", + "exportHeader": "Đầu trang", + "exportFooter": "Chân trang", + "exportNone": "Không có", + "exportDocumentTitle": "Tiêu đề tài liệu", + "exportBottomLeft": "Dưới bên trái", + "exportBottomCenter": "Dưới ở giữa", + "exportBottomRight": "Dưới bên phải", + "exportFirstPage": "Hiện đầu trang và chân trang ở trang đầu", + "exportAccent": "Màu nhấn / liên kết", + "exportTheme": "Giao diện", + "exportAutomatic": "Tự động", + "exportLayout": "Bố cục", + "exportContentWidth": "Chiều rộng nội dung tối đa", + "exportOutput": "Đầu ra", + "exportPackaging": "Đóng gói", + "exportSingleFile": "Một tệp HTML", + "exportAssetsDirectory": "HTML + thư mục tài nguyên", + "exportCustomCss": "Biểu định kiểu tùy chỉnh…", + "exportRemoveCss": "Xóa biểu định kiểu tùy chỉnh", + "exportCssNote": "Chọn tệp CSS UTF-8 tùy chọn (tối đa 256 KiB). Không chấp nhận nhập tài nguyên, URL tài nguyên, CSS thực thi hoặc có ký tự thoát. Kiểu được áp dụng sau CSS của BusyMark. Không tải tài nguyên từ xa.", + "exportSitePackagingNote": "Writerside giữ các trang chủ đề riêng có liên kết. Chế độ một tệp nhúng tài nguyên vào từng trang.", + "exportInvalidGeometry": "Sau khi trừ lề, hãy để nội dung rộng và cao ít nhất 20 mm.", + "exportInvalidColor": "Nhập màu theo dạng #RRGGBB.", + "exportInvalidCss": "Chọn tệp .css UTF-8 đọc được tối đa 256 KiB, không có nhập tài nguyên, URL tài nguyên, HTML, CSS thực thi hoặc ký tự thoát.", + "exportInvalidRange": "{field}: nhập số từ {minimum} đến {maximum}." } diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 12111228..b1fd8e44 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -96,5 +96,48 @@ "diagnosticWritersideSchema": "无效的 Writerside 标记:{element},{attribute}。{reason}", "diagnosticWritersideLlmsTxt": "请使用 true 或 false;不再支持 single-file。", "diagnosticWritersideReference": "无法解析 {kind}:{reference}", - "sortTableColumn": "排序 {column}" + "sortTableColumn": "排序 {column}", + "exportReset": "恢复默认值", + "exportToc": "包含目录", + "exportTocDepth": "目录深度", + "exportNumberHeadings": "为标题编号", + "exportLegal": "US Legal", + "exportCustom": "自定义", + "exportPageWidth": "页面宽度(mm)", + "exportPageHeight": "页面高度(mm)", + "exportMarginTop": "上边距(mm)", + "exportMarginRight": "右边距(mm)", + "exportMarginBottom": "下边距(mm)", + "exportMarginLeft": "左边距(mm)", + "exportTypography": "字体", + "exportSans": "无衬线", + "exportSerif": "衬线", + "exportBodySize": "正文字号", + "exportCodeSize": "代码字号", + "exportRunningText": "页眉和页脚", + "exportHeader": "页眉", + "exportFooter": "页脚", + "exportNone": "无", + "exportDocumentTitle": "文档标题", + "exportBottomLeft": "左下", + "exportBottomCenter": "底部居中", + "exportBottomRight": "右下", + "exportFirstPage": "在首页显示页眉和页脚", + "exportAccent": "强调色/链接颜色", + "exportTheme": "主题", + "exportAutomatic": "自动", + "exportLayout": "布局", + "exportContentWidth": "内容最大宽度", + "exportOutput": "输出", + "exportPackaging": "打包方式", + "exportSingleFile": "单个 HTML 文件", + "exportAssetsDirectory": "HTML + 资源目录", + "exportCustomCss": "自定义样式表…", + "exportRemoveCss": "移除自定义样式表", + "exportCssNote": "可选用 UTF-8 CSS 文件(最大 256 KiB)。不接受导入、资源 URL、可执行或转义 CSS。样式在 BusyMark 样式表之后应用。不会获取远程资源。", + "exportSitePackagingNote": "Writerside 保留独立且相互链接的主题页面。单文件模式将资源嵌入每个页面。", + "exportInvalidGeometry": "扣除边距后,请至少保留 20 mm 的内容宽度和高度。", + "exportInvalidColor": "请输入 #RRGGBB 格式的颜色。", + "exportInvalidCss": "请选择可读取的 UTF-8 .css 文件(最大 256 KiB),不得包含导入、资源 URL、HTML、可执行或转义 CSS。", + "exportInvalidRange": "{field}:请输入 {minimum} 到 {maximum} 之间的数字。" } diff --git a/lib/l10n/app_zh_CN.arb b/lib/l10n/app_zh_CN.arb index 0ffb25a7..cb36af3e 100644 --- a/lib/l10n/app_zh_CN.arb +++ b/lib/l10n/app_zh_CN.arb @@ -4654,5 +4654,48 @@ "diagnosticWritersideSchema": "无效的 Writerside 标记:{element},{attribute}。{reason}", "diagnosticWritersideLlmsTxt": "请使用 true 或 false;不再支持 single-file。", "diagnosticWritersideReference": "无法解析 {kind}:{reference}", - "sortTableColumn": "排序 {column}" + "sortTableColumn": "排序 {column}", + "exportReset": "恢复默认值", + "exportToc": "包含目录", + "exportTocDepth": "目录深度", + "exportNumberHeadings": "为标题编号", + "exportLegal": "US Legal", + "exportCustom": "自定义", + "exportPageWidth": "页面宽度(mm)", + "exportPageHeight": "页面高度(mm)", + "exportMarginTop": "上边距(mm)", + "exportMarginRight": "右边距(mm)", + "exportMarginBottom": "下边距(mm)", + "exportMarginLeft": "左边距(mm)", + "exportTypography": "字体", + "exportSans": "无衬线", + "exportSerif": "衬线", + "exportBodySize": "正文字号", + "exportCodeSize": "代码字号", + "exportRunningText": "页眉和页脚", + "exportHeader": "页眉", + "exportFooter": "页脚", + "exportNone": "无", + "exportDocumentTitle": "文档标题", + "exportBottomLeft": "左下", + "exportBottomCenter": "底部居中", + "exportBottomRight": "右下", + "exportFirstPage": "在首页显示页眉和页脚", + "exportAccent": "强调色/链接颜色", + "exportTheme": "主题", + "exportAutomatic": "自动", + "exportLayout": "布局", + "exportContentWidth": "内容最大宽度", + "exportOutput": "输出", + "exportPackaging": "打包方式", + "exportSingleFile": "单个 HTML 文件", + "exportAssetsDirectory": "HTML + 资源目录", + "exportCustomCss": "自定义样式表…", + "exportRemoveCss": "移除自定义样式表", + "exportCssNote": "可选用 UTF-8 CSS 文件(最大 256 KiB)。不接受导入、资源 URL、可执行或转义 CSS。样式在 BusyMark 样式表之后应用。不会获取远程资源。", + "exportSitePackagingNote": "Writerside 保留独立且相互链接的主题页面。单文件模式将资源嵌入每个页面。", + "exportInvalidGeometry": "扣除边距后,请至少保留 20 mm 的内容宽度和高度。", + "exportInvalidColor": "请输入 #RRGGBB 格式的颜色。", + "exportInvalidCss": "请选择可读取的 UTF-8 .css 文件(最大 256 KiB),不得包含导入、资源 URL、HTML、可执行或转义 CSS。", + "exportInvalidRange": "{field}:请输入 {minimum} 到 {maximum} 之间的数字。" } diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 0879248d..fb0e3f60 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -6286,6 +6286,264 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Sort {column}'** String sortTableColumn(String column); + + /// No description provided for @exportReset. + /// + /// In en, this message translates to: + /// **'Reset to defaults'** + String get exportReset; + + /// No description provided for @exportToc. + /// + /// In en, this message translates to: + /// **'Include table of contents'** + String get exportToc; + + /// No description provided for @exportTocDepth. + /// + /// In en, this message translates to: + /// **'TOC depth'** + String get exportTocDepth; + + /// No description provided for @exportNumberHeadings. + /// + /// In en, this message translates to: + /// **'Number headings'** + String get exportNumberHeadings; + + /// No description provided for @exportLegal. + /// + /// In en, this message translates to: + /// **'US Legal'** + String get exportLegal; + + /// No description provided for @exportCustom. + /// + /// In en, this message translates to: + /// **'Custom'** + String get exportCustom; + + /// No description provided for @exportPageWidth. + /// + /// In en, this message translates to: + /// **'Page width (mm)'** + String get exportPageWidth; + + /// No description provided for @exportPageHeight. + /// + /// In en, this message translates to: + /// **'Page height (mm)'** + String get exportPageHeight; + + /// No description provided for @exportMarginTop. + /// + /// In en, this message translates to: + /// **'Top margin (mm)'** + String get exportMarginTop; + + /// No description provided for @exportMarginRight. + /// + /// In en, this message translates to: + /// **'Right margin (mm)'** + String get exportMarginRight; + + /// No description provided for @exportMarginBottom. + /// + /// In en, this message translates to: + /// **'Bottom margin (mm)'** + String get exportMarginBottom; + + /// No description provided for @exportMarginLeft. + /// + /// In en, this message translates to: + /// **'Left margin (mm)'** + String get exportMarginLeft; + + /// No description provided for @exportTypography. + /// + /// In en, this message translates to: + /// **'Typography'** + String get exportTypography; + + /// No description provided for @exportSans. + /// + /// In en, this message translates to: + /// **'Sans-serif'** + String get exportSans; + + /// No description provided for @exportSerif. + /// + /// In en, this message translates to: + /// **'Serif'** + String get exportSerif; + + /// No description provided for @exportBodySize. + /// + /// In en, this message translates to: + /// **'Body font size'** + String get exportBodySize; + + /// No description provided for @exportCodeSize. + /// + /// In en, this message translates to: + /// **'Code font size'** + String get exportCodeSize; + + /// No description provided for @exportRunningText. + /// + /// In en, this message translates to: + /// **'Header & Footer'** + String get exportRunningText; + + /// No description provided for @exportHeader. + /// + /// In en, this message translates to: + /// **'Header'** + String get exportHeader; + + /// No description provided for @exportFooter. + /// + /// In en, this message translates to: + /// **'Footer'** + String get exportFooter; + + /// No description provided for @exportNone. + /// + /// In en, this message translates to: + /// **'None'** + String get exportNone; + + /// No description provided for @exportDocumentTitle. + /// + /// In en, this message translates to: + /// **'Document title'** + String get exportDocumentTitle; + + /// No description provided for @exportBottomLeft. + /// + /// In en, this message translates to: + /// **'Bottom left'** + String get exportBottomLeft; + + /// No description provided for @exportBottomCenter. + /// + /// In en, this message translates to: + /// **'Bottom center'** + String get exportBottomCenter; + + /// No description provided for @exportBottomRight. + /// + /// In en, this message translates to: + /// **'Bottom right'** + String get exportBottomRight; + + /// No description provided for @exportFirstPage. + /// + /// In en, this message translates to: + /// **'Show header and footer on first page'** + String get exportFirstPage; + + /// No description provided for @exportAccent. + /// + /// In en, this message translates to: + /// **'Accent / link color'** + String get exportAccent; + + /// No description provided for @exportTheme. + /// + /// In en, this message translates to: + /// **'Theme'** + String get exportTheme; + + /// No description provided for @exportAutomatic. + /// + /// In en, this message translates to: + /// **'Automatic'** + String get exportAutomatic; + + /// No description provided for @exportLayout. + /// + /// In en, this message translates to: + /// **'Layout'** + String get exportLayout; + + /// No description provided for @exportContentWidth. + /// + /// In en, this message translates to: + /// **'Maximum content width'** + String get exportContentWidth; + + /// No description provided for @exportOutput. + /// + /// In en, this message translates to: + /// **'Output'** + String get exportOutput; + + /// No description provided for @exportPackaging. + /// + /// In en, this message translates to: + /// **'Packaging'** + String get exportPackaging; + + /// No description provided for @exportSingleFile. + /// + /// In en, this message translates to: + /// **'Single HTML file'** + String get exportSingleFile; + + /// No description provided for @exportAssetsDirectory. + /// + /// In en, this message translates to: + /// **'HTML + assets directory'** + String get exportAssetsDirectory; + + /// No description provided for @exportCustomCss. + /// + /// In en, this message translates to: + /// **'Custom stylesheet…'** + String get exportCustomCss; + + /// No description provided for @exportRemoveCss. + /// + /// In en, this message translates to: + /// **'Remove custom stylesheet'** + String get exportRemoveCss; + + /// No description provided for @exportCssNote. + /// + /// In en, this message translates to: + /// **'Select an optional UTF-8 CSS file (up to 256 KiB). Imports, resource URLs, and executable or escaped CSS are not accepted. Styles are applied after BusyMark’s stylesheet. Remote resources are never fetched.'** + String get exportCssNote; + + /// No description provided for @exportSitePackagingNote. + /// + /// In en, this message translates to: + /// **'Writerside keeps separate linked topic pages. Single-file mode embeds resources in each page.'** + String get exportSitePackagingNote; + + /// No description provided for @exportInvalidGeometry. + /// + /// In en, this message translates to: + /// **'Leave at least 20 mm of content width and height after margins.'** + String get exportInvalidGeometry; + + /// No description provided for @exportInvalidColor. + /// + /// In en, this message translates to: + /// **'Enter a color as #RRGGBB.'** + String get exportInvalidColor; + + /// No description provided for @exportInvalidCss. + /// + /// In en, this message translates to: + /// **'Choose a readable UTF-8 .css file up to 256 KiB, without imports, resource URLs, HTML, or executable or escaped CSS.'** + String get exportInvalidCss; + + /// Invalid numeric export setting. + /// + /// In en, this message translates to: + /// **'{field}: enter a number between {minimum} and {maximum}.'** + String exportInvalidRange(String field, String minimum, String maximum); } class _AppLocalizationsDelegate diff --git a/lib/l10n/generated/app_localizations_ar.dart b/lib/l10n/generated/app_localizations_ar.dart index f521afef..99c4c3ef 100644 --- a/lib/l10n/generated/app_localizations_ar.dart +++ b/lib/l10n/generated/app_localizations_ar.dart @@ -3787,4 +3787,139 @@ class AppLocalizationsAr extends AppLocalizations { String sortTableColumn(String column) { return 'فرز $column'; } + + @override + String get exportReset => 'استعادة الإعدادات الافتراضية'; + + @override + String get exportToc => 'تضمين جدول المحتويات'; + + @override + String get exportTocDepth => 'عمق جدول المحتويات'; + + @override + String get exportNumberHeadings => 'ترقيم العناوين'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'مخصص'; + + @override + String get exportPageWidth => 'عرض الصفحة (مم)'; + + @override + String get exportPageHeight => 'ارتفاع الصفحة (مم)'; + + @override + String get exportMarginTop => 'الهامش العلوي (مم)'; + + @override + String get exportMarginRight => 'الهامش الأيمن (مم)'; + + @override + String get exportMarginBottom => 'الهامش السفلي (مم)'; + + @override + String get exportMarginLeft => 'الهامش الأيسر (مم)'; + + @override + String get exportTypography => 'الخطوط'; + + @override + String get exportSans => 'بلا زوائد'; + + @override + String get exportSerif => 'بزوائد'; + + @override + String get exportBodySize => 'حجم خط النص'; + + @override + String get exportCodeSize => 'حجم خط الشيفرة'; + + @override + String get exportRunningText => 'رأس الصفحة وتذييلها'; + + @override + String get exportHeader => 'رأس الصفحة'; + + @override + String get exportFooter => 'تذييل الصفحة'; + + @override + String get exportNone => 'بلا'; + + @override + String get exportDocumentTitle => 'عنوان المستند'; + + @override + String get exportBottomLeft => 'أسفل اليسار'; + + @override + String get exportBottomCenter => 'أسفل الوسط'; + + @override + String get exportBottomRight => 'أسفل اليمين'; + + @override + String get exportFirstPage => 'إظهار الرأس والتذييل في الصفحة الأولى'; + + @override + String get exportAccent => 'لون التمييز / الروابط'; + + @override + String get exportTheme => 'المظهر'; + + @override + String get exportAutomatic => 'تلقائي'; + + @override + String get exportLayout => 'التخطيط'; + + @override + String get exportContentWidth => 'العرض الأقصى للمحتوى'; + + @override + String get exportOutput => 'الإخراج'; + + @override + String get exportPackaging => 'التجميع'; + + @override + String get exportSingleFile => 'ملف HTML واحد'; + + @override + String get exportAssetsDirectory => 'HTML + مجلد موارد'; + + @override + String get exportCustomCss => 'ورقة أنماط مخصصة…'; + + @override + String get exportRemoveCss => 'إزالة ورقة الأنماط المخصصة'; + + @override + String get exportCssNote => + 'اختر ملف CSS اختياريًا بترميز UTF-8 (حتى 256 KiB). تُرفض عمليات الاستيراد وعناوين الموارد وCSS القابل للتنفيذ أو المحتوي على محارف هروب. تُطبق الأنماط بعد أنماط BusyMark. لا تُجلب موارد بعيدة.'; + + @override + String get exportSitePackagingNote => + 'يحتفظ Writerside بصفحات مواضيع منفصلة ومترابطة. يضمّن وضع الملف الواحد الموارد في كل صفحة.'; + + @override + String get exportInvalidGeometry => + 'اترك عرضًا وارتفاعًا للمحتوى لا يقلان عن 20 مم بعد الهوامش.'; + + @override + String get exportInvalidColor => 'أدخل لونًا بصيغة #RRGGBB.'; + + @override + String get exportInvalidCss => + 'اختر ملف .css مقروءًا بترميز UTF-8 حتى 256 KiB، دون استيراد أو عناوين موارد أو HTML أو CSS قابل للتنفيذ أو يحتوي على محارف هروب.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: أدخل رقمًا بين $minimum و$maximum.'; + } } diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index de970fab..e33b9039 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -3780,4 +3780,140 @@ class AppLocalizationsDe extends AppLocalizations { String sortTableColumn(String column) { return '$column sortieren'; } + + @override + String get exportReset => 'Auf Standardwerte zurücksetzen'; + + @override + String get exportToc => 'Inhaltsverzeichnis einfügen'; + + @override + String get exportTocDepth => 'Gliederungstiefe'; + + @override + String get exportNumberHeadings => 'Überschriften nummerieren'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Benutzerdefiniert'; + + @override + String get exportPageWidth => 'Seitenbreite (mm)'; + + @override + String get exportPageHeight => 'Seitenhöhe (mm)'; + + @override + String get exportMarginTop => 'Oberer Rand (mm)'; + + @override + String get exportMarginRight => 'Rechter Rand (mm)'; + + @override + String get exportMarginBottom => 'Unterer Rand (mm)'; + + @override + String get exportMarginLeft => 'Linker Rand (mm)'; + + @override + String get exportTypography => 'Typografie'; + + @override + String get exportSans => 'Serifenlos'; + + @override + String get exportSerif => 'Mit Serifen'; + + @override + String get exportBodySize => 'Schriftgröße des Texts'; + + @override + String get exportCodeSize => 'Schriftgröße für Code'; + + @override + String get exportRunningText => 'Kopf- und Fußzeile'; + + @override + String get exportHeader => 'Kopfzeile'; + + @override + String get exportFooter => 'Fußzeile'; + + @override + String get exportNone => 'Keine'; + + @override + String get exportDocumentTitle => 'Dokumenttitel'; + + @override + String get exportBottomLeft => 'Unten links'; + + @override + String get exportBottomCenter => 'Unten mittig'; + + @override + String get exportBottomRight => 'Unten rechts'; + + @override + String get exportFirstPage => + 'Kopf- und Fußzeile auf der ersten Seite anzeigen'; + + @override + String get exportAccent => 'Akzent-/Linkfarbe'; + + @override + String get exportTheme => 'Design'; + + @override + String get exportAutomatic => 'Automatisch'; + + @override + String get exportLayout => 'Layout'; + + @override + String get exportContentWidth => 'Maximale Inhaltsbreite'; + + @override + String get exportOutput => 'Ausgabe'; + + @override + String get exportPackaging => 'Verpackung'; + + @override + String get exportSingleFile => 'Einzelne HTML-Datei'; + + @override + String get exportAssetsDirectory => 'HTML + Ressourcenordner'; + + @override + String get exportCustomCss => 'Eigenes Stylesheet…'; + + @override + String get exportRemoveCss => 'Eigenes Stylesheet entfernen'; + + @override + String get exportCssNote => + 'Wählen Sie eine optionale UTF-8-CSS-Datei (bis 256 KiB). Importe, Ressourcen-URLs sowie ausführbares oder maskiertes CSS werden abgelehnt. Die Regeln folgen dem BusyMark-Stylesheet. Entfernte Ressourcen werden nie abgerufen.'; + + @override + String get exportSitePackagingNote => + 'Writerside behält getrennte, verknüpfte Themenseiten. Der Einzeldateimodus bettet Ressourcen in jede Seite ein.'; + + @override + String get exportInvalidGeometry => + 'Nach Abzug der Ränder müssen mindestens 20 mm Inhaltsbreite und -höhe bleiben.'; + + @override + String get exportInvalidColor => 'Geben Sie eine Farbe als #RRGGBB ein.'; + + @override + String get exportInvalidCss => + 'Wählen Sie eine lesbare UTF-8-CSS-Datei bis 256 KiB ohne Importe, Ressourcen-URLs, HTML sowie ausführbares oder maskiertes CSS.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: Geben Sie eine Zahl zwischen $minimum und $maximum ein.'; + } } diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 32dabc06..986b271d 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -3775,4 +3775,139 @@ class AppLocalizationsEn extends AppLocalizations { String sortTableColumn(String column) { return 'Sort $column'; } + + @override + String get exportReset => 'Reset to defaults'; + + @override + String get exportToc => 'Include table of contents'; + + @override + String get exportTocDepth => 'TOC depth'; + + @override + String get exportNumberHeadings => 'Number headings'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Custom'; + + @override + String get exportPageWidth => 'Page width (mm)'; + + @override + String get exportPageHeight => 'Page height (mm)'; + + @override + String get exportMarginTop => 'Top margin (mm)'; + + @override + String get exportMarginRight => 'Right margin (mm)'; + + @override + String get exportMarginBottom => 'Bottom margin (mm)'; + + @override + String get exportMarginLeft => 'Left margin (mm)'; + + @override + String get exportTypography => 'Typography'; + + @override + String get exportSans => 'Sans-serif'; + + @override + String get exportSerif => 'Serif'; + + @override + String get exportBodySize => 'Body font size'; + + @override + String get exportCodeSize => 'Code font size'; + + @override + String get exportRunningText => 'Header & Footer'; + + @override + String get exportHeader => 'Header'; + + @override + String get exportFooter => 'Footer'; + + @override + String get exportNone => 'None'; + + @override + String get exportDocumentTitle => 'Document title'; + + @override + String get exportBottomLeft => 'Bottom left'; + + @override + String get exportBottomCenter => 'Bottom center'; + + @override + String get exportBottomRight => 'Bottom right'; + + @override + String get exportFirstPage => 'Show header and footer on first page'; + + @override + String get exportAccent => 'Accent / link color'; + + @override + String get exportTheme => 'Theme'; + + @override + String get exportAutomatic => 'Automatic'; + + @override + String get exportLayout => 'Layout'; + + @override + String get exportContentWidth => 'Maximum content width'; + + @override + String get exportOutput => 'Output'; + + @override + String get exportPackaging => 'Packaging'; + + @override + String get exportSingleFile => 'Single HTML file'; + + @override + String get exportAssetsDirectory => 'HTML + assets directory'; + + @override + String get exportCustomCss => 'Custom stylesheet…'; + + @override + String get exportRemoveCss => 'Remove custom stylesheet'; + + @override + String get exportCssNote => + 'Select an optional UTF-8 CSS file (up to 256 KiB). Imports, resource URLs, and executable or escaped CSS are not accepted. Styles are applied after BusyMark’s stylesheet. Remote resources are never fetched.'; + + @override + String get exportSitePackagingNote => + 'Writerside keeps separate linked topic pages. Single-file mode embeds resources in each page.'; + + @override + String get exportInvalidGeometry => + 'Leave at least 20 mm of content width and height after margins.'; + + @override + String get exportInvalidColor => 'Enter a color as #RRGGBB.'; + + @override + String get exportInvalidCss => + 'Choose a readable UTF-8 .css file up to 256 KiB, without imports, resource URLs, HTML, or executable or escaped CSS.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: enter a number between $minimum and $maximum.'; + } } diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart index 54a063a8..893a8612 100644 --- a/lib/l10n/generated/app_localizations_es.dart +++ b/lib/l10n/generated/app_localizations_es.dart @@ -3784,4 +3784,139 @@ class AppLocalizationsEs extends AppLocalizations { String sortTableColumn(String column) { return 'Ordenar $column'; } + + @override + String get exportReset => 'Restablecer valores predeterminados'; + + @override + String get exportToc => 'Incluir índice'; + + @override + String get exportTocDepth => 'Profundidad del índice'; + + @override + String get exportNumberHeadings => 'Numerar encabezados'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Personalizado'; + + @override + String get exportPageWidth => 'Ancho de página (mm)'; + + @override + String get exportPageHeight => 'Alto de página (mm)'; + + @override + String get exportMarginTop => 'Margen superior (mm)'; + + @override + String get exportMarginRight => 'Margen derecho (mm)'; + + @override + String get exportMarginBottom => 'Margen inferior (mm)'; + + @override + String get exportMarginLeft => 'Margen izquierdo (mm)'; + + @override + String get exportTypography => 'Tipografía'; + + @override + String get exportSans => 'Sin serifas'; + + @override + String get exportSerif => 'Con serifas'; + + @override + String get exportBodySize => 'Tamaño del texto'; + + @override + String get exportCodeSize => 'Tamaño del código'; + + @override + String get exportRunningText => 'Encabezado y pie de página'; + + @override + String get exportHeader => 'Encabezado'; + + @override + String get exportFooter => 'Pie de página'; + + @override + String get exportNone => 'Ninguno'; + + @override + String get exportDocumentTitle => 'Título del documento'; + + @override + String get exportBottomLeft => 'Abajo a la izquierda'; + + @override + String get exportBottomCenter => 'Abajo en el centro'; + + @override + String get exportBottomRight => 'Abajo a la derecha'; + + @override + String get exportFirstPage => 'Mostrar encabezado y pie en la primera página'; + + @override + String get exportAccent => 'Color de acento / enlaces'; + + @override + String get exportTheme => 'Tema'; + + @override + String get exportAutomatic => 'Automático'; + + @override + String get exportLayout => 'Diseño'; + + @override + String get exportContentWidth => 'Ancho máximo del contenido'; + + @override + String get exportOutput => 'Salida'; + + @override + String get exportPackaging => 'Empaquetado'; + + @override + String get exportSingleFile => 'Un solo archivo HTML'; + + @override + String get exportAssetsDirectory => 'HTML + carpeta de recursos'; + + @override + String get exportCustomCss => 'Hoja de estilo personalizada…'; + + @override + String get exportRemoveCss => 'Quitar hoja de estilo'; + + @override + String get exportCssNote => + 'Seleccione un archivo CSS UTF-8 opcional (hasta 256 KiB). Se rechazan importaciones, URL de recursos y CSS ejecutable o escapado. Los estilos se aplican después de los de BusyMark. Nunca se descargan recursos remotos.'; + + @override + String get exportSitePackagingNote => + 'Writerside conserva páginas de temas separadas y enlazadas. El modo de archivo único incorpora los recursos en cada página.'; + + @override + String get exportInvalidGeometry => + 'Deje al menos 20 mm de ancho y alto de contenido después de los márgenes.'; + + @override + String get exportInvalidColor => 'Introduzca un color como #RRGGBB.'; + + @override + String get exportInvalidCss => + 'Elija un archivo .css UTF-8 legible de hasta 256 KiB, sin importaciones, URL de recursos, HTML ni CSS ejecutable o escapado.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: introduzca un número entre $minimum y $maximum.'; + } } diff --git a/lib/l10n/generated/app_localizations_et.dart b/lib/l10n/generated/app_localizations_et.dart index efe012a8..aa984a9c 100644 --- a/lib/l10n/generated/app_localizations_et.dart +++ b/lib/l10n/generated/app_localizations_et.dart @@ -3747,4 +3747,139 @@ class AppLocalizationsEt extends AppLocalizations { String sortTableColumn(String column) { return 'Sordi $column'; } + + @override + String get exportReset => 'Taasta vaikeväärtused'; + + @override + String get exportToc => 'Lisa sisukord'; + + @override + String get exportTocDepth => 'Sisukorra sügavus'; + + @override + String get exportNumberHeadings => 'Nummerda pealkirjad'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Kohandatud'; + + @override + String get exportPageWidth => 'Lehe laius (mm)'; + + @override + String get exportPageHeight => 'Lehe kõrgus (mm)'; + + @override + String get exportMarginTop => 'Ülaveeris (mm)'; + + @override + String get exportMarginRight => 'Paremveeris (mm)'; + + @override + String get exportMarginBottom => 'Alaveeris (mm)'; + + @override + String get exportMarginLeft => 'Vasakveeris (mm)'; + + @override + String get exportTypography => 'Tüpograafia'; + + @override + String get exportSans => 'Seriifideta'; + + @override + String get exportSerif => 'Seriifidega'; + + @override + String get exportBodySize => 'Põhiteksti suurus'; + + @override + String get exportCodeSize => 'Koodi suurus'; + + @override + String get exportRunningText => 'Päis ja jalus'; + + @override + String get exportHeader => 'Päis'; + + @override + String get exportFooter => 'Jalus'; + + @override + String get exportNone => 'Puudub'; + + @override + String get exportDocumentTitle => 'Dokumendi pealkiri'; + + @override + String get exportBottomLeft => 'All vasakul'; + + @override + String get exportBottomCenter => 'All keskel'; + + @override + String get exportBottomRight => 'All paremal'; + + @override + String get exportFirstPage => 'Näita päist ja jalust esimesel lehel'; + + @override + String get exportAccent => 'Rõhu-/lingivärv'; + + @override + String get exportTheme => 'Teema'; + + @override + String get exportAutomatic => 'Automaatne'; + + @override + String get exportLayout => 'Paigutus'; + + @override + String get exportContentWidth => 'Sisu suurim laius'; + + @override + String get exportOutput => 'Väljund'; + + @override + String get exportPackaging => 'Pakendamine'; + + @override + String get exportSingleFile => 'Üks HTML-fail'; + + @override + String get exportAssetsDirectory => 'HTML + ressursikaust'; + + @override + String get exportCustomCss => 'Kohandatud laadileht…'; + + @override + String get exportRemoveCss => 'Eemalda kohandatud laadileht'; + + @override + String get exportCssNote => + 'Vali soovi korral UTF-8 CSS-fail (kuni 256 KiB). Importimine, ressursside URL-id ning käivitatav või paojadadega CSS pole lubatud. Laadid järgnevad BusyMarki laadidele. Võrguressursse ei laadita.'; + + @override + String get exportSitePackagingNote => + 'Writerside säilitab eraldi lingitud teemalehed. Ühe faili režiim manustab ressursid igale lehele.'; + + @override + String get exportInvalidGeometry => + 'Jäta pärast veeriseid sisule vähemalt 20 mm laiust ja kõrgust.'; + + @override + String get exportInvalidColor => 'Sisesta värv kujul #RRGGBB.'; + + @override + String get exportInvalidCss => + 'Vali loetav UTF-8 .css-fail kuni 256 KiB, ilma importide, ressursside URL-ide, HTML-i ning käivitatava või paojadadega CSS-ita.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: sisesta arv vahemikus $minimum kuni $maximum.'; + } } diff --git a/lib/l10n/generated/app_localizations_fa.dart b/lib/l10n/generated/app_localizations_fa.dart index be5b8d4f..42a3fc0e 100644 --- a/lib/l10n/generated/app_localizations_fa.dart +++ b/lib/l10n/generated/app_localizations_fa.dart @@ -3792,4 +3792,139 @@ class AppLocalizationsFa extends AppLocalizations { String sortTableColumn(String column) { return 'مرتب‌سازی $column'; } + + @override + String get exportReset => 'بازنشانی به پیش‌فرض‌ها'; + + @override + String get exportToc => 'افزودن فهرست مطالب'; + + @override + String get exportTocDepth => 'عمق فهرست مطالب'; + + @override + String get exportNumberHeadings => 'شماره‌گذاری عنوان‌ها'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'سفارشی'; + + @override + String get exportPageWidth => 'عرض صفحه (میلی‌متر)'; + + @override + String get exportPageHeight => 'ارتفاع صفحه (میلی‌متر)'; + + @override + String get exportMarginTop => 'حاشیهٔ بالا (میلی‌متر)'; + + @override + String get exportMarginRight => 'حاشیهٔ راست (میلی‌متر)'; + + @override + String get exportMarginBottom => 'حاشیهٔ پایین (میلی‌متر)'; + + @override + String get exportMarginLeft => 'حاشیهٔ چپ (میلی‌متر)'; + + @override + String get exportTypography => 'حروف‌چینی'; + + @override + String get exportSans => 'بدون سریف'; + + @override + String get exportSerif => 'سریف'; + + @override + String get exportBodySize => 'اندازهٔ قلم متن'; + + @override + String get exportCodeSize => 'اندازهٔ قلم کد'; + + @override + String get exportRunningText => 'سرصفحه و پاصفحه'; + + @override + String get exportHeader => 'سرصفحه'; + + @override + String get exportFooter => 'پاصفحه'; + + @override + String get exportNone => 'هیچ‌کدام'; + + @override + String get exportDocumentTitle => 'عنوان سند'; + + @override + String get exportBottomLeft => 'پایین چپ'; + + @override + String get exportBottomCenter => 'پایین وسط'; + + @override + String get exportBottomRight => 'پایین راست'; + + @override + String get exportFirstPage => 'نمایش سرصفحه و پاصفحه در صفحهٔ نخست'; + + @override + String get exportAccent => 'رنگ تأکید / پیوند'; + + @override + String get exportTheme => 'پوسته'; + + @override + String get exportAutomatic => 'خودکار'; + + @override + String get exportLayout => 'چیدمان'; + + @override + String get exportContentWidth => 'بیشترین عرض محتوا'; + + @override + String get exportOutput => 'خروجی'; + + @override + String get exportPackaging => 'بسته‌بندی'; + + @override + String get exportSingleFile => 'یک فایل HTML'; + + @override + String get exportAssetsDirectory => 'HTML + پوشهٔ منابع'; + + @override + String get exportCustomCss => 'شیوه‌نامهٔ سفارشی…'; + + @override + String get exportRemoveCss => 'حذف شیوه‌نامهٔ سفارشی'; + + @override + String get exportCssNote => + 'یک فایل CSS اختیاری با UTF-8 انتخاب کنید (تا ۲۵۶ KiB). واردسازی، نشانی منابع و CSS اجرایی یا دارای نویسهٔ گریز پذیرفته نمی‌شود. سبک‌ها پس از CSS برنامه اعمال می‌شوند. منابع راه دور دریافت نمی‌شوند.'; + + @override + String get exportSitePackagingNote => + 'Writerside صفحه‌های موضوعی جدا و پیوندخورده را نگه می‌دارد. حالت تک‌فایلی منابع را در هر صفحه جاسازی می‌کند.'; + + @override + String get exportInvalidGeometry => + 'پس از حاشیه‌ها دست‌کم ۲۰ میلی‌متر عرض و ارتفاع برای محتوا باقی بگذارید.'; + + @override + String get exportInvalidColor => 'رنگ را به‌صورت #RRGGBB وارد کنید.'; + + @override + String get exportInvalidCss => + 'یک فایل .css خوانا با UTF-8 تا ۲۵۶ KiB انتخاب کنید، بدون واردسازی، نشانی منابع، HTML یا CSS اجرایی یا دارای نویسهٔ گریز.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: عددی بین $minimum و $maximum وارد کنید.'; + } } diff --git a/lib/l10n/generated/app_localizations_fr.dart b/lib/l10n/generated/app_localizations_fr.dart index 05de22f5..7efea910 100644 --- a/lib/l10n/generated/app_localizations_fr.dart +++ b/lib/l10n/generated/app_localizations_fr.dart @@ -3779,4 +3779,140 @@ class AppLocalizationsFr extends AppLocalizations { String sortTableColumn(String column) { return 'Trier $column'; } + + @override + String get exportReset => 'Rétablir les valeurs par défaut'; + + @override + String get exportToc => 'Inclure une table des matières'; + + @override + String get exportTocDepth => 'Profondeur de la table'; + + @override + String get exportNumberHeadings => 'Numéroter les titres'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Personnalisé'; + + @override + String get exportPageWidth => 'Largeur de page (mm)'; + + @override + String get exportPageHeight => 'Hauteur de page (mm)'; + + @override + String get exportMarginTop => 'Marge supérieure (mm)'; + + @override + String get exportMarginRight => 'Marge droite (mm)'; + + @override + String get exportMarginBottom => 'Marge inférieure (mm)'; + + @override + String get exportMarginLeft => 'Marge gauche (mm)'; + + @override + String get exportTypography => 'Typographie'; + + @override + String get exportSans => 'Sans empattement'; + + @override + String get exportSerif => 'Avec empattement'; + + @override + String get exportBodySize => 'Taille du texte'; + + @override + String get exportCodeSize => 'Taille du code'; + + @override + String get exportRunningText => 'En-tête et pied de page'; + + @override + String get exportHeader => 'En-tête'; + + @override + String get exportFooter => 'Pied de page'; + + @override + String get exportNone => 'Aucun'; + + @override + String get exportDocumentTitle => 'Titre du document'; + + @override + String get exportBottomLeft => 'En bas à gauche'; + + @override + String get exportBottomCenter => 'En bas au centre'; + + @override + String get exportBottomRight => 'En bas à droite'; + + @override + String get exportFirstPage => + 'Afficher l’en-tête et le pied sur la première page'; + + @override + String get exportAccent => 'Couleur d’accent / des liens'; + + @override + String get exportTheme => 'Thème'; + + @override + String get exportAutomatic => 'Automatique'; + + @override + String get exportLayout => 'Mise en page'; + + @override + String get exportContentWidth => 'Largeur maximale du contenu'; + + @override + String get exportOutput => 'Sortie'; + + @override + String get exportPackaging => 'Conditionnement'; + + @override + String get exportSingleFile => 'Fichier HTML unique'; + + @override + String get exportAssetsDirectory => 'HTML + dossier de ressources'; + + @override + String get exportCustomCss => 'Feuille de style personnalisée…'; + + @override + String get exportRemoveCss => 'Retirer la feuille de style'; + + @override + String get exportCssNote => + 'Choisissez un fichier CSS UTF-8 facultatif (256 KiB maximum). Les imports, URL de ressources et CSS exécutable ou échappé sont refusés. Les styles suivent ceux de BusyMark. Aucune ressource distante n’est téléchargée.'; + + @override + String get exportSitePackagingNote => + 'Writerside conserve des pages liées distinctes. Le mode fichier unique intègre les ressources dans chaque page.'; + + @override + String get exportInvalidGeometry => + 'Laissez au moins 20 mm de largeur et de hauteur de contenu après les marges.'; + + @override + String get exportInvalidColor => 'Saisissez une couleur au format #RRGGBB.'; + + @override + String get exportInvalidCss => + 'Choisissez un fichier .css UTF-8 lisible de 256 KiB maximum, sans imports, URL de ressources, HTML ni CSS exécutable ou échappé.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field : saisissez un nombre entre $minimum et $maximum.'; + } } diff --git a/lib/l10n/generated/app_localizations_hi.dart b/lib/l10n/generated/app_localizations_hi.dart index a8533ca3..0a33be32 100644 --- a/lib/l10n/generated/app_localizations_hi.dart +++ b/lib/l10n/generated/app_localizations_hi.dart @@ -3737,4 +3737,139 @@ class AppLocalizationsHi extends AppLocalizations { String sortTableColumn(String column) { return '$column क्रमबद्ध करें'; } + + @override + String get exportReset => 'डिफ़ॉल्ट पर रीसेट करें'; + + @override + String get exportToc => 'विषय-सूची शामिल करें'; + + @override + String get exportTocDepth => 'विषय-सूची की गहराई'; + + @override + String get exportNumberHeadings => 'शीर्षकों को क्रमांक दें'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'कस्टम'; + + @override + String get exportPageWidth => 'पृष्ठ की चौड़ाई (mm)'; + + @override + String get exportPageHeight => 'पृष्ठ की ऊँचाई (mm)'; + + @override + String get exportMarginTop => 'ऊपरी मार्जिन (mm)'; + + @override + String get exportMarginRight => 'दायाँ मार्जिन (mm)'; + + @override + String get exportMarginBottom => 'निचला मार्जिन (mm)'; + + @override + String get exportMarginLeft => 'बायाँ मार्जिन (mm)'; + + @override + String get exportTypography => 'टाइपोग्राफ़ी'; + + @override + String get exportSans => 'बिना सेरिफ़'; + + @override + String get exportSerif => 'सेरिफ़'; + + @override + String get exportBodySize => 'मुख्य पाठ का फ़ॉन्ट आकार'; + + @override + String get exportCodeSize => 'कोड का फ़ॉन्ट आकार'; + + @override + String get exportRunningText => 'शीर्षलेख और पादलेख'; + + @override + String get exportHeader => 'शीर्षलेख'; + + @override + String get exportFooter => 'पादलेख'; + + @override + String get exportNone => 'कोई नहीं'; + + @override + String get exportDocumentTitle => 'दस्तावेज़ का शीर्षक'; + + @override + String get exportBottomLeft => 'नीचे बाएँ'; + + @override + String get exportBottomCenter => 'नीचे बीच में'; + + @override + String get exportBottomRight => 'नीचे दाएँ'; + + @override + String get exportFirstPage => 'पहले पृष्ठ पर शीर्षलेख और पादलेख दिखाएँ'; + + @override + String get exportAccent => 'हाइलाइट / लिंक का रंग'; + + @override + String get exportTheme => 'थीम'; + + @override + String get exportAutomatic => 'स्वचालित'; + + @override + String get exportLayout => 'लेआउट'; + + @override + String get exportContentWidth => 'सामग्री की अधिकतम चौड़ाई'; + + @override + String get exportOutput => 'आउटपुट'; + + @override + String get exportPackaging => 'पैकेजिंग'; + + @override + String get exportSingleFile => 'एक HTML फ़ाइल'; + + @override + String get exportAssetsDirectory => 'HTML + संसाधन फ़ोल्डर'; + + @override + String get exportCustomCss => 'कस्टम स्टाइलशीट…'; + + @override + String get exportRemoveCss => 'कस्टम स्टाइलशीट हटाएँ'; + + @override + String get exportCssNote => + 'वैकल्पिक UTF-8 CSS फ़ाइल चुनें (256 KiB तक)। इंपोर्ट, संसाधन URL और निष्पादन योग्य या एस्केप वाला CSS स्वीकार नहीं किया जाता। शैलियाँ BusyMark CSS के बाद लागू होती हैं। दूरस्थ संसाधन डाउनलोड नहीं किए जाते।'; + + @override + String get exportSitePackagingNote => + 'Writerside अलग-अलग लिंक किए गए विषय पृष्ठ रखता है। एकल फ़ाइल मोड हर पृष्ठ में संसाधन एम्बेड करता है।'; + + @override + String get exportInvalidGeometry => + 'मार्जिन के बाद सामग्री के लिए कम से कम 20 mm चौड़ाई और ऊँचाई छोड़ें।'; + + @override + String get exportInvalidColor => 'रंग #RRGGBB के रूप में दर्ज करें।'; + + @override + String get exportInvalidCss => + '256 KiB तक की पढ़ने योग्य UTF-8 .css फ़ाइल चुनें, जिसमें इंपोर्ट, संसाधन URL, HTML और निष्पादन योग्य या एस्केप वाला CSS न हो।'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: $minimum से $maximum के बीच संख्या दर्ज करें।'; + } } diff --git a/lib/l10n/generated/app_localizations_id.dart b/lib/l10n/generated/app_localizations_id.dart index e7c165c9..940cbad3 100644 --- a/lib/l10n/generated/app_localizations_id.dart +++ b/lib/l10n/generated/app_localizations_id.dart @@ -3754,4 +3754,140 @@ class AppLocalizationsId extends AppLocalizations { String sortTableColumn(String column) { return 'Urutkan $column'; } + + @override + String get exportReset => 'Pulihkan nilai bawaan'; + + @override + String get exportToc => 'Sertakan daftar isi'; + + @override + String get exportTocDepth => 'Kedalaman daftar isi'; + + @override + String get exportNumberHeadings => 'Nomori judul'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Khusus'; + + @override + String get exportPageWidth => 'Lebar halaman (mm)'; + + @override + String get exportPageHeight => 'Tinggi halaman (mm)'; + + @override + String get exportMarginTop => 'Margin atas (mm)'; + + @override + String get exportMarginRight => 'Margin kanan (mm)'; + + @override + String get exportMarginBottom => 'Margin bawah (mm)'; + + @override + String get exportMarginLeft => 'Margin kiri (mm)'; + + @override + String get exportTypography => 'Tipografi'; + + @override + String get exportSans => 'Tanpa serif'; + + @override + String get exportSerif => 'Berserif'; + + @override + String get exportBodySize => 'Ukuran huruf isi'; + + @override + String get exportCodeSize => 'Ukuran huruf kode'; + + @override + String get exportRunningText => 'Kepala dan kaki halaman'; + + @override + String get exportHeader => 'Kepala halaman'; + + @override + String get exportFooter => 'Kaki halaman'; + + @override + String get exportNone => 'Tidak ada'; + + @override + String get exportDocumentTitle => 'Judul dokumen'; + + @override + String get exportBottomLeft => 'Kiri bawah'; + + @override + String get exportBottomCenter => 'Tengah bawah'; + + @override + String get exportBottomRight => 'Kanan bawah'; + + @override + String get exportFirstPage => + 'Tampilkan kepala dan kaki pada halaman pertama'; + + @override + String get exportAccent => 'Warna aksen / tautan'; + + @override + String get exportTheme => 'Tema'; + + @override + String get exportAutomatic => 'Otomatis'; + + @override + String get exportLayout => 'Tata letak'; + + @override + String get exportContentWidth => 'Lebar isi maksimum'; + + @override + String get exportOutput => 'Keluaran'; + + @override + String get exportPackaging => 'Pengemasan'; + + @override + String get exportSingleFile => 'Satu berkas HTML'; + + @override + String get exportAssetsDirectory => 'HTML + folder aset'; + + @override + String get exportCustomCss => 'Lembar gaya khusus…'; + + @override + String get exportRemoveCss => 'Hapus lembar gaya khusus'; + + @override + String get exportCssNote => + 'Pilih berkas CSS UTF-8 opsional (hingga 256 KiB). Impor, URL sumber daya, serta CSS yang dapat dieksekusi atau memakai escape ditolak. Gaya diterapkan setelah CSS BusyMark. Sumber daya jarak jauh tidak diunduh.'; + + @override + String get exportSitePackagingNote => + 'Writerside mempertahankan halaman topik terpisah yang saling tertaut. Mode berkas tunggal menyematkan sumber daya di setiap halaman.'; + + @override + String get exportInvalidGeometry => + 'Sisakan lebar dan tinggi isi minimal 20 mm setelah margin.'; + + @override + String get exportInvalidColor => 'Masukkan warna sebagai #RRGGBB.'; + + @override + String get exportInvalidCss => + 'Pilih berkas .css UTF-8 yang dapat dibaca hingga 256 KiB, tanpa impor, URL sumber daya, HTML, atau CSS yang dapat dieksekusi atau memakai escape.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: masukkan angka antara $minimum dan $maximum.'; + } } diff --git a/lib/l10n/generated/app_localizations_it.dart b/lib/l10n/generated/app_localizations_it.dart index 5a407c49..61db60dc 100644 --- a/lib/l10n/generated/app_localizations_it.dart +++ b/lib/l10n/generated/app_localizations_it.dart @@ -3776,4 +3776,140 @@ class AppLocalizationsIt extends AppLocalizations { String sortTableColumn(String column) { return 'Ordina $column'; } + + @override + String get exportReset => 'Ripristina i valori predefiniti'; + + @override + String get exportToc => 'Includi indice'; + + @override + String get exportTocDepth => 'Profondità dell’indice'; + + @override + String get exportNumberHeadings => 'Numera i titoli'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Personalizzato'; + + @override + String get exportPageWidth => 'Larghezza pagina (mm)'; + + @override + String get exportPageHeight => 'Altezza pagina (mm)'; + + @override + String get exportMarginTop => 'Margine superiore (mm)'; + + @override + String get exportMarginRight => 'Margine destro (mm)'; + + @override + String get exportMarginBottom => 'Margine inferiore (mm)'; + + @override + String get exportMarginLeft => 'Margine sinistro (mm)'; + + @override + String get exportTypography => 'Tipografia'; + + @override + String get exportSans => 'Senza grazie'; + + @override + String get exportSerif => 'Con grazie'; + + @override + String get exportBodySize => 'Dimensione del testo'; + + @override + String get exportCodeSize => 'Dimensione del codice'; + + @override + String get exportRunningText => 'Intestazione e piè di pagina'; + + @override + String get exportHeader => 'Intestazione'; + + @override + String get exportFooter => 'Piè di pagina'; + + @override + String get exportNone => 'Nessuno'; + + @override + String get exportDocumentTitle => 'Titolo del documento'; + + @override + String get exportBottomLeft => 'In basso a sinistra'; + + @override + String get exportBottomCenter => 'In basso al centro'; + + @override + String get exportBottomRight => 'In basso a destra'; + + @override + String get exportFirstPage => + 'Mostra intestazione e piè di pagina sulla prima pagina'; + + @override + String get exportAccent => 'Colore accento / collegamenti'; + + @override + String get exportTheme => 'Tema'; + + @override + String get exportAutomatic => 'Automatico'; + + @override + String get exportLayout => 'Impaginazione'; + + @override + String get exportContentWidth => 'Larghezza massima del contenuto'; + + @override + String get exportOutput => 'Uscita'; + + @override + String get exportPackaging => 'Pacchetto'; + + @override + String get exportSingleFile => 'Un solo file HTML'; + + @override + String get exportAssetsDirectory => 'HTML + cartella risorse'; + + @override + String get exportCustomCss => 'Foglio di stile personalizzato…'; + + @override + String get exportRemoveCss => 'Rimuovi il foglio di stile'; + + @override + String get exportCssNote => + 'Scegli un file CSS UTF-8 facoltativo (fino a 256 KiB). Importazioni, URL di risorse e CSS eseguibile o con escape non sono ammessi. Gli stili seguono quelli di BusyMark. Le risorse remote non vengono scaricate.'; + + @override + String get exportSitePackagingNote => + 'Writerside mantiene pagine separate e collegate. La modalità file singolo incorpora le risorse in ogni pagina.'; + + @override + String get exportInvalidGeometry => + 'Lascia almeno 20 mm di larghezza e altezza del contenuto dopo i margini.'; + + @override + String get exportInvalidColor => 'Inserisci un colore come #RRGGBB.'; + + @override + String get exportInvalidCss => + 'Scegli un file .css UTF-8 leggibile fino a 256 KiB, senza importazioni, URL di risorse, HTML o CSS eseguibile o con escape.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: inserisci un numero tra $minimum e $maximum.'; + } } diff --git a/lib/l10n/generated/app_localizations_ja.dart b/lib/l10n/generated/app_localizations_ja.dart index a9434cab..66bbc5b0 100644 --- a/lib/l10n/generated/app_localizations_ja.dart +++ b/lib/l10n/generated/app_localizations_ja.dart @@ -3647,4 +3647,138 @@ class AppLocalizationsJa extends AppLocalizations { String sortTableColumn(String column) { return '$column を並べ替え'; } + + @override + String get exportReset => '既定値に戻す'; + + @override + String get exportToc => '目次を含める'; + + @override + String get exportTocDepth => '目次の深さ'; + + @override + String get exportNumberHeadings => '見出しに番号を付ける'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'カスタム'; + + @override + String get exportPageWidth => 'ページ幅 (mm)'; + + @override + String get exportPageHeight => 'ページ高さ (mm)'; + + @override + String get exportMarginTop => '上余白 (mm)'; + + @override + String get exportMarginRight => '右余白 (mm)'; + + @override + String get exportMarginBottom => '下余白 (mm)'; + + @override + String get exportMarginLeft => '左余白 (mm)'; + + @override + String get exportTypography => '書体'; + + @override + String get exportSans => 'サンセリフ'; + + @override + String get exportSerif => 'セリフ'; + + @override + String get exportBodySize => '本文の文字サイズ'; + + @override + String get exportCodeSize => 'コードの文字サイズ'; + + @override + String get exportRunningText => 'ヘッダーとフッター'; + + @override + String get exportHeader => 'ヘッダー'; + + @override + String get exportFooter => 'フッター'; + + @override + String get exportNone => 'なし'; + + @override + String get exportDocumentTitle => '文書タイトル'; + + @override + String get exportBottomLeft => '左下'; + + @override + String get exportBottomCenter => '中央下'; + + @override + String get exportBottomRight => '右下'; + + @override + String get exportFirstPage => '最初のページにもヘッダーとフッターを表示'; + + @override + String get exportAccent => 'アクセント/リンクの色'; + + @override + String get exportTheme => 'テーマ'; + + @override + String get exportAutomatic => '自動'; + + @override + String get exportLayout => 'レイアウト'; + + @override + String get exportContentWidth => 'コンテンツの最大幅'; + + @override + String get exportOutput => '出力'; + + @override + String get exportPackaging => 'パッケージ形式'; + + @override + String get exportSingleFile => '単一の HTML ファイル'; + + @override + String get exportAssetsDirectory => 'HTML + アセットフォルダー'; + + @override + String get exportCustomCss => 'カスタムスタイルシート…'; + + @override + String get exportRemoveCss => 'カスタムスタイルシートを削除'; + + @override + String get exportCssNote => + '任意の UTF-8 CSS ファイルを選択できます(最大 256 KiB)。インポート、リソース URL、実行可能な CSS、エスケープを含む CSS は拒否されます。BusyMark のスタイルの後に適用されます。外部リソースは取得しません。'; + + @override + String get exportSitePackagingNote => + 'Writerside はリンクされた個別のトピックページを保持します。単一ファイルモードでは各ページにリソースを埋め込みます。'; + + @override + String get exportInvalidGeometry => '余白を除いたコンテンツの幅と高さをそれぞれ 20 mm 以上にしてください。'; + + @override + String get exportInvalidColor => '色を #RRGGBB 形式で入力してください。'; + + @override + String get exportInvalidCss => + '読み取り可能な UTF-8 .css ファイル(最大 256 KiB)を選択してください。インポート、リソース URL、HTML、実行可能な CSS、エスケープを含む CSS は使用できません。'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: $minimum から $maximum の数値を入力してください。'; + } } diff --git a/lib/l10n/generated/app_localizations_ko.dart b/lib/l10n/generated/app_localizations_ko.dart index 2aa89230..cc9c81b4 100644 --- a/lib/l10n/generated/app_localizations_ko.dart +++ b/lib/l10n/generated/app_localizations_ko.dart @@ -3643,4 +3643,138 @@ class AppLocalizationsKo extends AppLocalizations { String sortTableColumn(String column) { return '$column 정렬'; } + + @override + String get exportReset => '기본값으로 재설정'; + + @override + String get exportToc => '목차 포함'; + + @override + String get exportTocDepth => '목차 깊이'; + + @override + String get exportNumberHeadings => '제목 번호 매기기'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => '사용자 지정'; + + @override + String get exportPageWidth => '페이지 너비 (mm)'; + + @override + String get exportPageHeight => '페이지 높이 (mm)'; + + @override + String get exportMarginTop => '위쪽 여백 (mm)'; + + @override + String get exportMarginRight => '오른쪽 여백 (mm)'; + + @override + String get exportMarginBottom => '아래쪽 여백 (mm)'; + + @override + String get exportMarginLeft => '왼쪽 여백 (mm)'; + + @override + String get exportTypography => '글꼴'; + + @override + String get exportSans => '고딕체'; + + @override + String get exportSerif => '명조체'; + + @override + String get exportBodySize => '본문 글꼴 크기'; + + @override + String get exportCodeSize => '코드 글꼴 크기'; + + @override + String get exportRunningText => '머리글 및 바닥글'; + + @override + String get exportHeader => '머리글'; + + @override + String get exportFooter => '바닥글'; + + @override + String get exportNone => '없음'; + + @override + String get exportDocumentTitle => '문서 제목'; + + @override + String get exportBottomLeft => '왼쪽 아래'; + + @override + String get exportBottomCenter => '가운데 아래'; + + @override + String get exportBottomRight => '오른쪽 아래'; + + @override + String get exportFirstPage => '첫 페이지에 머리글과 바닥글 표시'; + + @override + String get exportAccent => '강조 / 링크 색상'; + + @override + String get exportTheme => '테마'; + + @override + String get exportAutomatic => '자동'; + + @override + String get exportLayout => '레이아웃'; + + @override + String get exportContentWidth => '최대 콘텐츠 너비'; + + @override + String get exportOutput => '출력'; + + @override + String get exportPackaging => '패키징'; + + @override + String get exportSingleFile => '단일 HTML 파일'; + + @override + String get exportAssetsDirectory => 'HTML + 리소스 폴더'; + + @override + String get exportCustomCss => '사용자 지정 스타일시트…'; + + @override + String get exportRemoveCss => '사용자 지정 스타일시트 제거'; + + @override + String get exportCssNote => + '선택적으로 UTF-8 CSS 파일을 지정하세요(최대 256 KiB). 가져오기, 리소스 URL, 실행 가능하거나 이스케이프된 CSS는 허용되지 않습니다. BusyMark 스타일 뒤에 적용됩니다. 원격 리소스를 가져오지 않습니다.'; + + @override + String get exportSitePackagingNote => + 'Writerside는 별도로 연결된 주제 페이지를 유지합니다. 단일 파일 모드는 각 페이지에 리소스를 포함합니다.'; + + @override + String get exportInvalidGeometry => '여백을 제외한 콘텐츠 너비와 높이를 각각 20 mm 이상 확보하세요.'; + + @override + String get exportInvalidColor => '#RRGGBB 형식으로 색상을 입력하세요.'; + + @override + String get exportInvalidCss => + '가져오기, 리소스 URL, HTML, 실행 가능하거나 이스케이프된 CSS가 없는 읽기 가능한 UTF-8 .css 파일(최대 256 KiB)을 선택하세요.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: $minimum에서 $maximum 사이의 숫자를 입력하세요.'; + } } diff --git a/lib/l10n/generated/app_localizations_nb.dart b/lib/l10n/generated/app_localizations_nb.dart index d78ec57f..f43512b1 100644 --- a/lib/l10n/generated/app_localizations_nb.dart +++ b/lib/l10n/generated/app_localizations_nb.dart @@ -3747,4 +3747,139 @@ class AppLocalizationsNb extends AppLocalizations { String sortTableColumn(String column) { return 'Sorter $column'; } + + @override + String get exportReset => 'Tilbakestill til standard'; + + @override + String get exportToc => 'Ta med innholdsfortegnelse'; + + @override + String get exportTocDepth => 'Dybde på innholdsfortegnelse'; + + @override + String get exportNumberHeadings => 'Nummerer overskrifter'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Egendefinert'; + + @override + String get exportPageWidth => 'Sidebredde (mm)'; + + @override + String get exportPageHeight => 'Sidehøyde (mm)'; + + @override + String get exportMarginTop => 'Toppmarg (mm)'; + + @override + String get exportMarginRight => 'Høyremarg (mm)'; + + @override + String get exportMarginBottom => 'Bunnmarg (mm)'; + + @override + String get exportMarginLeft => 'Venstremarg (mm)'; + + @override + String get exportTypography => 'Typografi'; + + @override + String get exportSans => 'Uten seriffer'; + + @override + String get exportSerif => 'Med seriffer'; + + @override + String get exportBodySize => 'Tekststørrelse'; + + @override + String get exportCodeSize => 'Kodestørrelse'; + + @override + String get exportRunningText => 'Topp- og bunntekst'; + + @override + String get exportHeader => 'Topptekst'; + + @override + String get exportFooter => 'Bunntekst'; + + @override + String get exportNone => 'Ingen'; + + @override + String get exportDocumentTitle => 'Dokumenttittel'; + + @override + String get exportBottomLeft => 'Nederst til venstre'; + + @override + String get exportBottomCenter => 'Nederst i midten'; + + @override + String get exportBottomRight => 'Nederst til høyre'; + + @override + String get exportFirstPage => 'Vis topp- og bunntekst på første side'; + + @override + String get exportAccent => 'Aksent-/lenkefarge'; + + @override + String get exportTheme => 'Tema'; + + @override + String get exportAutomatic => 'Automatisk'; + + @override + String get exportLayout => 'Oppsett'; + + @override + String get exportContentWidth => 'Maksimal innholdsbredde'; + + @override + String get exportOutput => 'Utdata'; + + @override + String get exportPackaging => 'Pakking'; + + @override + String get exportSingleFile => 'Én HTML-fil'; + + @override + String get exportAssetsDirectory => 'HTML + ressursmappe'; + + @override + String get exportCustomCss => 'Egendefinert stilark…'; + + @override + String get exportRemoveCss => 'Fjern egendefinert stilark'; + + @override + String get exportCssNote => + 'Velg en valgfri UTF-8-CSS-fil (opptil 256 KiB). Importer, ressurs-URL-er og kjørbar eller escaped CSS avvises. Stilene følger BusyMarks stilark. Eksterne ressurser hentes aldri.'; + + @override + String get exportSitePackagingNote => + 'Writerside beholder separate, lenkede emnesider. Enkeltfilmodus bygger ressursene inn i hver side.'; + + @override + String get exportInvalidGeometry => + 'La minst 20 mm innholdsbredde og -høyde stå igjen etter margene.'; + + @override + String get exportInvalidColor => 'Skriv inn en farge som #RRGGBB.'; + + @override + String get exportInvalidCss => + 'Velg en lesbar UTF-8 .css-fil opptil 256 KiB uten importer, ressurs-URL-er, HTML eller kjørbar eller escaped CSS.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: skriv inn et tall mellom $minimum og $maximum.'; + } } diff --git a/lib/l10n/generated/app_localizations_nl.dart b/lib/l10n/generated/app_localizations_nl.dart index cdda3937..c7de92e6 100644 --- a/lib/l10n/generated/app_localizations_nl.dart +++ b/lib/l10n/generated/app_localizations_nl.dart @@ -3790,4 +3790,139 @@ class AppLocalizationsNl extends AppLocalizations { String sortTableColumn(String column) { return '$column sorteren'; } + + @override + String get exportReset => 'Standaardwaarden herstellen'; + + @override + String get exportToc => 'Inhoudsopgave opnemen'; + + @override + String get exportTocDepth => 'Diepte inhoudsopgave'; + + @override + String get exportNumberHeadings => 'Koppen nummeren'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Aangepast'; + + @override + String get exportPageWidth => 'Paginabreedte (mm)'; + + @override + String get exportPageHeight => 'Paginahoogte (mm)'; + + @override + String get exportMarginTop => 'Bovenmarge (mm)'; + + @override + String get exportMarginRight => 'Rechtermarge (mm)'; + + @override + String get exportMarginBottom => 'Ondermarge (mm)'; + + @override + String get exportMarginLeft => 'Linkermarge (mm)'; + + @override + String get exportTypography => 'Typografie'; + + @override + String get exportSans => 'Schreefloos'; + + @override + String get exportSerif => 'Met schreef'; + + @override + String get exportBodySize => 'Tekstgrootte'; + + @override + String get exportCodeSize => 'Codegrootte'; + + @override + String get exportRunningText => 'Kop- en voettekst'; + + @override + String get exportHeader => 'Koptekst'; + + @override + String get exportFooter => 'Voettekst'; + + @override + String get exportNone => 'Geen'; + + @override + String get exportDocumentTitle => 'Documenttitel'; + + @override + String get exportBottomLeft => 'Linksonder'; + + @override + String get exportBottomCenter => 'Middenonder'; + + @override + String get exportBottomRight => 'Rechtsonder'; + + @override + String get exportFirstPage => 'Kop- en voettekst op de eerste pagina tonen'; + + @override + String get exportAccent => 'Accent-/linkkleur'; + + @override + String get exportTheme => 'Thema'; + + @override + String get exportAutomatic => 'Automatisch'; + + @override + String get exportLayout => 'Indeling'; + + @override + String get exportContentWidth => 'Maximale inhoudsbreedte'; + + @override + String get exportOutput => 'Uitvoer'; + + @override + String get exportPackaging => 'Verpakking'; + + @override + String get exportSingleFile => 'Eén HTML-bestand'; + + @override + String get exportAssetsDirectory => 'HTML + middelenmap'; + + @override + String get exportCustomCss => 'Aangepast stijlblad…'; + + @override + String get exportRemoveCss => 'Aangepast stijlblad verwijderen'; + + @override + String get exportCssNote => + 'Kies een optioneel UTF-8-CSS-bestand (maximaal 256 KiB). Imports, bron-URL’s en uitvoerbare of ontsnapte CSS worden geweigerd. De stijlen volgen die van BusyMark. Externe bronnen worden nooit opgehaald.'; + + @override + String get exportSitePackagingNote => + 'Writerside behoudt aparte gekoppelde onderwerppagina’s. De enkelbestandsmodus sluit bronnen in elke pagina in.'; + + @override + String get exportInvalidGeometry => + 'Laat na de marges minimaal 20 mm inhoudsbreedte en -hoogte over.'; + + @override + String get exportInvalidColor => 'Voer een kleur in als #RRGGBB.'; + + @override + String get exportInvalidCss => + 'Kies een leesbaar UTF-8 .css-bestand tot 256 KiB zonder imports, bron-URL’s, HTML of uitvoerbare of ontsnapte CSS.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: voer een getal tussen $minimum en $maximum in.'; + } } diff --git a/lib/l10n/generated/app_localizations_pl.dart b/lib/l10n/generated/app_localizations_pl.dart index 1ce07490..0786619b 100644 --- a/lib/l10n/generated/app_localizations_pl.dart +++ b/lib/l10n/generated/app_localizations_pl.dart @@ -3799,4 +3799,139 @@ class AppLocalizationsPl extends AppLocalizations { String sortTableColumn(String column) { return 'Sortuj $column'; } + + @override + String get exportReset => 'Przywróć domyślne'; + + @override + String get exportToc => 'Dołącz spis treści'; + + @override + String get exportTocDepth => 'Głębokość spisu treści'; + + @override + String get exportNumberHeadings => 'Numeruj nagłówki'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Niestandardowy'; + + @override + String get exportPageWidth => 'Szerokość strony (mm)'; + + @override + String get exportPageHeight => 'Wysokość strony (mm)'; + + @override + String get exportMarginTop => 'Margines górny (mm)'; + + @override + String get exportMarginRight => 'Margines prawy (mm)'; + + @override + String get exportMarginBottom => 'Margines dolny (mm)'; + + @override + String get exportMarginLeft => 'Margines lewy (mm)'; + + @override + String get exportTypography => 'Typografia'; + + @override + String get exportSans => 'Bezszeryfowa'; + + @override + String get exportSerif => 'Szeryfowa'; + + @override + String get exportBodySize => 'Rozmiar tekstu'; + + @override + String get exportCodeSize => 'Rozmiar kodu'; + + @override + String get exportRunningText => 'Nagłówek i stopka'; + + @override + String get exportHeader => 'Nagłówek'; + + @override + String get exportFooter => 'Stopka'; + + @override + String get exportNone => 'Brak'; + + @override + String get exportDocumentTitle => 'Tytuł dokumentu'; + + @override + String get exportBottomLeft => 'Na dole po lewej'; + + @override + String get exportBottomCenter => 'Na dole na środku'; + + @override + String get exportBottomRight => 'Na dole po prawej'; + + @override + String get exportFirstPage => 'Pokaż nagłówek i stopkę na pierwszej stronie'; + + @override + String get exportAccent => 'Kolor akcentu / łączy'; + + @override + String get exportTheme => 'Motyw'; + + @override + String get exportAutomatic => 'Automatyczny'; + + @override + String get exportLayout => 'Układ'; + + @override + String get exportContentWidth => 'Maksymalna szerokość treści'; + + @override + String get exportOutput => 'Wyjście'; + + @override + String get exportPackaging => 'Pakowanie'; + + @override + String get exportSingleFile => 'Jeden plik HTML'; + + @override + String get exportAssetsDirectory => 'HTML + katalog zasobów'; + + @override + String get exportCustomCss => 'Własny arkusz stylów…'; + + @override + String get exportRemoveCss => 'Usuń własny arkusz stylów'; + + @override + String get exportCssNote => + 'Wybierz opcjonalny plik CSS UTF-8 (do 256 KiB). Importy, adresy zasobów oraz wykonywalny CSS lub sekwencje ucieczki są odrzucane. Style następują po arkuszu BusyMark. Zdalne zasoby nie są pobierane.'; + + @override + String get exportSitePackagingNote => + 'Writerside zachowuje osobne połączone strony tematów. Tryb jednego pliku osadza zasoby w każdej stronie.'; + + @override + String get exportInvalidGeometry => + 'Po odjęciu marginesów pozostaw co najmniej 20 mm szerokości i wysokości treści.'; + + @override + String get exportInvalidColor => 'Wpisz kolor w formacie #RRGGBB.'; + + @override + String get exportInvalidCss => + 'Wybierz czytelny plik .css UTF-8 do 256 KiB, bez importów, adresów zasobów, HTML oraz wykonywalnego CSS i sekwencji ucieczki.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: wpisz liczbę między $minimum a $maximum.'; + } } diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart index 0ef6bd99..1dd11b08 100644 --- a/lib/l10n/generated/app_localizations_pt.dart +++ b/lib/l10n/generated/app_localizations_pt.dart @@ -3778,6 +3778,141 @@ class AppLocalizationsPt extends AppLocalizations { String sortTableColumn(String column) { return 'Ordenar $column'; } + + @override + String get exportReset => 'Restaurar predefinições'; + + @override + String get exportToc => 'Incluir índice'; + + @override + String get exportTocDepth => 'Profundidade do índice'; + + @override + String get exportNumberHeadings => 'Numerar títulos'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Personalizado'; + + @override + String get exportPageWidth => 'Largura da página (mm)'; + + @override + String get exportPageHeight => 'Altura da página (mm)'; + + @override + String get exportMarginTop => 'Margem superior (mm)'; + + @override + String get exportMarginRight => 'Margem direita (mm)'; + + @override + String get exportMarginBottom => 'Margem inferior (mm)'; + + @override + String get exportMarginLeft => 'Margem esquerda (mm)'; + + @override + String get exportTypography => 'Tipografia'; + + @override + String get exportSans => 'Sem serifas'; + + @override + String get exportSerif => 'Com serifas'; + + @override + String get exportBodySize => 'Tamanho do texto'; + + @override + String get exportCodeSize => 'Tamanho do código'; + + @override + String get exportRunningText => 'Cabeçalho e rodapé'; + + @override + String get exportHeader => 'Cabeçalho'; + + @override + String get exportFooter => 'Rodapé'; + + @override + String get exportNone => 'Nenhum'; + + @override + String get exportDocumentTitle => 'Título do documento'; + + @override + String get exportBottomLeft => 'Em baixo à esquerda'; + + @override + String get exportBottomCenter => 'Em baixo ao centro'; + + @override + String get exportBottomRight => 'Em baixo à direita'; + + @override + String get exportFirstPage => 'Mostrar cabeçalho e rodapé na primeira página'; + + @override + String get exportAccent => 'Cor de destaque / ligações'; + + @override + String get exportTheme => 'Tema'; + + @override + String get exportAutomatic => 'Automático'; + + @override + String get exportLayout => 'Disposição'; + + @override + String get exportContentWidth => 'Largura máxima do conteúdo'; + + @override + String get exportOutput => 'Saída'; + + @override + String get exportPackaging => 'Empacotamento'; + + @override + String get exportSingleFile => 'Um único ficheiro HTML'; + + @override + String get exportAssetsDirectory => 'HTML + pasta de recursos'; + + @override + String get exportCustomCss => 'Folha de estilo personalizada…'; + + @override + String get exportRemoveCss => 'Remover folha de estilo'; + + @override + String get exportCssNote => + 'Escolha um ficheiro CSS UTF-8 opcional (até 256 KiB). Importações, URL de recursos e CSS executável ou com escapes são rejeitados. Os estilos seguem os do BusyMark. Nunca são transferidos recursos remotos.'; + + @override + String get exportSitePackagingNote => + 'O Writerside mantém páginas de tópicos separadas e ligadas. O modo de ficheiro único incorpora os recursos em cada página.'; + + @override + String get exportInvalidGeometry => + 'Deixe pelo menos 20 mm de largura e altura de conteúdo após as margens.'; + + @override + String get exportInvalidColor => 'Introduza uma cor como #RRGGBB.'; + + @override + String get exportInvalidCss => + 'Escolha um ficheiro .css UTF-8 legível até 256 KiB, sem importações, URL de recursos, HTML ou CSS executável ou com escapes.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: introduza um número entre $minimum e $maximum.'; + } } /// The translations for Portuguese, as used in Brazil (`pt_BR`). @@ -7555,4 +7690,139 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { String sortTableColumn(String column) { return 'Ordenar $column'; } + + @override + String get exportReset => 'Restaurar padrões'; + + @override + String get exportToc => 'Incluir índice'; + + @override + String get exportTocDepth => 'Profundidade do índice'; + + @override + String get exportNumberHeadings => 'Numerar títulos'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Personalizado'; + + @override + String get exportPageWidth => 'Largura da página (mm)'; + + @override + String get exportPageHeight => 'Altura da página (mm)'; + + @override + String get exportMarginTop => 'Margem superior (mm)'; + + @override + String get exportMarginRight => 'Margem direita (mm)'; + + @override + String get exportMarginBottom => 'Margem inferior (mm)'; + + @override + String get exportMarginLeft => 'Margem esquerda (mm)'; + + @override + String get exportTypography => 'Tipografia'; + + @override + String get exportSans => 'Sem serifas'; + + @override + String get exportSerif => 'Com serifas'; + + @override + String get exportBodySize => 'Tamanho do texto'; + + @override + String get exportCodeSize => 'Tamanho do código'; + + @override + String get exportRunningText => 'Cabeçalho e rodapé'; + + @override + String get exportHeader => 'Cabeçalho'; + + @override + String get exportFooter => 'Rodapé'; + + @override + String get exportNone => 'Nenhum'; + + @override + String get exportDocumentTitle => 'Título do documento'; + + @override + String get exportBottomLeft => 'Embaixo à esquerda'; + + @override + String get exportBottomCenter => 'Embaixo ao centro'; + + @override + String get exportBottomRight => 'Embaixo à direita'; + + @override + String get exportFirstPage => 'Mostrar cabeçalho e rodapé na primeira página'; + + @override + String get exportAccent => 'Cor de destaque / links'; + + @override + String get exportTheme => 'Tema'; + + @override + String get exportAutomatic => 'Automático'; + + @override + String get exportLayout => 'Layout'; + + @override + String get exportContentWidth => 'Largura máxima do conteúdo'; + + @override + String get exportOutput => 'Saída'; + + @override + String get exportPackaging => 'Empacotamento'; + + @override + String get exportSingleFile => 'Um único arquivo HTML'; + + @override + String get exportAssetsDirectory => 'HTML + pasta de recursos'; + + @override + String get exportCustomCss => 'Folha de estilo personalizada…'; + + @override + String get exportRemoveCss => 'Remover folha de estilo'; + + @override + String get exportCssNote => + 'Escolha um arquivo CSS UTF-8 opcional (até 256 KiB). Importações, URL de recursos e CSS executável ou com escapes são rejeitados. Os estilos seguem os do BusyMark. Nunca são baixados recursos remotos.'; + + @override + String get exportSitePackagingNote => + 'O Writerside mantém páginas de tópicos separadas e vinculadas. O modo de arquivo único incorpora os recursos em cada página.'; + + @override + String get exportInvalidGeometry => + 'Deixe pelo menos 20 mm de largura e altura de conteúdo após as margens.'; + + @override + String get exportInvalidColor => 'Insira uma cor como #RRGGBB.'; + + @override + String get exportInvalidCss => + 'Escolha um arquivo .css UTF-8 legível até 256 KiB, sem importações, URL de recursos, HTML ou CSS executável ou com escapes.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: insira um número entre $minimum e $maximum.'; + } } diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart index d243ee2e..27b7c36c 100644 --- a/lib/l10n/generated/app_localizations_ru.dart +++ b/lib/l10n/generated/app_localizations_ru.dart @@ -3798,4 +3798,139 @@ class AppLocalizationsRu extends AppLocalizations { String sortTableColumn(String column) { return 'Сортировать $column'; } + + @override + String get exportReset => 'Восстановить значения по умолчанию'; + + @override + String get exportToc => 'Добавить оглавление'; + + @override + String get exportTocDepth => 'Глубина оглавления'; + + @override + String get exportNumberHeadings => 'Нумеровать заголовки'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Другой'; + + @override + String get exportPageWidth => 'Ширина страницы (мм)'; + + @override + String get exportPageHeight => 'Высота страницы (мм)'; + + @override + String get exportMarginTop => 'Верхнее поле (мм)'; + + @override + String get exportMarginRight => 'Правое поле (мм)'; + + @override + String get exportMarginBottom => 'Нижнее поле (мм)'; + + @override + String get exportMarginLeft => 'Левое поле (мм)'; + + @override + String get exportTypography => 'Типографика'; + + @override + String get exportSans => 'Без засечек'; + + @override + String get exportSerif => 'С засечками'; + + @override + String get exportBodySize => 'Размер основного шрифта'; + + @override + String get exportCodeSize => 'Размер шрифта кода'; + + @override + String get exportRunningText => 'Колонтитулы'; + + @override + String get exportHeader => 'Верхний колонтитул'; + + @override + String get exportFooter => 'Нижний колонтитул'; + + @override + String get exportNone => 'Нет'; + + @override + String get exportDocumentTitle => 'Название документа'; + + @override + String get exportBottomLeft => 'Снизу слева'; + + @override + String get exportBottomCenter => 'Снизу по центру'; + + @override + String get exportBottomRight => 'Снизу справа'; + + @override + String get exportFirstPage => 'Показывать колонтитулы на первой странице'; + + @override + String get exportAccent => 'Цвет акцента / ссылок'; + + @override + String get exportTheme => 'Тема'; + + @override + String get exportAutomatic => 'Автоматически'; + + @override + String get exportLayout => 'Макет'; + + @override + String get exportContentWidth => 'Максимальная ширина содержимого'; + + @override + String get exportOutput => 'Вывод'; + + @override + String get exportPackaging => 'Упаковка'; + + @override + String get exportSingleFile => 'Один файл HTML'; + + @override + String get exportAssetsDirectory => 'HTML + папка ресурсов'; + + @override + String get exportCustomCss => 'Свой файл стилей…'; + + @override + String get exportRemoveCss => 'Удалить свой файл стилей'; + + @override + String get exportCssNote => + 'Выберите необязательный файл CSS в UTF-8 (до 256 КиБ). Импорты, URL ресурсов, исполняемый CSS и escape-последовательности запрещены. Стили применяются после стилей BusyMark. Удалённые ресурсы не загружаются.'; + + @override + String get exportSitePackagingNote => + 'Writerside сохраняет отдельные связанные страницы тем. Режим одного файла встраивает ресурсы в каждую страницу.'; + + @override + String get exportInvalidGeometry => + 'После вычета полей оставьте не менее 20 мм ширины и высоты содержимого.'; + + @override + String get exportInvalidColor => 'Введите цвет в формате #RRGGBB.'; + + @override + String get exportInvalidCss => + 'Выберите читаемый файл .css в UTF-8 до 256 КиБ без импортов, URL ресурсов, HTML, исполняемого CSS и escape-последовательностей.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: введите число от $minimum до $maximum.'; + } } diff --git a/lib/l10n/generated/app_localizations_tr.dart b/lib/l10n/generated/app_localizations_tr.dart index dbebc93b..ec033e49 100644 --- a/lib/l10n/generated/app_localizations_tr.dart +++ b/lib/l10n/generated/app_localizations_tr.dart @@ -3749,4 +3749,139 @@ class AppLocalizationsTr extends AppLocalizations { String sortTableColumn(String column) { return '$column sırala'; } + + @override + String get exportReset => 'Varsayılanlara sıfırla'; + + @override + String get exportToc => 'İçindekiler tablosunu ekle'; + + @override + String get exportTocDepth => 'İçindekiler derinliği'; + + @override + String get exportNumberHeadings => 'Başlıkları numaralandır'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Özel'; + + @override + String get exportPageWidth => 'Sayfa genişliği (mm)'; + + @override + String get exportPageHeight => 'Sayfa yüksekliği (mm)'; + + @override + String get exportMarginTop => 'Üst kenar boşluğu (mm)'; + + @override + String get exportMarginRight => 'Sağ kenar boşluğu (mm)'; + + @override + String get exportMarginBottom => 'Alt kenar boşluğu (mm)'; + + @override + String get exportMarginLeft => 'Sol kenar boşluğu (mm)'; + + @override + String get exportTypography => 'Tipografi'; + + @override + String get exportSans => 'Serifsiz'; + + @override + String get exportSerif => 'Serifli'; + + @override + String get exportBodySize => 'Gövde yazı tipi boyutu'; + + @override + String get exportCodeSize => 'Kod yazı tipi boyutu'; + + @override + String get exportRunningText => 'Üst bilgi ve alt bilgi'; + + @override + String get exportHeader => 'Üst bilgi'; + + @override + String get exportFooter => 'Alt bilgi'; + + @override + String get exportNone => 'Yok'; + + @override + String get exportDocumentTitle => 'Belge başlığı'; + + @override + String get exportBottomLeft => 'Sol alt'; + + @override + String get exportBottomCenter => 'Alt orta'; + + @override + String get exportBottomRight => 'Sağ alt'; + + @override + String get exportFirstPage => 'İlk sayfada üst ve alt bilgiyi göster'; + + @override + String get exportAccent => 'Vurgu / bağlantı rengi'; + + @override + String get exportTheme => 'Tema'; + + @override + String get exportAutomatic => 'Otomatik'; + + @override + String get exportLayout => 'Düzen'; + + @override + String get exportContentWidth => 'En fazla içerik genişliği'; + + @override + String get exportOutput => 'Çıktı'; + + @override + String get exportPackaging => 'Paketleme'; + + @override + String get exportSingleFile => 'Tek HTML dosyası'; + + @override + String get exportAssetsDirectory => 'HTML + kaynak klasörü'; + + @override + String get exportCustomCss => 'Özel stil sayfası…'; + + @override + String get exportRemoveCss => 'Özel stil sayfasını kaldır'; + + @override + String get exportCssNote => + 'İsteğe bağlı UTF-8 CSS dosyası seçin (en fazla 256 KiB). İçe aktarımlar, kaynak URL’leri ve çalıştırılabilir veya kaçışlı CSS reddedilir. Stiller BusyMark CSS’inden sonra uygulanır. Uzak kaynaklar indirilmez.'; + + @override + String get exportSitePackagingNote => + 'Writerside ayrı bağlantılı konu sayfalarını korur. Tek dosya modu kaynakları her sayfaya gömer.'; + + @override + String get exportInvalidGeometry => + 'Kenar boşluklarından sonra en az 20 mm içerik genişliği ve yüksekliği bırakın.'; + + @override + String get exportInvalidColor => '#RRGGBB biçiminde bir renk girin.'; + + @override + String get exportInvalidCss => + 'İçe aktarım, kaynak URL’si, HTML, çalıştırılabilir veya kaçışlı CSS içermeyen, okunabilir UTF-8 .css dosyası seçin (en fazla 256 KiB).'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: $minimum ile $maximum arasında bir sayı girin.'; + } } diff --git a/lib/l10n/generated/app_localizations_uk.dart b/lib/l10n/generated/app_localizations_uk.dart index 83913d13..1b27b7d9 100644 --- a/lib/l10n/generated/app_localizations_uk.dart +++ b/lib/l10n/generated/app_localizations_uk.dart @@ -3806,4 +3806,139 @@ class AppLocalizationsUk extends AppLocalizations { String sortTableColumn(String column) { return 'Сортувати $column'; } + + @override + String get exportReset => 'Відновити типові значення'; + + @override + String get exportToc => 'Додати зміст'; + + @override + String get exportTocDepth => 'Глибина змісту'; + + @override + String get exportNumberHeadings => 'Нумерувати заголовки'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Власний'; + + @override + String get exportPageWidth => 'Ширина сторінки (мм)'; + + @override + String get exportPageHeight => 'Висота сторінки (мм)'; + + @override + String get exportMarginTop => 'Верхнє поле (мм)'; + + @override + String get exportMarginRight => 'Праве поле (мм)'; + + @override + String get exportMarginBottom => 'Нижнє поле (мм)'; + + @override + String get exportMarginLeft => 'Ліве поле (мм)'; + + @override + String get exportTypography => 'Типографіка'; + + @override + String get exportSans => 'Без зарубок'; + + @override + String get exportSerif => 'Із зарубками'; + + @override + String get exportBodySize => 'Розмір основного шрифту'; + + @override + String get exportCodeSize => 'Розмір шрифту коду'; + + @override + String get exportRunningText => 'Колонтитули'; + + @override + String get exportHeader => 'Верхній колонтитул'; + + @override + String get exportFooter => 'Нижній колонтитул'; + + @override + String get exportNone => 'Немає'; + + @override + String get exportDocumentTitle => 'Назва документа'; + + @override + String get exportBottomLeft => 'Знизу ліворуч'; + + @override + String get exportBottomCenter => 'Знизу по центру'; + + @override + String get exportBottomRight => 'Знизу праворуч'; + + @override + String get exportFirstPage => 'Показувати колонтитули на першій сторінці'; + + @override + String get exportAccent => 'Колір акценту / посилань'; + + @override + String get exportTheme => 'Тема'; + + @override + String get exportAutomatic => 'Автоматично'; + + @override + String get exportLayout => 'Макет'; + + @override + String get exportContentWidth => 'Максимальна ширина вмісту'; + + @override + String get exportOutput => 'Вивід'; + + @override + String get exportPackaging => 'Пакування'; + + @override + String get exportSingleFile => 'Один файл HTML'; + + @override + String get exportAssetsDirectory => 'HTML + папка ресурсів'; + + @override + String get exportCustomCss => 'Власний файл стилів…'; + + @override + String get exportRemoveCss => 'Вилучити власний файл стилів'; + + @override + String get exportCssNote => + 'Виберіть необов’язковий файл CSS у UTF-8 (до 256 КіБ). Імпорти, URL ресурсів, виконуваний CSS і escape-послідовності заборонені. Стилі застосовуються після стилів BusyMark. Віддалені ресурси не завантажуються.'; + + @override + String get exportSitePackagingNote => + 'Writerside зберігає окремі пов’язані сторінки тем. Режим одного файлу вбудовує ресурси в кожну сторінку.'; + + @override + String get exportInvalidGeometry => + 'Після віднімання полів залиште щонайменше 20 мм ширини й висоти вмісту.'; + + @override + String get exportInvalidColor => 'Введіть колір у форматі #RRGGBB.'; + + @override + String get exportInvalidCss => + 'Виберіть читабельний файл .css у UTF-8 до 256 КіБ без імпортів, URL ресурсів, HTML, виконуваного CSS і escape-послідовностей.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: введіть число від $minimum до $maximum.'; + } } diff --git a/lib/l10n/generated/app_localizations_vi.dart b/lib/l10n/generated/app_localizations_vi.dart index 57aa903a..e93687f1 100644 --- a/lib/l10n/generated/app_localizations_vi.dart +++ b/lib/l10n/generated/app_localizations_vi.dart @@ -3743,4 +3743,139 @@ class AppLocalizationsVi extends AppLocalizations { String sortTableColumn(String column) { return 'Sắp xếp $column'; } + + @override + String get exportReset => 'Khôi phục mặc định'; + + @override + String get exportToc => 'Bao gồm mục lục'; + + @override + String get exportTocDepth => 'Độ sâu mục lục'; + + @override + String get exportNumberHeadings => 'Đánh số tiêu đề'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => 'Tùy chỉnh'; + + @override + String get exportPageWidth => 'Chiều rộng trang (mm)'; + + @override + String get exportPageHeight => 'Chiều cao trang (mm)'; + + @override + String get exportMarginTop => 'Lề trên (mm)'; + + @override + String get exportMarginRight => 'Lề phải (mm)'; + + @override + String get exportMarginBottom => 'Lề dưới (mm)'; + + @override + String get exportMarginLeft => 'Lề trái (mm)'; + + @override + String get exportTypography => 'Kiểu chữ'; + + @override + String get exportSans => 'Không chân'; + + @override + String get exportSerif => 'Có chân'; + + @override + String get exportBodySize => 'Cỡ chữ nội dung'; + + @override + String get exportCodeSize => 'Cỡ chữ mã'; + + @override + String get exportRunningText => 'Đầu trang và chân trang'; + + @override + String get exportHeader => 'Đầu trang'; + + @override + String get exportFooter => 'Chân trang'; + + @override + String get exportNone => 'Không có'; + + @override + String get exportDocumentTitle => 'Tiêu đề tài liệu'; + + @override + String get exportBottomLeft => 'Dưới bên trái'; + + @override + String get exportBottomCenter => 'Dưới ở giữa'; + + @override + String get exportBottomRight => 'Dưới bên phải'; + + @override + String get exportFirstPage => 'Hiện đầu trang và chân trang ở trang đầu'; + + @override + String get exportAccent => 'Màu nhấn / liên kết'; + + @override + String get exportTheme => 'Giao diện'; + + @override + String get exportAutomatic => 'Tự động'; + + @override + String get exportLayout => 'Bố cục'; + + @override + String get exportContentWidth => 'Chiều rộng nội dung tối đa'; + + @override + String get exportOutput => 'Đầu ra'; + + @override + String get exportPackaging => 'Đóng gói'; + + @override + String get exportSingleFile => 'Một tệp HTML'; + + @override + String get exportAssetsDirectory => 'HTML + thư mục tài nguyên'; + + @override + String get exportCustomCss => 'Biểu định kiểu tùy chỉnh…'; + + @override + String get exportRemoveCss => 'Xóa biểu định kiểu tùy chỉnh'; + + @override + String get exportCssNote => + 'Chọn tệp CSS UTF-8 tùy chọn (tối đa 256 KiB). Không chấp nhận nhập tài nguyên, URL tài nguyên, CSS thực thi hoặc có ký tự thoát. Kiểu được áp dụng sau CSS của BusyMark. Không tải tài nguyên từ xa.'; + + @override + String get exportSitePackagingNote => + 'Writerside giữ các trang chủ đề riêng có liên kết. Chế độ một tệp nhúng tài nguyên vào từng trang.'; + + @override + String get exportInvalidGeometry => + 'Sau khi trừ lề, hãy để nội dung rộng và cao ít nhất 20 mm.'; + + @override + String get exportInvalidColor => 'Nhập màu theo dạng #RRGGBB.'; + + @override + String get exportInvalidCss => + 'Chọn tệp .css UTF-8 đọc được tối đa 256 KiB, không có nhập tài nguyên, URL tài nguyên, HTML, CSS thực thi hoặc ký tự thoát.'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field: nhập số từ $minimum đến $maximum.'; + } } diff --git a/lib/l10n/generated/app_localizations_zh.dart b/lib/l10n/generated/app_localizations_zh.dart index d7499877..45147432 100644 --- a/lib/l10n/generated/app_localizations_zh.dart +++ b/lib/l10n/generated/app_localizations_zh.dart @@ -3765,6 +3765,140 @@ class AppLocalizationsZh extends AppLocalizations { String sortTableColumn(String column) { return '排序 $column'; } + + @override + String get exportReset => '恢复默认值'; + + @override + String get exportToc => '包含目录'; + + @override + String get exportTocDepth => '目录深度'; + + @override + String get exportNumberHeadings => '为标题编号'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => '自定义'; + + @override + String get exportPageWidth => '页面宽度(mm)'; + + @override + String get exportPageHeight => '页面高度(mm)'; + + @override + String get exportMarginTop => '上边距(mm)'; + + @override + String get exportMarginRight => '右边距(mm)'; + + @override + String get exportMarginBottom => '下边距(mm)'; + + @override + String get exportMarginLeft => '左边距(mm)'; + + @override + String get exportTypography => '字体'; + + @override + String get exportSans => '无衬线'; + + @override + String get exportSerif => '衬线'; + + @override + String get exportBodySize => '正文字号'; + + @override + String get exportCodeSize => '代码字号'; + + @override + String get exportRunningText => '页眉和页脚'; + + @override + String get exportHeader => '页眉'; + + @override + String get exportFooter => '页脚'; + + @override + String get exportNone => '无'; + + @override + String get exportDocumentTitle => '文档标题'; + + @override + String get exportBottomLeft => '左下'; + + @override + String get exportBottomCenter => '底部居中'; + + @override + String get exportBottomRight => '右下'; + + @override + String get exportFirstPage => '在首页显示页眉和页脚'; + + @override + String get exportAccent => '强调色/链接颜色'; + + @override + String get exportTheme => '主题'; + + @override + String get exportAutomatic => '自动'; + + @override + String get exportLayout => '布局'; + + @override + String get exportContentWidth => '内容最大宽度'; + + @override + String get exportOutput => '输出'; + + @override + String get exportPackaging => '打包方式'; + + @override + String get exportSingleFile => '单个 HTML 文件'; + + @override + String get exportAssetsDirectory => 'HTML + 资源目录'; + + @override + String get exportCustomCss => '自定义样式表…'; + + @override + String get exportRemoveCss => '移除自定义样式表'; + + @override + String get exportCssNote => + '可选用 UTF-8 CSS 文件(最大 256 KiB)。不接受导入、资源 URL、可执行或转义 CSS。样式在 BusyMark 样式表之后应用。不会获取远程资源。'; + + @override + String get exportSitePackagingNote => + 'Writerside 保留独立且相互链接的主题页面。单文件模式将资源嵌入每个页面。'; + + @override + String get exportInvalidGeometry => '扣除边距后,请至少保留 20 mm 的内容宽度和高度。'; + + @override + String get exportInvalidColor => '请输入 #RRGGBB 格式的颜色。'; + + @override + String get exportInvalidCss => + '请选择可读取的 UTF-8 .css 文件(最大 256 KiB),不得包含导入、资源 URL、HTML、可执行或转义 CSS。'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field:请输入 $minimum 到 $maximum 之间的数字。'; + } } /// The translations for Chinese, as used in China (`zh_CN`). @@ -7343,4 +7477,138 @@ class AppLocalizationsZhCn extends AppLocalizationsZh { String sortTableColumn(String column) { return '排序 $column'; } + + @override + String get exportReset => '恢复默认值'; + + @override + String get exportToc => '包含目录'; + + @override + String get exportTocDepth => '目录深度'; + + @override + String get exportNumberHeadings => '为标题编号'; + + @override + String get exportLegal => 'US Legal'; + + @override + String get exportCustom => '自定义'; + + @override + String get exportPageWidth => '页面宽度(mm)'; + + @override + String get exportPageHeight => '页面高度(mm)'; + + @override + String get exportMarginTop => '上边距(mm)'; + + @override + String get exportMarginRight => '右边距(mm)'; + + @override + String get exportMarginBottom => '下边距(mm)'; + + @override + String get exportMarginLeft => '左边距(mm)'; + + @override + String get exportTypography => '字体'; + + @override + String get exportSans => '无衬线'; + + @override + String get exportSerif => '衬线'; + + @override + String get exportBodySize => '正文字号'; + + @override + String get exportCodeSize => '代码字号'; + + @override + String get exportRunningText => '页眉和页脚'; + + @override + String get exportHeader => '页眉'; + + @override + String get exportFooter => '页脚'; + + @override + String get exportNone => '无'; + + @override + String get exportDocumentTitle => '文档标题'; + + @override + String get exportBottomLeft => '左下'; + + @override + String get exportBottomCenter => '底部居中'; + + @override + String get exportBottomRight => '右下'; + + @override + String get exportFirstPage => '在首页显示页眉和页脚'; + + @override + String get exportAccent => '强调色/链接颜色'; + + @override + String get exportTheme => '主题'; + + @override + String get exportAutomatic => '自动'; + + @override + String get exportLayout => '布局'; + + @override + String get exportContentWidth => '内容最大宽度'; + + @override + String get exportOutput => '输出'; + + @override + String get exportPackaging => '打包方式'; + + @override + String get exportSingleFile => '单个 HTML 文件'; + + @override + String get exportAssetsDirectory => 'HTML + 资源目录'; + + @override + String get exportCustomCss => '自定义样式表…'; + + @override + String get exportRemoveCss => '移除自定义样式表'; + + @override + String get exportCssNote => + '可选用 UTF-8 CSS 文件(最大 256 KiB)。不接受导入、资源 URL、可执行或转义 CSS。样式在 BusyMark 样式表之后应用。不会获取远程资源。'; + + @override + String get exportSitePackagingNote => + 'Writerside 保留独立且相互链接的主题页面。单文件模式将资源嵌入每个页面。'; + + @override + String get exportInvalidGeometry => '扣除边距后,请至少保留 20 mm 的内容宽度和高度。'; + + @override + String get exportInvalidColor => '请输入 #RRGGBB 格式的颜色。'; + + @override + String get exportInvalidCss => + '请选择可读取的 UTF-8 .css 文件(最大 256 KiB),不得包含导入、资源 URL、HTML、可执行或转义 CSS。'; + + @override + String exportInvalidRange(String field, String minimum, String maximum) { + return '$field:请输入 $minimum 到 $maximum 之间的数字。'; + } } diff --git a/lib/src/app/app_settings.dart b/lib/src/app/app_settings.dart index 78ad943c..cbcc9209 100644 --- a/lib/src/app/app_settings.dart +++ b/lib/src/app/app_settings.dart @@ -7,6 +7,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; +import '../export/export_options.dart'; import 'app_locale.dart'; enum BusyMarkThemeModePreference { system, light, dark } @@ -95,6 +96,8 @@ class AppSettings { required this.allowRemoteImages, required this.remoteImageAllowedWorkspacePaths, required this.trustedGitWorkspacePaths, + this.pdfExportOptions = const PdfExportOptions(), + this.htmlExportOptions = const HtmlExportOptions(), required this.selectedWritersideInstanceIds, required this.writersideInstanceIconColors, required this.reopenPreviousWorkspaceOnStartup, @@ -202,6 +205,8 @@ class AppSettings { trustedGitWorkspacePaths: _gitWorkspacePathListFromJson( json['trustedGitWorkspacePaths'], ), + pdfExportOptions: PdfExportOptions.fromJson(json['pdfExportOptions']), + htmlExportOptions: HtmlExportOptions.fromJson(json['htmlExportOptions']), selectedWritersideInstanceIds: _stringMapFromJson( json['selectedWritersideInstanceIds'], ), @@ -247,6 +252,8 @@ class AppSettings { final bool allowRemoteImages; final List remoteImageAllowedWorkspacePaths; final List trustedGitWorkspacePaths; + final PdfExportOptions pdfExportOptions; + final HtmlExportOptions htmlExportOptions; final Map selectedWritersideInstanceIds; final Map writersideInstanceIconColors; final bool reopenPreviousWorkspaceOnStartup; @@ -280,6 +287,8 @@ class AppSettings { 'allowRemoteImages': allowRemoteImages, 'remoteImageAllowedWorkspacePaths': remoteImageAllowedWorkspacePaths, 'trustedGitWorkspacePaths': trustedGitWorkspacePaths, + 'pdfExportOptions': pdfExportOptions.toJson(), + 'htmlExportOptions': htmlExportOptions.toJson(), 'selectedWritersideInstanceIds': selectedWritersideInstanceIds, 'writersideInstanceIconColors': writersideInstanceIconColors, 'reopenPreviousWorkspaceOnStartup': reopenPreviousWorkspaceOnStartup, @@ -352,6 +361,8 @@ class AppSettings { bool? allowRemoteImages, List? remoteImageAllowedWorkspacePaths, List? trustedGitWorkspacePaths, + PdfExportOptions? pdfExportOptions, + HtmlExportOptions? htmlExportOptions, Map? selectedWritersideInstanceIds, Map? writersideInstanceIconColors, bool? reopenPreviousWorkspaceOnStartup, @@ -390,6 +401,8 @@ class AppSettings { this.remoteImageAllowedWorkspacePaths, trustedGitWorkspacePaths: trustedGitWorkspacePaths ?? this.trustedGitWorkspacePaths, + pdfExportOptions: pdfExportOptions ?? this.pdfExportOptions, + htmlExportOptions: htmlExportOptions ?? this.htmlExportOptions, selectedWritersideInstanceIds: selectedWritersideInstanceIds ?? this.selectedWritersideInstanceIds, writersideInstanceIconColors: @@ -493,6 +506,16 @@ class AppSettingsController extends Notifier { Future waitUntilLoaded() => _loadFuture; + Future setPdfExportOptions(PdfExportOptions options) { + options.validateOrThrow(); + return _mutate((settings) => settings.copyWith(pdfExportOptions: options)); + } + + Future setHtmlExportOptions(HtmlExportOptions options) { + options.validateOrThrow(); + return _mutate((settings) => settings.copyWith(htmlExportOptions: options)); + } + Future setThemeModePreference(BusyMarkThemeModePreference preference) { return _mutate( (settings) => settings.copyWith(themeModePreference: preference), diff --git a/lib/src/app/busymark_design.dart b/lib/src/app/busymark_design.dart index 0422bc38..6de6a43b 100644 --- a/lib/src/app/busymark_design.dart +++ b/lib/src/app/busymark_design.dart @@ -10,6 +10,15 @@ import 'package:yaru/yaru.dart'; import '../platform/native_menu_service.dart'; import 'busymark_glyphs.dart'; +/// Resolve an explicit six-digit RGB color chosen in a document/export control. +/// This does not inherit the application's theme accent. +Color busyMarkRgbHexColor(String value) { + if (!RegExp(r'^#[0-9a-fA-F]{6}$').hasMatch(value)) { + throw ArgumentError.value(value, 'value'); + } + return Color(int.parse(value.substring(1), radix: 16) | 0xff000000); +} + abstract final class BusyMarkSpacing { static const double xxs = 2; static const double xs = 4; diff --git a/lib/src/export/export_metadata_mapper.dart b/lib/src/export/export_metadata_mapper.dart new file mode 100644 index 00000000..7fdb4164 --- /dev/null +++ b/lib/src/export/export_metadata_mapper.dart @@ -0,0 +1,70 @@ +import 'package:path/path.dart' as p; +import '../markdown/busymark_document.dart'; +import 'markdown_export_document.dart'; + +class ExportMetadataMapper { + const ExportMetadataMapper(); + MarkdownExportMetadata map( + BusyDocument document, { + String? titleOverride, + String defaultLanguage = 'en', + }) { + final frontMatter = { + for (final entry in document.frontMatter.entries) + entry.key.toLowerCase().trim(): entry.value.trim(), + }; + final title = _firstNonEmpty([ + titleOverride, + frontMatter['title'], + document.title, + document.filePath.isEmpty + ? null + : p.basenameWithoutExtension(document.filePath), + 'Untitled', + ])!; + final keywords = _firstNonEmpty([ + frontMatter['keywords'], + frontMatter['tags'], + ]); + return MarkdownExportMetadata( + title: title, + author: + _firstNonEmpty([frontMatter['author'], frontMatter['authors']]) ?? '', + description: + _firstNonEmpty([ + frontMatter['description'], + frontMatter['summary'], + frontMatter['web-summary'], + ]) ?? + '', + language: _normalizedLanguage( + _firstNonEmpty([frontMatter['lang'], frontMatter['language']]) ?? + defaultLanguage, + ), + keywords: keywords == null + ? const [] + : keywords + .split(RegExp(r'[,;]')) + .map((value) => value.trim()) + .where((value) => value.isNotEmpty) + .take(32) + .toList(growable: false), + ); + } + + String _normalizedLanguage(String? value) { + final normalized = value?.trim().replaceAll('_', '-') ?? 'en'; + return RegExp(r'^[A-Za-z]{2,8}(?:-[A-Za-z0-9]{1,8})*$').hasMatch(normalized) + ? normalized + : 'und'; + } + + String? _firstNonEmpty(Iterable values) { + for (final value in values) { + if (value != null && value.trim().isNotEmpty) { + return value.trim(); + } + } + return null; + } +} diff --git a/lib/src/export/export_options.dart b/lib/src/export/export_options.dart new file mode 100644 index 00000000..49cc4a2a --- /dev/null +++ b/lib/src/export/export_options.dart @@ -0,0 +1,481 @@ +import 'package:flutter/foundation.dart'; + +/// Content choices whose meaning is the same in every output format. +@immutable +class ExportContentOptions { + const ExportContentOptions({ + this.includeToc = false, + this.tocDepth = 6, + this.numberHeadings = false, + }); + final bool includeToc, numberHeadings; + final int tocDepth; + ExportContentOptions copyWith({ + bool? includeToc, + int? tocDepth, + bool? numberHeadings, + }) => ExportContentOptions( + includeToc: includeToc ?? this.includeToc, + tocDepth: tocDepth ?? this.tocDepth, + numberHeadings: numberHeadings ?? this.numberHeadings, + ); + Map toJson() => { + 'includeToc': includeToc, + 'tocDepth': tocDepth, + 'numberHeadings': numberHeadings, + }; + factory ExportContentOptions.fromJson( + Object? source, { + ExportContentOptions defaults = const ExportContentOptions(), + }) { + final json = _map(source); + return ExportContentOptions( + includeToc: _bool(json['includeToc'], defaults.includeToc), + tocDepth: _number( + json['tocDepth'], + defaults.tocDepth.toDouble(), + 1, + 6, + integer: true, + ).toInt(), + numberHeadings: _bool(json['numberHeadings'], defaults.numberHeadings), + ); + } + List validate() => [ + if (tocDepth < 1 || tocDepth > 6) + const ExportOptionIssue('tocDepth', minimum: 1, maximum: 6), + ]; +} + +enum ExportBodyTypography { sansSerif, serif } + +enum PdfPageSize { a4, letter, legal, custom } + +enum PdfOrientation { portrait, landscape } + +enum PdfMarginPreset { narrow, normal, wide, custom } + +enum PdfRunningText { none, documentTitle } + +enum PdfPageNumberPosition { off, bottomLeft, bottomCenter, bottomRight } + +enum HtmlExportTheme { light, dark, automatic } + +enum HtmlPackaging { singleFile, assetsDirectory } + +@immutable +class ExportOptionIssue { + const ExportOptionIssue(this.field, {this.minimum, this.maximum}); + final String field; + final double? minimum, maximum; +} + +class ExportOptionsException implements Exception { + const ExportOptionsException(this.issues); + final List issues; + @override + String toString() => + 'Invalid export options: ${issues.map((issue) => issue.field).join(', ')}'; +} + +@immutable +class PdfMargins { + const PdfMargins({ + this.top = normalMm, + this.right = normalMm, + this.bottom = normalMm, + this.left = normalMm, + }); + static const normalMm = 57 * 25.4 / 72; + final double top, right, bottom, left; + PdfMargins copyWith({ + double? top, + double? right, + double? bottom, + double? left, + }) => PdfMargins( + top: top ?? this.top, + right: right ?? this.right, + bottom: bottom ?? this.bottom, + left: left ?? this.left, + ); + Map toJson() => { + 'top': top, + 'right': right, + 'bottom': bottom, + 'left': left, + }; + factory PdfMargins.fromJson(Object? source) { + final json = _map(source); + return PdfMargins( + top: _number(json['top'], normalMm, 0, 500), + right: _number(json['right'], normalMm, 0, 500), + bottom: _number(json['bottom'], normalMm, 0, 500), + left: _number(json['left'], normalMm, 0, 500), + ); + } +} + +@immutable +class PdfPageGeometry { + const PdfPageGeometry({ + required this.widthMm, + required this.heightMm, + required this.margins, + }); + static const pointsPerMm = 72 / 25.4; + final double widthMm, heightMm; + final PdfMargins margins; + double get widthPt => widthMm * pointsPerMm; + double get heightPt => heightMm * pointsPerMm; + double get contentWidthPt => + (widthMm - margins.left - margins.right) * pointsPerMm; + double get contentHeightPt => + (heightMm - margins.top - margins.bottom) * pointsPerMm; + Map toJson() => { + 'widthPt': widthPt, + 'heightPt': heightPt, + 'marginsPt': { + for (final e in margins.toJson().entries) + e.key: (e.value as double) * pointsPerMm, + }, + }; +} + +/// Shared by Markdown and Writerside PDF. No editor preferences enter this model. +@immutable +class PdfExportOptions { + const PdfExportOptions({ + this.content = const ExportContentOptions(), + this.pageSize = PdfPageSize.a4, + this.orientation = PdfOrientation.portrait, + this.margin = PdfMarginPreset.normal, + this.customWidthMm = 210, + this.customHeightMm = 297, + this.customMargins = const PdfMargins(), + this.bodyTypography = ExportBodyTypography.serif, + this.bodyFontSize = 10.5, + this.codeFontSize = 8.4, + this.accentColor = '#2563a5', + this.header = PdfRunningText.none, + this.footer = PdfRunningText.none, + this.pageNumbers = PdfPageNumberPosition.bottomCenter, + this.showHeaderFooterOnFirstPage = true, + }); + final ExportContentOptions content; + final PdfPageSize pageSize; + final PdfOrientation orientation; + final PdfMarginPreset margin; + final double customWidthMm, customHeightMm; + final PdfMargins customMargins; + final ExportBodyTypography bodyTypography; + final double bodyFontSize, codeFontSize; + final String accentColor; + final PdfRunningText header, footer; + final PdfPageNumberPosition pageNumbers; + final bool showHeaderFooterOnFirstPage; + + String get bodyFont => bodyTypography == ExportBodyTypography.sansSerif + ? 'Noto Sans' + : 'Noto Serif'; + String get codeFont => 'Noto Sans Mono'; + // Ratios preserve BusyMark's original heading scale at the default 10.5pt. + double headingFontSize(int level) => + bodyFontSize * + const [ + 22 / 10.5, + 17 / 10.5, + 13.5 / 10.5, + 11.5 / 10.5, + 1.0, + 1.0, + ][level.clamp(1, 6) - 1]; + PdfPageGeometry get geometry { + final (width, height) = switch (pageSize) { + PdfPageSize.a4 => (210.0, 297.0), + PdfPageSize.letter => (215.9, 279.4), + PdfPageSize.legal => (215.9, 355.6), + PdfPageSize.custom => (customWidthMm, customHeightMm), + }; + final (horizontal, vertical) = switch (margin) { + PdfMarginPreset.narrow => (36.0, 36.0), + PdfMarginPreset.normal => (57.0, 57.0), + PdfMarginPreset.wide => (78.0, 72.0), + PdfMarginPreset.custom => (0.0, 0.0), + }; + final margins = margin == PdfMarginPreset.custom + ? customMargins + : PdfMargins( + top: vertical / PdfPageGeometry.pointsPerMm, + bottom: vertical / PdfPageGeometry.pointsPerMm, + left: horizontal / PdfPageGeometry.pointsPerMm, + right: horizontal / PdfPageGeometry.pointsPerMm, + ); + return PdfPageGeometry( + widthMm: orientation == PdfOrientation.landscape ? height : width, + heightMm: orientation == PdfOrientation.landscape ? width : height, + margins: margins, + ); + } + + List validate() => [ + ...content.validate(), + // Validate inactive custom fields too: confirmed options must always be + // JSON-serializable and remain valid when their controls are re-enabled. + if (!_between(customWidthMm, 50, 1200)) + const ExportOptionIssue('customWidthMm', minimum: 50, maximum: 1200), + if (!_between(customHeightMm, 50, 1200)) + const ExportOptionIssue('customHeightMm', minimum: 50, maximum: 1200), + for (final e in customMargins.toJson().entries) + if (!_between(e.value as double, 0, 500)) + ExportOptionIssue('margin.${e.key}', minimum: 0, maximum: 500), + if (!geometry.contentWidthPt.isFinite || + !geometry.contentHeightPt.isFinite || + geometry.contentWidthPt < 20 * PdfPageGeometry.pointsPerMm || + geometry.contentHeightPt < 20 * PdfPageGeometry.pointsPerMm) + const ExportOptionIssue('pageGeometry'), + if (!_between(bodyFontSize, 8, 24)) + const ExportOptionIssue('bodyFontSize', minimum: 8, maximum: 24), + if (!_between(codeFontSize, 6, 20)) + const ExportOptionIssue('codeFontSize', minimum: 6, maximum: 20), + if (!validExportColor(accentColor)) const ExportOptionIssue('accentColor'), + ]; + void validateOrThrow() { + final issues = validate(); + if (issues.isNotEmpty) throw ExportOptionsException(issues); + } + + PdfExportOptions copyWith({ + ExportContentOptions? content, + PdfPageSize? pageSize, + PdfOrientation? orientation, + PdfMarginPreset? margin, + double? customWidthMm, + double? customHeightMm, + PdfMargins? customMargins, + ExportBodyTypography? bodyTypography, + double? bodyFontSize, + double? codeFontSize, + String? accentColor, + PdfRunningText? header, + PdfRunningText? footer, + PdfPageNumberPosition? pageNumbers, + bool? showHeaderFooterOnFirstPage, + }) => PdfExportOptions( + content: content ?? this.content, + pageSize: pageSize ?? this.pageSize, + orientation: orientation ?? this.orientation, + margin: margin ?? this.margin, + customWidthMm: customWidthMm ?? this.customWidthMm, + customHeightMm: customHeightMm ?? this.customHeightMm, + customMargins: customMargins ?? this.customMargins, + bodyTypography: bodyTypography ?? this.bodyTypography, + bodyFontSize: bodyFontSize ?? this.bodyFontSize, + codeFontSize: codeFontSize ?? this.codeFontSize, + accentColor: accentColor ?? this.accentColor, + header: header ?? this.header, + footer: footer ?? this.footer, + pageNumbers: pageNumbers ?? this.pageNumbers, + showHeaderFooterOnFirstPage: + showHeaderFooterOnFirstPage ?? this.showHeaderFooterOnFirstPage, + ); + Map toJson() => { + 'content': content.toJson(), + 'pageSize': pageSize.name, + 'orientation': orientation.name, + 'margin': margin.name, + 'customWidthMm': customWidthMm, + 'customHeightMm': customHeightMm, + 'customMargins': customMargins.toJson(), + 'bodyTypography': bodyTypography.name, + 'bodyFontSize': bodyFontSize, + 'codeFontSize': codeFontSize, + 'accentColor': accentColor, + 'header': header.name, + 'footer': footer.name, + 'pageNumbers': pageNumbers.name, + 'showHeaderFooterOnFirstPage': showHeaderFooterOnFirstPage, + }; + factory PdfExportOptions.fromJson(Object? source) { + final j = _map(source); + const d = PdfExportOptions(); + var result = PdfExportOptions( + content: ExportContentOptions.fromJson(j['content']), + pageSize: _enum(PdfPageSize.values, j['pageSize'], d.pageSize), + orientation: _enum( + PdfOrientation.values, + j['orientation'], + d.orientation, + ), + margin: _enum(PdfMarginPreset.values, j['margin'], d.margin), + customWidthMm: _number(j['customWidthMm'], d.customWidthMm, 50, 1200), + customHeightMm: _number(j['customHeightMm'], d.customHeightMm, 50, 1200), + customMargins: PdfMargins.fromJson(j['customMargins']), + bodyTypography: _enum( + ExportBodyTypography.values, + j['bodyTypography'], + d.bodyTypography, + ), + bodyFontSize: _number(j['bodyFontSize'], d.bodyFontSize, 8, 24), + codeFontSize: _number(j['codeFontSize'], d.codeFontSize, 6, 20), + accentColor: + j['accentColor'] is String && + validExportColor(j['accentColor'] as String) + ? (j['accentColor'] as String).toLowerCase() + : d.accentColor, + header: _enum(PdfRunningText.values, j['header'], d.header), + footer: _enum(PdfRunningText.values, j['footer'], d.footer), + pageNumbers: _enum( + PdfPageNumberPosition.values, + j['pageNumbers'], + d.pageNumbers, + ), + showHeaderFooterOnFirstPage: _bool( + j['showHeaderFooterOnFirstPage'], + d.showHeaderFooterOnFirstPage, + ), + ); + // Restore only incompatible geometry, preserving independent valid fields. + if (result.validate().any((i) => i.field == 'pageGeometry')) { + result = result.copyWith(customMargins: d.customMargins); + if (result.validate().any((i) => i.field == 'pageGeometry')) { + result = result.copyWith( + customWidthMm: d.customWidthMm, + customHeightMm: d.customHeightMm, + ); + } + } + return result; + } +} + +@immutable +class HtmlExportOptions { + const HtmlExportOptions({ + this.content = const ExportContentOptions(includeToc: true), + this.theme = HtmlExportTheme.light, + this.bodyTypography = ExportBodyTypography.sansSerif, + this.baseFontSize = 17, + this.contentMaxWidth = 918, + this.accentColor = '#1559aa', + this.customCssPath, + this.packaging = HtmlPackaging.assetsDirectory, + }); + final ExportContentOptions content; + final HtmlExportTheme theme; + final ExportBodyTypography bodyTypography; + final double baseFontSize, contentMaxWidth; + final String accentColor; + final String? customCssPath; + final HtmlPackaging packaging; + static const maximumCssBytes = 256 * 1024; + double headingFontSize(int level) => + baseFontSize * + const [2.3, 1.75, 1.3, 1.0, 1.0, 1.0][level.clamp(1, 6) - 1]; + double get mathContainerWidth => + (contentMaxWidth - baseFontSize * 6).clamp(160, 1800).toDouble(); + HtmlExportOptions copyWith({ + ExportContentOptions? content, + HtmlExportTheme? theme, + ExportBodyTypography? bodyTypography, + double? baseFontSize, + double? contentMaxWidth, + String? accentColor, + Object? customCssPath = _unset, + HtmlPackaging? packaging, + }) => HtmlExportOptions( + content: content ?? this.content, + theme: theme ?? this.theme, + bodyTypography: bodyTypography ?? this.bodyTypography, + baseFontSize: baseFontSize ?? this.baseFontSize, + contentMaxWidth: contentMaxWidth ?? this.contentMaxWidth, + accentColor: accentColor ?? this.accentColor, + customCssPath: identical(customCssPath, _unset) + ? this.customCssPath + : customCssPath as String?, + packaging: packaging ?? this.packaging, + ); + List validate() => [ + ...content.validate(), + if (!_between(baseFontSize, 12, 28)) + const ExportOptionIssue('baseFontSize', minimum: 12, maximum: 28), + if (!_between(contentMaxWidth, 320, 1920)) + const ExportOptionIssue('contentMaxWidth', minimum: 320, maximum: 1920), + if (!validExportColor(accentColor)) const ExportOptionIssue('accentColor'), + if (customCssPath != null && !validCssPath(customCssPath!)) + const ExportOptionIssue('customCssPath'), + ]; + void validateOrThrow() { + final issues = validate(); + if (issues.isNotEmpty) throw ExportOptionsException(issues); + } + + static bool validCssPath(String value) => + value.startsWith('/') && + value.toLowerCase().endsWith('.css') && + !RegExp(r'[\x00-\x1f\x7f]').hasMatch(value) && + value.length <= 4096; + Map toJson() => { + 'content': content.toJson(), + 'theme': theme.name, + 'bodyTypography': bodyTypography.name, + 'baseFontSize': baseFontSize, + 'contentMaxWidth': contentMaxWidth, + 'accentColor': accentColor, + 'customCssPath': customCssPath, + 'packaging': packaging.name, + }; + factory HtmlExportOptions.fromJson(Object? source) { + final j = _map(source); + const d = HtmlExportOptions(); + return HtmlExportOptions( + content: ExportContentOptions.fromJson(j['content'], defaults: d.content), + theme: _enum(HtmlExportTheme.values, j['theme'], d.theme), + bodyTypography: _enum( + ExportBodyTypography.values, + j['bodyTypography'], + d.bodyTypography, + ), + baseFontSize: _number(j['baseFontSize'], d.baseFontSize, 12, 28), + contentMaxWidth: _number( + j['contentMaxWidth'], + d.contentMaxWidth, + 320, + 1920, + ), + accentColor: + j['accentColor'] is String && + validExportColor(j['accentColor'] as String) + ? (j['accentColor'] as String).toLowerCase() + : d.accentColor, + customCssPath: + j['customCssPath'] is String && + validCssPath(j['customCssPath'] as String) + ? j['customCssPath'] as String + : null, + packaging: _enum(HtmlPackaging.values, j['packaging'], d.packaging), + ); + } +} + +bool validExportColor(String value) => + RegExp(r'^#[0-9a-fA-F]{6}$').hasMatch(value); +const _unset = Object(); +Map _map(Object? value) => value is Map ? value : const {}; +T _enum(List values, Object? value, T fallback) => + values.where((e) => e.name == value).firstOrNull ?? fallback; +bool _bool(Object? value, bool fallback) => value is bool ? value : fallback; +bool _between(double value, double minimum, double maximum) => + value.isFinite && value >= minimum && value <= maximum; +double _number( + Object? value, + double fallback, + double minimum, + double maximum, { + bool integer = false, +}) => + value is num && + _between(value.toDouble(), minimum, maximum) && + (!integer || value == value.truncateToDouble()) + ? value.toDouble() + : fallback; diff --git a/lib/src/export/export_options_editor.dart b/lib/src/export/export_options_editor.dart new file mode 100644 index 00000000..2acb3183 --- /dev/null +++ b/lib/src/export/export_options_editor.dart @@ -0,0 +1,618 @@ +import 'package:file_selector/file_selector.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import '../app/app_settings.dart'; +import '../app/busymark_design.dart'; +import '../app/busymark_dialogs.dart'; +import '../app/localization.dart'; +import '../platform/linux_header_bar_service.dart'; +import '../writerside/writerside_model.dart'; +import 'export_options.dart'; +import 'html_export_styles.dart'; + +class ExportOptionsSelection { + const ExportOptionsSelection({this.pdf, this.html, this.instance}); + final PdfExportOptions? pdf; + final HtmlExportOptions? html; + final WritersideInstance? instance; +} + +Future showExportOptions( + BuildContext context, + WidgetRef ref, { + required bool pdf, + List instances = const [], + String? workspaceRoot, +}) async { + final controller = ref.read(appSettingsControllerProvider.notifier); + await controller.waitUntilLoaded(); + if (!context.mounted) return null; + final settings = ref.read(appSettingsControllerProvider); + final bar = ref.read(linuxHeaderBarServiceProvider); + final selection = await showBusyMarkModalEditorDialog( + context, + headerBarService: bar.isAvailable ? bar : null, + maxWidth: 720, + builder: (context) => ExportOptionsDialog( + pdf: pdf ? settings.pdfExportOptions : null, + html: pdf ? null : settings.htmlExportOptions, + instances: instances, + instanceId: workspaceRoot == null + ? null + : settings.selectedWritersideInstanceId(workspaceRoot), + ), + ); + if (selection == null) return null; + if (selection.pdf case final options?) { + await controller.setPdfExportOptions(options); + } + if (selection.html case final options?) { + await controller.setHtmlExportOptions(options); + } + if (workspaceRoot != null && selection.instance != null) { + await controller.selectWritersideInstance( + workspaceRoot, + selection.instance!.id, + ); + } + return selection; +} + +class ExportOptionsDialog extends StatefulWidget { + const ExportOptionsDialog({ + super.key, + this.pdf, + this.html, + this.instances = const [], + this.instanceId, + }) : assert((pdf == null) != (html == null)); + final PdfExportOptions? pdf; + final HtmlExportOptions? html; + final List instances; + final String? instanceId; + @override + State createState() => _ExportOptionsDialogState(); +} + +class _ExportOptionsDialogState extends State { + late PdfExportOptions? _pdf = widget.pdf; + late HtmlExportOptions? _html = widget.html; + late WritersideInstance? _instance = + widget.instances.where((i) => i.id == widget.instanceId).firstOrNull ?? + widget.instances.firstOrNull; + var _revision = 0; + var _saving = false; + List _fileErrors = []; + List get _issues => [ + ...?_pdf?.validate(), + ...?_html?.validate(), + ..._fileErrors, + ]; + + Future _submit() async { + if (_issues.isNotEmpty) return; + final selection = ExportOptionsSelection( + pdf: _pdf, + html: _html, + instance: _instance, + ); + setState(() => _saving = true); + try { + if (selection.html case final html?) { + await HtmlExportStyles.readCustomCss(html); + } + if (mounted) { + Navigator.pop(context, selection); + } + } on ExportOptionsException catch (error) { + if (mounted) { + setState(() { + _saving = false; + _fileErrors = error.issues; + }); + } + } + } + + @override + Widget build(BuildContext context) => BusyMarkModalEditorScaffold( + title: _pdf == null ? context.l10n.exportAsHtml : context.l10n.exportAsPdf, + cancelLabel: context.l10n.cancel, + saveLabel: context.l10n.export, + onCancel: () => Navigator.pop(context), + onSave: _issues.isEmpty && !_saving ? _submit : null, + saving: _saving, + children: [ + BusyMarkDialogButton( + label: context.l10n.exportReset, + onPressed: _saving + ? null + : () => setState(() { + if (_pdf != null) _pdf = const PdfExportOptions(); + if (_html != null) _html = const HtmlExportOptions(); + _revision++; + _fileErrors = []; + }), + ), + const SizedBox(height: BusyMarkSpacing.md), + if (_issues.isNotEmpty) + Padding( + padding: const EdgeInsets.only(bottom: BusyMarkSpacing.md), + child: Text( + _issues.map((i) => exportOptionError(context, i)).join('\n'), + style: TextStyle(color: Theme.of(context).colorScheme.error), + ), + ), + if (_pdf != null) + PdfExportOptionsEditor( + key: ValueKey(_revision), + value: _pdf!, + instance: _instanceRow(context), + onChanged: (value) => setState(() => _pdf = value), + ) + else + HtmlExportOptionsEditor( + key: ValueKey(_revision), + value: _html!, + instance: _instanceRow(context), + onChanged: (value) => setState(() { + _html = value; + _fileErrors = []; + }), + ), + ], + ); + + Widget? _instanceRow(BuildContext context) => _instance == null + ? null + : BusyMarkComboRow( + title: context.l10n.htmlInstance, + selected: _instance!, + values: widget.instances, + labelFor: (i) => '${i.name} (${i.id})', + onSelected: (i) => setState(() => _instance = i), + ); +} + +String exportOptionError(BuildContext context, ExportOptionIssue issue) { + final l = context.l10n; + if (issue.field == 'pageGeometry') return l.exportInvalidGeometry; + if (issue.field == 'accentColor') return l.exportInvalidColor; + if (issue.field.startsWith('customCss')) return l.exportInvalidCss; + final name = switch (issue.field) { + 'customWidthMm' => l.exportPageWidth, + 'customHeightMm' => l.exportPageHeight, + 'bodyFontSize' || 'baseFontSize' => l.exportBodySize, + 'codeFontSize' => l.exportCodeSize, + 'contentMaxWidth' => l.exportContentWidth, + 'tocDepth' => l.exportTocDepth, + _ => l.pdfMargins, + }; + return l.exportInvalidRange( + name, + '${issue.minimum ?? 0}', + '${issue.maximum ?? 500}', + ); +} + +class ExportContentOptionsEditor extends StatelessWidget { + const ExportContentOptionsEditor({ + super.key, + required this.value, + required this.onChanged, + this.instance, + }); + final ExportContentOptions value; + final ValueChanged onChanged; + final Widget? instance; + @override + Widget build(BuildContext context) => BusyMarkGroupedList( + title: context.l10n.writersidePdfContent, + filled: true, + children: [ + if (instance != null) instance!, + BusyMarkSwitchRow( + title: context.l10n.exportToc, + value: value.includeToc, + onChanged: (v) => onChanged(value.copyWith(includeToc: v)), + ), + BusyMarkComboRow( + title: context.l10n.exportTocDepth, + values: const [1, 2, 3, 4, 5, 6], + selected: value.tocDepth.clamp(1, 6), + enabled: value.includeToc, + labelFor: (v) => '$v', + onSelected: (v) => onChanged(value.copyWith(tocDepth: v)), + ), + BusyMarkSwitchRow( + title: context.l10n.exportNumberHeadings, + value: value.numberHeadings, + onChanged: (v) => onChanged(value.copyWith(numberHeadings: v)), + ), + ], + ); +} + +class PdfExportOptionsEditor extends StatelessWidget { + const PdfExportOptionsEditor({ + super.key, + required this.value, + required this.onChanged, + this.instance, + }); + final PdfExportOptions value; + final ValueChanged onChanged; + final Widget? instance; + @override + Widget build(BuildContext context) { + final l = context.l10n; + final o = value; + final errors = o.validate(); + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ExportContentOptionsEditor( + value: o.content, + onChanged: (v) => onChanged(o.copyWith(content: v)), + instance: instance, + ), + _group(l.writersidePdfPage, [ + BusyMarkComboRow( + title: l.pdfPageSize, + values: PdfPageSize.values, + selected: o.pageSize, + labelFor: (v) => switch (v) { + PdfPageSize.a4 => l.pdfPageSizeA4, + PdfPageSize.letter => l.pdfPageSizeLetter, + PdfPageSize.legal => l.exportLegal, + PdfPageSize.custom => l.exportCustom, + }, + onSelected: (v) => onChanged(o.copyWith(pageSize: v)), + ), + if (o.pageSize == PdfPageSize.custom) ...[ + _number( + context, + l.exportPageWidth, + 'customWidthMm', + o.customWidthMm, + errors, + (v) => onChanged(o.copyWith(customWidthMm: v)), + ), + _number( + context, + l.exportPageHeight, + 'customHeightMm', + o.customHeightMm, + errors, + (v) => onChanged(o.copyWith(customHeightMm: v)), + ), + ], + BusyMarkComboRow( + title: l.pdfOrientation, + values: PdfOrientation.values, + selected: o.orientation, + labelFor: (v) => + v == PdfOrientation.portrait ? l.pdfPortrait : l.pdfLandscape, + onSelected: (v) => onChanged(o.copyWith(orientation: v)), + ), + BusyMarkComboRow( + title: l.pdfMargins, + values: PdfMarginPreset.values, + selected: o.margin, + labelFor: (v) => switch (v) { + PdfMarginPreset.narrow => l.pdfMarginNarrow, + PdfMarginPreset.normal => l.pdfMarginNormal, + PdfMarginPreset.wide => l.pdfMarginWide, + PdfMarginPreset.custom => l.exportCustom, + }, + onSelected: (v) => onChanged(o.copyWith(margin: v)), + ), + if (o.margin == PdfMarginPreset.custom) ...[ + _number( + context, + l.exportMarginTop, + 'margin.top', + o.customMargins.top, + errors, + (v) => onChanged( + o.copyWith(customMargins: o.customMargins.copyWith(top: v)), + ), + ), + _number( + context, + l.exportMarginRight, + 'margin.right', + o.customMargins.right, + errors, + (v) => onChanged( + o.copyWith(customMargins: o.customMargins.copyWith(right: v)), + ), + ), + _number( + context, + l.exportMarginBottom, + 'margin.bottom', + o.customMargins.bottom, + errors, + (v) => onChanged( + o.copyWith(customMargins: o.customMargins.copyWith(bottom: v)), + ), + ), + _number( + context, + l.exportMarginLeft, + 'margin.left', + o.customMargins.left, + errors, + (v) => onChanged( + o.copyWith(customMargins: o.customMargins.copyWith(left: v)), + ), + ), + ], + ]), + _group(l.exportTypography, [ + _typography( + context, + o.bodyTypography, + (v) => onChanged(o.copyWith(bodyTypography: v)), + ), + _number( + context, + '${l.exportBodySize} (pt)', + 'bodyFontSize', + o.bodyFontSize, + errors, + (v) => onChanged(o.copyWith(bodyFontSize: v)), + ), + _number( + context, + '${l.exportCodeSize} (pt)', + 'codeFontSize', + o.codeFontSize, + errors, + (v) => onChanged(o.copyWith(codeFontSize: v)), + ), + ]), + _group(l.exportRunningText, [ + for (final header in [true, false]) + BusyMarkComboRow( + title: header ? l.exportHeader : l.exportFooter, + values: PdfRunningText.values, + selected: header ? o.header : o.footer, + labelFor: (v) => v == PdfRunningText.none + ? l.exportNone + : l.exportDocumentTitle, + onSelected: (v) => onChanged( + header ? o.copyWith(header: v) : o.copyWith(footer: v), + ), + ), + BusyMarkComboRow( + title: l.pdfIncludePageNumbers, + values: PdfPageNumberPosition.values, + selected: o.pageNumbers, + labelFor: (v) => switch (v) { + PdfPageNumberPosition.off => l.exportNone, + PdfPageNumberPosition.bottomLeft => l.exportBottomLeft, + PdfPageNumberPosition.bottomCenter => l.exportBottomCenter, + PdfPageNumberPosition.bottomRight => l.exportBottomRight, + }, + onSelected: (v) => onChanged(o.copyWith(pageNumbers: v)), + ), + BusyMarkSwitchRow( + title: l.exportFirstPage, + value: o.showHeaderFooterOnFirstPage, + enabled: + o.header != PdfRunningText.none || + o.footer != PdfRunningText.none || + o.pageNumbers != PdfPageNumberPosition.off, + onChanged: (v) => + onChanged(o.copyWith(showHeaderFooterOnFirstPage: v)), + ), + ]), + _group(l.appearance, [ + _AccentEditor( + value: o.accentColor, + onChanged: (v) => onChanged(o.copyWith(accentColor: v)), + ), + ]), + const SizedBox(height: BusyMarkSpacing.md), + Text(l.pdfRemoteImagesNote), + ], + ); + } +} + +class HtmlExportOptionsEditor extends StatelessWidget { + const HtmlExportOptionsEditor({ + super.key, + required this.value, + required this.onChanged, + this.instance, + }); + final HtmlExportOptions value; + final ValueChanged onChanged; + final Widget? instance; + @override + Widget build(BuildContext context) { + final l = context.l10n, o = value; + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ExportContentOptionsEditor( + value: o.content, + onChanged: (v) => onChanged(o.copyWith(content: v)), + instance: instance, + ), + _group(l.appearance, [ + BusyMarkComboRow( + title: l.exportTheme, + values: HtmlExportTheme.values, + selected: o.theme, + labelFor: (v) => switch (v) { + HtmlExportTheme.light => l.lightTheme, + HtmlExportTheme.dark => l.darkTheme, + HtmlExportTheme.automatic => l.exportAutomatic, + }, + onSelected: (v) => onChanged(o.copyWith(theme: v)), + ), + _typography( + context, + o.bodyTypography, + (v) => onChanged(o.copyWith(bodyTypography: v)), + ), + _number( + context, + '${l.exportBodySize} (px)', + 'baseFontSize', + o.baseFontSize, + o.validate(), + (v) => onChanged(o.copyWith(baseFontSize: v)), + ), + _AccentEditor( + value: o.accentColor, + onChanged: (v) => onChanged(o.copyWith(accentColor: v)), + ), + ]), + _group(l.exportLayout, [ + _number( + context, + '${l.exportContentWidth} (px)', + 'contentMaxWidth', + o.contentMaxWidth, + o.validate(), + (v) => onChanged(o.copyWith(contentMaxWidth: v)), + ), + ]), + _group(l.exportOutput, [ + BusyMarkComboRow( + title: l.exportPackaging, + values: HtmlPackaging.values, + selected: o.packaging, + labelFor: (v) => v == HtmlPackaging.singleFile + ? l.exportSingleFile + : l.exportAssetsDirectory, + onSelected: (v) => onChanged(o.copyWith(packaging: v)), + ), + BusyMarkActionRow( + title: l.exportCustomCss, + subtitle: o.customCssPath ?? l.exportNone, + onTap: () async { + final file = await openFile( + acceptedTypeGroups: [ + XTypeGroup( + label: l.exportCustomCss, + extensions: const ['css'], + ), + ], + ); + if (file != null && context.mounted) { + onChanged(o.copyWith(customCssPath: file.path)); + } + }, + ), + if (o.customCssPath != null) + BusyMarkActionRow( + title: l.exportRemoveCss, + onTap: () => onChanged(o.copyWith(customCssPath: null)), + ), + ]), + const SizedBox(height: BusyMarkSpacing.md), + Text(l.exportCssNote), + if (instance != null) Text(l.exportSitePackagingNote), + ], + ); + } +} + +Widget _group(String title, List children) => Padding( + padding: const EdgeInsets.only(top: BusyMarkSpacing.lg), + child: BusyMarkGroupedList(title: title, filled: true, children: children), +); +Widget _typography( + BuildContext context, + ExportBodyTypography value, + ValueChanged onChanged, +) => BusyMarkComboRow( + title: context.l10n.exportTypography, + values: ExportBodyTypography.values, + selected: value, + labelFor: (v) => v == ExportBodyTypography.sansSerif + ? context.l10n.exportSans + : context.l10n.exportSerif, + onSelected: onChanged, +); +Widget _number( + BuildContext context, + String title, + String field, + double value, + List errors, + ValueChanged onChanged, +) => BusyMarkGroupedTextEntry( + key: ValueKey(field), + label: title, + initialValue: value.isFinite + ? value.toStringAsFixed(2).replaceFirst(RegExp(r'\.?0+$'), '') + : '', + keyboardType: const TextInputType.numberWithOptions(decimal: true), + errorText: errors.any((i) => i.field == field) + ? exportOptionError(context, errors.firstWhere((i) => i.field == field)) + : null, + onChanged: (v) => + onChanged(double.tryParse(v.replaceAll(',', '.')) ?? double.nan), +); + +class _AccentEditor extends StatefulWidget { + const _AccentEditor({required this.value, required this.onChanged}); + final String value; + final ValueChanged onChanged; + @override + State<_AccentEditor> createState() => _AccentEditorState(); +} + +class _AccentEditorState extends State<_AccentEditor> { + static const palette = [ + '#2563a5', + '#1559aa', + '#247550', + '#a34200', + '#7651a8', + '#b3261e', + ]; + late bool _custom = !palette.contains(widget.value); + @override + Widget build(BuildContext context) => Column( + children: [ + BusyMarkComboRow( + title: context.l10n.exportAccent, + values: [...palette, 'custom'], + selected: _custom ? 'custom' : widget.value, + leading: validExportColor(widget.value) + ? Container( + width: 18, + height: 18, + decoration: BoxDecoration( + color: busyMarkRgbHexColor(widget.value), + borderRadius: BorderRadius.circular(4), + ), + ) + : null, + labelFor: (v) => v == 'custom' ? context.l10n.exportCustom : v, + onSelected: (v) { + setState(() => _custom = v == 'custom'); + if (!_custom) widget.onChanged(v); + }, + ), + if (_custom) + BusyMarkGroupedTextEntry( + label: context.l10n.exportAccent, + initialValue: widget.value, + hintText: '#2563a5', + errorText: validExportColor(widget.value) + ? null + : context.l10n.exportInvalidColor, + onChanged: widget.onChanged, + ), + ], + ); +} diff --git a/lib/src/export/html_document_writer.dart b/lib/src/export/html_document_writer.dart index c5d55ab1..897490e0 100644 --- a/lib/src/export/html_document_writer.dart +++ b/lib/src/export/html_document_writer.dart @@ -9,6 +9,8 @@ import '../markdown/raw_html_policy.dart'; import '../visualization/visualization_models.dart'; import '../writerside/writerside_document.dart'; import 'html_export_links.dart'; +import 'html_export_styles.dart'; +import 'export_metadata_mapper.dart'; import 'html_export_models.dart'; import 'html_publication_plan.dart'; import 'html_rich_content.dart'; @@ -37,12 +39,16 @@ class HtmlDocumentWriter { required this.stylesheet, required this.warnings, this.limits = const HtmlExportLimits(), + this.options = const HtmlExportOptions(), + this.customCss = '', this.navigationLabel = 'Documentation', this.outlineLabel = 'On this page', this.workInProgressLabel = 'Work in progress', this.contentLabel = 'Content', this.disclosureLabel = 'Details', }); + final HtmlExportOptions options; + final String customCss; final HtmlPage page; final HtmlPublicationPlan plan; final HtmlExportLinks links; @@ -71,6 +77,8 @@ class HtmlDocumentWriter { ); Future write() async { + options.validateOrThrow(); + HtmlExportStyles.validateCss(customCss); var contentId = 'busymark-content'; while (page.ids.contains(contentId)) { contentId = '$contentId-main'; @@ -90,6 +98,7 @@ class HtmlDocumentWriter { if (article.querySelector('h1') == null) { article.nodes.insert(0, _el('h1', text: page.title)); } + final numbers = _prepareOutline(article); final body = _el( 'body', children: [ @@ -117,7 +126,7 @@ class HtmlDocumentWriter { 'main', attrs: {'id': contentId, 'tabindex': '-1'}, children: [ - if (page.outline.where((h) => h.level > 1).length > 1) + if (options.content.includeToc && page.outline.isNotEmpty) _el( 'nav', attrs: {'class': 'outline', 'aria-label': outlineLabel}, @@ -126,26 +135,7 @@ class HtmlDocumentWriter { 'details', children: [ _el('summary', text: outlineLabel), - _el( - 'ul', - children: [ - for (final h in page.outline.where( - (h) => h.level > 1, - )) - _el( - 'li', - children: [ - _el( - 'a', - text: h.title, - attrs: { - 'href': '#${Uri.encodeComponent(h.id)}', - }, - ), - ], - ), - ], - ), + _outline(numbers), ], ), ], @@ -155,18 +145,21 @@ class HtmlDocumentWriter { ), ], ); - final css = '$stylesheet\n${_rules.join('\n')}'; + final css = + '$stylesheet\n${HtmlExportStyles.generate(options)}\n${_rules.join('\n')}\n$customCss'; // Meta CSP cannot enforce frame-ancestors or sandbox. All active source // content has already been rejected. file: images need an explicit source // in browsers that assign each local document an opaque origin. + final embeddedSource = options.packaging == HtmlPackaging.singleFile + ? ' data:' + : ''; final csp = - "default-src 'none'; script-src 'none'; connect-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'; frame-src 'none'; font-src 'none'; img-src 'self' file:; media-src 'self' file:; style-src 'sha256-${base64.encode(sha256.convert(utf8.encode(css)).bytes)}'"; - final metadata = page.document.frontMatter; - final lang = metadata['lang'] ?? metadata['language'] ?? 'und'; - final language = - RegExp(r'^[A-Za-z]{2,8}(?:-[A-Za-z0-9]{1,8})*$').hasMatch(lang) - ? lang - : 'und'; + "default-src 'none'; script-src 'none'; connect-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'; frame-src 'none'; font-src 'none'; img-src 'self' file:$embeddedSource; media-src 'self' file:$embeddedSource; style-src 'sha256-${base64.encode(sha256.convert(utf8.encode(css)).bytes)}'"; + final metadata = const ExportMetadataMapper().map( + page.document, + titleOverride: page.title, + defaultLanguage: 'und', + ); final head = _el( 'head', children: [ @@ -182,22 +175,23 @@ class HtmlDocumentWriter { 'content': 'width=device-width, initial-scale=1', }, ), - _el('title', text: page.title), - for (final key in ['author', 'description', 'keywords']) - if (metadata[key] case final value?) - _el('meta', attrs: {'name': key, 'content': value}), - if (metadata['web-summary'] case final summary? - when !metadata.containsKey('description')) - _el('meta', attrs: {'name': 'description', 'content': summary}), + _el('title', text: metadata.title), + for (final entry in { + 'author': metadata.author, + 'description': metadata.description, + 'keywords': metadata.keywords.join(', '), + }.entries) + if (entry.value.isNotEmpty) + _el('meta', attrs: {'name': entry.key, 'content': entry.value}), _el('style', text: css), ], ); final root = _el( 'html', attrs: { - 'lang': language, - if ({'rtl', 'ltr', 'auto'}.contains(metadata['dir'])) - 'dir': metadata['dir']!, + 'lang': metadata.language, + if ({'rtl', 'ltr', 'auto'}.contains(page.document.frontMatter['dir'])) + 'dir': page.document.frontMatter['dir']!, }, children: [head, body], ); @@ -205,6 +199,73 @@ class HtmlDocumentWriter { return '\n${root.outerHtml}\n'; } + // The publication plan's headings are the same semantic headings used for + // IDs and links. Numbering is renderer-owned and never changes source blocks. + Map _prepareOutline(dom.Element article) { + final result = {}; + final elements = { + for (final h in article.querySelectorAll('h1,h2,h3,h4,h5,h6')) h.id: h, + }; + // Static API headings are added during rich-content preparation. Keep the + // single publication outline in the final document order before numbering. + final positions = { + for (final (index, id) in elements.keys.indexed) id: index, + }; + page.outline.sort( + (a, b) => (positions[a.id] ?? 0).compareTo(positions[b.id] ?? 0), + ); + if (!options.content.numberHeadings) return result; + final counts = List.filled(6, 0); + for (final heading in page.outline) { + final level = heading.level.clamp(1, 6); + counts[level - 1]++; + for (var i = level; i < 6; i++) { + counts[i] = 0; + } + final number = counts.take(level).join('.'); + result[heading.id] = number; + elements[heading.id]?.nodes.insert( + 0, + _el('span', text: '$number ', attrs: {'class': 'heading-number'}), + ); + } + return result; + } + + dom.Element _outline(Map numbers) { + final root = _el('ul'); + final stack = <({int level, dom.Element item})>[]; + for (final h in page.outline.where( + (h) => h.level <= options.content.tocDepth, + )) { + while (stack.isNotEmpty && stack.last.level >= h.level) { + stack.removeLast(); + } + var list = root; + if (stack.isNotEmpty) { + final parent = stack.last.item; + list = + parent.children.where((e) => e.localName == 'ul').firstOrNull ?? + _el('ul'); + if (list.parentNode == null) parent.nodes.add(list); + } + final item = _el( + 'li', + children: [ + _el( + 'a', + text: + '${numbers[h.id] == null ? '' : '${numbers[h.id]} '}${h.title}', + attrs: {'href': '#${Uri.encodeComponent(h.id)}'}, + ), + ], + ); + list.nodes.add(item); + stack.add((level: h.level, item: item)); + } + return root; + } + Future _navigation(List entries) async { final items = []; for (final entry in entries) { @@ -889,13 +950,10 @@ class HtmlDocumentWriter { BusyBlock block, ) async { final fontSize = block.kind == BusyBlockKind.heading - ? switch (block.attributes['level']) { - '1' => 39.1, - '2' => 29.75, - '3' => 22.1, - _ => 17.0, - } - : 17.0; + ? options.headingFontSize( + int.tryParse(block.attributes['level'] ?? '') ?? 1, + ) + : options.baseFontSize; final image = await rich.formula( expression, display, @@ -1137,7 +1195,34 @@ class HtmlDocumentWriter { ); void _validateBoundary(dom.Element root) { + // Bound serialization before constructing the final string. Repeated + // embedded images share one validated asset, but each occurrence adds its + // encoded bytes to the HTML output. + var outputBytes = 32; + void addBytes(int count) { + outputBytes += count; + if (outputBytes > limits.sourceBytes * 4) { + throw const HtmlExportException( + 'Generated HTML exceeds the output byte limit.', + ); + } + } + for (final element in [root, ...root.querySelectorAll('*')]) { + addBytes((element.localName?.length ?? 0) * 2 + 5); + for (final text in element.nodes.whereType()) { + addBytes( + utf8 + .encode( + element.localName == 'style' + ? text.data + : const HtmlEscape( + HtmlEscapeMode.element, + ).convert(text.data), + ) + .length, + ); + } if ({ 'script', 'iframe', @@ -1153,6 +1238,17 @@ class HtmlDocumentWriter { } for (final entry in element.attributes.entries) { final key = entry.key.toString(); + addBytes( + utf8.encode(key).length + + 4 + + utf8 + .encode( + const HtmlEscape( + HtmlEscapeMode.attribute, + ).convert(entry.value), + ) + .length, + ); if (key.startsWith('on') || key == 'style' || key.startsWith('busymark-source')) { @@ -1165,6 +1261,10 @@ class HtmlDocumentWriter { if (HtmlExportLinks.external(value) != null && key == 'href') { continue; } + if (links.assets.ownsEmbeddedUrl(value) && + (key == 'src' || element.attributes.containsKey('download'))) { + continue; + } final uri = Uri.tryParse(value); if (uri == null || uri.hasScheme || diff --git a/lib/src/export/html_export_assets.dart b/lib/src/export/html_export_assets.dart index d8d3caad..344da910 100644 --- a/lib/src/export/html_export_assets.dart +++ b/lib/src/export/html_export_assets.dart @@ -16,7 +16,14 @@ class HtmlExportAssets { required this.token, required this.warnings, this.limits = const HtmlExportLimits(), + this.packaging = HtmlPackaging.assetsDirectory, }); + final HtmlPackaging packaging; + final Map _embedded = {}; + final Set _ownedEmbeddedUrls = {}; + bool ownsEmbeddedUrl(String url) => _ownedEmbeddedUrls.contains(url); + bool get hasExternalAssets => + packaging == HtmlPackaging.assetsDirectory && filenames.isNotEmpty; final Directory directory; final String urlDirectory; final List allowedRoots; @@ -156,12 +163,35 @@ class HtmlExportAssets { _total + bytes.length > limits.totalAssetBytes) { throw const HtmlExportException('The export asset limit was reached.'); } - await directory.create(recursive: true); - await File(p.join(directory.path, name)).writeAsBytes(bytes, flush: true); + if (packaging == HtmlPackaging.singleFile) { + final mime = switch (extension) { + '.png' => 'image/png', + '.jpg' => 'image/jpeg', + '.gif' => 'image/gif', + '.svg' => 'image/svg+xml', + '.webp' => 'image/webp', + '.mp4' => 'video/mp4', + '.webm' => 'video/webm', + '.pdf' => 'application/pdf', + '.zip' => 'application/zip', + '.json' => 'application/json', + '.csv' => 'text/csv', + _ => 'text/plain', + }; + final url = 'data:$mime;base64,${base64.encode(bytes)}'; + _embedded[name] = url; + _ownedEmbeddedUrls.add(url); + } else { + await directory.create(recursive: true); + await File( + p.join(directory.path, name), + ).writeAsBytes(bytes, flush: true); + } filenames.add(name); _total += bytes.length; } - return '${Uri.encodeComponent(urlDirectory)}/${Uri.encodeComponent(name)}'; + return _embedded[name] ?? + '${Uri.encodeComponent(urlDirectory)}/${Uri.encodeComponent(name)}'; } static String safeSvg(String source) { diff --git a/lib/src/export/html_export_models.dart b/lib/src/export/html_export_models.dart index b48d2078..ba279fca 100644 --- a/lib/src/export/html_export_models.dart +++ b/lib/src/export/html_export_models.dart @@ -1,4 +1,6 @@ import '../markdown/markdown_model.dart'; +import 'export_options.dart'; +export 'export_options.dart'; import '../markdown/busymark_document.dart'; class HtmlExportWarning { @@ -82,11 +84,13 @@ class MarkdownHtmlExportRequest { this.overwrite = false, this.mode = MarkdownMode.commonMark, this.document, + this.options = const HtmlExportOptions(), }); final String source, filePath, workspaceRoot, destinationPath; final bool overwrite; final MarkdownMode mode; final BusyDocument? document; + final HtmlExportOptions options; } class HtmlExportResult { diff --git a/lib/src/export/html_export_service.dart b/lib/src/export/html_export_service.dart index 158dbda6..1ffd2498 100644 --- a/lib/src/export/html_export_service.dart +++ b/lib/src/export/html_export_service.dart @@ -19,6 +19,7 @@ import 'html_export_publisher.dart'; import 'html_publication_plan.dart'; import 'html_document_writer.dart'; import 'html_rich_content.dart'; +import 'html_export_styles.dart'; class HtmlExportService { const HtmlExportService({ @@ -45,6 +46,9 @@ class HtmlExportService { }) async { final token = cancellationToken ?? HtmlExportCancellationToken(); token.check(); + request.options.validateOrThrow(); + final customCss = await HtmlExportStyles.readCustomCss(request.options); + token.check(); if (utf8.encode(request.source).length > limits.sourceBytes) { throw const HtmlExportException( 'The document exceeds the source byte limit.', @@ -85,6 +89,8 @@ class HtmlExportService { plan, destination, site: false, + options: request.options, + customCss: customCss, overwrite: request.overwrite, roots: [ if (request.filePath.isNotEmpty) p.dirname(request.filePath), @@ -104,12 +110,16 @@ class HtmlExportService { required String instanceId, required String destinationPath, bool overwrite = false, + HtmlExportOptions options = const HtmlExportOptions(), WritersideProject? capturedProject, HtmlExportCancellationToken? cancellationToken, HtmlExportProgress? onProgress, }) async { final token = cancellationToken ?? HtmlExportCancellationToken(); token.check(); + options.validateOrThrow(); + final customCss = await HtmlExportStyles.readCustomCss(options); + token.check(); final project = capturedProject ?? await const WritersideProjectService( @@ -143,6 +153,8 @@ class HtmlExportService { plan, p.normalize(p.absolute(destinationPath)), site: true, + options: options, + customCss: customCss, overwrite: overwrite, roots: project.modules.map((m) => m.rootPath).toList(), modules: project.modules, @@ -156,6 +168,8 @@ class HtmlExportService { HtmlPublicationPlan plan, String destination, { required bool site, + required HtmlExportOptions options, + required String customCss, required bool overwrite, required List roots, List modules = const [], @@ -180,6 +194,7 @@ class HtmlExportService { final assets = HtmlExportAssets( directory: Directory(p.join(stage.path, assetName)), urlDirectory: assetName, + packaging: options.packaging, allowedRoots: canonicalRoots, token: token, warnings: warnings, @@ -202,6 +217,7 @@ class HtmlExportService { token: token, warnings: warnings, exportId: p.basename(stage.path), + options: options, math: math, visualization: visualization, limits: limits, @@ -237,6 +253,7 @@ class HtmlExportService { await captureGraphics(page, page.document.blocks); } final outputs = {}; + var outputBytes = 0; for (final (index, page) in plan.pages.indexed) { token.check(); onProgress?.call(index, plan.pages.length); @@ -246,9 +263,17 @@ class HtmlExportService { links: links, rich: rich, stylesheet: css, + options: options, + customCss: customCss, warnings: warnings, limits: limits, ).write(); + outputBytes += utf8.encode(outputs[page.filename]!).length; + if (outputBytes > limits.sourceBytes * 4) { + throw const HtmlExportException( + 'Generated HTML exceeds the output byte limit.', + ); + } } if (site) outputs['index.html'] = outputs[plan.startPage.filename]!; _validateOutputs(outputs, assets); @@ -278,7 +303,7 @@ class HtmlExportService { onProgress?.call(plan.pages.length, plan.pages.length); return HtmlExportResult( entryPointPath: site ? p.join(destination, 'index.html') : destination, - assetsPath: assets.filenames.isEmpty + assetsPath: !assets.hasExternalAssets ? null : p.join(site ? destination : p.dirname(destination), assetName), pageCount: plan.pages.length, @@ -393,7 +418,10 @@ class HtmlExportService { final doc = html.parse(entry.value); for (final element in doc.querySelectorAll('[href],[src]')) { final value = element.attributes['href'] ?? element.attributes['src']!; - if (HtmlExportLinks.external(value) != null) continue; + if (HtmlExportLinks.external(value) != null || + assets.ownsEmbeddedUrl(value)) { + continue; + } final uri = Uri.parse(value); final path = Uri.decodeComponent(uri.path); if (path.startsWith('${assets.urlDirectory}/')) { diff --git a/lib/src/export/html_export_styles.dart b/lib/src/export/html_export_styles.dart new file mode 100644 index 00000000..9d2ce2ab --- /dev/null +++ b/lib/src/export/html_export_styles.dart @@ -0,0 +1,94 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:csslib/parser.dart' as css_parser; +import 'package:csslib/visitor.dart' as css; +import 'export_options.dart'; + +/// Generated style data and bounded, inert user CSS. No resource is loaded by +/// this reader; custom styles cannot extend the export's resource authority. +abstract final class HtmlExportStyles { + static Future readCustomCss(HtmlExportOptions options) async { + options.validateOrThrow(); + final path = options.customCssPath; + if (path == null) return ''; + try { + final file = File(path); + if (await file.length() > HtmlExportOptions.maximumCssBytes) { + throw const ExportOptionsException([ + ExportOptionIssue('customCssSize'), + ]); + } + // Bound the read as well as the initial stat (the file may be edited). + final bytes = []; + await for (final chunk in file.openRead()) { + if (bytes.length + chunk.length > HtmlExportOptions.maximumCssBytes) { + throw const ExportOptionsException([ + ExportOptionIssue('customCssSize'), + ]); + } + bytes.addAll(chunk); + } + final source = utf8.decode(bytes); + validateCss(source); + return source; + } on ExportOptionsException { + rethrow; + } on Object { + throw const ExportOptionsException([ExportOptionIssue('customCssPath')]); + } + } + + static void validateCss(String source) { + // Disallow escaped identifiers and HTML terminators before CSS tokenization. + // This intentionally accepts a conservative stylesheet subset, not executable + // preprocessors, imports, browser extensions, or external dependencies. + if (source.contains('\\') || + source.contains('\u0000') || + RegExp( + r'[]; + final sheet = css_parser.parse(source, errors: errors); + final validator = _CssValidator(); + sheet.visit(validator); + if (errors.any((e) => e.level == css_parser.MessageLevel.severe) || + !validator.safe) { + throw const ExportOptionsException([ + ExportOptionIssue('customCssUnsafe'), + ]); + } + } + + static String generate(HtmlExportOptions options) { + options.validateOrThrow(); + const light = + '--fg:#20242b;--bg:#fff;--heading:#111827;--muted:#4b5563;--border:#d8dee6;--code:#f6f8fa;--inline-code:#f1f3f5;--surface:#f5f7fa;--table:#eef2f6;--warning:#fff6e9;--tip:#f0faf4;--note:#f1f7fd;--status:#713b12;--focus:#a34200;--math-filter:none;--link:var(--accent);'; + const dark = + '--fg:#e2e7ef;--bg:#15191f;--heading:#f4f6fa;--muted:#b5becc;--border:#46515f;--code:#202731;--inline-code:#28313c;--surface:#202630;--table:#2b3543;--warning:#372b1d;--tip:#1a3025;--note:#1c2b40;--status:#f4c396;--focus:#f2b86b;--math-filter:invert(1) hue-rotate(180deg);--link:color-mix(in srgb,var(--accent) 65%,white);'; + final family = options.bodyTypography == ExportBodyTypography.serif + ? '"Noto Serif",Georgia,serif' + : '"Noto Sans",system-ui,sans-serif'; + final palette = options.theme == HtmlExportTheme.dark ? dark : light; + return ':root{--accent:${options.accentColor};--body-font:$family;--body-size:${options.baseFontSize}px;--content-width:${options.contentMaxWidth}px;color-scheme:${options.theme == HtmlExportTheme.dark ? 'dark' : 'light'};$palette}\n' + '${options.theme == HtmlExportTheme.automatic ? '@media(prefers-color-scheme:dark){:root{color-scheme:dark;$dark}}' : ''}\n' + '@media print{:root{color-scheme:light;$light}}'; + } +} + +class _CssValidator extends css.Visitor { + bool safe = true; + @override + void visitUriTerm(css.UriTerm node) { + safe = false; + } + + @override + void visitImportDirective(css.ImportDirective node) { + safe = false; + } +} diff --git a/lib/src/export/html_export_ui.dart b/lib/src/export/html_export_ui.dart index 00a604ae..bda62501 100644 --- a/lib/src/export/html_export_ui.dart +++ b/lib/src/export/html_export_ui.dart @@ -5,7 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path/path.dart' as p; import 'package:url_launcher/url_launcher.dart'; -import '../app/app_settings.dart'; +import 'export_options_editor.dart'; import '../app/busymark_design.dart'; import '../app/busymark_dialogs.dart'; import '../app/localization.dart'; @@ -16,7 +16,6 @@ import '../visualization/visualization_providers.dart'; import '../workspace/workspace_controller.dart'; import '../workspace/workspace_model.dart'; import '../workspace/workspace_safety.dart'; -import '../writerside/writerside_model.dart'; import 'markdown_pdf_export_ui.dart' show canExportActiveMarkdown; import 'writerside_pdf_export_ui.dart' show canExportWritersidePdf; import 'html_export_models.dart'; @@ -42,48 +41,20 @@ Future exportWorkspaceToHtml(BuildContext context, WidgetRef ref) async { } final workspace = snapshot.workspace!; final headerBar = ref.read(linuxHeaderBarServiceProvider); - WritersideInstance? instance; - if (site) { - final instances = workspace.writersideModule!.instances - .where((i) => !i.isLibrary) - .toList(); - final stored = ref - .read(appSettingsControllerProvider) - .selectedWritersideInstanceId(workspace.rootPath); - var selected = - instances.where((i) => i.id == stored).firstOrNull ?? instances.first; - instance = await showBusyMarkModalDialog( - context, - headerBarService: headerBar.isAvailable ? headerBar : null, - builder: (context) => StatefulBuilder( - builder: (context, setState) => BusyMarkDialogShell( - title: context.l10n.exportAsHtml, - actions: [ - BusyMarkDialogButton( - label: context.l10n.cancel, - onPressed: () => Navigator.pop(context), - ), - BusyMarkDialogButton( - label: context.l10n.export, - suggested: true, - onPressed: () => Navigator.pop(context, selected), - ), - ], - children: [ - Text(context.l10n.htmlInstanceDescription), - BusyMarkComboRow( - title: context.l10n.htmlInstance, - values: instances, - selected: selected, - labelFor: (i) => i.name, - onSelected: (i) => setState(() => selected = i), - ), - ], - ), - ), - ); - if (instance == null || !context.mounted) return; - } + final selection = await showExportOptions( + context, + ref, + pdf: false, + instances: site + ? workspace.writersideModule!.instances + .where((i) => !i.isLibrary) + .toList() + : const [], + workspaceRoot: site ? workspace.rootPath : null, + ); + if (selection == null || !context.mounted) return; + final instance = selection.instance; + final options = selection.html!; final path = workspace.activeFilePath ?? workspace.markdown?.filePath ?? ''; final name = path.isEmpty ? context.l10n.untitledMarkdownFileName @@ -149,6 +120,7 @@ Future exportWorkspaceToHtml(BuildContext context, WidgetRef ref) async { workspaceRoot: workspace.rootPath, destinationPath: destination, overwrite: overwrite, + options: options, mode: workspace.markdown?.mode ?? MarkdownMode.commonMark, ); final selected = instance; @@ -166,6 +138,7 @@ Future exportWorkspaceToHtml(BuildContext context, WidgetRef ref) async { instanceId: selected!.id, destinationPath: destination, overwrite: overwrite, + options: options, cancellationToken: token, onProgress: progress, ) diff --git a/lib/src/export/html_release_smoke.dart b/lib/src/export/html_release_smoke.dart index 1ebd45df..32d73aa6 100644 --- a/lib/src/export/html_release_smoke.dart +++ b/lib/src/export/html_release_smoke.dart @@ -102,6 +102,43 @@ paths: if (document.warnings.isNotEmpty) { throw StateError('HTML smoke diagnostics: ${document.warnings.join('; ')}'); } + final customStyles = File(p.join(sourceRoot.path, 'custom.css')); + await customStyles.writeAsString('article { --custom-css-proof: applied; }'); + for (final variant in ['automatic-single', 'dark-assets']) { + final customized = await exporter.exportMarkdown( + MarkdownHtmlExportRequest( + source: markdown, + filePath: documentPath, + workspaceRoot: sourceRoot.path, + destinationPath: p.join(outputRoot.path, '$variant.html'), + mode: MarkdownMode.gfm, + overwrite: true, + options: HtmlExportOptions( + theme: variant == 'automatic-single' + ? HtmlExportTheme.automatic + : HtmlExportTheme.dark, + packaging: variant == 'automatic-single' + ? HtmlPackaging.singleFile + : HtmlPackaging.assetsDirectory, + bodyTypography: ExportBodyTypography.serif, + baseFontSize: 20, + contentMaxWidth: 1000, + accentColor: '#7651a8', + customCssPath: customStyles.path, + content: const ExportContentOptions( + includeToc: true, + tocDepth: 2, + numberHeadings: true, + ), + ), + ), + ); + if (customized.warnings.isNotEmpty) { + throw StateError( + 'Custom HTML diagnostics: ${customized.warnings.join('; ')}', + ); + } + } final module = Directory(p.join(sourceRoot.path, 'writerside')); Future put(String path, String source) async { final file = File(p.join(module.path, path)); @@ -142,10 +179,35 @@ paths: 'Writerside HTML smoke diagnostics: ${site.warnings.join('; ')}', ); } + final embeddedSite = await exporter.exportWriterside( + projectRoot: module.path, + moduleRoot: module.path, + instanceId: 'guide', + destinationPath: p.join(outputRoot.path, 'writerside-embedded'), + overwrite: true, + options: const HtmlExportOptions( + packaging: HtmlPackaging.singleFile, + theme: HtmlExportTheme.dark, + baseFontSize: 20, + bodyTypography: ExportBodyTypography.serif, + content: ExportContentOptions( + includeToc: true, + tocDepth: 2, + numberHeadings: true, + ), + ), + ); + if (embeddedSite.warnings.isNotEmpty) { + throw StateError( + 'Embedded Writerside diagnostics: ${embeddedSite.warnings.join('; ')}', + ); + } return { 'markdownHtml': document.entryPointPath, 'writersideHtml': site.entryPointPath, - 'htmlPages': site.pageCount + 1, + 'customHtml': p.join(outputRoot.path, 'automatic-single.html'), + 'embeddedWritersideHtml': embeddedSite.entryPointPath, + 'htmlPages': site.pageCount * 2 + 3, 'htmlWarnings': 0, }; } diff --git a/lib/src/export/html_rich_content.dart b/lib/src/export/html_rich_content.dart index 0747a64d..2327111d 100644 --- a/lib/src/export/html_rich_content.dart +++ b/lib/src/export/html_rich_content.dart @@ -33,10 +33,12 @@ class HtmlRichContent { required this.token, required this.warnings, required this.exportId, + this.options = const HtmlExportOptions(), this.math, this.visualization, this.limits = const HtmlExportLimits(), }); + final HtmlExportOptions options; final HtmlExportAssets assets; final HtmlExportCancellationToken token; final List warnings; @@ -157,7 +159,7 @@ class HtmlRichContent { editRevision: 0, em: fontSize, ex: fontSize / 2, - containerWidth: 800, + containerWidth: options.mathContainerWidth, renderProfile: 'html', ), ]); diff --git a/lib/src/export/markdown_export_mapper.dart b/lib/src/export/markdown_export_mapper.dart index 29c3c1d0..6243a8c9 100644 --- a/lib/src/export/markdown_export_mapper.dart +++ b/lib/src/export/markdown_export_mapper.dart @@ -1,21 +1,10 @@ import '../markdown/table_grid.dart'; -import 'package:path/path.dart' as p; import '../core/uri_utils.dart'; import '../markdown/busymark_document.dart'; import '../writerside/writerside_video.dart'; import 'markdown_export_document.dart'; - -const double busyMarkPdfBodyTextSize = 10.5; - -double busyMarkPdfHeadingTextSize(int level) => switch (level.clamp(1, 6)) { - 1 => 22, - 2 => 17, - 3 => 13.5, - 4 => 11.5, - 5 || 6 => busyMarkPdfBodyTextSize, - _ => busyMarkPdfBodyTextSize, -}; +import 'export_metadata_mapper.dart'; class MarkdownExportMapper { const MarkdownExportMapper(); @@ -25,52 +14,11 @@ class MarkdownExportMapper { Map blockOverrides = const {}, }) { return MarkdownExportDocument( - metadata: _metadata(document), + metadata: const ExportMetadataMapper().map(document), blocks: _mapBlocks(document.blocks, blockOverrides), ); } - MarkdownExportMetadata _metadata(BusyDocument document) { - final frontMatter = { - for (final entry in document.frontMatter.entries) - entry.key.toLowerCase().trim(): entry.value.trim(), - }; - final title = _firstNonEmpty([ - frontMatter['title'], - document.title, - document.filePath.isEmpty - ? null - : p.basenameWithoutExtension(document.filePath), - 'Untitled', - ])!; - final keywords = _firstNonEmpty([ - frontMatter['keywords'], - frontMatter['tags'], - ]); - return MarkdownExportMetadata( - title: title, - author: - _firstNonEmpty([frontMatter['author'], frontMatter['authors']]) ?? '', - description: - _firstNonEmpty([ - frontMatter['description'], - frontMatter['summary'], - ]) ?? - '', - language: _normalizedLanguage( - _firstNonEmpty([frontMatter['lang'], frontMatter['language']]), - ), - keywords: keywords == null - ? const [] - : keywords - .split(RegExp(r'[,;]')) - .map((value) => value.trim()) - .where((value) => value.isNotEmpty) - .take(32) - .toList(growable: false), - ); - } - List _mapBlocks( List blocks, Map blockOverrides, @@ -295,10 +243,7 @@ class MarkdownExportMapper { int.tryParse(block.attributes['level'] ?? '')?.clamp(1, 6) ?? 1; return MarkdownExportBlock( kind: MarkdownExportBlockKind.heading, - inlines: _mapInlines( - block.inlines, - mathEm: busyMarkPdfHeadingTextSize(level), - ), + inlines: _mapInlines(block.inlines), attributes: { 'level': level, if (_safeAnchor(block.attributes['id']) case final id?) 'id': id, @@ -407,20 +352,12 @@ class MarkdownExportMapper { ); } - List _mapInlines( - List inlines, { - double mathEm = busyMarkPdfBodyTextSize, - }) { - return List.unmodifiable( - inlines.map((inline) => _mapInline(inline, mathEm: mathEm)), - ); + List _mapInlines(List inlines) { + return List.unmodifiable(inlines.map(_mapInline)); } - MarkdownExportInline _mapInline( - BusyInline inline, { - double mathEm = busyMarkPdfBodyTextSize, - }) { - final children = _mapInlines(inline.children, mathEm: mathEm); + MarkdownExportInline _mapInline(BusyInline inline) { + final children = _mapInlines(inline.children); return switch (inline.kind) { BusyInlineKind.text => MarkdownExportInline( kind: MarkdownExportInlineKind.text, @@ -460,8 +397,6 @@ class MarkdownExportMapper { attributes: { 'mathId': inline.attributes['expressionId'] ?? inline.text, 'display': 'false', - 'renderEm': '$mathEm', - 'renderEx': '${mathEm / 2}', if (inline.attributes['mathSourceForm'] case final sourceForm?) 'sourceForm': sourceForm, }, @@ -578,22 +513,4 @@ class MarkdownExportMapper { ? normalized : null; } - - String _normalizedLanguage(String? value) { - final normalized = value?.trim().replaceAll('_', '-').toLowerCase(); - if (normalized == null || - !RegExp(r'^[a-z]{2,3}(?:-[a-z]{2})?$').hasMatch(normalized)) { - return 'en'; - } - return normalized.split('-').first; - } - - String? _firstNonEmpty(Iterable values) { - for (final value in values) { - if (value != null && value.trim().isNotEmpty) { - return value.trim(); - } - } - return null; - } } diff --git a/lib/src/export/markdown_math_export.dart b/lib/src/export/markdown_math_export.dart index e02d70a1..40f816f3 100644 --- a/lib/src/export/markdown_math_export.dart +++ b/lib/src/export/markdown_math_export.dart @@ -36,15 +36,21 @@ class MarkdownMathExportRenderer { final int maximumExpressions; final int maximumGeneratedBytes; static const _svgPreprocessor = MathSvgPreprocessor(); + // Bundled Noto Sans and Noto Serif OS/2 sxHeight=536, unitsPerEm=1000. + static const _notoXHeightRatio = 0.536; Future prepare({ required MarkdownExportDocument document, required Directory exportRoot, - required double containerWidth, + required PdfExportOptions options, required MarkdownPdfCancellationToken cancellationToken, }) async { + options.validateOrThrow(); final annotated = _annotate(document); - final candidates = _mathCandidates(annotated).toList(growable: false); + final candidates = _mathCandidates( + annotated, + options, + ).toList(growable: false); if (candidates.isEmpty) { return MarkdownMathExportPreparation( document: document, @@ -74,7 +80,7 @@ class MarkdownMathExportRenderer { editRevision: 0, em: item.em, ex: item.ex, - containerWidth: containerWidth, + containerWidth: options.geometry.contentWidthPt, renderProfile: 'pdf', ), ]); @@ -215,9 +221,11 @@ class MarkdownMathExportRenderer { Iterable<_MathExportCandidate> _mathCandidates( MarkdownExportDocument document, + PdfExportOptions options, ) sync* { Iterable<_MathExportCandidate> inlines( List values, + double size, ) sync* { for (final value in values) { if (value.kind == MarkdownExportInlineKind.math) { @@ -225,11 +233,11 @@ class MarkdownMathExportRenderer { renderKey: value.attributes['mathRenderKey']!, expression: value.text, display: false, - em: double.tryParse(value.attributes['renderEm'] ?? '') ?? 10.5, - ex: double.tryParse(value.attributes['renderEx'] ?? '') ?? 5.25, + em: size, + ex: size * _notoXHeightRatio, ); } - yield* inlines(value.children); + yield* inlines(value.children, size); } } @@ -237,16 +245,19 @@ class MarkdownMathExportRenderer { List values, ) sync* { for (final value in values) { + final size = value.kind == MarkdownExportBlockKind.heading + ? options.headingFontSize((value.attributes['level'] as int?) ?? 1) + : options.bodyFontSize; if (value.kind == MarkdownExportBlockKind.math) { yield _MathExportCandidate( renderKey: value.attributes['mathRenderKey']! as String, expression: value.text, display: true, - em: 10.5, - ex: 5.25, + em: size, + ex: size * _notoXHeightRatio, ); } - yield* inlines(value.inlines); + yield* inlines(value.inlines, size); yield* blocks(value.children); } } diff --git a/lib/src/export/markdown_pdf_export_service.dart b/lib/src/export/markdown_pdf_export_service.dart index 5f1949bc..75a48431 100644 --- a/lib/src/export/markdown_pdf_export_service.dart +++ b/lib/src/export/markdown_pdf_export_service.dart @@ -51,6 +51,7 @@ class MarkdownPdfExportService { }) async { final token = cancellationToken ?? MarkdownPdfCancellationToken(); token.throwIfCancelled(); + request.options.validateOrThrow(); final executable = compilerLocator.locate(); if (executable == null) { throw const MarkdownPdfExportException( @@ -108,7 +109,7 @@ class MarkdownPdfExportService { : await mathRenderer!.prepare( document: mappedDocument, exportRoot: exportRoot, - containerWidth: _pdfContentWidth(request.options), + options: request.options, cancellationToken: token, ); token.throwIfCancelled(); @@ -211,27 +212,6 @@ class MarkdownPdfExportService { } } - double _pdfContentWidth(MarkdownPdfOptions options) { - final pageWidth = switch (options.pageSize) { - MarkdownPdfPageSize.a4 => 595.28, - MarkdownPdfPageSize.letter => 612.0, - }; - final pageHeight = switch (options.pageSize) { - MarkdownPdfPageSize.a4 => 841.89, - MarkdownPdfPageSize.letter => 792.0, - }; - final horizontalMargin = switch (options.margin) { - MarkdownPdfMargin.narrow => 36.0, - MarkdownPdfMargin.normal => 57.0, - MarkdownPdfMargin.wide => 78.0, - }; - final orientedWidth = - options.orientation == MarkdownPdfOrientation.landscape - ? pageHeight - : pageWidth; - return orientedWidth - 2 * horizontalMargin; - } - static Future _loadBundledTemplate() { return rootBundle.loadString('assets/export/markdown.typ'); } diff --git a/lib/src/export/markdown_pdf_export_ui.dart b/lib/src/export/markdown_pdf_export_ui.dart index ac82bb85..e7de3fb5 100644 --- a/lib/src/export/markdown_pdf_export_ui.dart +++ b/lib/src/export/markdown_pdf_export_ui.dart @@ -9,7 +9,6 @@ import 'package:url_launcher/url_launcher.dart'; import '../app/busymark_dialogs.dart'; import '../app/busymark_design.dart'; -import '../app/busymark_glyphs.dart'; import '../app/busymark_toast.dart'; import '../app/localization.dart'; import '../platform/linux_header_bar_service.dart'; @@ -18,6 +17,7 @@ import '../workspace/workspace_model.dart'; import '../workspace/workspace_controller.dart'; import '../visualization/visualization_providers.dart'; import 'markdown_visualization_export.dart'; +import 'export_options_editor.dart'; import 'markdown_math_export.dart'; import 'markdown_pdf_export_service.dart'; import 'markdown_pdf_models.dart'; @@ -76,14 +76,9 @@ Future exportActiveMarkdownToPdf( } final workspace = snapshot.workspace!; final headerBar = ref.read(linuxHeaderBarServiceProvider); - final options = await showBusyMarkModalDialog( - context, - headerBarService: headerBar.isAvailable ? headerBar : null, - builder: (context) => const _MarkdownPdfOptionsDialog(), - ); - if (options == null || !context.mounted) { - return; - } + final selection = await showExportOptions(context, ref, pdf: true); + if (selection == null || !context.mounted) return; + final options = selection.pdf!; final activePath = workspace.activeFilePath ?? workspace.markdown?.filePath; final baseName = activePath == null || activePath.isEmpty @@ -251,105 +246,6 @@ Future _showPdfExportError( ); } -class _MarkdownPdfOptionsDialog extends StatefulWidget { - const _MarkdownPdfOptionsDialog(); - - @override - State<_MarkdownPdfOptionsDialog> createState() => - _MarkdownPdfOptionsDialogState(); -} - -class _MarkdownPdfOptionsDialogState extends State<_MarkdownPdfOptionsDialog> { - var _options = const MarkdownPdfOptions(); - - @override - Widget build(BuildContext context) { - return BusyMarkDialogShell( - title: context.l10n.exportAsPdf, - maxWidth: 520, - actions: [ - BusyMarkDialogButton( - label: context.l10n.cancel, - onPressed: () => Navigator.pop(context), - ), - BusyMarkDialogButton( - label: context.l10n.export, - icon: BusyMarkGlyphs.exportPdf, - suggested: true, - onPressed: () => Navigator.pop(context, _options), - ), - ], - children: [ - Text(context.l10n.pdfExportDescription), - BusyMarkGroupedList( - filled: true, - children: [ - BusyMarkComboRow( - title: context.l10n.pdfPageSize, - values: MarkdownPdfPageSize.values, - selected: _options.pageSize, - labelFor: (value) => switch (value) { - MarkdownPdfPageSize.a4 => context.l10n.pdfPageSizeA4, - MarkdownPdfPageSize.letter => context.l10n.pdfPageSizeLetter, - }, - onSelected: (value) => - setState(() => _options = _options.copyWith(pageSize: value)), - ), - BusyMarkComboRow( - title: context.l10n.pdfOrientation, - values: MarkdownPdfOrientation.values, - selected: _options.orientation, - labelFor: (value) => switch (value) { - MarkdownPdfOrientation.portrait => context.l10n.pdfPortrait, - MarkdownPdfOrientation.landscape => context.l10n.pdfLandscape, - }, - onSelected: (value) => setState( - () => _options = _options.copyWith(orientation: value), - ), - ), - BusyMarkComboRow( - title: context.l10n.pdfMargins, - values: MarkdownPdfMargin.values, - selected: _options.margin, - labelFor: (value) => switch (value) { - MarkdownPdfMargin.narrow => context.l10n.pdfMarginNarrow, - MarkdownPdfMargin.normal => context.l10n.pdfMarginNormal, - MarkdownPdfMargin.wide => context.l10n.pdfMarginWide, - }, - onSelected: (value) => - setState(() => _options = _options.copyWith(margin: value)), - ), - BusyMarkSwitchRow( - title: context.l10n.pdfIncludePageNumbers, - value: _options.pageNumbers, - onChanged: (value) => setState( - () => _options = _options.copyWith(pageNumbers: value), - ), - ), - ], - ), - const SizedBox(height: BusyMarkSpacing.md), - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Padding( - padding: EdgeInsetsDirectional.only(top: 2), - child: Icon(BusyMarkGlyphs.info, size: BusyMarkSizes.iconSm), - ), - const SizedBox(width: BusyMarkSpacing.sm), - Expanded( - child: Text( - context.l10n.pdfRemoteImagesNote, - style: Theme.of(context).textTheme.bodySmall, - ), - ), - ], - ), - ], - ); - } -} - class _MarkdownPdfProgressDialog extends StatefulWidget { const _MarkdownPdfProgressDialog({ required this.operation, diff --git a/lib/src/export/markdown_pdf_models.dart b/lib/src/export/markdown_pdf_models.dart index dea0d12b..4985e5ac 100644 --- a/lib/src/export/markdown_pdf_models.dart +++ b/lib/src/export/markdown_pdf_models.dart @@ -1,57 +1,10 @@ import 'package:flutter/foundation.dart'; import '../markdown/markdown_model.dart'; +import 'export_options.dart'; import '../markdown/busymark_document.dart'; -enum MarkdownPdfPageSize { a4, letter } - -enum MarkdownPdfOrientation { portrait, landscape } - -enum MarkdownPdfMargin { narrow, normal, wide } - -@immutable -class MarkdownPdfOptions { - const MarkdownPdfOptions({ - this.pageSize = MarkdownPdfPageSize.a4, - this.orientation = MarkdownPdfOrientation.portrait, - this.margin = MarkdownPdfMargin.normal, - this.pageNumbers = true, - }); - - final MarkdownPdfPageSize pageSize; - final MarkdownPdfOrientation orientation; - final MarkdownPdfMargin margin; - final bool pageNumbers; - - MarkdownPdfOptions copyWith({ - MarkdownPdfPageSize? pageSize, - MarkdownPdfOrientation? orientation, - MarkdownPdfMargin? margin, - bool? pageNumbers, - }) { - return MarkdownPdfOptions( - pageSize: pageSize ?? this.pageSize, - orientation: orientation ?? this.orientation, - margin: margin ?? this.margin, - pageNumbers: pageNumbers ?? this.pageNumbers, - ); - } - - Map toJson() { - final (horizontalMargin, verticalMargin) = switch (margin) { - MarkdownPdfMargin.narrow => (36, 36), - MarkdownPdfMargin.normal => (57, 57), - MarkdownPdfMargin.wide => (78, 72), - }; - return { - 'paper': pageSize == MarkdownPdfPageSize.a4 ? 'a4' : 'us-letter', - 'landscape': orientation == MarkdownPdfOrientation.landscape, - 'marginHorizontalPt': horizontalMargin, - 'marginVerticalPt': verticalMargin, - 'pageNumbers': pageNumbers, - }; - } -} +export 'export_options.dart'; enum MarkdownPdfWarningCode { remoteImageSkipped, @@ -92,7 +45,7 @@ class MarkdownPdfExportRequest { final String filePath; final String workspaceRoot; final String destinationPath; - final MarkdownPdfOptions options; + final PdfExportOptions options; final bool overwrite; final MarkdownMode mode; diff --git a/lib/src/export/typst_compiler.dart b/lib/src/export/typst_compiler.dart index 3455276f..322f61ec 100644 --- a/lib/src/export/typst_compiler.dart +++ b/lib/src/export/typst_compiler.dart @@ -84,8 +84,11 @@ class DartTypstCommandRunner implements TypstCommandRunner { try { process = await Process.start( executable, - const [ + [ 'compile', + '--ignore-system-fonts', + '--font-path', + _fontDirectory(executable), '--root', '.', '--format', @@ -101,6 +104,7 @@ class DartTypstCommandRunner implements TypstCommandRunner { ], workingDirectory: workingDirectory.path, environment: { + 'TYPST_FONT_PATHS': _fontDirectory(executable), 'TYPST_PACKAGE_PATH': p.join(workingDirectory.path, 'packages'), 'TYPST_PACKAGE_CACHE_PATH': p.join(workingDirectory.path, 'cache'), }, @@ -170,6 +174,13 @@ class DartTypstCommandRunner implements TypstCommandRunner { } } + String _fontDirectory(String executable) => p.join( + p.dirname(p.dirname(p.dirname(executable))), + 'share', + 'busymark', + 'fonts', + ); + Future _collectBounded(Stream> stream) async { final bytes = []; await for (final chunk in stream) { diff --git a/lib/src/export/typst_payload_builder.dart b/lib/src/export/typst_payload_builder.dart index 64ce21bf..a7216453 100644 --- a/lib/src/export/typst_payload_builder.dart +++ b/lib/src/export/typst_payload_builder.dart @@ -6,13 +6,32 @@ class TypstPayloadBuilder { Map build({ required MarkdownExportDocument document, - required MarkdownPdfOptions options, + required PdfExportOptions options, required Map assets, }) { + options.validateOrThrow(); return { - 'schemaVersion': 1, + 'schemaVersion': 2, 'metadata': document.metadata.toJson(), - 'options': options.toJson(), + 'options': { + 'page': options.geometry.toJson(), + 'typography': { + 'bodyFont': options.bodyFont, + 'codeFont': options.codeFont, + 'bodySizePt': options.bodyFontSize, + 'codeSizePt': options.codeFontSize, + 'headingSizesPt': [ + for (var level = 1; level <= 6; level++) + options.headingFontSize(level), + ], + }, + 'content': options.content.toJson(), + 'header': options.header.name, + 'footer': options.footer.name, + 'pageNumbers': options.pageNumbers.name, + 'showHeaderFooterOnFirstPage': options.showHeaderFooterOnFirstPage, + 'accentColor': options.accentColor.toLowerCase(), + }, 'blocks': [for (final block in document.blocks) _block(block, assets)], }; } diff --git a/lib/src/export/writerside_pdf_export_ui.dart b/lib/src/export/writerside_pdf_export_ui.dart index 84906f21..1a79166b 100644 --- a/lib/src/export/writerside_pdf_export_ui.dart +++ b/lib/src/export/writerside_pdf_export_ui.dart @@ -7,7 +7,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path/path.dart' as p; import 'package:url_launcher/url_launcher.dart'; -import '../app/app_settings.dart'; +import 'export_options_editor.dart'; import '../app/busymark_design.dart'; import '../app/busymark_dialogs.dart'; import '../app/busymark_toast.dart'; @@ -21,7 +21,6 @@ import '../workspace/workspace_safety.dart'; import '../writerside/writerside_model.dart'; import 'markdown_math_export.dart'; import 'markdown_pdf_export_service.dart'; -import 'markdown_pdf_models.dart'; import 'markdown_visualization_export.dart'; import 'writerside_pdf_export_service.dart'; import 'writerside_pdf_models.dart'; @@ -73,31 +72,15 @@ Future exportWritersideModuleToPdf( final instances = module.instances .where((instance) => !instance.isLibrary) .toList(growable: false); - final storedInstanceId = ref - .read(appSettingsControllerProvider) - .selectedWritersideInstanceId(workspace.rootPath); - final initialInstance = instances - .where((instance) => instance.id == storedInstanceId) - .firstOrNull; final headerBar = ref.read(linuxHeaderBarServiceProvider); - final selection = - await showBusyMarkModalEditorDialog<_WritersidePdfSelection>( - context, - headerBarService: headerBar.isAvailable ? headerBar : null, - maxWidth: BusyMarkSizes.dialog, - builder: (context) => _WritersidePdfOptionsDialog( - instances: instances, - initialInstance: initialInstance ?? instances.first, - ), - ); - if (selection == null || !context.mounted) { - return; - } - unawaited( - ref - .read(appSettingsControllerProvider.notifier) - .selectWritersideInstance(workspace.rootPath, selection.instance.id), + final selection = await showExportOptions( + context, + ref, + pdf: true, + instances: instances, + workspaceRoot: workspace.rootPath, ); + if (selection == null || !context.mounted) return; final location = await getSaveLocation( acceptedTypeGroups: [ XTypeGroup( @@ -106,7 +89,7 @@ Future exportWritersideModuleToPdf( mimeTypes: const ['application/pdf'], ), ], - suggestedName: '${selection.instance.id}.pdf', + suggestedName: '${selection.instance!.id}.pdf', initialDirectory: module.rootPath, confirmButtonText: context.l10n.export, ); @@ -130,10 +113,10 @@ Future exportWritersideModuleToPdf( final request = WritersidePdfExportRequest( moduleRoot: module.rootPath, projectRoot: workspace.rootPath, - instanceId: selection.instance.id, + instanceId: selection.instance!.id, destinationPath: destination, overwrite: overwrite, - options: selection.options, + options: selection.pdf!, ); final outcome = await showBusyMarkModalDialog<_WritersidePdfOutcome>( context, @@ -170,129 +153,6 @@ Future exportWritersideModuleToPdf( ); } -class _WritersidePdfOptionsDialog extends StatefulWidget { - const _WritersidePdfOptionsDialog({ - required this.instances, - required this.initialInstance, - }); - - final List instances; - final WritersideInstance initialInstance; - - @override - State<_WritersidePdfOptionsDialog> createState() => - _WritersidePdfOptionsDialogState(); -} - -class _WritersidePdfOptionsDialogState - extends State<_WritersidePdfOptionsDialog> { - late WritersideInstance _instance; - var _pageSize = MarkdownPdfPageSize.a4; - var _orientation = MarkdownPdfOrientation.portrait; - var _margin = MarkdownPdfMargin.normal; - var _pageNumbers = true; - - @override - void initState() { - super.initState(); - _instance = widget.initialInstance; - } - - @override - Widget build(BuildContext context) { - return BusyMarkModalEditorScaffold( - title: context.l10n.exportWritersideAsPdf, - cancelLabel: context.l10n.cancel, - saveLabel: context.l10n.export, - onCancel: () => Navigator.pop(context), - onSave: _submit, - children: [ - BusyMarkGroupedList( - title: context.l10n.writersidePdfContent, - filled: true, - children: [ - BusyMarkComboRow( - title: context.l10n.instanceName, - values: widget.instances, - selected: _instance, - labelFor: (instance) => '${instance.name} (${instance.id})', - onSelected: (instance) => setState(() => _instance = instance), - ), - ], - ), - BusyMarkGroupedList( - title: context.l10n.writersidePdfPage, - filled: true, - children: [ - BusyMarkComboRow( - title: context.l10n.pdfPageSize, - values: MarkdownPdfPageSize.values, - selected: _pageSize, - labelFor: (value) => switch (value) { - MarkdownPdfPageSize.a4 => context.l10n.pdfPageSizeA4, - MarkdownPdfPageSize.letter => context.l10n.pdfPageSizeLetter, - }, - onSelected: (value) => setState(() => _pageSize = value), - ), - BusyMarkComboRow( - title: context.l10n.pdfOrientation, - values: MarkdownPdfOrientation.values, - selected: _orientation, - labelFor: (value) => switch (value) { - MarkdownPdfOrientation.portrait => context.l10n.pdfPortrait, - MarkdownPdfOrientation.landscape => context.l10n.pdfLandscape, - }, - onSelected: (value) => setState(() => _orientation = value), - ), - BusyMarkComboRow( - title: context.l10n.pdfMargins, - values: MarkdownPdfMargin.values, - selected: _margin, - labelFor: (value) => switch (value) { - MarkdownPdfMargin.narrow => context.l10n.pdfMarginNarrow, - MarkdownPdfMargin.normal => context.l10n.pdfMarginNormal, - MarkdownPdfMargin.wide => context.l10n.pdfMarginWide, - }, - onSelected: (value) => setState(() => _margin = value), - ), - BusyMarkSwitchRow( - title: context.l10n.pdfIncludePageNumbers, - value: _pageNumbers, - onChanged: (value) => setState(() => _pageNumbers = value), - ), - ], - ), - const SizedBox(height: BusyMarkSpacing.lg), - ], - ); - } - - void _submit() { - Navigator.pop( - context, - _WritersidePdfSelection( - instance: _instance, - options: MarkdownPdfOptions( - pageSize: _pageSize, - orientation: _orientation, - margin: _margin, - pageNumbers: _pageNumbers, - ), - ), - ); - } -} - -class _WritersidePdfSelection { - const _WritersidePdfSelection({ - required this.instance, - required this.options, - }); - - final WritersideInstance instance; - final MarkdownPdfOptions options; -} - class _WritersidePdfProgressDialog extends StatefulWidget { const _WritersidePdfProgressDialog({ required this.operation, @@ -463,7 +323,3 @@ String _withPdfExtension(String path) { ? normalized : '$normalized.pdf'; } - -extension _FirstOrNull on Iterable { - T? get firstOrNull => isEmpty ? null : first; -} diff --git a/lib/src/export/writerside_pdf_models.dart b/lib/src/export/writerside_pdf_models.dart index f7403934..b66b7ac3 100644 --- a/lib/src/export/writerside_pdf_models.dart +++ b/lib/src/export/writerside_pdf_models.dart @@ -10,7 +10,7 @@ class WritersidePdfExportRequest { required this.destinationPath, required this.overwrite, this.projectRoot, - this.options = const MarkdownPdfOptions(), + this.options = const PdfExportOptions(), }); final String moduleRoot; @@ -18,7 +18,7 @@ class WritersidePdfExportRequest { final String instanceId; final String destinationPath; final bool overwrite; - final MarkdownPdfOptions options; + final PdfExportOptions options; } @immutable diff --git a/lib/src/math/math_models.dart b/lib/src/math/math_models.dart index d4a59ed8..cca4937e 100644 --- a/lib/src/math/math_models.dart +++ b/lib/src/math/math_models.dart @@ -37,7 +37,10 @@ class MathRenderRequest { final double containerWidth; final String renderProfile; - double get widthBucket => (containerWidth / 16).round() * 16.0; + // Preview resizes share cache buckets. Exports must use their real geometry. + double get renderWidth => renderProfile == 'preview' + ? (containerWidth / 16).round() * 16.0 + : containerWidth; String get cacheKey => sha256 .convert( @@ -53,7 +56,7 @@ class MathRenderRequest { renderProfile, em.toStringAsFixed(3), ex.toStringAsFixed(3), - widthBucket.toStringAsFixed(0), + renderWidth.toString(), ].join('\u0000'), ), ) diff --git a/lib/src/math/math_renderer.dart b/lib/src/math/math_renderer.dart index 2d1900ad..c6c87510 100644 --- a/lib/src/math/math_renderer.dart +++ b/lib/src/math/math_renderer.dart @@ -67,7 +67,7 @@ class MathRenderer { 'display': request.display, 'em': request.em, 'ex': request.ex, - 'containerWidth': request.widthBucket, + 'containerWidth': request.renderWidth, 'renderProfile': request.renderProfile, 'svgIdPrefix': 'bm-${request.cacheKey.substring(0, 16)}', }); diff --git a/lib/src/visualization/visualization_release_smoke.dart b/lib/src/visualization/visualization_release_smoke.dart index 22231cbf..65f6a5ef 100644 --- a/lib/src/visualization/visualization_release_smoke.dart +++ b/lib/src/visualization/visualization_release_smoke.dart @@ -271,7 +271,7 @@ Future runVisualizationReleaseSmoke(String reportPath) async { filePath: p.join(workingDirectory.path, 'visualization-smoke.md'), workspaceRoot: workingDirectory.path, destinationPath: pdfPath, - options: const MarkdownPdfOptions(), + options: const PdfExportOptions(), overwrite: true, ), ); @@ -291,6 +291,55 @@ Future runVisualizationReleaseSmoke(String reportPath) async { checks['pdfEmbeddedImages'] = embeddedImages; checks['pdfPath'] = pdfPath; + final customizedPdf = + await MarkdownPdfExportService( + visualizationRenderer: MarkdownVisualizationExportRenderer( + coordinator: coordinator, + ), + mathRenderer: MarkdownMathExportRenderer( + coordinator: mathCoordinator, + ), + ).export( + MarkdownPdfExportRequest( + source: _pdfSource, + filePath: p.join(workingDirectory.path, 'visualization-smoke.md'), + workspaceRoot: workingDirectory.path, + destinationPath: p.join(reportFile.parent.path, 'customized.pdf'), + overwrite: true, + options: const PdfExportOptions( + pageSize: PdfPageSize.custom, + customWidthMm: 240, + customHeightMm: 320, + margin: PdfMarginPreset.custom, + customMargins: PdfMargins( + top: 18, + right: 20, + bottom: 25, + left: 30, + ), + bodyTypography: ExportBodyTypography.sansSerif, + bodyFontSize: 14, + codeFontSize: 11, + content: ExportContentOptions( + includeToc: true, + tocDepth: 3, + numberHeadings: true, + ), + accentColor: '#7651a8', + header: PdfRunningText.documentTitle, + footer: PdfRunningText.documentTitle, + pageNumbers: PdfPageNumberPosition.bottomRight, + showHeaderFooterOnFirstPage: false, + ), + ), + ); + if (customizedPdf.warnings.isNotEmpty) { + throw StateError( + 'Customized PDF: ${customizedPdf.warnings.map((w) => w.destination).join('; ')}', + ); + } + checks['customPdfPath'] = customizedPdf.destinationPath; + await checkpoint('exporting offline HTML documents'); checks.addAll( await runHtmlReleaseSmoke( diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index ff692ddd..55fb617a 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -94,6 +94,17 @@ add_custom_target(busymark_typst ALL ) add_dependencies(${BINARY_NAME} busymark_typst) +# Bundle Noto families for controlled PDF typography and script fallback. +# Font discovery at runtime is restricted to this directory, never host fonts. +find_path(BUSYMARK_NOTO_FONT_DIR NAMES NotoSans-Regular.ttf + HINTS "$ENV{CRAFT_STAGE}/usr/share/fonts/truetype/noto" + PATHS "/usr/share/fonts/truetype/noto") +foreach(FONT NotoSans-Regular.ttf NotoSans-Bold.ttf NotoSerif-Regular.ttf NotoSerif-Bold.ttf NotoSansMono-Regular.ttf) + if(NOT EXISTS "${BUSYMARK_NOTO_FONT_DIR}/${FONT}") + message(FATAL_ERROR "PDF fonts missing: ${FONT}. Install fonts-noto-core and fonts-noto-mono or set BUSYMARK_NOTO_FONT_DIR.") + endif() +endforeach() + # Offline visualization engines and the pinned D2 CLI. JavaScript is bundled # at build time; Node.js is not installed in or required by the application. set(VISUALIZATION_WEB_DIR "${CMAKE_BINARY_DIR}/visualization/web") @@ -204,6 +215,18 @@ install(PROGRAMS "${TYPST_EXECUTABLE}" DESTINATION "${CMAKE_INSTALL_PREFIX}/libexec/busymark" COMPONENT Runtime) +install(DIRECTORY "${BUSYMARK_NOTO_FONT_DIR}/" + DESTINATION "${CMAKE_INSTALL_PREFIX}/share/busymark/fonts" + COMPONENT Runtime FILES_MATCHING PATTERN "Noto*.ttf") +foreach(FONT_PACKAGE fonts-noto-core fonts-noto-mono) + find_file(${FONT_PACKAGE}_LICENSE NAMES copyright + HINTS "$ENV{CRAFT_STAGE}/usr/share/doc/${FONT_PACKAGE}" + PATHS "/usr/share/doc/${FONT_PACKAGE}" NO_DEFAULT_PATH) + if(${FONT_PACKAGE}_LICENSE) + install(FILES "${${FONT_PACKAGE}_LICENSE}" + DESTINATION "${CMAKE_INSTALL_PREFIX}/share/licenses/${FONT_PACKAGE}" COMPONENT Runtime) + endif() +endforeach() install(FILES "${TYPST_LICENSE}" "${TYPST_NOTICE}" "${TYPST_VERSION_FILE}" DESTINATION "${CMAKE_INSTALL_PREFIX}/share/licenses/typst" COMPONENT Runtime) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index dd320f4d..43be85f1 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -68,6 +68,8 @@ parts: build-snaps: - node/24/stable build-packages: + - fonts-noto-core + - fonts-noto-mono - curl - libhandy-1-dev - libsecret-1-dev @@ -94,6 +96,7 @@ parts: - libxcb1 - git - fonts-noto-core + - fonts-noto-mono - openssh-client - util-linux - yaru-theme-gtk diff --git a/test/src/export_options_editor_test.dart b/test/src/export_options_editor_test.dart new file mode 100644 index 00000000..8b602763 --- /dev/null +++ b/test/src/export_options_editor_test.dart @@ -0,0 +1,301 @@ +import 'dart:io'; +import 'package:busymark/l10n/generated/app_localizations.dart'; +import 'package:busymark/src/app/app_settings.dart'; +import 'package:busymark/src/app/busymark_design.dart'; +import 'package:busymark/src/app/app_theme.dart'; +import 'package:busymark/src/export/export_options.dart'; +import 'package:busymark/src/export/export_options_editor.dart'; +import 'package:busymark/src/writerside/writerside_module_service.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + for (final pdf in [true, false]) { + for (final writerside in [false, true]) { + testWidgets( + '${writerside ? 'Writerside' : 'Markdown'} ${pdf ? 'PDF' : 'HTML'} loads confirmed settings and shares controls', + (tester) async { + final module = await tester.runAsync( + () => const WritersideModuleService().load( + 'test/fixtures/writerside/basic_project', + ), + ); + final settings = _Settings( + AppSettings.defaults() + .copyWith( + pdfExportOptions: const PdfExportOptions(bodyFontSize: 14), + htmlExportOptions: const HtmlExportOptions(baseFontSize: 21), + ) + .toJson(), + ); + ExportOptionsSelection? selected; + await tester.pumpWidget( + ProviderScope( + overrides: [ + localSettingsStoreProvider.overrideWithValue(settings), + ], + child: MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: buildBusyMarkTheme( + brightness: Brightness.light, + accentColor: Colors.blue, + ), + home: Scaffold( + body: Consumer( + builder: (context, ref, _) => TextButton( + child: const Text('Configure'), + onPressed: () async { + selected = await showExportOptions( + context, + ref, + pdf: pdf, + instances: writerside + ? module!.instances + .where((i) => !i.isLibrary) + .toList() + : const [], + workspaceRoot: writerside ? module!.rootPath : null, + ); + }, + ), + ), + ), + ), + ), + ); + await tester.tap(find.text('Configure')); + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 40)), + ); + await tester.pumpAndSettle(); + expect(find.byType(ExportContentOptionsEditor), findsOneWidget); + if (pdf) { + expect( + tester + .widget( + find.byType(PdfExportOptionsEditor), + ) + .value + .bodyFontSize, + 14, + ); + expect(find.byType(HtmlExportOptionsEditor), findsNothing); + } else { + expect( + tester + .widget( + find.byType(HtmlExportOptionsEditor), + ) + .value + .baseFontSize, + 21, + ); + expect(find.byType(PdfExportOptionsEditor), findsNothing); + } + final toc = tester.widget>( + find.byWidgetPredicate( + (w) => w is BusyMarkComboRow && w.title == 'TOC depth', + ), + ); + expect(toc.enabled, !pdf); + await tester.tap(find.text('Reset to defaults')); + await tester.pumpAndSettle(); + if (pdf) { + expect( + tester + .widget( + find.byType(PdfExportOptionsEditor), + ) + .value + .bodyFontSize, + 10.5, + ); + } else { + expect( + tester + .widget( + find.byType(HtmlExportOptionsEditor), + ) + .value + .baseFontSize, + 17, + ); + } + await tester.tap(find.text('Export')); + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 40)), + ); + await tester.pumpAndSettle(); + expect(selected, isNotNull); + expect(selected!.instance != null, writerside); + final stored = AppSettings.fromJson(settings.data); + expect( + pdf + ? stored.pdfExportOptions.bodyFontSize + : stored.htmlExportOptions.baseFontSize, + pdf ? 10.5 : 17, + ); + // The other format's remembered appearance is unaffected. + expect( + pdf + ? stored.htmlExportOptions.baseFontSize + : stored.pdfExportOptions.bodyFontSize, + pdf ? 21 : 14, + ); + await tester.pumpWidget(const SizedBox()); + }, + ); + } + } + + testWidgets( + 'custom geometry controls, TOC enablement and invalid input at minimum size', + (tester) async { + tester.view.physicalSize = const Size(900, 600); + tester.view.devicePixelRatio = 1; + addTearDown(tester.view.resetPhysicalSize); + addTearDown(tester.view.resetDevicePixelRatio); + var value = const PdfExportOptions(); + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: StatefulBuilder( + builder: (context, setState) => SingleChildScrollView( + child: PdfExportOptionsEditor( + value: value, + onChanged: (v) => setState(() => value = v), + ), + ), + ), + ), + ), + ); + expect(find.text('Page width (mm)'), findsNothing); + final size = tester.widget>( + find.byWidgetPredicate((w) => w is BusyMarkComboRow), + ); + size.onSelected(PdfPageSize.custom); + await tester.pumpAndSettle(); + expect(find.text('Page width (mm)'), findsOneWidget); + final margin = tester.widget>( + find.byWidgetPredicate((w) => w is BusyMarkComboRow), + ); + margin.onSelected(PdfMarginPreset.custom); + await tester.pumpAndSettle(); + expect(find.text('Left margin (mm)'), findsOneWidget); + final tocSwitch = tester.widget( + find.byWidgetPredicate( + (w) => + w is BusyMarkSwitchRow && w.title == 'Include table of contents', + ), + ); + tocSwitch.onChanged(true); + await tester.pumpAndSettle(); + expect( + tester + .widget>( + find.byWidgetPredicate((w) => w is BusyMarkComboRow), + ) + .enabled, + true, + ); + final width = find.descendant( + of: find.byKey(const ValueKey('customWidthMm')), + matching: find.byType(TextFormField), + ); + await tester.ensureVisible(width); + await tester.enterText(width, '1'); + await tester.pumpAndSettle(); + expect(value.validate(), isNotEmpty); + expect(tester.takeException(), isNull); + }, + ); + + testWidgets('cancelling settings does not confirm or persist edits', ( + tester, + ) async { + final settings = _Settings(AppSettings.defaults().toJson()); + final before = Map.from(settings.data); + var confirmed = false; + await tester.pumpWidget( + ProviderScope( + overrides: [localSettingsStoreProvider.overrideWithValue(settings)], + child: MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: Consumer( + builder: (context, ref, _) => TextButton( + child: const Text('Configure'), + onPressed: () async { + confirmed = + await showExportOptions(context, ref, pdf: false) != null; + }, + ), + ), + ), + ), + ), + ); + await tester.tap(find.text('Configure')); + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 40)), + ); + await tester.pumpAndSettle(); + await tester.tap(find.text('Cancel')); + await tester.pumpAndSettle(); + expect(confirmed, false); + expect(settings.data, before); + }); + + test( + 'JSON settings store retains both format settings across controllers', + () async { + final dir = await Directory.systemTemp.createTemp('export-settings-'); + addTearDown(() => dir.delete(recursive: true)); + final store = JsonFileLocalSettingsStore( + settingsFilePathOverride: '${dir.path}/settings.json', + ); + final first = ProviderContainer( + overrides: [localSettingsStoreProvider.overrideWithValue(store)], + ); + final controller = first.read(appSettingsControllerProvider.notifier); + await controller.waitUntilLoaded(); + await controller.setPdfExportOptions( + const PdfExportOptions(pageSize: PdfPageSize.legal), + ); + await controller.setHtmlExportOptions( + const HtmlExportOptions(theme: HtmlExportTheme.dark), + ); + first.dispose(); + final next = ProviderContainer( + overrides: [localSettingsStoreProvider.overrideWithValue(store)], + ); + addTearDown(next.dispose); + await next.read(appSettingsControllerProvider.notifier).waitUntilLoaded(); + expect( + next.read(appSettingsControllerProvider).pdfExportOptions.pageSize, + PdfPageSize.legal, + ); + expect( + next.read(appSettingsControllerProvider).htmlExportOptions.theme, + HtmlExportTheme.dark, + ); + }, + ); +} + +class _Settings implements LocalSettingsStore { + _Settings(this.data); + Map data; + @override + Future> load() async => data; + @override + Future save(Map json) async { + data = json; + } +} diff --git a/test/src/export_options_test.dart b/test/src/export_options_test.dart new file mode 100644 index 00000000..b52a7b11 --- /dev/null +++ b/test/src/export_options_test.dart @@ -0,0 +1,243 @@ +import 'dart:convert'; +import 'package:busymark/src/app/app_settings.dart'; +import 'package:busymark/src/export/export_options.dart'; +import 'package:busymark/src/export/markdown_export_mapper.dart'; +import 'package:busymark/src/export/typst_payload_builder.dart'; +import 'package:busymark/src/markdown/markdown_parser.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test( + 'defaults retain PDF geometry and independent HTML reading appearance', + () { + const pdf = PdfExportOptions(); + const html = HtmlExportOptions(); + expect(pdf.geometry.widthMm, 210); + expect(pdf.geometry.heightMm, 297); + expect(pdf.geometry.contentWidthPt, closeTo(595.27559 - 114, .001)); + expect(pdf.bodyFontSize, 10.5); + expect(pdf.headingFontSize(1), 22); + expect(pdf.accentColor, '#2563a5'); + expect(pdf.pageNumbers, PdfPageNumberPosition.bottomCenter); + expect(pdf.content.includeToc, isFalse); + expect(html.content.includeToc, isTrue); // Existing HTML heading outline. + expect(html.baseFontSize, 17); + expect(html.contentMaxWidth, 918); + expect(html.theme, HtmlExportTheme.light); + expect(html.packaging, HtmlPackaging.assetsDirectory); + expect( + [pdf.content.numberHeadings, html.content.numberHeadings], + [false, false], + ); + expect(pdf.validate(), isEmpty); + expect(html.validate(), isEmpty); + }, + ); + + const pdf = PdfExportOptions( + content: ExportContentOptions( + includeToc: true, + tocDepth: 3, + numberHeadings: true, + ), + pageSize: PdfPageSize.custom, + customWidthMm: 240, + customHeightMm: 310, + orientation: PdfOrientation.landscape, + margin: PdfMarginPreset.custom, + customMargins: PdfMargins(top: 10, right: 20, bottom: 30, left: 40), + bodyTypography: ExportBodyTypography.sansSerif, + bodyFontSize: 14, + codeFontSize: 11, + accentColor: '#123abc', + header: PdfRunningText.documentTitle, + footer: PdfRunningText.documentTitle, + pageNumbers: PdfPageNumberPosition.bottomRight, + showHeaderFooterOnFirstPage: false, + ); + const html = HtmlExportOptions( + content: ExportContentOptions( + includeToc: false, + tocDepth: 4, + numberHeadings: true, + ), + theme: HtmlExportTheme.automatic, + bodyTypography: ExportBodyTypography.serif, + baseFontSize: 20, + contentMaxWidth: 1100, + accentColor: '#ab1234', + customCssPath: '/styles/custom.css', + packaging: HtmlPackaging.singleFile, + ); + + test('every option persists and copies without losing unrelated fields', () { + expect( + PdfExportOptions.fromJson(jsonDecode(jsonEncode(pdf.toJson()))).toJson(), + pdf.toJson(), + ); + expect( + HtmlExportOptions.fromJson( + jsonDecode(jsonEncode(html.toJson())), + ).toJson(), + html.toJson(), + ); + expect( + pdf.copyWith(bodyFontSize: 15).copyWith(bodyFontSize: 14).toJson(), + pdf.toJson(), + ); + expect(html.copyWith(customCssPath: null).customCssPath, isNull); + expect(html.copyWith().toJson(), html.toJson()); + final settings = AppSettings.defaults().copyWith( + pdfExportOptions: pdf, + htmlExportOptions: html, + ); + final loaded = AppSettings.fromJson( + jsonDecode(jsonEncode(settings.toJson())) as Map, + ); + expect(loaded.pdfExportOptions.toJson(), pdf.toJson()); + expect(loaded.htmlExportOptions.toJson(), html.toJson()); + }); + + test('absent and malformed persisted values fall back per field', () { + final settings = AppSettings.fromJson({}); + expect( + settings.pdfExportOptions.toJson(), + const PdfExportOptions().toJson(), + ); + expect( + settings.htmlExportOptions.toJson(), + const HtmlExportOptions().toJson(), + ); + final broken = PdfExportOptions.fromJson({ + 'pageSize': 'wrong', + 'margin': 'custom', + 'customMargins': {'left': 500, 'right': -1}, + 'bodyFontSize': '14', + 'codeFontSize': 11, + 'accentColor': '#abc', + 'content': {'tocDepth': 7, 'numberHeadings': true}, + }); + expect(broken.validate(), isEmpty); + expect(broken.bodyFontSize, 10.5); + expect(broken.codeFontSize, 11); + expect(broken.content.numberHeadings, isTrue); + expect(broken.content.tocDepth, 6); + final brokenHtml = HtmlExportOptions.fromJson({ + 'theme': [], + 'baseFontSize': double.infinity, + 'contentMaxWidth': 1000, + 'customCssPath': 'https://example.com/a.css', + 'packaging': false, + }); + expect(brokenHtml.validate(), isEmpty); + expect(brokenHtml.baseFontSize, 17); + expect(brokenHtml.contentMaxWidth, 1000); + expect(brokenHtml.customCssPath, isNull); + expect( + AppSettings.fromJson({ + 'pdfExportOptions': [], + 'htmlExportOptions': false, + }).pdfExportOptions.validate(), + isEmpty, + ); + }); + + test( + 'geometry resolves dimensions, orientation and four independent margins', + () { + expect(pdf.geometry.widthMm, 310); + expect(pdf.geometry.heightMm, 240); + expect(pdf.geometry.contentWidthPt, closeTo(250 * 72 / 25.4, .001)); + expect(pdf.geometry.contentHeightPt, closeTo(200 * 72 / 25.4, .001)); + expect( + pdf + .copyWith( + pageSize: PdfPageSize.letter, + orientation: PdfOrientation.portrait, + ) + .geometry + .widthPt, + closeTo(612, .001), + ); + expect( + pdf + .copyWith( + pageSize: PdfPageSize.legal, + orientation: PdfOrientation.portrait, + ) + .geometry + .heightPt, + closeTo(1008, .001), + ); + for (final value in [double.nan, double.infinity, -1.0, 0.0, 1201.0]) { + expect(pdf.copyWith(customWidthMm: value).validate(), isNotEmpty); + } + expect( + pdf + .copyWith(customMargins: const PdfMargins(left: 300, right: 20)) + .validate() + .map((i) => i.field), + contains('pageGeometry'), + ); + expect( + pdf + .copyWith(customMargins: const PdfMargins(top: -1)) + .validate() + .map((i) => i.field), + contains('margin.top'), + ); + expect(pdf.copyWith(bodyFontSize: 25).validate(), isNotEmpty); + expect(pdf.copyWith(codeFontSize: 5).validate(), isNotEmpty); + expect( + pdf.copyWith(accentColor: 'red); eval("bad")').validate(), + isNotEmpty, + ); + expect( + html.copyWith(baseFontSize: 11, contentMaxWidth: 2000).validate(), + hasLength(2), + ); + expect( + () => html + .copyWith(content: const ExportContentOptions(tocDepth: 0)) + .validateOrThrow(), + throwsA(isA()), + ); + }, + ); + + test( + 'payload contains resolved geometry and every renderer option as data', + () { + final doc = const MarkdownExportMapper().map( + const MarkdownParser() + .parse(filePath: '/source.md', source: '# Title\n\nSafe text') + .busyDocument, + ); + final payload = const TypstPayloadBuilder().build( + document: doc, + options: pdf, + assets: {}, + ); + expect(payload['schemaVersion'], 2); + final options = payload['options'] as Map; + expect(options['page'], pdf.geometry.toJson()); + expect(options['typography'], { + 'bodyFont': 'Noto Sans', + 'codeFont': 'Noto Sans Mono', + 'bodySizePt': 14.0, + 'codeSizePt': 11.0, + 'headingSizesPt': [ + for (var level = 1; level <= 6; level++) pdf.headingFontSize(level), + ], + }); + expect(options['content'], pdf.content.toJson()); + expect(options['header'], 'documentTitle'); + expect(options['footer'], 'documentTitle'); + expect(options['pageNumbers'], 'bottomRight'); + expect(options['showHeaderFooterOnFirstPage'], false); + expect(options['accentColor'], '#123abc'); + expect(options.containsKey('customWidthMm'), isFalse); + expect(jsonEncode(payload), isNot(contains('renderEm'))); + }, + ); +} diff --git a/test/src/html_export_options_test.dart b/test/src/html_export_options_test.dart new file mode 100644 index 00000000..a4a32a40 --- /dev/null +++ b/test/src/html_export_options_test.dart @@ -0,0 +1,279 @@ +import 'dart:convert'; +import 'dart:io'; +import 'package:busymark/src/export/html_export_models.dart'; +import 'package:busymark/src/export/html_export_service.dart'; +import 'package:busymark/src/export/html_export_styles.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:html/parser.dart' as html; +import 'package:path/path.dart' as p; + +void main() { + late Directory root; + final service = HtmlExportService( + stylesheetLoader: () => File('assets/export/html.css').readAsString(), + ); + setUp(() async { + root = await Directory.systemTemp.createTemp('html-options-'); + }); + tearDown(() => root.delete(recursive: true)); + Future export( + HtmlExportOptions options, { + String source = '# Title\n\n## One\n\n### Child\n\n## Two', + bool overwrite = false, + }) => service.exportMarkdown( + MarkdownHtmlExportRequest( + source: source, + filePath: p.join(root.path, 'source.md'), + workspaceRoot: root.path, + destinationPath: p.join(root.path, 'output.html'), + options: options, + overwrite: overwrite, + ), + ); + + test( + 'TOC and numbering use the semantic hierarchy and preserve anchor IDs', + () async { + final result = await export( + const HtmlExportOptions( + content: ExportContentOptions( + includeToc: true, + tocDepth: 2, + numberHeadings: true, + ), + ), + ); + final doc = html.parse(await File(result.entryPointPath).readAsString()); + expect( + doc + .querySelectorAll('article h1, article h2, article h3') + .map((e) => e.text), + ['1 Title', '1.1 One', '1.1.1 Child', '1.2 Two'], + ); + expect(doc.querySelectorAll('.outline a').map((e) => e.text), [ + '1 Title', + '1.1 One', + '1.2 Two', + ]); + expect( + doc.querySelectorAll('.outline > details > ul > li > ul > li'), + hasLength(2), + ); + expect(doc.getElementById('one')!.localName, 'h2'); + final no = await export( + const HtmlExportOptions(content: ExportContentOptions()), + overwrite: true, + ); + final none = html.parse(await File(no.entryPointPath).readAsString()); + expect(none.querySelector('.outline'), isNull); + expect(none.querySelector('.heading-number'), isNull); + }, + ); + + for (final theme in HtmlExportTheme.values) { + test( + '$theme emits complete color variables, responsive width and metadata', + () async { + final result = await export( + HtmlExportOptions( + theme: theme, + bodyTypography: ExportBodyTypography.serif, + baseFontSize: 21, + contentMaxWidth: 1050, + accentColor: '#123456', + ), + source: + '---\ntitle: "Safe "\nauthors: "A & B"\ndescription: "An <example>"\nlang: fr-CA\n---\n# Content', + ); + final doc = html.parse( + await File(result.entryPointPath).readAsString(), + ); + expect(doc.querySelector('title')!.text, 'Safe <title>'); + expect(doc.documentElement!.attributes['lang'], 'fr-CA'); + expect( + doc.querySelector('meta[name="author"]')!.attributes['content'], + 'A & B', + ); + expect( + doc.querySelector('meta[name="description"]')!.attributes['content'], + 'An <example>', + ); + expect(doc.querySelector('meta[name="viewport"]'), isNotNull); + final css = doc.querySelector('style')!.text; + expect(css, contains('--body-size:21.0px')); + expect(css, contains('--content-width:1050.0px')); + expect(css, contains('max-width:var(--content-width')); + expect(css, contains('--accent:#123456')); + expect(css, contains('"Noto Serif",Georgia,serif')); + expect( + css.contains('@media(prefers-color-scheme:dark)'), + theme == HtmlExportTheme.automatic, + ); + expect( + css, + contains( + 'color-scheme:${theme == HtmlExportTheme.dark ? 'dark' : 'light'}', + ), + ); + }, + ); + } + + test( + 'custom CSS follows generated rules and is captured before processing', + () async { + final css = File(p.join(root.path, 'custom.css')); + await css.writeAsString( + 'h1 { color: #665544; } @media print { p { font-size: 12pt; } }', + ); + final result = await service.exportMarkdown( + MarkdownHtmlExportRequest( + source: '# Styled', + filePath: p.join(root.path, 'source.md'), + workspaceRoot: root.path, + destinationPath: p.join(root.path, 'output.html'), + options: HtmlExportOptions(customCssPath: css.path), + ), + onProgress: (_, _) { + css.writeAsStringSync('h1 { color: red; }'); + }, + ); + final doc = html.parse(await File(result.entryPointPath).readAsString()); + expect( + doc.querySelector('style')!.text.trim(), + endsWith( + 'h1 { color: #665544; } @media print { p { font-size: 12pt; } }', + ), + ); + expect( + doc.querySelector('meta[http-equiv]')!.attributes['content'], + contains("style-src 'sha256-"), + ); + expect( + await File(result.entryPointPath).readAsString(), + isNot(contains(css.path)), + ); + }, + ); + + test( + 'CSS rejects unsafe URLs, imports, HTML, unreadable and oversized files', + () async { + for (final css in [ + '@import "https://example.com/a.css";', + 'p { background: url(https://example.com/a.png) }', + 'p { background: url(local.png) }', + '</style><script>alert(1)</script>', + r'p { background: u\72l(https://example.com) }', + 'p { width: expression(alert(1)); }', + 'p { background: image-set("https://example.com/a.png" 1x); }', + ]) { + expect( + () => HtmlExportStyles.validateCss(css), + throwsA(isA<ExportOptionsException>()), + reason: css, + ); + } + final path = p.join(root.path, 'missing.css'); + await expectLater( + export(HtmlExportOptions(customCssPath: path)), + throwsA(isA<ExportOptionsException>()), + ); + await File( + path, + ).writeAsString('/*${'é' * HtmlExportOptions.maximumCssBytes}*/'); + await expectLater( + export(HtmlExportOptions(customCssPath: path)), + throwsA(isA<ExportOptionsException>()), + ); + expect(await File(p.join(root.path, 'output.html')).exists(), false); + }, + ); + + test( + 'repeated embedded assets are bounded before publication and keep old output', + () async { + final asset = File(p.join(root.path, 'large.svg')); + await asset.writeAsString( + '<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">${List.filled(200, '<rect width="1" height="1"/>').join()}</svg>', + ); + final destination = File(p.join(root.path, 'old.html')); + await destination.writeAsString('Previous export'); + await expectLater( + HtmlExportService( + limits: const HtmlExportLimits(sourceBytes: 4096), + stylesheetLoader: () async => '', + ).exportMarkdown( + MarkdownHtmlExportRequest( + source: + '# Images\n\n${List.filled(30, '![Image](large.svg)').join('\n\n')}', + filePath: p.join(root.path, 'source.md'), + workspaceRoot: root.path, + destinationPath: destination.path, + overwrite: true, + options: const HtmlExportOptions( + packaging: HtmlPackaging.singleFile, + ), + ), + ), + throwsA( + isA<HtmlExportException>().having( + (e) => e.message, + 'diagnostic', + contains('output byte limit'), + ), + ), + ); + expect(await destination.readAsString(), 'Previous export'); + expect( + await root + .list() + .where((e) => p.basename(e.path).startsWith('.busymark-html-')) + .length, + 0, + ); + }, + ); + + for (final packaging in HtmlPackaging.values) { + test( + '$packaging packages validated assets without source paths or fetching', + () async { + const svg = + '<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"><rect width="20" height="20" fill="red"/></svg>'; + await File(p.join(root.path, 'image.svg')).writeAsString(svg); + final result = await export( + HtmlExportOptions(packaging: packaging), + source: + '# Assets\n\n![Local](image.svg)\n\n![Remote](https://example.invalid/image.png)', + ); + final text = await File(result.entryPointPath).readAsString(); + final doc = html.parse(text); + final url = doc.querySelector('img')!.attributes['src']!; + if (packaging == HtmlPackaging.singleFile) { + expect(url, startsWith('data:image/svg+xml;base64,')); + expect( + utf8.decode(base64.decode(url.split(',').last)), + contains('<rect'), + ); + expect(result.assetsPath, isNull); + expect( + await Directory(p.join(root.path, 'output.assets')).exists(), + false, + ); + } else { + expect(url, startsWith('output.assets/')); + expect(await File(p.join(root.path, url)).exists(), true); + expect(result.assetsPath, isNotNull); + } + expect(text, isNot(contains(root.path))); + expect(doc.querySelectorAll('img'), hasLength(1)); + expect( + result.warnings.map((w) => w.code), + contains('asset.unavailable'), + ); + expect(doc.querySelector('script'), isNull); + }, + ); + } +} diff --git a/test/src/html_export_ui_test.dart b/test/src/html_export_ui_test.dart index 8a4c104e..3d93a123 100644 --- a/test/src/html_export_ui_test.dart +++ b/test/src/html_export_ui_test.dart @@ -119,6 +119,11 @@ void main() { .read(workspaceControllerProvider.notifier) .updateActiveText('# Captured unsaved'); await tester.tap(find.text('Run HTML')); + await tester.runAsync( + () => Future<void>.delayed(const Duration(milliseconds: 80)), + ); + await tester.pumpAndSettle(); + await tester.tap(find.text('Export')); await tester.pumpAndSettle(); expect(suggestion, endsWith('.html')); ref @@ -290,6 +295,7 @@ class _RecordingExporter extends HtmlExportService { required String instanceId, required String destinationPath, bool overwrite = false, + HtmlExportOptions options = const HtmlExportOptions(), WritersideProject? capturedProject, HtmlExportCancellationToken? cancellationToken, HtmlExportProgress? onProgress, diff --git a/test/src/html_publication_test.dart b/test/src/html_publication_test.dart index 29c1ddb7..9c3e269b 100644 --- a/test/src/html_publication_test.dart +++ b/test/src/html_publication_test.dart @@ -40,13 +40,68 @@ void main() { String dir = 'module', String output = 'site', bool overwrite = false, + HtmlExportOptions options = const HtmlExportOptions(), }) => const HtmlExportService().exportWriterside( projectRoot: root.path, moduleRoot: p.join(root.path, dir), instanceId: 'guide', destinationPath: p.join(root.path, output), overwrite: overwrite, + options: options, ); + test( + 'Writerside shares HTML appearance without changing TOC status or source', + () async { + await module( + 'module', + 'module', + '<instance-profile id="guide" name="Guide" start-page="Start.topic"><toc-element topic="Start.topic"/><toc-element topic="Hidden.topic" hidden="true"/><toc-element topic="Wip.topic" wip="true"/></instance-profile>', + ); + const source = + '<topic id="Start" title="%product%"><chapter id="one" title="First"><p>Body</p></chapter><chapter id="two" title="Second"/></topic>'; + await put('module/topics/Start.topic', source); + await put( + 'module/topics/Hidden.topic', + '<topic id="Hidden" title="Hidden"><p>Hidden content</p></topic>', + ); + await put( + 'module/topics/Wip.topic', + '<topic id="Wip" title="Wip"><p>Work in progress</p></topic>', + ); + const options = HtmlExportOptions( + theme: HtmlExportTheme.dark, + bodyTypography: ExportBodyTypography.serif, + baseFontSize: 19, + packaging: HtmlPackaging.singleFile, + content: ExportContentOptions( + includeToc: true, + tocDepth: 2, + numberHeadings: true, + ), + ); + final result = await site(options: options); + expect(result.pageCount, 3); + final doc = html.parse(await File(result.entryPointPath).readAsString()); + expect(doc.querySelector('style')!.text, contains('--body-size:19.0px')); + expect(doc.querySelector('style')!.text, contains('color-scheme:dark')); + expect(doc.querySelector('.heading-number'), isNotNull); + expect(doc.querySelector('h1')!.text, contains('BusyMark')); + final nav = doc.querySelector('.instance-nav')!.text; + expect(nav, isNot(contains('Hidden'))); + expect(nav, contains('Work in progress')); + expect( + await File(p.join(root.path, 'site/hidden.html')).exists(), + isTrue, + ); + expect( + await File( + p.join(root.path, 'module/topics/Start.topic'), + ).readAsString(), + source, + ); + }, + ); + test( 'Writerside module origins preserve includes, variables, file identity and nullable links', () async { diff --git a/test/src/html_rich_export_test.dart b/test/src/html_rich_export_test.dart index 36dc703b..13b003e8 100644 --- a/test/src/html_rich_export_test.dart +++ b/test/src/html_rich_export_test.dart @@ -64,6 +64,8 @@ a -> b ```openapi openapi: 3.1.0 ``` + +## After API ''', filePath: p.join(root.path, 'source.md'), workspaceRoot: root.path, @@ -76,6 +78,15 @@ openapi: 3.1.0 expect(doc.querySelectorAll('.math-display').length, 1); expect(doc.querySelectorAll('img').length, 7); expect(doc.body!.text, contains('Test API')); + final outline = doc + .querySelectorAll('.outline a') + .map((e) => e.text) + .toList(); + expect(outline.last, 'After API'); + expect( + outline.indexWhere((e) => e.contains('Test API')), + lessThan(outline.indexOf('After API')), + ); expect( renderer.requests.map((r) => r.profile), everyElement(VisualizationRenderProfile.html), @@ -85,7 +96,7 @@ openapi: 3.1.0 host.requests.map((r) => r['renderProfile']), everyElement('html'), ); - expect(host.requests.first['em'], 39.1); + expect(host.requests.first['em'], closeTo(39.1, .0001)); expect(host.requests.skip(1).map((r) => r['em']), everyElement(17.0)); for (final file in await Directory( result.assetsPath!, @@ -97,6 +108,62 @@ openapi: 3.1.0 }, ); + test( + 'custom HTML metrics and embedded rich assets stay self-contained', + () async { + final root = await Directory.systemTemp.createTemp('html-rich-options-'); + addTearDown(() => root.delete(recursive: true)); + final host = _MathHost(); + final math = MathCoordinator(renderer: MathRenderer(host: host)); + addTearDown(math.dispose); + final visualization = VisualizationCoordinator( + renderers: [_Diagrams()], + cache: VisualizationCache( + diskRoot: Directory(p.join(root.path, 'cache')), + ), + ); + addTearDown(visualization.dispose); + const options = HtmlExportOptions( + baseFontSize: 22, + contentMaxWidth: 1100, + packaging: HtmlPackaging.singleFile, + ); + final result = + await HtmlExportService( + math: math, + visualization: visualization, + ).exportMarkdown( + MarkdownHtmlExportRequest( + source: + r'# Heading $h$' + '\n\n' + r'Inline $x$' + '\n\n' + r'$$d$$' + '\n\n```mermaid\ngraph LR; A-->B\n```', + filePath: p.join(root.path, 'source.md'), + workspaceRoot: root.path, + destinationPath: p.join(root.path, 'out.html'), + options: options, + ), + ); + expect(result.warnings, isEmpty); + expect(result.assetsPath, isNull); + final doc = html.parse(await File(result.entryPointPath).readAsString()); + expect(doc.querySelectorAll('img'), hasLength(4)); + expect( + doc.querySelectorAll('img').map((e) => e.attributes['src']), + everyElement(startsWith('data:image/svg+xml;base64,')), + ); + expect( + host.requests.map((r) => r['containerWidth']), + everyElement(968.0), + ); + expect(host.requests.first['em'], options.headingFontSize(1)); + expect(host.requests.skip(1).map((r) => r['em']), everyElement(22.0)); + }, + ); + test('all diagram dependencies are captured before rendering begins', () async { final root = await Directory.systemTemp.createTemp('html-dependencies-'); addTearDown(() => root.delete(recursive: true)); diff --git a/test/src/localization_audit_test.dart b/test/src/localization_audit_test.dart index f52de488..55025e10 100644 --- a/test/src/localization_audit_test.dart +++ b/test/src/localization_audit_test.dart @@ -679,6 +679,7 @@ const _sharedEnglishMatches = <String>{ 'xml', 'fileTypeMarkdown', 'pdfPageSizeA4', + 'exportLegal', // International paper format name. 'headingLevelAbbreviation', 'git', 'gitPull', @@ -693,6 +694,7 @@ const _sharedEnglishMatches = <String>{ const _localeSpecificEnglishMatches = <String, Set<String>>{ 'de': { + 'exportLayout', 'aboutWebsite', 'editor', 'horizontal', @@ -746,6 +748,7 @@ const _localeSpecificEnglishMatches = <String, Set<String>>{ 'nb': {'systemTheme', 'systemLanguage', 'gitCommit', 'instanceStatus'}, 'pl': {'folder', 'foldKindTag', 'aiModel'}, 'pt_BR': { + 'exportLayout', 'editor', 'link', 'toc', diff --git a/test/src/markdown_export_mapper_test.dart b/test/src/markdown_export_mapper_test.dart index bd9d4f87..a06cc718 100644 --- a/test/src/markdown_export_mapper_test.dart +++ b/test/src/markdown_export_mapper_test.dart @@ -42,7 +42,7 @@ Text with **bold**, [safe](https://example.com), and [unsafe](javascript:alert(1 expect(document.metadata.title, 'Export guide'); expect(document.metadata.author, 'BusyMark Team'); - expect(document.metadata.language, 'fr'); + expect(document.metadata.language, 'fr-CA'); expect(document.metadata.keywords, ['markdown', 'pdf']); expect( document.blocks.map((block) => block.kind), @@ -102,7 +102,7 @@ Review [the export guide][1]. final payload = const TypstPayloadBuilder().build( document: document, - options: const MarkdownPdfOptions(), + options: const PdfExportOptions(), assets: const {}, ); expect(jsonEncode(payload), isNot(contains('[1]:'))); @@ -118,7 +118,7 @@ Review [the export guide][1]. final document = mapper.map(parsed.busyDocument); final payload = const TypstPayloadBuilder().build( document: document, - options: const MarkdownPdfOptions(), + options: const PdfExportOptions(), assets: const {'private/diagram.png': 'assets/safe.png'}, ); final json = jsonEncode(payload); diff --git a/test/src/markdown_math_export_test.dart b/test/src/markdown_math_export_test.dart index 52cd9248..e96af596 100644 --- a/test/src/markdown_math_export_test.dart +++ b/test/src/markdown_math_export_test.dart @@ -38,7 +38,7 @@ void main() { await MarkdownMathExportRenderer(coordinator: coordinator).prepare( document: mapped, exportRoot: root, - containerWidth: 480, + options: const PdfExportOptions(), cancellationToken: MarkdownPdfCancellationToken(), ); @@ -48,12 +48,61 @@ void main() { final request = requests.singleWhere( (item) => item['expression'] == 'h$level', ); - final expected = busyMarkPdfHeadingTextSize(level); + final expected = const PdfExportOptions().headingFontSize(level); expect(request['em'], expected, reason: 'heading level $level'); - expect(request['ex'], expected / 2, reason: 'heading level $level'); + expect(request['ex'], expected * 0.536, reason: 'heading level $level'); } }); + test('custom typography and four margins control actual math jobs', () async { + final root = await Directory.systemTemp.createTemp('pdf-math-options-'); + addTearDown(() => root.delete(recursive: true)); + final host = _PdfMathHost(); + final coordinator = MathCoordinator(renderer: MathRenderer(host: host)); + addTearDown(coordinator.dispose); + final document = const MarkdownExportMapper().map( + const MarkdownParser() + .parse( + filePath: '/math.md', + source: + r'# Heading $h$' + '\n\n' + r'Body $b$' + '\n\n' + r'$$d$$', + ) + .busyDocument, + ); + const options = PdfExportOptions( + pageSize: PdfPageSize.custom, + customWidthMm: 280, + customHeightMm: 300, + margin: PdfMarginPreset.custom, + customMargins: PdfMargins(left: 30, right: 40, top: 20, bottom: 25), + bodyTypography: ExportBodyTypography.sansSerif, + bodyFontSize: 16, + ); + await MarkdownMathExportRenderer(coordinator: coordinator).prepare( + document: document, + exportRoot: root, + options: options, + cancellationToken: MarkdownPdfCancellationToken(), + ); + final requests = host.batches.expand((e) => e).toList(); + expect(requests, hasLength(3)); + expect( + requests.map((r) => r['containerWidth']), + everyElement(closeTo(210 * 72 / 25.4, .001)), + ); + expect(requests.first['em'], options.headingFontSize(1)); + expect(requests.skip(1).map((r) => r['em']), everyElement(16.0)); + expect(requests.skip(1).map((r) => r['ex']), everyElement(16 * .536)); + expect( + document.blocks.first.inlines.last.attributes, + isNot(contains('renderEm')), + ); + }); + test( 'prepares inline and display math as deterministic vector assets', () async { @@ -82,7 +131,7 @@ $$ await MarkdownMathExportRenderer(coordinator: coordinator).prepare( document: mapped, exportRoot: root, - containerWidth: 480, + options: const PdfExportOptions(), cancellationToken: MarkdownPdfCancellationToken(), ); @@ -127,7 +176,7 @@ $$ final payload = const TypstPayloadBuilder().build( document: preparation.document, - options: const MarkdownPdfOptions(), + options: const PdfExportOptions(), assets: const {}, ); final json = jsonEncode(payload); @@ -169,7 +218,7 @@ Failed but visible: $BAD$. filePath: p.join(root.path, 'math.md'), workspaceRoot: root.path, destinationPath: destination, - options: const MarkdownPdfOptions(), + options: const PdfExportOptions(), overwrite: false, ), ); diff --git a/test/src/markdown_pdf_export_service_test.dart b/test/src/markdown_pdf_export_service_test.dart index 0439cd8e..f678a2cc 100644 --- a/test/src/markdown_pdf_export_service_test.dart +++ b/test/src/markdown_pdf_export_service_test.dart @@ -65,7 +65,7 @@ void main() => print("Hello"); filePath: p.absolute('test/fixtures/markdown/export-test.md'), workspaceRoot: p.absolute('test/fixtures'), destinationPath: destination, - options: const MarkdownPdfOptions(), + options: const PdfExportOptions(), overwrite: false, ), ); @@ -111,7 +111,7 @@ void main() => print("Hello"); filePath: p.absolute('test/fixtures/markdown/video.md'), workspaceRoot: p.absolute('test/fixtures'), destinationPath: destination, - options: const MarkdownPdfOptions(), + options: const PdfExportOptions(), overwrite: false, ), ); @@ -160,7 +160,7 @@ void main() => print("Hello"); filePath: p.absolute('test/fixtures/markdown/admonitions.md'), workspaceRoot: p.absolute('test/fixtures'), destinationPath: destination, - options: const MarkdownPdfOptions(), + options: const PdfExportOptions(), overwrite: false, ), ); diff --git a/test/src/markdown_pdf_export_test.dart b/test/src/markdown_pdf_export_test.dart index 9c67b2c1..d0cbc59a 100644 --- a/test/src/markdown_pdf_export_test.dart +++ b/test/src/markdown_pdf_export_test.dart @@ -125,7 +125,7 @@ void main() { filePath: p.join(temporaryDirectory.path, 'document.md'), workspaceRoot: temporaryDirectory.path, destinationPath: destination, - options: const MarkdownPdfOptions(), + options: const PdfExportOptions(), overwrite: false, ), ), diff --git a/test/src/markdown_visualization_export_test.dart b/test/src/markdown_visualization_export_test.dart index dc3dd8f0..c0291255 100644 --- a/test/src/markdown_visualization_export_test.dart +++ b/test/src/markdown_visualization_export_test.dart @@ -297,7 +297,7 @@ void main() { filePath: p.join(temporaryDirectory.path, 'guide.md'), workspaceRoot: temporaryDirectory.path, destinationPath: destination, - options: const MarkdownPdfOptions(), + options: const PdfExportOptions(), overwrite: false, ), ); diff --git a/test/src/pdf_export_options_render_test.dart b/test/src/pdf_export_options_render_test.dart new file mode 100644 index 00000000..ca3b1880 --- /dev/null +++ b/test/src/pdf_export_options_render_test.dart @@ -0,0 +1,265 @@ +import 'dart:io'; +import 'package:xml/xml.dart'; +import 'package:busymark/src/export/markdown_pdf_export_service.dart'; +import 'package:busymark/src/export/markdown_pdf_models.dart'; +import 'package:busymark/src/export/typst_compiler.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:path/path.dart' as p; + +void main() { + final typst = Platform.environment['BUSYMARK_TYPST_PATH']; + final available = typst != null && File(typst).existsSync(); + final profiles = <String, PdfExportOptions>{ + 'default-a4': const PdfExportOptions(), + 'letter-landscape': const PdfExportOptions( + pageSize: PdfPageSize.letter, + orientation: PdfOrientation.landscape, + margin: PdfMarginPreset.narrow, + pageNumbers: PdfPageNumberPosition.bottomLeft, + ), + 'legal-serif': const PdfExportOptions( + pageSize: PdfPageSize.legal, + margin: PdfMarginPreset.wide, + bodyFontSize: 13, + codeFontSize: 10, + pageNumbers: PdfPageNumberPosition.bottomRight, + ), + 'custom-sans': const PdfExportOptions( + pageSize: PdfPageSize.custom, + customWidthMm: 240, + customHeightMm: 320, + margin: PdfMarginPreset.custom, + customMargins: PdfMargins(top: 12, right: 23, bottom: 34, left: 45), + bodyTypography: ExportBodyTypography.sansSerif, + bodyFontSize: 16, + codeFontSize: 12, + accentColor: '#247550', + header: PdfRunningText.documentTitle, + footer: PdfRunningText.documentTitle, + showHeaderFooterOnFirstPage: false, + content: ExportContentOptions( + includeToc: true, + tocDepth: 2, + numberHeadings: true, + ), + ), + 'no-numbers': const PdfExportOptions( + pageNumbers: PdfPageNumberPosition.off, + header: PdfRunningText.documentTitle, + footer: PdfRunningText.documentTitle, + content: ExportContentOptions(includeToc: true, tocDepth: 6), + ), + 'numbered-no-outline': const PdfExportOptions( + content: ExportContentOptions(numberHeadings: true), + footer: PdfRunningText.documentTitle, + ), + }; + for (final profile in profiles.entries) { + test( + 'bundled Typst compiles ${profile.key} and preserves document data', + () async { + final root = await Directory.systemTemp.createTemp( + 'pdf-options-render-', + ); + addTearDown(() => root.delete(recursive: true)); + final source = + '''--- +title: 'Running title #eval("not code")' +author: BusyMark +lang: en-CA +--- +# Main + +[Child link](#child) and [External](https://example.com). + +## Child + +### Nested + +```dart +void main() { print("<safe>"); } +``` + +${List.filled(140, 'A paragraph of readable content to exercise later pages.\n').join('\n')} +'''; + final result = + await MarkdownPdfExportService( + compilerLocator: TypstCompilerLocator( + environment: {'BUSYMARK_TYPST_PATH': typst!}, + ), + templateLoader: () => + File('assets/export/markdown.typ').readAsString(), + ).export( + MarkdownPdfExportRequest( + source: source, + filePath: p.join(root.path, 'source.md'), + workspaceRoot: root.path, + destinationPath: p.join(root.path, 'result.pdf'), + options: profile.value, + overwrite: false, + ), + ); + expect(result.warnings, isEmpty); + final bytes = await File(result.destinationPath).readAsBytes(); + expect(bytes.take(5), [37, 80, 68, 70, 45]); + expect(bytes.length, greaterThan(2000)); + if (await File('/usr/bin/pdfinfo').exists()) { + final info = await Process.run('/usr/bin/pdfinfo', [ + result.destinationPath, + ]); + expect(info.exitCode, 0); + final dims = RegExp( + r'Page size:\s+([\d.]+) x ([\d.]+) pts', + ).firstMatch(info.stdout as String)!; + expect( + double.parse(dims[1]!), + closeTo(profile.value.geometry.widthPt, .01), + ); + expect( + double.parse(dims[2]!), + closeTo(profile.value.geometry.heightPt, .01), + ); + } + if (await File('/usr/bin/pdftohtml').exists()) { + final converted = await Process.run('/usr/bin/pdftohtml', [ + '-xml', + '-i', + '-zoom', + '1', + '-stdout', + result.destinationPath, + ]); + final xml = XmlDocument.parse(converted.stdout as String); + final fonts = { + for (final font in xml.findAllElements('fontspec')) + font.getAttribute('id'): double.parse(font.getAttribute('size')!), + }; + final code = xml + .findAllElements('text') + .firstWhere((t) => t.innerText == 'void'); + final body = xml + .findAllElements('text') + .firstWhere((t) => t.innerText.startsWith('A paragraph')); + expect( + fonts[code.getAttribute('font')], + closeTo(profile.value.codeFontSize, 1), + ); + expect( + fonts[body.getAttribute('font')], + closeTo(profile.value.bodyFontSize, 1), + ); + } + if (await File('/usr/bin/pdffonts').exists()) { + final fonts = await Process.run('/usr/bin/pdffonts', [ + result.destinationPath, + ]); + expect( + fonts.stdout, + contains( + profile.value.bodyTypography == ExportBodyTypography.sansSerif + ? 'NotoSans' + : 'NotoSerif', + ), + ); + expect(fonts.stdout, contains('NotoSansMono')); + } + if (await File('/usr/bin/pdftotext').exists()) { + final positioned = await Process.run('/usr/bin/pdftotext', [ + '-bbox', + result.destinationPath, + '-', + ]); + final boxes = XmlDocument.parse(positioned.stdout as String) + .descendants + .whereType<XmlElement>() + .where((e) => e.name.local == 'page') + .toList(); + final o = profile.value; + for (final pageIndex in [0, 1]) { + final pageBox = boxes[pageIndex]; + final bottom = + o.geometry.heightPt - + o.geometry.margins.bottom * PdfPageGeometry.pointsPerMm; + final counters = pageBox.descendants + .whereType<XmlElement>() + .where( + (e) => + e.name.local == 'word' && + e.innerText == '${pageIndex + 1}' && + double.parse(e.getAttribute('yMin')!) > bottom, + ) + .toList(); + final visible = + o.pageNumbers != PdfPageNumberPosition.off && + (pageIndex > 0 || o.showHeaderFooterOnFirstPage); + expect(counters, hasLength(visible ? 1 : 0)); + if (visible) { + final left = double.parse(counters.single.getAttribute('xMin')!); + final right = double.parse(counters.single.getAttribute('xMax')!); + final contentLeft = + o.geometry.margins.left * PdfPageGeometry.pointsPerMm; + final contentRight = + o.geometry.widthPt - + o.geometry.margins.right * PdfPageGeometry.pointsPerMm; + switch (o.pageNumbers) { + case PdfPageNumberPosition.bottomLeft: + expect(left, closeTo(contentLeft, 1)); + case PdfPageNumberPosition.bottomRight: + expect(right, closeTo(contentRight, 1)); + case PdfPageNumberPosition.bottomCenter: + expect( + (left + right) / 2, + closeTo((contentLeft + contentRight) / 2, 1), + ); + case PdfPageNumberPosition.off: + break; + } + } + } + final text = await Process.run('/usr/bin/pdftotext', [ + '-layout', + result.destinationPath, + '-', + ]); + expect(text.exitCode, 0); + final pages = (text.stdout as String).split('\f'); + expect(pages.first, contains('Main')); + expect( + pages.first.contains('Contents'), + profile.value.content.includeToc, + ); + if (profile.value.content.includeToc) { + expect( + pages.first.split('Main').skip(1).join('Main'), + matches(r'Child[^\n]*1'), + reason: + 'Native outline retains destination page numbers even with hidden first-page footers.', + ); + } + expect(text.stdout, contains('void main()')); + if (profile.value.content.numberHeadings) { + expect(text.stdout, matches(r'1\.1\s+Child')); + } + if (profile.value.header != PdfRunningText.none || + profile.value.footer != PdfRunningText.none) { + expect( + pages.first.contains('Running title #eval'), + profile.value.showHeaderFooterOnFirstPage, + ); + expect(pages[1], contains('Running title #eval')); + } + if (profile.value.content.includeToc && + profile.value.content.tocDepth == 2) { + final beforeBody = pages.first + .split(RegExp(r'\n\s*1\s+Main')) + .first; + expect(beforeBody, isNot(contains('Nested'))); + } + } + }, + skip: available + ? false + : 'Set BUSYMARK_TYPST_PATH to the bundled compiler.', + ); + } +} diff --git a/test/src/writerside_pdf_export_test.dart b/test/src/writerside_pdf_export_test.dart index 272118a2..6334866b 100644 --- a/test/src/writerside_pdf_export_test.dart +++ b/test/src/writerside_pdf_export_test.dart @@ -45,7 +45,7 @@ void main() { document: const MarkdownExportMapper().map( recording.request!.document!, ), - options: const MarkdownPdfOptions(), + options: const PdfExportOptions(), assets: {}, ); await File( @@ -137,9 +137,20 @@ void main() { instanceId: 'guide', destinationPath: destination, overwrite: false, - options: const MarkdownPdfOptions( - pageSize: MarkdownPdfPageSize.letter, - orientation: MarkdownPdfOrientation.landscape, + options: const PdfExportOptions( + pageSize: PdfPageSize.letter, + orientation: PdfOrientation.landscape, + content: ExportContentOptions( + includeToc: true, + tocDepth: 3, + numberHeadings: true, + ), + bodyTypography: ExportBodyTypography.sansSerif, + bodyFontSize: 15, + codeFontSize: 12, + accentColor: '#247550', + header: PdfRunningText.documentTitle, + pageNumbers: PdfPageNumberPosition.bottomRight, ), ), ); @@ -149,8 +160,22 @@ void main() { expect(result.pageCount, 3); expect(request.mode, MarkdownMode.writersideMarkdown); expect(request.workspaceRoot, fixture.module.path); - expect(request.options.pageSize, MarkdownPdfPageSize.letter); - expect(request.options.orientation, MarkdownPdfOrientation.landscape); + expect(request.options.pageSize, PdfPageSize.letter); + expect(request.options.orientation, PdfOrientation.landscape); + expect(request.options.bodyFontSize, 15); + expect(request.options.codeFontSize, 12); + expect(request.options.bodyFont, 'Noto Sans'); + expect( + request.options.content.toJson(), + const ExportContentOptions( + includeToc: true, + tocDepth: 3, + numberHeadings: true, + ).toJson(), + ); + expect(request.options.header, PdfRunningText.documentTitle); + expect(request.options.accentColor, '#247550'); + expect(request.options.pageNumbers, PdfPageNumberPosition.bottomRight); expect(request.source, isEmpty); expect(request.document, isNotNull); final blocks = _allBlocks(request.document!.blocks).toList(); diff --git a/tools/verify_html_export_browser.py b/tools/verify_html_export_browser.py index c8118883..febaba2a 100644 --- a/tools/verify_html_export_browser.py +++ b/tools/verify_html_export_browser.py @@ -33,7 +33,10 @@ def main(): args = parser.parse_args() args.output.mkdir(parents=True, exist_ok=True) relocated = Path(tempfile.mkdtemp(prefix='busymark-relocated-html-')) - for name in ['offline.html', 'offline.assets', 'writerside']: + names = ['offline.html', 'offline.assets', 'writerside'] + customized = (args.export_root / 'automatic-single.html').exists() + if customized: names += ['automatic-single.html', 'dark-assets.html', 'dark-assets.assets', 'writerside-embedded'] + for name in names: source = args.export_root / name if source.is_dir(): shutil.copytree(source, relocated / name) else: shutil.copy2(source, relocated / name) @@ -42,7 +45,9 @@ def main(): threading.Thread(target=server.serve_forever, daemon=True).start() report = {'relocated_root': str(relocated), 'checks': []} try: - for engine in ['chromium', 'firefox']: + profiles = [('chromium', None), ('firefox', 'light')] + if customized: profiles.append(('firefox', 'dark')) + for engine, firefox_scheme in profiles: if engine == 'chromium': options = webdriver.ChromeOptions() options.binary_location = args.chrome @@ -56,6 +61,7 @@ def main(): options.binary_location = args.firefox options.add_argument('-headless') options.enable_bidi = True + options.set_preference('layout.css.prefers-color-scheme.content-override', 0 if firefox_scheme == 'dark' else 1) for key, value in {'network.proxy.type': 1, 'network.proxy.http': '127.0.0.1', 'network.proxy.http_port': 9, 'network.proxy.ssl': '127.0.0.1', 'network.proxy.ssl_port': 9, 'network.proxy.no_proxies_on': '127.0.0.1,localhost', @@ -71,14 +77,19 @@ def observe(event): data = event if isinstance(event, dict) else vars(event) request = data.get('request') or {} url = request.get('url', '') if isinstance(request, dict) else request.url - requests.append(url) + requests.append(url if not url.startswith('data:') else url.split(',')[0] + ',…') parsed = urlparse(url) if parsed.scheme in ('http', 'https') and parsed.hostname not in ('127.0.0.1', 'localhost'): blocked.append(url) browser.network.add_event_handler('before_request', observe) try: for mode in ['file', 'http']: - for relative in ['offline.html', 'writerside/index.html', 'writerside/Welcome.html', 'writerside/reference.html', 'writerside/hidden.html']: + pages = ['offline.html', 'writerside/index.html', 'writerside/Welcome.html', 'writerside/reference.html', 'writerside/hidden.html'] + if customized: pages += ['automatic-single.html', 'dark-assets.html', 'writerside-embedded/index.html', 'writerside-embedded/Welcome.html', 'writerside-embedded/reference.html', 'writerside-embedded/hidden.html'] + if firefox_scheme == 'dark': pages = ['automatic-single.html'] + for relative in pages: + custom = relative in ('automatic-single.html', 'dark-assets.html') or relative.startswith('writerside-embedded/') + embedded = relative == 'automatic-single.html' or relative.startswith('writerside-embedded/') url = (relocated / relative).as_uri() if mode == 'file' else f'http://127.0.0.1:{server.server_port}/{relative}' requests.clear(); blocked.clear() browser.get(url) @@ -90,10 +101,28 @@ def observe(event): width:document.documentElement.scrollWidth,viewport:innerWidth, anchors:[...document.querySelectorAll('a[href^="#"]')].every(a=>!!document.getElementById(decodeURIComponent(a.hash.slice(1))))};''') assert values['scripts'] == 0, values - assert values['css'] > 20 and values['font'] == '17px', values + assert values['css'] > 20 and values['font'] == ('20px' if custom else '17px'), values assert all(image['ok'] for image in values['images']), values assert values['anchors'] and values['width'] <= values['viewport'], values assert not blocked, blocked + if embedded: + assert all(image['src'].startswith('data:image/') for image in values['images']), values + if custom: + assert browser.find_elements(By.CSS_SELECTOR, '.heading-number') + assert 'serif' in browser.execute_script('return getComputedStyle(document.documentElement).fontFamily') + if relative in ('automatic-single.html', 'dark-assets.html'): + assert browser.execute_script("return getComputedStyle(document.querySelector('article')).getPropertyValue('--custom-css-proof').trim()") == 'applied' + if relative == 'automatic-single.html': + preferences = ['dark', 'light'] if engine == 'chromium' else [firefox_scheme] + for preference in preferences: + if engine == 'chromium': + browser.execute_cdp_cmd('Emulation.setEmulatedMedia', {'features': [{'name': 'prefers-color-scheme', 'value': preference}]}) + background = 'rgb(21, 25, 31)' if preference == 'dark' else 'rgb(255, 255, 255)' + assert browser.execute_script('return getComputedStyle(document.documentElement).backgroundColor') == background + browser.save_screenshot(str(args.output / f'{engine}-{mode}-automatic-{preference}.png')) + if engine == 'chromium': browser.execute_cdp_cmd('Emulation.setEmulatedMedia', {'features': []}) + else: + assert browser.execute_script('return getComputedStyle(document.documentElement).backgroundColor') == 'rgb(21, 25, 31)' browser.find_element(By.TAG_NAME, 'body').send_keys(Keys.TAB) assert browser.execute_script('return document.activeElement.tagName') == 'A' details = browser.find_elements(By.CSS_SELECTOR, 'article details > summary') @@ -104,22 +133,22 @@ def observe(event): summary.send_keys(Keys.SPACE) assert browser.execute_script('return arguments[0].parentElement.open', summary) != before browser.execute_script('arguments[0].parentElement.open=false', summary) - if relative == 'offline.html': + if relative in ('offline.html', 'automatic-single.html', 'dark-assets.html'): assert browser.find_elements(By.CSS_SELECTOR, 'sup a[href="#fn-one"]') assert browser.find_elements(By.CSS_SELECTOR, '.footnotes #fn-one a[href="#fnref-one"]') assert 'Footnote[^one]' not in browser.find_element(By.TAG_NAME, 'article').text browser.find_element(By.CSS_SELECTOR, 'article a[href="#tables"]').click() assert browser.execute_script('return decodeURIComponent(location.hash)') == '#tables' browser.execute_script('scrollTo(0,0)') - if relative.startswith('writerside/'): + if relative.startswith(('writerside/', 'writerside-embedded/')): assert browser.find_elements(By.CSS_SELECTOR, '.instance-nav a[aria-current="page"]') or relative.endswith('hidden.html') - stem = f'{engine}-{mode}-{relative.replace("/", "-")}' + stem = f'{engine}{"-dark" if firefox_scheme == "dark" else ""}-{mode}-{relative.replace("/", "-")}' browser.save_screenshot(str(args.output / f'{stem}.png')) options = PrintOptions(); options.background = True pdf = args.output / f'{stem}.pdf' pdf.write_bytes(base64.b64decode(browser.print_page(options))) printed = subprocess.check_output(['pdftotext', '-layout', str(pdf), '-'], text=True) - if relative == 'offline.html': assert 'Disclosure body must print.' in printed, printed + if relative in ('offline.html', 'automatic-single.html', 'dark-assets.html'): assert 'Disclosure body must print.' in printed, printed if relative.endswith('reference.html'): assert 'All details are printable.' in printed, printed if relative.endswith(('index.html','Welcome.html')): assert 'All Linux instructions.' in printed and 'All Windows instructions.' in printed @@ -129,7 +158,7 @@ def observe(event): assert browser.execute_script('return window.__htmlProbe || 0') == 0 assert not blocked, blocked report['checks'].append({'engine':engine,'version':browser.capabilities['browserVersion'], - 'mode':mode,'page':relative,'images':len(values['images']), + 'mode':mode,'page':relative,'browser_color_scheme':firefox_scheme,'images':len(values['images']), 'requests':list(requests),'print_bytes':pdf.stat().st_size}) print(engine, mode, relative, 'PASS', flush=True) finally: From 710edc297bc8f67900013ad43e866c3fde78f922 Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Sat, 5 Sep 2026 17:16:40 -0700 Subject: [PATCH 09/37] Update Flutter SDK constraints in pubspec files --- pubspec.lock | 2 +- pubspec.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 95ba64d3..dbed2c87 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1140,4 +1140,4 @@ packages: version: "0.0.4" sdks: dart: ">=3.12.1 <4.0.0" - flutter: ">=3.44.0" + flutter: ">=3.47.0 <3.48.0" diff --git a/pubspec.yaml b/pubspec.yaml index 32c71490..6be12592 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,8 +4,8 @@ publish_to: 'none' version: 0.3.5 environment: - sdk: ^3.12.1 - flutter: 3.47.0 + sdk: ">=3.12.1 <4.0.0" + flutter: ">=3.47.0 <3.48.0" dependencies: flutter: From ba949dc6d78753ab29e1fa4bc1ad5c79c874b2bb Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Mon, 7 Sep 2026 13:38:38 -0700 Subject: [PATCH 10/37] Fix floating toolbar color blending for disabled state --- lib/src/editor/wysiwyg/wysiwyg_toolbar.dart | 3 +- test/src/busymark_design_test.dart | 97 ++++++++++++++++----- 2 files changed, 77 insertions(+), 23 deletions(-) diff --git a/lib/src/editor/wysiwyg/wysiwyg_toolbar.dart b/lib/src/editor/wysiwyg/wysiwyg_toolbar.dart index 40698d41..5d2c2b3d 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_toolbar.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_toolbar.dart @@ -417,7 +417,8 @@ class BusyMarkWysiwygToolbar extends StatelessWidget { final colors = BusyMarkSurfaceColors.of(context); return WidgetStateProperty.resolveWith((states) { if (states.contains(WidgetState.disabled)) { - return colors.disabledControl; + // The floating toolbar has no surface beneath its translucent fills. + return Color.alphaBlend(colors.disabledControl, colors.view); } return theme.colorScheme.primary; }); diff --git a/test/src/busymark_design_test.dart b/test/src/busymark_design_test.dart index 5f9eb6cc..25c89ce3 100644 --- a/test/src/busymark_design_test.dart +++ b/test/src/busymark_design_test.dart @@ -1305,6 +1305,14 @@ void main() { ); final colors = theme.extension<BusyMarkSurfaceColors>()!; final boundaryKey = GlobalKey(); + var backdrop = colors.view; + var blockCommandsEnabled = true; + var blockCommandCalls = 0; + late StateSetter rebuild; + final disabledBackground = Color.alphaBlend( + colors.disabledControl, + colors.view, + ); tester.view ..physicalSize = const Size(900, 240) ..devicePixelRatio = 1; @@ -1318,25 +1326,31 @@ void main() { home: RepaintBoundary( key: boundaryKey, child: Scaffold( - body: ColoredBox( - color: colors.view, - child: BusyMarkWysiwygToolbar( - onBlockCommand: (_) {}, - onAdmonitionCommand: (_) {}, - admonitionsEnabled: true, - onInlineCommand: (_) {}, - onLinkCommand: () {}, - onInlineMathCommand: () {}, - onDisplayMathCommand: () {}, - onImageCommand: () {}, - onInlineImageCommand: () {}, - onTableCommand: () {}, - onHtmlCommand: () {}, - onIndentCommand: () {}, - onOutdentCommand: () {}, - onToggleTaskCommand: () {}, - onHardBreakCommand: () {}, - ), + body: StatefulBuilder( + builder: (context, setState) { + rebuild = setState; + return ColoredBox( + color: backdrop, + child: BusyMarkWysiwygToolbar( + onBlockCommand: (_) => blockCommandCalls++, + isBlockCommandEnabled: (_) => blockCommandsEnabled, + onAdmonitionCommand: (_) {}, + admonitionsEnabled: true, + onInlineCommand: (_) {}, + onLinkCommand: () {}, + onInlineMathCommand: () {}, + onDisplayMathCommand: () {}, + onImageCommand: () {}, + onInlineImageCommand: () {}, + onTableCommand: () {}, + onHtmlCommand: () {}, + onIndentCommand: () {}, + onOutdentCommand: () {}, + onToggleTaskCommand: () {}, + onHardBreakCommand: () {}, + ), + ); + }, ), ), ), @@ -1370,7 +1384,7 @@ void main() { popups.every( (popup) => popup.backgroundColor?.resolve({WidgetState.disabled}) == - colors.disabledControl, + disabledBackground, ), isTrue, ); @@ -1462,7 +1476,7 @@ void main() { actions.every( (button) => button.backgroundColor?.resolve({WidgetState.disabled}) == - colors.disabledControl, + disabledBackground, ), isTrue, ); @@ -1490,7 +1504,7 @@ void main() { ); expect( button.style?.backgroundColor?.resolve({WidgetState.disabled}), - colors.disabledControl, + disabledBackground, ); } @@ -1519,6 +1533,45 @@ void main() { ); _expectColorNear(hover, expectedHover); expect(hover, isNot(rest)); + + await mouse.moveTo(Offset.zero); + rebuild(() => blockCommandsEnabled = false); + await tester.pumpAndSettle(); + expect(tester.widget<IconButton>(actionButton).onPressed, isNull); + final disabledPixels = await _capturePixels(tester, boundaryKey); + final disabled = _pixelAtLocal( + tester, + disabledPixels, + actionButton, + probe, + ); + + // Selection or text beneath the floating toolbar must not show through + // a disabled button's background. + rebuild(() { + backdrop = Color.alphaBlend( + accent.withValues(alpha: 0.25), + colors.view, + ); + }); + await tester.pumpAndSettle(); + final selectedPixels = await _capturePixels(tester, boundaryKey); + _expectColorNear( + _pixelAtLocal(tester, selectedPixels, actionButton, probe), + disabled, + ); + await tester.tap(actionButton); + expect(blockCommandCalls, 0); + + rebuild(() => blockCommandsEnabled = true); + await tester.pumpAndSettle(); + final restoredPixels = await _capturePixels(tester, boundaryKey); + _expectColorNear( + _pixelAtLocal(tester, restoredPixels, actionButton, probe), + accent, + ); + await tester.tap(actionButton); + expect(blockCommandCalls, 1); }); } From 7d96516b660ed5087dc36b55029e45af89a03bcc Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Mon, 7 Sep 2026 15:03:00 -0700 Subject: [PATCH 11/37] Add rich clipboard support for Linux and enhance WYSIWYG clipboard handling --- docs/clipboard-fix-plan.md | 74 +++ lib/l10n/app_en.arb | 2 + lib/l10n/generated/app_localizations.dart | 6 + lib/l10n/generated/app_localizations_ar.dart | 4 + lib/l10n/generated/app_localizations_de.dart | 4 + lib/l10n/generated/app_localizations_en.dart | 4 + lib/l10n/generated/app_localizations_es.dart | 4 + lib/l10n/generated/app_localizations_et.dart | 4 + lib/l10n/generated/app_localizations_fa.dart | 4 + lib/l10n/generated/app_localizations_fr.dart | 4 + lib/l10n/generated/app_localizations_hi.dart | 4 + lib/l10n/generated/app_localizations_id.dart | 4 + lib/l10n/generated/app_localizations_it.dart | 4 + lib/l10n/generated/app_localizations_ja.dart | 4 + lib/l10n/generated/app_localizations_ko.dart | 4 + lib/l10n/generated/app_localizations_nb.dart | 4 + lib/l10n/generated/app_localizations_nl.dart | 4 + lib/l10n/generated/app_localizations_pl.dart | 4 + lib/l10n/generated/app_localizations_pt.dart | 4 + lib/l10n/generated/app_localizations_ru.dart | 4 + lib/l10n/generated/app_localizations_tr.dart | 4 + lib/l10n/generated/app_localizations_uk.dart | 4 + lib/l10n/generated/app_localizations_vi.dart | 4 + lib/l10n/generated/app_localizations_zh.dart | 4 + .../wysiwyg/wysiwyg_clipboard_fragment.dart | 347 +++++++++++ .../wysiwyg/wysiwyg_clipboard_html.dart | 435 +++++++++++++ .../wysiwyg/wysiwyg_document_controller.dart | 162 +++-- lib/src/editor/wysiwyg/wysiwyg_editor.dart | 355 ++++++++--- lib/src/platform/rich_clipboard_service.dart | 102 ++++ linux/runner/CMakeLists.txt | 1 + linux/runner/my_application.cc | 4 + linux/runner/rich_clipboard_host.cc | 212 +++++++ linux/runner/rich_clipboard_host.h | 9 + test/flutter_test_config.dart | 7 + test/src/busymark_document_test.dart | 4 + test/src/wysiwyg_clipboard_test.dart | 572 ++++++++++++++++++ .../wysiwyg_structured_regression_test.dart | 3 + test/support/memory_rich_clipboard.dart | 19 + tools/clipboard_smoke.dart | 140 +++++ 39 files changed, 2406 insertions(+), 132 deletions(-) create mode 100644 docs/clipboard-fix-plan.md create mode 100644 lib/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart create mode 100644 lib/src/editor/wysiwyg/wysiwyg_clipboard_html.dart create mode 100644 lib/src/platform/rich_clipboard_service.dart create mode 100644 linux/runner/rich_clipboard_host.cc create mode 100644 linux/runner/rich_clipboard_host.h create mode 100644 test/src/wysiwyg_clipboard_test.dart create mode 100644 test/support/memory_rich_clipboard.dart create mode 100644 tools/clipboard_smoke.dart diff --git a/docs/clipboard-fix-plan.md b/docs/clipboard-fix-plan.md new file mode 100644 index 00000000..7859a9be --- /dev/null +++ b/docs/clipboard-fix-plan.md @@ -0,0 +1,74 @@ +# Editor clipboard fix + +Status: implemented for the Linux desktop host. + +Editor copy previously published only plain text. Formatting stayed in a private +cache inside one Editor widget, so a fresh Editor or another application could +not retrieve it. Copy now publishes three representations in one GTK clipboard +operation, and ordinary paste uses the richest supported representation. + +| Representation | Purpose | +| --- | --- | +| `application/x-busymark-fragment+json` | Preserve BusyMark structure, inline formatting, task states, tables, and Writerside content between instances. | +| `text/html` | Preserve headings, emphasis, links, lists, tables, and code in compatible external applications. Tasks have visible checked/unchecked symbols. | +| Standard GTK text targets | Support text-only destinations and Paste without formatting. | + +## Implementation + +- `rich_clipboard_service.dart` serializes competing writes and reads the system + clipboard without a private formatting cache. A native write publishes all + formats together; it is never followed by a plain write that would erase them. +- `rich_clipboard_host.cc` owns immutable payload bytes independently of the + originating widget. Reads are asynchronous and reject data from an owner that + changes during the read. Transfers are limited to 16 MiB. The host advertises + all formats for clipboard-manager storage using + [`gtk_clipboard_set_can_store`](https://docs.gtk.org/gtk3/method.Clipboard.set_can_store.html). + GTK's existing application shutdown performs the storage request. +- `wysiwyg_clipboard_fragment.dart` uses a versioned, bounded, validated JSON + schema. Block IDs are regenerated during insertion. Relative links are rebased + and resolved local media paths are carried between documents/projects. +- `wysiwyg_clipboard_html.dart` exports semantic HTML directly from the copied + blocks. On import it normalizes supported CSS emphasis and checkbox state, + strips executable markup and unsafe URLs, and uses the existing HTML adapter. + It does not change the document HTML policy or write publication assets. +- Editor copy snapshots the selection before asynchronous work. Cut deletes only + after a successful write. Paste and cut recheck the file, document generation, + active block/cell, and selection before changing the document. Nested children + are copied once; complete blockquotes retain their container. +- Insertion preserves inline nodes, including image references, and supports + partial selections and one-step undo/redo. Table cells retain supported inline + styles while block boundaries become spaces. Cells displayed as math source + retain their existing text insertion behavior. + +## Validation + +- 237 editor/model regression tests pass, including fresh Editor instances, + same-Editor cut/paste, partial selections, nested lists, blockquotes, tasks, + tables, code, Writerside, images, RTL, math, undo/redo, malformed fragments, + serialized writes, failed cut, delayed paste, and a later plain-text copy. +- Both reported files, `issues.md` and `writerside-support.md`, passed a read-only + codec and insertion probe. Heading, task, table, blockquote, and code content + survived; exported HTML also imported successfully. +- Separate compiled BusyMark processes exchanged JSON, HTML, and plain text on + isolated X11 and headless GNOME Wayland displays. A subsequent Flutter plain + copy cleared the rich formats. +- LibreOffice Writer pasted a Heading 1 paragraph, bold text, and visible checked + and unchecked task states from the compiled Linux implementation. + +The native probe entrypoint is `tools/clipboard_smoke.dart`. Build it with +`flutter build linux --debug -t tools/clipboard_smoke.dart`, then run `write`, +`read`, or `plain` with the same temporary output directory on an isolated display. +Keep `write` running until the reads complete; creating a `stop` file in that +directory closes it. Rebuild with the default entrypoint afterward. + +## Interoperability limits + +Clipboard persistence after the source process exits depends on the desktop's +clipboard manager and the formats it retains. That exit scenario remains a manual +check. Source-widget disposal does not discard clipboard payloads. External +applications choose which offered format to consume; plain-text applications +will still paste plain text. Writerside-specific structures remain editable +through the BusyMark format and use readable HTML fallbacks externally. Local +media references point to existing files and do not bundle their bytes. + +Hosts without the Linux method channel currently fall back to plain text. diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 9dbf1a73..cbab63d6 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -90,6 +90,8 @@ "chooseLocation": "Choose location", "@chooseLocation": {"description": "File picker confirmation label for choosing a directory."}, "copy": "Copy", + "clipboardCopyFailed": "Could not copy the selection to the clipboard.", + "@clipboardCopyFailed": {"description": "Shown when Editor copy or cut cannot write the clipboard; cut leaves the document intact."}, "@copy": {"description": "Copy command label."}, "copyName": "Copy name", "@copyName": {"description": "Menu action that copies the selected file, folder, or workspace name."}, diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index fb0e3f60..e4cd8712 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -403,6 +403,12 @@ abstract class AppLocalizations { /// **'Copy'** String get copy; + /// Shown when Editor copy or cut cannot write the clipboard; cut leaves the document intact. + /// + /// In en, this message translates to: + /// **'Could not copy the selection to the clipboard.'** + String get clipboardCopyFailed; + /// Menu action that copies the selected file, folder, or workspace name. /// /// In en, this message translates to: diff --git a/lib/l10n/generated/app_localizations_ar.dart b/lib/l10n/generated/app_localizations_ar.dart index 99c4c3ef..c4c9f117 100644 --- a/lib/l10n/generated/app_localizations_ar.dart +++ b/lib/l10n/generated/app_localizations_ar.dart @@ -152,6 +152,10 @@ class AppLocalizationsAr extends AppLocalizations { @override String get copy => 'نسخ'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'نسخ الاسم'; diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index e33b9039..dcf74d0a 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -156,6 +156,10 @@ class AppLocalizationsDe extends AppLocalizations { @override String get copy => 'Kopieren'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Namen kopieren'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 986b271d..7464d107 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -153,6 +153,10 @@ class AppLocalizationsEn extends AppLocalizations { @override String get copy => 'Copy'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Copy name'; diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart index 893a8612..1343c9a3 100644 --- a/lib/l10n/generated/app_localizations_es.dart +++ b/lib/l10n/generated/app_localizations_es.dart @@ -155,6 +155,10 @@ class AppLocalizationsEs extends AppLocalizations { @override String get copy => 'Copiar'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Copiar nombre'; diff --git a/lib/l10n/generated/app_localizations_et.dart b/lib/l10n/generated/app_localizations_et.dart index aa984a9c..5c2ea647 100644 --- a/lib/l10n/generated/app_localizations_et.dart +++ b/lib/l10n/generated/app_localizations_et.dart @@ -152,6 +152,10 @@ class AppLocalizationsEt extends AppLocalizations { @override String get copy => 'Kopeeri'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Kopeeri nimi'; diff --git a/lib/l10n/generated/app_localizations_fa.dart b/lib/l10n/generated/app_localizations_fa.dart index 42a3fc0e..33a7f95f 100644 --- a/lib/l10n/generated/app_localizations_fa.dart +++ b/lib/l10n/generated/app_localizations_fa.dart @@ -152,6 +152,10 @@ class AppLocalizationsFa extends AppLocalizations { @override String get copy => 'کپی'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'کپی نام'; diff --git a/lib/l10n/generated/app_localizations_fr.dart b/lib/l10n/generated/app_localizations_fr.dart index 7efea910..a3c66db9 100644 --- a/lib/l10n/generated/app_localizations_fr.dart +++ b/lib/l10n/generated/app_localizations_fr.dart @@ -155,6 +155,10 @@ class AppLocalizationsFr extends AppLocalizations { @override String get copy => 'Copier'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Copier le nom'; diff --git a/lib/l10n/generated/app_localizations_hi.dart b/lib/l10n/generated/app_localizations_hi.dart index 0a33be32..50c0ad22 100644 --- a/lib/l10n/generated/app_localizations_hi.dart +++ b/lib/l10n/generated/app_localizations_hi.dart @@ -154,6 +154,10 @@ class AppLocalizationsHi extends AppLocalizations { @override String get copy => 'कॉपी करें'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'नाम कॉपी करें'; diff --git a/lib/l10n/generated/app_localizations_id.dart b/lib/l10n/generated/app_localizations_id.dart index 940cbad3..e31761d2 100644 --- a/lib/l10n/generated/app_localizations_id.dart +++ b/lib/l10n/generated/app_localizations_id.dart @@ -154,6 +154,10 @@ class AppLocalizationsId extends AppLocalizations { @override String get copy => 'Salin'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Salin nama'; diff --git a/lib/l10n/generated/app_localizations_it.dart b/lib/l10n/generated/app_localizations_it.dart index 61db60dc..3971a211 100644 --- a/lib/l10n/generated/app_localizations_it.dart +++ b/lib/l10n/generated/app_localizations_it.dart @@ -154,6 +154,10 @@ class AppLocalizationsIt extends AppLocalizations { @override String get copy => 'Copia'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Copia nome'; diff --git a/lib/l10n/generated/app_localizations_ja.dart b/lib/l10n/generated/app_localizations_ja.dart index 66bbc5b0..25a11b95 100644 --- a/lib/l10n/generated/app_localizations_ja.dart +++ b/lib/l10n/generated/app_localizations_ja.dart @@ -149,6 +149,10 @@ class AppLocalizationsJa extends AppLocalizations { @override String get copy => 'コピー'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => '名前をコピー'; diff --git a/lib/l10n/generated/app_localizations_ko.dart b/lib/l10n/generated/app_localizations_ko.dart index cc9c81b4..44061bdf 100644 --- a/lib/l10n/generated/app_localizations_ko.dart +++ b/lib/l10n/generated/app_localizations_ko.dart @@ -148,6 +148,10 @@ class AppLocalizationsKo extends AppLocalizations { @override String get copy => '복사'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => '이름 복사'; diff --git a/lib/l10n/generated/app_localizations_nb.dart b/lib/l10n/generated/app_localizations_nb.dart index f43512b1..627fe8a5 100644 --- a/lib/l10n/generated/app_localizations_nb.dart +++ b/lib/l10n/generated/app_localizations_nb.dart @@ -155,6 +155,10 @@ class AppLocalizationsNb extends AppLocalizations { @override String get copy => 'Kopier'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Kopier navn'; diff --git a/lib/l10n/generated/app_localizations_nl.dart b/lib/l10n/generated/app_localizations_nl.dart index c7de92e6..1a2dbb5d 100644 --- a/lib/l10n/generated/app_localizations_nl.dart +++ b/lib/l10n/generated/app_localizations_nl.dart @@ -155,6 +155,10 @@ class AppLocalizationsNl extends AppLocalizations { @override String get copy => 'Kopiëren'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Kopieer naam'; diff --git a/lib/l10n/generated/app_localizations_pl.dart b/lib/l10n/generated/app_localizations_pl.dart index 0786619b..177ef81d 100644 --- a/lib/l10n/generated/app_localizations_pl.dart +++ b/lib/l10n/generated/app_localizations_pl.dart @@ -154,6 +154,10 @@ class AppLocalizationsPl extends AppLocalizations { @override String get copy => 'Kopiuj'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Kopiuj nazwę'; diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart index 1dd11b08..a88eacdb 100644 --- a/lib/l10n/generated/app_localizations_pt.dart +++ b/lib/l10n/generated/app_localizations_pt.dart @@ -153,6 +153,10 @@ class AppLocalizationsPt extends AppLocalizations { @override String get copy => 'Copy'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Copy name'; diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart index 27b7c36c..f751c192 100644 --- a/lib/l10n/generated/app_localizations_ru.dart +++ b/lib/l10n/generated/app_localizations_ru.dart @@ -155,6 +155,10 @@ class AppLocalizationsRu extends AppLocalizations { @override String get copy => 'Копировать'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Копировать имя'; diff --git a/lib/l10n/generated/app_localizations_tr.dart b/lib/l10n/generated/app_localizations_tr.dart index ec033e49..73b2eb45 100644 --- a/lib/l10n/generated/app_localizations_tr.dart +++ b/lib/l10n/generated/app_localizations_tr.dart @@ -155,6 +155,10 @@ class AppLocalizationsTr extends AppLocalizations { @override String get copy => 'Kopyala'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Adı kopyala'; diff --git a/lib/l10n/generated/app_localizations_uk.dart b/lib/l10n/generated/app_localizations_uk.dart index 1b27b7d9..1f2d279b 100644 --- a/lib/l10n/generated/app_localizations_uk.dart +++ b/lib/l10n/generated/app_localizations_uk.dart @@ -154,6 +154,10 @@ class AppLocalizationsUk extends AppLocalizations { @override String get copy => 'Копіювати'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Копіювати назву'; diff --git a/lib/l10n/generated/app_localizations_vi.dart b/lib/l10n/generated/app_localizations_vi.dart index e93687f1..8e185a67 100644 --- a/lib/l10n/generated/app_localizations_vi.dart +++ b/lib/l10n/generated/app_localizations_vi.dart @@ -153,6 +153,10 @@ class AppLocalizationsVi extends AppLocalizations { @override String get copy => 'Sao chép'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Sao chép tên'; diff --git a/lib/l10n/generated/app_localizations_zh.dart b/lib/l10n/generated/app_localizations_zh.dart index 45147432..7ab5ae1d 100644 --- a/lib/l10n/generated/app_localizations_zh.dart +++ b/lib/l10n/generated/app_localizations_zh.dart @@ -153,6 +153,10 @@ class AppLocalizationsZh extends AppLocalizations { @override String get copy => 'Copy'; + @override + String get clipboardCopyFailed => + 'Could not copy the selection to the clipboard.'; + @override String get copyName => 'Copy name'; diff --git a/lib/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart b/lib/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart new file mode 100644 index 00000000..49d5a439 --- /dev/null +++ b/lib/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart @@ -0,0 +1,347 @@ +import 'dart:convert'; + +import 'package:path/path.dart' as p; + +import '../../markdown/busymark_document.dart'; +import '../../markdown/markdown_model.dart'; +import '../../platform/rich_clipboard_service.dart'; +import 'wysiwyg_document_controller.dart'; +import 'wysiwyg_inline_controller.dart'; + +const _maxNodes = 10000; +const _maxDepth = 64; + +class WysiwygClipboardFragment { + const WysiwygClipboardFragment({ + required this.blocks, + required this.mode, + this.sourcePath = '', + this.mediaPaths = const {}, + }); + + final List<BusyWysiwygStyledBlock> blocks; + final MarkdownMode mode; + final String sourcePath; + final Map<String, String> mediaPaths; + + List<BusyBlock> get documentBlocks => [ + for (final block in blocks) busyMarkWysiwygClipboardBlock(block), + ]; + + String encode() => jsonEncode({ + 'version': 1, + 'mode': mode.name, + 'sourcePath': sourcePath, + 'mediaPaths': mediaPaths, + 'blocks': [ + for (final block in blocks) + { + 'kind': block.kind.name, + 'text': block.text, + 'attributes': block.attributes, + 'ranges': [ + for (final range in block.ranges) + { + 'start': range.start, + 'end': range.end, + 'kind': range.kind.name, + if (range.destination != null) 'destination': range.destination, + }, + ], + if (block.completeBlock != null) + 'completeBlock': _encodeBlock(block.completeBlock!), + }, + ], + }); + + static WysiwygClipboardFragment? decode(String source) { + if (source.length > maxRichClipboardBytes || + utf8.encode(source).length > maxRichClipboardBytes || + !_boundedJsonDepth(source)) { + return null; + } + try { + final reader = _FragmentReader(); + final map = reader.map(jsonDecode(source)); + if (map['version'] != 1) return null; + final mode = MarkdownMode.values.byName(reader.string(map['mode'])); + final origin = reader.string(map['sourcePath']); + final media = map['mediaPaths'] == null + ? const <String, String>{} + : reader.attributes(map['mediaPaths']); + final blocks = <BusyWysiwygStyledBlock>[]; + for (final item in reader.list(map['blocks'])) { + reader.visit(0); + final block = reader.map(item); + final kind = BusyBlockKind.values.byName(reader.string(block['kind'])); + final text = reader.string(block['text']); + final ranges = <BusyInlineStyleRange>[]; + for (final item in reader.list(block['ranges'])) { + reader.visit(0); + final range = reader.map(item); + final start = range['start']; + final end = range['end']; + if (start is! int || + end is! int || + start < 0 || + end < start || + end > text.length) { + throw const FormatException('Invalid clipboard text range'); + } + ranges.add( + BusyInlineStyleRange( + start: start, + end: end, + kind: BusyInlineKind.values.byName(reader.string(range['kind'])), + destination: reader.optionalString(range['destination']), + ), + ); + } + final complete = block['completeBlock'] == null + ? null + : reader.block(block['completeBlock'], 0); + if (complete != null && + (complete.kind != kind || complete.plainText != text)) { + throw const FormatException('Inconsistent clipboard block'); + } + blocks.add( + BusyWysiwygStyledBlock( + kind: kind, + text: text, + ranges: List.unmodifiable(ranges), + attributes: reader.attributes(block['attributes']), + completeBlock: complete, + ), + ); + } + return blocks.isEmpty + ? null + : WysiwygClipboardFragment( + blocks: List.unmodifiable(blocks), + mode: mode, + sourcePath: origin, + mediaPaths: media, + ); + } on FormatException { + return null; + } on ArgumentError { + return null; + } + } + + /// Rebase authored references, without opening or fetching clipboard URLs. + WysiwygClipboardFragment rebase(String targetPath) { + if (sourcePath.isEmpty || + targetPath.isEmpty || + p.equals(sourcePath, targetPath)) { + return this; + } + String? destination(String? value, {bool media = false}) { + if (value == null || value.isEmpty) return value; + if (media) { + final resolved = mediaPaths[value]; + if (resolved != null && p.isAbsolute(resolved)) { + return Uri(path: resolved).toString(); + } + } + final uri = Uri.tryParse(value); + if (uri == null || uri.hasScheme || uri.hasAuthority) return value; + final resolved = Uri.file(p.absolute(sourcePath)).resolveUri(uri); + final path = p.relative( + Uri(scheme: 'file', path: resolved.path).toFilePath(), + from: p.dirname(p.absolute(targetPath)), + ); + return Uri( + path: path, + query: uri.hasQuery ? uri.query : null, + fragment: uri.hasFragment ? uri.fragment : null, + ).toString(); + } + + Map<String, String> attributes(Map<String, String> values) => { + for (final entry in values.entries) + entry.key: {'src', 'href', 'destination'}.contains(entry.key) + ? destination(entry.value, media: entry.key == 'src') ?? entry.value + : entry.value, + }; + BusyInline inline(BusyInline value) => BusyInline( + kind: value.kind, + text: value.text, + destination: destination( + value.destination, + media: value.kind == BusyInlineKind.image, + ), + attributes: attributes(value.attributes), + children: [for (final child in value.children) inline(child)], + ); + BusyBlock block(BusyBlock value) => BusyBlock( + id: value.id, + kind: value.kind, + inlines: [for (final child in value.inlines) inline(child)], + children: [for (final child in value.children) block(child)], + attributes: attributes(value.attributes), + rawSource: value.rawSource, + preserveRaw: value.preserveRaw, + isSourceOnly: value.isSourceOnly, + isGenerated: value.isGenerated, + isSourceProtected: value.isSourceProtected, + dirty: true, + ); + return WysiwygClipboardFragment( + mode: mode, + sourcePath: targetPath, + mediaPaths: mediaPaths, + blocks: [ + for (final value in blocks) + BusyWysiwygStyledBlock( + kind: value.kind, + text: value.text, + attributes: attributes(value.attributes), + ranges: [ + for (final range in value.ranges) + BusyInlineStyleRange( + start: range.start, + end: range.end, + kind: range.kind, + destination: destination( + range.destination, + media: range.kind == BusyInlineKind.image, + ), + ), + ], + completeBlock: value.completeBlock == null + ? null + : block(value.completeBlock!), + ), + ], + ); + } +} + +Map<String, Object?> _encodeInline(BusyInline inline) => { + 'kind': inline.kind.name, + 'text': inline.text, + if (inline.destination != null) 'destination': inline.destination, + 'attributes': inline.attributes, + 'children': [for (final child in inline.children) _encodeInline(child)], +}; + +Map<String, Object?> _encodeBlock(BusyBlock block) => { + 'kind': block.kind.name, + 'inlines': [for (final inline in block.inlines) _encodeInline(inline)], + 'children': [for (final child in block.children) _encodeBlock(child)], + 'attributes': block.attributes, + if (block.rawSource != null) 'rawSource': block.rawSource, + 'preserveRaw': block.preserveRaw, + 'sourceOnly': block.isSourceOnly, + 'generated': block.isGenerated, + 'sourceProtected': block.isSourceProtected, +}; + +bool _boundedJsonDepth(String source) { + var depth = 0; + var quoted = false; + var escaped = false; + for (final unit in source.codeUnits) { + if (quoted) { + if (escaped) { + escaped = false; + } else if (unit == 92) { + escaped = true; + } else if (unit == 34) { + quoted = false; + } + } else if (unit == 34) { + quoted = true; + } else if (unit == 91 || unit == 123) { + if (++depth > _maxDepth * 2 + 8) return false; + } else if (unit == 93 || unit == 125) { + depth--; + } + } + return true; +} + +class _FragmentReader { + var nodes = 0; + + void visit(int depth) { + if (++nodes > _maxNodes || depth > _maxDepth) { + throw const FormatException('Clipboard nesting or node limit exceeded'); + } + } + + Map<String, dynamic> map(dynamic value) { + if (value is! Map<String, dynamic>) { + throw const FormatException('Expected object'); + } + return value; + } + + List<dynamic> list(dynamic value) { + if (value is! List || value.length > _maxNodes) { + throw const FormatException('Expected bounded list'); + } + return value; + } + + String string(dynamic value) { + if (value is! String || value.contains('\u0000')) { + throw const FormatException('Expected text'); + } + return value; + } + + String? optionalString(dynamic value) => value == null ? null : string(value); + bool boolean(dynamic value) { + if (value is! bool) throw const FormatException('Expected boolean'); + return value; + } + + Map<String, String> attributes(dynamic value) { + final entries = map(value); + if (entries.length > 256) { + throw const FormatException('Too many attributes'); + } + return Map.unmodifiable({ + for (final entry in entries.entries) entry.key: string(entry.value), + }); + } + + BusyInline inline(dynamic value, int depth) { + visit(depth); + final data = map(value); + return BusyInline( + kind: BusyInlineKind.values.byName(string(data['kind'])), + text: string(data['text']), + destination: optionalString(data['destination']), + attributes: attributes(data['attributes']), + children: List.unmodifiable([ + for (final child in list(data['children'])) inline(child, depth + 1), + ]), + ); + } + + BusyBlock block(dynamic value, int depth) { + visit(depth); + final data = map(value); + final id = 'clipboard-$nodes'; + return BusyBlock( + id: id, + kind: BusyBlockKind.values.byName(string(data['kind'])), + inlines: List.unmodifiable([ + for (final child in list(data['inlines'])) inline(child, depth + 1), + ]), + children: List.unmodifiable([ + for (final child in list(data['children'])) block(child, depth + 1), + ]), + attributes: attributes(data['attributes']), + rawSource: optionalString(data['rawSource']), + preserveRaw: boolean(data['preserveRaw']), + isSourceOnly: boolean(data['sourceOnly']), + isGenerated: boolean(data['generated']), + isSourceProtected: boolean(data['sourceProtected']), + dirty: true, + ); + } +} diff --git a/lib/src/editor/wysiwyg/wysiwyg_clipboard_html.dart b/lib/src/editor/wysiwyg/wysiwyg_clipboard_html.dart new file mode 100644 index 00000000..e749669c --- /dev/null +++ b/lib/src/editor/wysiwyg/wysiwyg_clipboard_html.dart @@ -0,0 +1,435 @@ +import 'dart:convert'; + +import 'package:html/dom.dart' as dom; +import 'package:html/parser.dart' as html; +import 'package:path/path.dart' as p; + +import '../../markdown/busymark_document.dart'; +import '../../markdown/markdown_model.dart'; +import '../../markdown/raw_html_adapter.dart'; +import '../../markdown/raw_html_policy.dart'; +import '../../platform/rich_clipboard_service.dart'; +import 'wysiwyg_clipboard_fragment.dart'; +import 'wysiwyg_document_controller.dart'; +import 'wysiwyg_inline_controller.dart'; + +class WysiwygClipboardHtml { + const WysiwygClipboardHtml(); + + String encode(WysiwygClipboardFragment fragment) { + final writer = _HtmlWriter(fragment.sourcePath, fragment.mediaPaths); + final body = dom.Element.tag('div') + ..nodes.addAll(writer.blocks(fragment.documentBlocks)); + return '<html><head><meta charset="utf-8"></head><body>' + '<!--StartFragment-->${body.innerHtml}<!--EndFragment-->' + '</body></html>'; + } + + WysiwygClipboardFragment? decode( + String source, { + required MarkdownMode mode, + }) { + if (source.length > maxRichClipboardBytes || + utf8.encode(source).length > maxRichClipboardBytes) { + return null; + } + try { + final start = source.indexOf('<!--StartFragment-->'); + final end = source.indexOf('<!--EndFragment-->'); + final content = start >= 0 && end > start + ? source.substring(start + '<!--StartFragment-->'.length, end) + : source; + final body = html.parse(content).body; + if (body == null) return null; + final normalizer = _HtmlNormalizer(); + final clean = dom.Element.tag('div') + ..nodes.addAll(normalizer.nodes(body.nodes, 0, const {})); + var id = 0; + final parsed = const RawHtmlAdapter().parseRawHtmlBlock( + clean.outerHtml, + () => 'clipboard-html-${id++}', + ); + if (parsed == null || !parsed.safe || parsed.blocks.isEmpty) return null; + BusyBlock task(BusyBlock block) { + final children = [for (final child in block.children) task(child)]; + if ((block.kind == BusyBlockKind.unorderedListItem || + block.kind == BusyBlockKind.orderedListItem) && + RegExp(r'^[☐☑]\s').hasMatch(block.plainText)) { + final checked = block.plainText.startsWith('☑'); + var remaining = 2; + BusyInline strip(BusyInline value) { + if (remaining == 0) return value; + if (value.children.isNotEmpty) { + return value.copyWith( + children: [for (final child in value.children) strip(child)], + ); + } + final count = remaining.clamp(0, value.text.length); + remaining -= count; + return value.copyWith(text: value.text.substring(count)); + } + + return block.copyWith( + kind: BusyBlockKind.taskListItem, + inlines: [for (final value in block.inlines) strip(value)], + children: children, + attributes: {...block.attributes, 'task': '$checked'}, + dirty: true, + ); + } + return block.copyWith(children: children, dirty: true); + } + + return WysiwygClipboardFragment( + mode: mode, + blocks: [ + for (final value in parsed.blocks.map(task)) + BusyWysiwygStyledBlock( + kind: value.kind, + text: value.plainText, + ranges: busyInlineStyleRanges(value.inlines), + attributes: value.attributes, + completeBlock: value, + ), + ], + ); + } on FormatException { + return null; + } on ArgumentError { + return null; + } + } +} + +dom.Element _element( + String tag, + Iterable<dom.Node> children, [ + Map<String, String> attrs = const {}, +]) { + return dom.Element.tag(tag) + ..attributes.addAll(attrs) + ..nodes.addAll(children); +} + +class _HtmlWriter { + _HtmlWriter(this.sourcePath, this.mediaPaths); + final String sourcePath; + final Map<String, String> mediaPaths; + var count = 0; + + void visit(int depth) { + if (++count > maxRawHtmlNodes || depth > maxRawHtmlDepth) { + throw const FormatException('Clipboard HTML is too complex'); + } + } + + String? url(String? value, String tag, String attribute) { + if (value == null || value.isEmpty) return null; + if (attribute == 'src' && mediaPaths[value] != null) { + return Uri.file(mediaPaths[value]!).toString(); + } + final uri = Uri.tryParse(value); + if (uri == null) return null; + if (uri.scheme == 'file') return uri.toString(); + if (!isSafeHtmlUrlAttribute(tag, attribute, value)) return null; + return !uri.hasScheme && sourcePath.isNotEmpty + ? Uri.file(p.absolute(sourcePath)).resolveUri(uri).toString() + : value; + } + + List<dom.Node> blocks(List<BusyBlock> values, [int depth = 0]) { + final out = <dom.Node>[]; + for (var i = 0; i < values.length; i++) { + final b = values[i]; + visit(depth); + if (b.isSourceOnly || b.kind == BusyBlockKind.frontMatter) continue; + if (_isList(b)) { + final ordered = _ordered(b); + final list = dom.Element.tag(ordered ? 'ol' : 'ul'); + final start = int.tryParse( + (b.attributes['marker'] ?? '').replaceAll(RegExp(r'\D'), ''), + ); + if (ordered && start != null && start != 1) { + list.attributes['start'] = '$start'; + } + while (i < values.length && + _isList(values[i]) && + _ordered(values[i]) == ordered) { + final item = values[i++]; + final li = dom.Element.tag('li'); + if (item.kind == BusyBlockKind.taskListItem) { + li.nodes.add( + dom.Text(item.attributes['task'] == 'true' ? '☑ ' : '☐ '), + ); + } + li.nodes.addAll(inlines(item.inlines, depth + 1)); + li.nodes.addAll(blocks(item.children, depth + 1)); + list.nodes.add(li); + } + i--; + out.add(list); + continue; + } + List<dom.Node> content() => inlines(b.inlines, depth + 1); + switch (b.kind) { + case BusyBlockKind.heading: + final level = (int.tryParse(b.attributes['level'] ?? '') ?? 1).clamp( + 1, + 6, + ); + out.add(_element('h$level', content())); + out.addAll(blocks(b.children, depth + 1)); + case BusyBlockKind.paragraph: + out.add(_element('p', content())); + out.addAll(blocks(b.children, depth + 1)); + case BusyBlockKind.codeBlock: + out.add( + _element('pre', [ + _element( + 'code', + [dom.Text(b.plainText)], + { + if (b.attributes['language'] case final language?) + 'class': 'language-$language', + }, + ), + ]), + ); + case BusyBlockKind.thematicBreak: + out.add(dom.Element.tag('hr')); + case BusyBlockKind.table: + final table = dom.Element.tag('table')..attributes['border'] = '1'; + for (final row in b.children) { + final tr = dom.Element.tag('tr'); + for (final cell in row.children) { + final header = + cell.attributes['header'] == 'true' || + cell.attributes['cell'] == 'th' || + row.attributes['header'] == 'true'; + tr.nodes.add( + _element( + header ? 'th' : 'td', + [ + ...inlines(cell.inlines, depth + 1), + ...blocks(cell.children, depth + 1), + ], + { + for (final key in ['rowspan', 'colspan', 'align']) + if (cell.attributes[key] case final value?) key: value, + }, + ), + ); + } + table.nodes.add(tr); + } + out.add(table); + case BusyBlockKind.blockquote: + case BusyBlockKind.writersideAdmonition: + out.add( + _element('blockquote', [ + ...content(), + ...blocks(b.children, depth + 1), + ]), + ); + case BusyBlockKind.image: + if (b.inlines.isNotEmpty) { + out.add(_element('p', content())); + } else { + out.add(image(b.attributes['src'], b.attributes['alt'] ?? '')); + } + case BusyBlockKind.video: + final href = url(b.attributes['src'], 'a', 'href'); + out.add( + _element('p', [ + _element( + 'a', + [dom.Text(b.attributes['title'] ?? 'Video')], + {if (href != null) 'href': href}, + ), + ]), + ); + case BusyBlockKind.htmlBlock: + final adapted = const RawHtmlAdapter().parseRawHtmlBlock( + b.rawSource ?? '', + () => 'html-export-${count++}', + ); + if (adapted != null && adapted.safe && adapted.blocks.isNotEmpty) { + out.addAll(blocks(adapted.blocks, depth + 1)); + } else { + out.add(_element('pre', [dom.Text(b.rawSource ?? b.plainText)])); + } + default: + if (b.children.isNotEmpty) { + out.add( + _element('div', [...content(), ...blocks(b.children, depth + 1)]), + ); + } else { + out.add(_element('pre', [dom.Text(b.rawSource ?? b.plainText)])); + } + } + } + return out; + } + + bool _isList(BusyBlock b) => { + BusyBlockKind.unorderedListItem, + BusyBlockKind.orderedListItem, + BusyBlockKind.taskListItem, + }.contains(b.kind); + bool _ordered(BusyBlock b) => + b.kind == BusyBlockKind.orderedListItem || + b.attributes['ordered'] == 'true'; + dom.Node image(String? src, String alt) { + final resolved = url(src, 'img', 'src'); + return resolved == null + ? dom.Text(alt) + : _element('img', [], {'src': resolved, 'alt': alt}); + } + + List<dom.Node> inlines(List<BusyInline> values, int depth) { + final out = <dom.Node>[]; + for (final value in values) { + visit(depth); + List<dom.Node> children() => value.children.isEmpty + ? <dom.Node>[dom.Text(value.text)] + : inlines(value.children, depth + 1); + switch (value.kind) { + case BusyInlineKind.strong: + out.add(_element('strong', children())); + case BusyInlineKind.emphasis: + out.add(_element('em', children())); + case BusyInlineKind.underline: + out.add(_element('u', children())); + case BusyInlineKind.strikethrough: + out.add(_element('del', children())); + case BusyInlineKind.code: + out.add(_element('code', [dom.Text(value.text)])); + case BusyInlineKind.hardBreak: + out.add(dom.Element.tag('br')); + case BusyInlineKind.softBreak: + out.add(dom.Text('\n')); + case BusyInlineKind.image: + out.add(image(value.destination, value.text)); + case BusyInlineKind.link: + final href = url(value.destination, 'a', 'href'); + out.add(_element('a', children(), {if (href != null) 'href': href})); + default: + out.addAll(children()); + } + } + return out; + } +} + +class _HtmlNormalizer { + var count = 0; + static const _discard = { + 'script', + 'style', + 'head', + 'meta', + 'link', + 'iframe', + 'object', + 'embed', + 'template', + 'svg', + 'math', + }; + + List<dom.Node> nodes( + Iterable<dom.Node> input, + int depth, + Set<String> styles, + ) { + if (depth > maxRawHtmlDepth) { + throw const FormatException('Clipboard HTML nesting limit'); + } + final out = <dom.Node>[]; + for (final node in input) { + if (++count > maxRawHtmlNodes) { + throw const FormatException('Clipboard HTML node limit'); + } + if (node is dom.Text) { + dom.Node text = dom.Text(node.data); + if (node.data.trim().isNotEmpty) { + for (final tag in styles) { + text = _element(tag, [text]); + } + } + out.add(text); + continue; + } + if (node is! dom.Element) continue; + var tag = node.localName ?? ''; + if (_discard.contains(tag)) continue; + if (tag == 'input') { + if (node.attributes['type']?.toLowerCase() == 'checkbox') { + out.add( + dom.Text(node.attributes.containsKey('checked') ? '☑ ' : '☐ '), + ); + } + continue; + } + final inherited = {...styles}; + for (final declaration in (node.attributes['style'] ?? '').split(';')) { + final colon = declaration.indexOf(':'); + if (colon < 0) continue; + final name = declaration.substring(0, colon).trim().toLowerCase(); + final value = declaration + .substring(colon + 1) + .replaceAll('!important', '') + .trim() + .toLowerCase(); + if (name == 'font-weight') { + if (value == 'bold' || (int.tryParse(value) ?? 0) >= 600) { + inherited.add('strong'); + } else if (value == 'normal' || (int.tryParse(value) ?? 600) < 600) { + inherited.remove('strong'); + } + } else if (name == 'font-style') { + if (value == 'italic' || value == 'oblique') { + inherited.add('em'); + } else if (value == 'normal') { + inherited.remove('em'); + } + } else if (name == 'text-decoration' || + name == 'text-decoration-line') { + if (value.contains('underline')) inherited.add('u'); + if (value.contains('line-through')) inherited.add('del'); + if (value == 'none') { + inherited + ..remove('u') + ..remove('del'); + } + } + } + final children = nodes(node.nodes, depth + 1, inherited); + tag = switch (tag) { + 'b' => 'strong', + 'i' => 'em', + 'strike' => 'del', + 'font' => 'span', + _ => tag, + }; + if (!isSafeHtmlTag(tag)) { + out.addAll(children); + continue; + } + final attrs = <String, String>{}; + for (final entry in node.attributes.entries) { + final name = entry.key.toString().toLowerCase(); + if (name == 'style' || name.startsWith('on')) continue; + // IDs from another document must not collide with destination anchors. + if (name == 'id') continue; + if (isSafeHtmlUrlAttribute(tag, name, entry.value)) { + attrs[name] = entry.value; + } + } + out.add( + _element(tag, children, sanitizeHtmlAttributes(tag, attrs) ?? const {}), + ); + } + return out; + } +} diff --git a/lib/src/editor/wysiwyg/wysiwyg_document_controller.dart b/lib/src/editor/wysiwyg/wysiwyg_document_controller.dart index 0cd3d6d1..666ea622 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_document_controller.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_document_controller.dart @@ -467,6 +467,67 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { ); } + /// A table cell accepts inline formatting; block boundaries become spaces. + int? insertStyledInlinesInTableCell({ + required String tableBlockId, + required String cellId, + required int selectionStart, + required int selectionEnd, + required List<BusyWysiwygStyledBlock> blocks, + }) { + final cell = blockById(cellId); + final table = blockById(tableBlockId); + if (cell == null || table?.kind != BusyBlockKind.table || blocks.isEmpty) { + return null; + } + BusyInline normalize(BusyInline inline) => + inline.kind == BusyInlineKind.hardBreak || + inline.kind == BusyInlineKind.softBreak + ? const BusyInline(kind: BusyInlineKind.text, text: ' ') + : inline.copyWith( + text: busyMarkNormalizeTableCellText(inline.text), + children: [for (final child in inline.children) normalize(child)], + ); + final inserted = <BusyInline>[]; + void append(BusyBlock block) { + if (inserted.isNotEmpty) { + inserted.add(const BusyInline(kind: BusyInlineKind.text, text: ' ')); + } + inserted.addAll(block.inlines.map(normalize)); + for (final child in block.children) { + append(child); + } + } + + for (final block in blocks) { + append(busyMarkWysiwygClipboardBlock(block)); + } + final start = selectionStart.clamp(0, cell.plainText.length); + final end = selectionEnd.clamp(start, cell.plainText.length); + final partition = _partitionInlinesForReplacement(cell.inlines, start, end); + _replaceBlock( + tableBlockId, + (table) => table.copyWith( + children: _replaceInBlocks( + table.children, + cellId, + (cell) => cell.copyWith( + inlines: [...partition.before, ...inserted, ...partition.after], + preserveRaw: false, + dirty: true, + ), + ), + preserveRaw: false, + dirty: true, + ), + ); + return start + + inserted.fold<int>( + 0, + (length, inline) => length + inline.plainText.length, + ); + } + void _updateTableCellText( String tableBlockId, String cellId, @@ -1680,11 +1741,13 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { final text = block.plainText; final start = selectionStart.clamp(0, text.length).toInt(); final end = selectionEnd.clamp(start, text.length).toInt(); - final oldRanges = busyInlineStyleRanges(block.inlines); final beforeText = text.substring(0, start); final afterText = text.substring(end); - final beforeRanges = _styleRangesForSlice(oldRanges, 0, start); - final afterRanges = _styleRangesForSlice(oldRanges, end, text.length); + final partition = _partitionInlinesForReplacement( + block.inlines, + start, + end, + ); if (blocks.any(_requiresCompleteBlockInsertion)) { return _insertCompleteBlocksAtSelection( @@ -1692,8 +1755,8 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { blockId: blockId, beforeText: beforeText, afterText: afterText, - beforeRanges: beforeRanges, - afterRanges: afterRanges, + beforeInlines: partition.before, + afterInlines: partition.after, blocks: blocks, ); } @@ -1701,15 +1764,6 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { final replacements = <BusyBlock>[]; if (blocks.length == 1) { final inserted = blocks.single; - final nextText = beforeText + inserted.text + afterText; - final nextRanges = [ - ...beforeRanges, - ..._shiftStyleRanges(inserted.ranges, beforeText.length), - ..._shiftStyleRanges( - afterRanges, - beforeText.length + inserted.text.length, - ), - ]; replacements.add( block.copyWith( kind: beforeText.isEmpty && afterText.isEmpty @@ -1718,7 +1772,11 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { attributes: beforeText.isEmpty && afterText.isEmpty ? inserted.attributes : block.attributes, - inlines: _inlinesFromStyleRanges(nextText, nextRanges), + inlines: [ + ...partition.before, + ...busyMarkWysiwygClipboardBlock(inserted).inlines, + ...partition.after, + ], preserveRaw: false, dirty: true, ), @@ -1734,15 +1792,14 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { } final first = blocks.first; - final firstText = beforeText + first.text; replacements.add( block.copyWith( kind: beforeText.isEmpty ? first.kind : block.kind, attributes: beforeText.isEmpty ? first.attributes : block.attributes, - inlines: _inlinesFromStyleRanges(firstText, [ - ...beforeRanges, - ..._shiftStyleRanges(first.ranges, beforeText.length), - ]), + inlines: [ + ...partition.before, + ...busyMarkWysiwygClipboardBlock(first).inlines, + ], preserveRaw: false, dirty: true, ), @@ -1753,14 +1810,12 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { } final last = blocks.last; - final lastText = last.text + afterText; - final lastBlock = _styledBlockToBusyBlock( - last, - text: lastText, - ranges: [ - ...last.ranges, - ..._shiftStyleRanges(afterRanges, last.text.length), + final lastBlock = _styledBlockToBusyBlock(last).copyWith( + inlines: [ + ...busyMarkWysiwygClipboardBlock(last).inlines, + ...partition.after, ], + dirty: true, ); replacements.add(lastBlock); @@ -1779,8 +1834,8 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { required String blockId, required String beforeText, required String afterText, - required List<BusyInlineStyleRange> beforeRanges, - required List<BusyInlineStyleRange> afterRanges, + required List<BusyInline> beforeInlines, + required List<BusyInline> afterInlines, required List<BusyWysiwygStyledBlock> blocks, }) { final replacements = <BusyBlock>[]; @@ -1788,7 +1843,7 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { if (beforeText.isNotEmpty) { replacements.add( block.copyWith( - inlines: _inlinesFromStyleRanges(beforeText, beforeRanges), + inlines: beforeInlines, attributes: _attributesForText( block.attributes, block.kind, @@ -1814,7 +1869,7 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { focusBlock = BusyBlock( id: originalIdAvailable ? block.id : _nextGeneratedBlockId('paragraph'), kind: BusyBlockKind.paragraph, - inlines: _inlinesFromStyleRanges(afterText, afterRanges), + inlines: afterInlines, dirty: true, ); replacements.add(focusBlock); @@ -2140,7 +2195,7 @@ class BusyMarkWysiwygDocumentController extends ChangeNotifier { String? rootId, }) { final completeBlock = styled.completeBlock; - if (completeBlock != null && _requiresCompleteBlockInsertion(styled)) { + if (completeBlock != null && text == null && ranges == null) { return _cloneClipboardBlock(completeBlock, rootId: rootId); } final kind = styled.kind; @@ -2200,6 +2255,31 @@ class BusyWysiwygStyledBlock { final BusyBlock? completeBlock; } +/// Materializes a clipboard slice without inserting it into a document. +BusyBlock busyMarkWysiwygClipboardBlock(BusyWysiwygStyledBlock styled) { + return styled.completeBlock ?? + BusyBlock( + id: 'clipboard-slice', + kind: styled.kind, + inlines: _inlinesFromStyleRanges(styled.text, styled.ranges), + attributes: styled.attributes, + dirty: true, + ); +} + +List<BusyInline> busyMarkWysiwygClipboardInlineSlice( + List<BusyInline> inlines, + int start, + int end, +) { + final afterStart = _partitionInlinesForReplacement(inlines, 0, start).after; + return _partitionInlinesForReplacement( + afterStart, + end - start, + end - start, + ).before; +} + bool _requiresCompleteBlockInsertion(BusyWysiwygStyledBlock styled) { final block = styled.completeBlock; return block != null && @@ -3499,24 +3579,6 @@ List<BusyInlineStyleRange> _styleRangesForSlice( ]; } -List<BusyInlineStyleRange> _shiftStyleRanges( - List<BusyInlineStyleRange> ranges, - int offset, -) { - if (offset == 0) { - return ranges; - } - return [ - for (final range in ranges) - BusyInlineStyleRange( - start: range.start + offset, - end: range.end + offset, - kind: range.kind, - destination: range.destination, - ), - ]; -} - List<BusyInlineStyleRange> _normalizedStyleRanges( List<BusyInlineStyleRange> ranges, int textLength, diff --git a/lib/src/editor/wysiwyg/wysiwyg_editor.dart b/lib/src/editor/wysiwyg/wysiwyg_editor.dart index 0dc9407f..c21b579c 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_editor.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_editor.dart @@ -23,11 +23,13 @@ import '../../app/busymark_toast.dart'; import '../../app/command_registry.dart'; import '../../app/localization.dart'; import '../../core/source_span.dart'; +import '../../core/local_image_resolver.dart'; import '../../markdown/busymark_document.dart'; import '../../markdown/document_outline.dart'; import '../../markdown/markdown_model.dart'; import '../../markdown/markdown_parser.dart'; import '../../platform/linux_header_bar_service.dart'; +import '../../platform/rich_clipboard_service.dart'; import '../document_callout.dart'; import '../document_code_block.dart'; import '../document_collapsible.dart'; @@ -36,6 +38,8 @@ import '../document_surface.dart'; import '../document_text_geometry.dart'; import 'wysiwyg_block_widgets.dart'; import 'wysiwyg_commands.dart'; +import 'wysiwyg_clipboard_fragment.dart'; +import 'wysiwyg_clipboard_html.dart'; import 'wysiwyg_document_controller.dart'; import 'wysiwyg_inline_controller.dart'; import 'wysiwyg_session_state.dart'; @@ -75,6 +79,7 @@ class BusyMarkWysiwygEditor extends StatefulWidget { this.assetWorkspaceKind, this.assetIngestionService = const AssetIngestionService(), this.assetInputService, + this.clipboardService, this.onAssetSaveRequired, this.allowRemoteImages = false, this.onRemoteImageBlocked, @@ -113,6 +118,7 @@ class BusyMarkWysiwygEditor extends StatefulWidget { final AssetWorkspaceKind? assetWorkspaceKind; final AssetIngestionService assetIngestionService; final AssetInputService? assetInputService; + final RichClipboardService? clipboardService; final VoidCallback? onAssetSaveRequired; final bool allowRemoteImages; final VoidCallback? onRemoteImageBlocked; @@ -173,7 +179,6 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { String? _verticalCaretMovementBlockId; TextPosition? _verticalCaretMovementPosition; double? _preferredVerticalCaretX; - _WysiwygInternalClipboard? _internalClipboard; final _pendingInlineKindsByBlockId = <String, Set<BusyInlineKind>>{}; int _preserveSelectionFocusCallbacks = 0; bool _internalChange = false; @@ -184,6 +189,9 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { String get _documentId => widget.documentId ?? widget.document.filePath; + RichClipboardService get _clipboard => + widget.clipboardService ?? busyMarkRichClipboardService; + @visibleForTesting int get debugUndoControllerCount => _textUndoControllers.length; @@ -3935,15 +3943,30 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { } Future<void> _pasteIntoActiveBlock() async { - final data = await Clipboard.getData(Clipboard.kTextPlain); - final text = data?.text; - if (text != null && text.isNotEmpty) { - final internalClipboard = _internalClipboard; - if (internalClipboard != null && - internalClipboard.text == text && - _pasteInternalClipboardIntoActiveBlock(internalClipboard)) { + final target = _captureClipboardTarget(); + final data = await _clipboard.read(); + if (!_isClipboardTargetCurrent(target)) return; + var fragment = data.fragment == null + ? null + : WysiwygClipboardFragment.decode(data.fragment!); + fragment ??= data.html == null + ? null + : const WysiwygClipboardHtml().decode( + data.html!, + mode: _documentController.document.mode, + ); + if (fragment != null) { + fragment = fragment.rebase(_documentController.document.filePath); + if (_pasteStyledClipboardIntoActiveBlock( + fragment.blocks, + data.text ?? + fragment.documentBlocks.map(_copyTextForBlock).join('\n\n'), + )) { return; } + } + final text = data.text; + if (text != null && text.isNotEmpty) { final filePath = _localFilePathFromClipboardText(text); if (filePath != null && await _ingestExternalImageFile( @@ -3953,11 +3976,14 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { )) { return; } - await _pastePlainTextIntoActiveBlock(textOverride: text); + if (_isClipboardTargetCurrent(target)) { + await _pastePlainTextIntoActiveBlock(textOverride: text); + } return; } final assetInput = widget.assetInputService ?? busyMarkAssetInputService; final clipboardFiles = await assetInput.readClipboardImageFiles(); + if (!_isClipboardTargetCurrent(target)) return; if (clipboardFiles.isNotEmpty && await _ingestExternalImageFile( clipboardFiles.first, @@ -3966,6 +3992,7 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { return; } final png = await assetInput.readClipboardImagePng(); + if (!_isClipboardTargetCurrent(target)) return; if (png != null && png.isNotEmpty) { await _ingestExternalImageBytes( png, @@ -3976,14 +4003,15 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { } } - bool _pasteInternalClipboardIntoActiveBlock( - _WysiwygInternalClipboard clipboard, + bool _pasteStyledClipboardIntoActiveBlock( + List<BusyWysiwygStyledBlock> blocks, + String text, ) { if (_hasBlockSelection) { - return _replaceDocumentSelectionWithStyledBlocks(clipboard.blocks); + return _replaceDocumentSelectionWithStyledBlocks(blocks); } if (_activeCellId != null) { - return _replaceActiveTableCellSelection(clipboard.text); + return _replaceActiveTableCellSelection(text, styledBlocks: blocks); } final target = _activeTextTarget(); if (target == null) { @@ -4008,7 +4036,7 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { blockId: blockId, selectionStart: start, selectionEnd: end, - blocks: clipboard.blocks, + blocks: blocks, ); if (result == null) { return false; @@ -4021,17 +4049,17 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { } Future<void> _pastePlainTextIntoActiveBlock({String? textOverride}) async { + final captured = _captureClipboardTarget(); + final text = textOverride ?? await _clipboard.readPlainText(); + if (!_isClipboardTargetCurrent(captured) || text == null || text.isEmpty) { + return; + } final target = _activeTextTarget(); if (target == null) { return; } final blockId = target.targetId; final controller = target.controller; - final text = - textOverride ?? (await Clipboard.getData(Clipboard.kTextPlain))?.text; - if (text == null || text.isEmpty) { - return; - } if (_activeCellId != null) { _replaceActiveTableCellSelection(text); return; @@ -4063,7 +4091,10 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { ); } - bool _replaceActiveTableCellSelection(String replacement) { + bool _replaceActiveTableCellSelection( + String replacement, { + List<BusyWysiwygStyledBlock>? styledBlocks, + }) { final cellId = _activeCellId; final tableId = _activeBlockId; if (cellId == null || tableId == null) { @@ -4085,6 +4116,21 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { .max(selection.start, selection.end) .clamp(start, controller.text.length) .toInt(); + if (styledBlocks != null && !busyMarkWysiwygBlockContainsMath(cell)) { + final undoSnapshot = _historySnapshot(); + final offset = _documentController.insertStyledInlinesInTableCell( + tableBlockId: tableId, + cellId: cellId, + selectionStart: start, + selectionEnd: end, + blocks: styledBlocks, + ); + if (offset == null) return false; + _recordUndoSnapshot(undoSnapshot); + _emitMarkdown(); + _focusTextTargetAfterFrame(cellId, offset: offset); + return true; + } final acceptedReplacement = busyMarkNormalizeTableCellText(replacement); final nextText = controller.text.replaceRange( start, @@ -5724,51 +5770,200 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { return _cutCurrentSelection(); } - bool _copyCurrentSelection() { - if (_hasBlockSelection) { - return _copyDocumentSelectionToClipboard(); + bool _copyCurrentSelection() => _copyOrCutSelection(cut: false); + + bool _cutCurrentSelection() => _copyOrCutSelection(cut: true); + + bool _copyOrCutSelection({required bool cut}) { + final documentSelection = _hasBlockSelection; + final allRanges = documentSelection + ? _selectedTextRanges(null, true) + : _currentSelectionRanges(); + if (allRanges.isEmpty) return false; + final ranges = documentSelection + ? _withoutEmptySelectionEndpoints(allRanges) + : allRanges + .where((range) => _copyTextForRange(range).trim().isNotEmpty) + .toList(); + if (ranges.isEmpty) return false; + final target = _captureClipboardTarget(); + final blocks = _clipboardBlocksForRanges(ranges); + final fragment = WysiwygClipboardFragment( + mode: _documentController.document.mode, + sourcePath: _documentController.document.filePath, + blocks: blocks, + mediaPaths: _clipboardMediaPaths(blocks), + ); + final text = ranges.map(_copyTextForRange).join('\n\n'); + unawaited( + _writeClipboardSelection( + fragment: fragment, + text: text, + onWritten: () { + if (!cut || !_isClipboardTargetCurrent(target)) return; + if (documentSelection) { + _deleteBlockSelection(); + } else { + _deleteActiveTextSelection(ranges.single); + } + }, + ), + ); + return true; + } + + Future<void> _writeClipboardSelection({ + required WysiwygClipboardFragment fragment, + required String text, + required VoidCallback onWritten, + }) async { + var success = false; + try { + String? html; + try { + html = const WysiwygClipboardHtml().encode(fragment); + } on FormatException { + // Large selections can still transfer their native structure and text. + } + success = await _clipboard.write( + RichClipboardData(text: text, html: html, fragment: fragment.encode()), + ); + } on FormatException { + success = false; } - final ranges = _currentSelectionRanges(); - if (ranges.isEmpty) { - return false; + if (!mounted) return; + if (success) { + onWritten(); + } else { + BusyMarkToastOverlay.show( + context, + message: context.l10n.clipboardCopyFailed, + ); } - return _copyRangesToClipboard(ranges); } - bool _cutCurrentSelection() { - if (_hasBlockSelection) { - if (!_copyDocumentSelectionToClipboard()) { - return false; + List<BusyWysiwygStyledBlock> _clipboardBlocksForRanges( + List<_SelectedTextRange> ranges, + ) { + final selected = {for (final range in ranges) range.block.id: range}; + final editable = _editableBlocks( + _documentController.document.blocks, + ).map((block) => block.id).toSet(); + final included = <String>{}; + final containers = <String, BusyBlock>{}; + void preserveQuotes(List<BusyBlock> blocks) { + for (final block in blocks) { + if (_isStructuralBlockquote(block)) { + final descendants = _editableBlocks(block.children); + if (descendants.isNotEmpty && + descendants.every( + (child) => selected[child.id]?.coversWholeBlock == true, + )) { + for (final child in descendants) { + containers.putIfAbsent(child.id, () => block); + } + } + } + preserveQuotes(block.children); } - return _deleteBlockSelection(); } - final ranges = _currentSelectionRanges(); - if (ranges.isEmpty || !_copyRangesToClipboard(ranges)) { - return false; + + preserveQuotes(_documentController.document.blocks); + BusyBlock? snapshot(BusyBlock block) { + final range = selected[block.id]; + if (editable.contains(block.id) && range == null) return null; + included.add(block.id); + if (range != null && !range.coversWholeBlock) { + return busyMarkWysiwygClipboardBlock(_styledBlockForRange(range)); + } + return busyMarkWysiwygImmutableBlockSnapshot( + block.copyWith( + children: [ + for (final child in block.children) + if (snapshot(child) case final copied?) copied, + ], + ), + ); + } + + final result = <BusyWysiwygStyledBlock>[]; + for (final range in ranges) { + if (included.contains(range.block.id)) continue; + final block = containers[range.block.id] ?? range.block; + if (range.coversWholeBlock) { + final copied = snapshot(block)!; + result.add( + BusyWysiwygStyledBlock( + kind: copied.kind, + text: copied.plainText, + ranges: busyInlineStyleRanges(copied.inlines), + attributes: copied.attributes, + completeBlock: copied, + ), + ); + } else { + result.add(_styledBlockForRange(range)); + } } - return _deleteActiveTextSelection(ranges.single); + return result; } - bool _copyDocumentSelectionToClipboard() { - final allRanges = _selectedTextRanges(null, true); - if (allRanges.isEmpty) { - return false; + Map<String, String> _clipboardMediaPaths( + List<BusyWysiwygStyledBlock> blocks, + ) { + final references = <String>{}; + void inline(BusyInline value) { + if (value.kind == BusyInlineKind.image && value.destination != null) { + references.add(value.destination!); + } + value.children.forEach(inline); } - final ranges = allRanges.any((range) => range.end > range.start) - ? _withoutEmptySelectionEndpoints(allRanges) - : allRanges; - final clipboardText = ranges.map(_copyTextForRange).join('\n\n'); - final clipboardBlocks = [ - for (final range in ranges) _styledBlockForRange(range), - ]; - _internalClipboard = _WysiwygInternalClipboard( - text: clipboardText, - blocks: clipboardBlocks, - ); - unawaited(Clipboard.setData(ClipboardData(text: clipboardText))); - return true; + + void block(BusyBlock value) { + if ({BusyBlockKind.image, BusyBlockKind.video}.contains(value.kind) && + value.attributes['src'] != null) { + references.add(value.attributes['src']!); + } + value.inlines.forEach(inline); + value.children.forEach(block); + } + + for (final value in blocks) { + block(busyMarkWysiwygClipboardBlock(value)); + } + final resolved = <String, String>{}; + for (final value in references.take(256)) { + if (Uri.tryParse(value)?.hasScheme == true) continue; + final path = resolveLocalMediaPath( + activeFilePath: _documentController.document.filePath, + destination: value, + workspaceRoot: widget.workspaceRoot, + writersideRoot: widget.writersideRoot, + imagesDir: widget.imagesDir, + maxRecursiveEntries: 1000, + ); + if (path != null) resolved[value] = path; + } + return resolved; } + _ClipboardTarget _captureClipboardTarget() => _ClipboardTarget( + document: _captureDialogTarget(), + documentId: _documentId, + activeBlockId: _activeBlockId, + activeCellId: _activeCellId, + selection: _documentSelection, + textSelection: _activeTextTarget()?.controller.selection, + ); + + bool _isClipboardTargetCurrent(_ClipboardTarget target) => + _isDialogTargetCurrent(target.document) && + target.documentId == _documentId && + target.activeBlockId == _activeBlockId && + target.activeCellId == _activeCellId && + target.selection == _documentSelection && + target.textSelection == _activeTextTarget()?.controller.selection; + List<_SelectedTextRange> _withoutEmptySelectionEndpoints( List<_SelectedTextRange> ranges, ) { @@ -5783,29 +5978,6 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { return ranges.sublist(start, end); } - bool _copyRangesToClipboard(List<_SelectedTextRange> ranges) { - final clipboardBlocks = <BusyWysiwygStyledBlock>[]; - final clipboardTexts = <String>[]; - for (final range in ranges) { - final clipboardText = _copyTextForRange(range); - if (clipboardText.trim().isEmpty) { - continue; - } - clipboardTexts.add(clipboardText); - clipboardBlocks.add(_styledBlockForRange(range)); - } - if (clipboardTexts.isEmpty || clipboardBlocks.isEmpty) { - return false; - } - final clipboardText = clipboardTexts.join('\n\n'); - _internalClipboard = _WysiwygInternalClipboard( - text: clipboardText, - blocks: clipboardBlocks, - ); - unawaited(Clipboard.setData(ClipboardData(text: clipboardText))); - return true; - } - List<_SelectedTextRange> _currentSelectionRanges() { final selectedRanges = _selectedTextRanges(); if (selectedRanges.isNotEmpty) { @@ -5854,7 +6026,16 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { attributes: range.coversWholeBlock ? range.block.attributes : const {}, completeBlock: range.coversWholeBlock ? busyMarkWysiwygImmutableBlockSnapshot(range.block) - : null, + : BusyBlock( + id: 'clipboard-slice', + kind: BusyBlockKind.paragraph, + inlines: busyMarkWysiwygClipboardInlineSlice( + range.block.inlines, + start, + end, + ), + dirty: true, + ), ); } @@ -6084,11 +6265,21 @@ class _OrderedDocumentSelection { final _DocumentTextPosition end; } -class _WysiwygInternalClipboard { - const _WysiwygInternalClipboard({required this.text, required this.blocks}); - - final String text; - final List<BusyWysiwygStyledBlock> blocks; +class _ClipboardTarget { + const _ClipboardTarget({ + required this.document, + required this.documentId, + required this.activeBlockId, + required this.activeCellId, + required this.selection, + required this.textSelection, + }); + final _WysiwygDialogTarget document; + final String documentId; + final String? activeBlockId; + final String? activeCellId; + final _DocumentTextSelection? selection; + final TextSelection? textSelection; } class _ContinuousTextEdit { diff --git a/lib/src/platform/rich_clipboard_service.dart b/lib/src/platform/rich_clipboard_service.dart new file mode 100644 index 00000000..e3bdfb0a --- /dev/null +++ b/lib/src/platform/rich_clipboard_service.dart @@ -0,0 +1,102 @@ +import 'dart:async'; + +import 'package:flutter/services.dart'; + +const richClipboardChannelName = 'com.busymark.app/rich_clipboard'; +const busyMarkClipboardMimeType = 'application/x-busymark-fragment+json'; +const maxRichClipboardBytes = 16 * 1024 * 1024; + +class RichClipboardData { + const RichClipboardData({this.text, this.html, this.fragment}); + + final String? text; + final String? html; + final String? fragment; + + Map<String, String> toMap() => { + if (text != null) 'text': text!, + if (html != null) 'html': html!, + if (fragment != null) 'fragment': fragment!, + }; +} + +/// One write publishes all representations of the same immutable selection. +/// The platform owns the data, including after the originating Editor closes. +class RichClipboardService { + RichClipboardService({ + MethodChannel channel = const MethodChannel(richClipboardChannelName), + }) : _channel = channel; + + final MethodChannel _channel; + Future<void>? _pendingWrite; + + Future<bool> write(RichClipboardData data) { + final result = _pendingWrite?.then((_) => _write(data)) ?? _write(data); + final pending = result.then<void>((_) {}); + _pendingWrite = pending; + unawaited( + pending.whenComplete(() { + if (identical(_pendingWrite, pending)) _pendingWrite = null; + }), + ); + return result; + } + + Future<bool> _write(RichClipboardData data) async { + try { + return await _channel.invokeMethod<bool>('write', data.toMap()) ?? false; + } on MissingPluginException { + // Unsupported hosts can still exchange plain text. Never recover rich + // data from a text-equality cache: a different copy may contain that text. + try { + await Clipboard.setData(ClipboardData(text: data.text ?? '')); + return true; + } on PlatformException { + return false; + } on MissingPluginException { + return false; + } + } on PlatformException { + return false; + } + } + + Future<RichClipboardData> read() async { + await _pendingWrite; + try { + final value = await _channel + .invokeMapMethod<String, dynamic>('read') + .timeout(const Duration(seconds: 5)); + String? field(String name) => + value?[name] is String ? value![name] as String : null; + return RichClipboardData( + text: field('text'), + html: field('html'), + fragment: field('fragment'), + ); + } on MissingPluginException { + return RichClipboardData(text: await readPlainText()); + } on PlatformException { + return const RichClipboardData(); + } on TimeoutException { + return const RichClipboardData(); + } + } + + Future<String?> readPlainText() async { + await _pendingWrite; + try { + return (await Clipboard.getData( + Clipboard.kTextPlain, + ).timeout(const Duration(seconds: 5)))?.text; + } on PlatformException { + return null; + } on MissingPluginException { + return null; + } on TimeoutException { + return null; + } + } +} + +final busyMarkRichClipboardService = RichClipboardService(); diff --git a/linux/runner/CMakeLists.txt b/linux/runner/CMakeLists.txt index 4d8b9860..ea077532 100644 --- a/linux/runner/CMakeLists.txt +++ b/linux/runner/CMakeLists.txt @@ -9,6 +9,7 @@ project(runner LANGUAGES CXX) add_executable(${BINARY_NAME} "main.cc" "my_application.cc" + "rich_clipboard_host.cc" "secure_credential_host.cc" "video_player_host.cc" "web_render_host.cc" diff --git a/linux/runner/my_application.cc b/linux/runner/my_application.cc index 4c2437f6..54eee74f 100644 --- a/linux/runner/my_application.cc +++ b/linux/runner/my_application.cc @@ -10,6 +10,7 @@ #include <cstring> #include "flutter/generated_plugin_registrant.h" +#include "rich_clipboard_host.h" #include "secure_credential_host.h" #include "video_player_host.h" #include "web_render_host.h" @@ -85,6 +86,7 @@ struct _MyApplication { FlMethodChannel* native_menu_channel; FlMethodChannel* asset_input_channel; FlMethodChannel* secure_credential_channel; + FlMethodChannel* rich_clipboard_channel; BusyMarkWebRenderHost* visualization_host; BusyMarkVideoPlayerHost* video_player_host; GtkCssProvider* header_bar_css_provider; @@ -2994,6 +2996,7 @@ static void my_application_activate(GApplication* application) { register_header_bar_channel(self, view); register_native_menu_channel(self, view); register_asset_input_channel(self, view); + self->rich_clipboard_channel = busymark_rich_clipboard_channel_new(view); self->secure_credential_channel = busymark_secure_credential_channel_new(view); self->visualization_host = @@ -3059,6 +3062,7 @@ static void my_application_dispose(GObject* object) { g_clear_object(&self->header_bar_channel); g_clear_object(&self->native_menu_channel); g_clear_object(&self->asset_input_channel); + g_clear_object(&self->rich_clipboard_channel); g_clear_object(&self->secure_credential_channel); if (self->visualization_host != nullptr) { busymark_web_render_host_shutdown(self->visualization_host); diff --git a/linux/runner/rich_clipboard_host.cc b/linux/runner/rich_clipboard_host.cc new file mode 100644 index 00000000..ab8b26d0 --- /dev/null +++ b/linux/runner/rich_clipboard_host.cc @@ -0,0 +1,212 @@ +#include "rich_clipboard_host.h" + +#include <cstring> +#include <memory> +#include <string> + +namespace { +constexpr char kChannel[] = "com.busymark.app/rich_clipboard"; +constexpr char kFragment[] = "application/x-busymark-fragment+json"; +constexpr gsize kMaximumBytes = 16 * 1024 * 1024; + +struct Payload { + std::string text; + std::string html; + std::string fragment; +}; + +void provide(GtkClipboard*, GtkSelectionData* selection, guint info, + gpointer user_data) { + const auto* payload = static_cast<Payload*>(user_data); + if (info == 0) { + gtk_selection_data_set_text(selection, payload->text.c_str(), + payload->text.size()); + return; + } + const auto& bytes = info == 1 ? payload->html : payload->fragment; + gtk_selection_data_set(selection, gtk_selection_data_get_target(selection), + 8, reinterpret_cast<const guchar*>(bytes.data()), + bytes.size()); +} + +void clear_payload(GtkClipboard*, gpointer data) { + delete static_cast<Payload*>(data); +} + +struct Host { + GtkClipboard* clipboard; + guint64 generation = 0; + gulong owner_changed; + + explicit Host(GtkClipboard* value) + : clipboard(GTK_CLIPBOARD(g_object_ref(value))) { + owner_changed = g_signal_connect( + clipboard, "owner-change", + G_CALLBACK(+[](GtkClipboard*, GdkEventOwnerChange*, gpointer data) { + static_cast<Host*>(data)->generation++; + }), this); + } + ~Host() { + g_signal_handler_disconnect(clipboard, owner_changed); + g_object_unref(clipboard); + } +}; + +using SharedHost = std::shared_ptr<Host>; + +bool argument(FlValue* args, const char* key, std::string* out, bool required) { + FlValue* value = fl_value_lookup_string(args, key); + if (value == nullptr) return !required; + if (fl_value_get_type(value) != FL_VALUE_TYPE_STRING) return false; + const char* text = fl_value_get_string(value); + const gsize length = strlen(text); + if (length > kMaximumBytes || !g_utf8_validate(text, length, nullptr)) { + return false; + } + out->assign(text, length); + return true; +} + +void write_clipboard(const SharedHost& host, FlMethodCall* call) { + FlValue* args = fl_method_call_get_args(call); + auto payload = std::make_unique<Payload>(); + if (args == nullptr || fl_value_get_type(args) != FL_VALUE_TYPE_MAP || + !argument(args, "text", &payload->text, true) || + !argument(args, "html", &payload->html, false) || + !argument(args, "fragment", &payload->fragment, false) || + payload->text.size() + payload->html.size() + payload->fragment.size() > + kMaximumBytes) { + fl_method_call_respond_error(call, "clipboard.invalid-data", + "Clipboard content is invalid or too large.", + nullptr, nullptr); + return; + } + GtkTargetList* list = gtk_target_list_new(nullptr, 0); + gtk_target_list_add_text_targets(list, 0); + if (!payload->html.empty()) { + gtk_target_list_add(list, gdk_atom_intern_static_string("text/html"), 0, 1); + } + if (!payload->fragment.empty()) { + gtk_target_list_add(list, gdk_atom_intern_static_string(kFragment), 0, 2); + } + gint count = 0; + GtkTargetEntry* targets = gtk_target_table_new_from_list(list, &count); + const gboolean success = gtk_clipboard_set_with_data( + host->clipboard, targets, count, provide, clear_payload, payload.get()); + if (success) { + payload.release(); + host->generation++; + gtk_clipboard_set_can_store(host->clipboard, nullptr, 0); + } + gtk_target_table_free(targets, count); + gtk_target_list_unref(list); + g_autoptr(FlValue) result = fl_value_new_bool(success); + fl_method_call_respond_success(call, result, nullptr); +} + +struct Read { + SharedHost host; + FlMethodCall* call; + FlValue* result = fl_value_new_map(); + guint64 generation; + guint step = 0; + gsize bytes = 0; + + Read(SharedHost value, FlMethodCall* request) + : host(std::move(value)), + call(FL_METHOD_CALL(g_object_ref(request))), + generation(host->generation) {} + ~Read() { + fl_value_unref(result); + g_object_unref(call); + } + bool current() const { return generation == host->generation; } +}; + +void next_read(Read* request); + +void received(GtkClipboard*, GtkSelectionData* selection, gpointer data) { + auto* request = static_cast<Read*>(data); + const gint length = gtk_selection_data_get_length(selection); + const guchar* bytes = gtk_selection_data_get_data(selection); + if (request->current() && length > 0 && + static_cast<gsize>(length) <= kMaximumBytes - request->bytes && + gtk_selection_data_get_format(selection) == 8) { + // Some HTML providers include a terminating NUL in the byte count. + gsize size = length; + while (size > 0 && bytes[size - 1] == 0) size--; + if (g_utf8_validate(reinterpret_cast<const char*>(bytes), size, nullptr)) { + const char* key = request->step == 1 ? "fragment" : "html"; + fl_value_set_string_take( + request->result, key, + fl_value_new_string_sized(reinterpret_cast<const char*>(bytes), size)); + request->bytes += size; + } + } + next_read(request); +} + +void received_text(GtkClipboard*, const gchar* text, gpointer data) { + auto* request = static_cast<Read*>(data); + if (request->current() && text != nullptr) { + const gsize length = strlen(text); + if (length <= kMaximumBytes - request->bytes) { + fl_value_set_string_take(request->result, "text", fl_value_new_string(text)); + } + } + next_read(request); +} + +void next_read(Read* request) { + if (!request->current() || request->step == 3) { + // Never combine representations from different clipboard owners. + if (!request->current()) { + fl_value_unref(request->result); + request->result = fl_value_new_map(); + } + fl_method_call_respond_success(request->call, request->result, nullptr); + delete request; + return; + } + switch (request->step++) { + case 0: + gtk_clipboard_request_contents(request->host->clipboard, + gdk_atom_intern_static_string(kFragment), + received, request); + break; + case 1: + gtk_clipboard_request_contents(request->host->clipboard, + gdk_atom_intern_static_string("text/html"), + received, request); + break; + case 2: + gtk_clipboard_request_text(request->host->clipboard, received_text, request); + break; + } +} + +void method_call(FlMethodChannel*, FlMethodCall* call, gpointer data) { + const auto& host = *static_cast<SharedHost*>(data); + const char* method = fl_method_call_get_name(call); + if (strcmp(method, "write") == 0) { + write_clipboard(host, call); + } else if (strcmp(method, "read") == 0) { + next_read(new Read(host, call)); + } else { + fl_method_call_respond_not_implemented(call, nullptr); + } +} +} // namespace + +FlMethodChannel* busymark_rich_clipboard_channel_new(FlView* view) { + auto host = std::make_shared<Host>(gtk_widget_get_clipboard( + GTK_WIDGET(view), GDK_SELECTION_CLIPBOARD)); + g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new(); + FlMethodChannel* channel = fl_method_channel_new( + fl_engine_get_binary_messenger(fl_view_get_engine(view)), kChannel, + FL_METHOD_CODEC(codec)); + fl_method_channel_set_method_call_handler( + channel, method_call, new SharedHost(std::move(host)), + +[](gpointer data) { delete static_cast<SharedHost*>(data); }); + return channel; +} diff --git a/linux/runner/rich_clipboard_host.h b/linux/runner/rich_clipboard_host.h new file mode 100644 index 00000000..c1b43502 --- /dev/null +++ b/linux/runner/rich_clipboard_host.h @@ -0,0 +1,9 @@ +#ifndef RUNNER_RICH_CLIPBOARD_HOST_H_ +#define RUNNER_RICH_CLIPBOARD_HOST_H_ + +#include <flutter_linux/flutter_linux.h> + +// The caller owns the channel; GTK owns copied payloads until ownership changes. +FlMethodChannel* busymark_rich_clipboard_channel_new(FlView* view); + +#endif // RUNNER_RICH_CLIPBOARD_HOST_H_ diff --git a/test/flutter_test_config.dart b/test/flutter_test_config.dart index 3cbf5265..22905e4e 100644 --- a/test/flutter_test_config.dart +++ b/test/flutter_test_config.dart @@ -1,12 +1,14 @@ import 'dart:async'; import 'package:busymark/src/platform/native_menu_service.dart'; +import 'package:busymark/src/platform/rich_clipboard_service.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; Future<void> testExecutable(FutureOr<void> Function() testMain) async { TestWidgetsFlutterBinding.ensureInitialized(); const channel = MethodChannel(nativeMenuChannelName); + const clipboardChannel = MethodChannel(richClipboardChannelName); final messenger = TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger; setUp(() { @@ -14,9 +16,14 @@ Future<void> testExecutable(FutureOr<void> Function() testMain) async { channel, (_) async => throw MissingPluginException(), ); + messenger.setMockMethodCallHandler( + clipboardChannel, + (_) async => throw MissingPluginException(), + ); }); tearDown(() { messenger.setMockMethodCallHandler(channel, null); + messenger.setMockMethodCallHandler(clipboardChannel, null); }); await testMain(); } diff --git a/test/src/busymark_document_test.dart b/test/src/busymark_document_test.dart index 580eed28..cedfe61e 100644 --- a/test/src/busymark_document_test.dart +++ b/test/src/busymark_document_test.dart @@ -39,6 +39,8 @@ import 'package:markdown/markdown.dart' as md; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'package:yaru/yaru.dart'; +import '../support/memory_rich_clipboard.dart'; + void main() { const parser = MarkdownParser(); @@ -3030,6 +3032,7 @@ void main() {} width: 900, height: 640, child: BusyMarkWysiwygEditor( + clipboardService: MemoryRichClipboard(), document: parsed.busyDocument, onSourceChanged: (filePath, value) => markdown = value, ), @@ -3107,6 +3110,7 @@ void main() {} width: 900, height: 640, child: BusyMarkWysiwygEditor( + clipboardService: MemoryRichClipboard(), document: parsed.busyDocument, onSourceChanged: (filePath, value) => markdown = value, ), diff --git a/test/src/wysiwyg_clipboard_test.dart b/test/src/wysiwyg_clipboard_test.dart new file mode 100644 index 00000000..e145f343 --- /dev/null +++ b/test/src/wysiwyg_clipboard_test.dart @@ -0,0 +1,572 @@ +import 'dart:async'; +import 'dart:convert'; + +import 'package:busymark/l10n/generated/app_localizations.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_clipboard_html.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_document_controller.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_editor.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_inline_controller.dart'; +import 'package:busymark/src/markdown/busymark_document.dart'; +import 'package:busymark/src/markdown/markdown_model.dart'; +import 'package:busymark/src/markdown/markdown_parser.dart'; +import 'package:busymark/src/platform/rich_clipboard_service.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:html/parser.dart' as html; + +const _source = + '# Issues\n\n**When** selecting all, keep *formatting*.\n\n- [ ] First task\n- [x] Second task\n'; +const _parser = MarkdownParser(); + +WysiwygClipboardFragment _fragment( + String source, { + String path = '/source/topic.md', +}) { + final document = _parser + .parse( + filePath: path, + source: source, + mode: MarkdownMode.writersideMarkdown, + ) + .busyDocument; + return WysiwygClipboardFragment( + mode: document.mode, + sourcePath: path, + blocks: [ + for (final block in document.blocks) + BusyWysiwygStyledBlock( + kind: block.kind, + text: block.plainText, + ranges: busyInlineStyleRanges(block.inlines), + attributes: block.attributes, + completeBlock: busyMarkWysiwygImmutableBlockSnapshot(block), + ), + ], + ); +} + +String _insert( + WysiwygClipboardFragment fragment, { + String source = 'Target\n', +}) { + final target = _parser + .parse(filePath: '/destination/topic.md', source: source) + .busyDocument; + final controller = BusyMarkWysiwygDocumentController(document: target); + final result = controller.insertStyledBlocksAtSelection( + blockId: target.blocks.first.id, + selectionStart: 0, + selectionEnd: target.blocks.first.plainText.length, + blocks: fragment.blocks, + ); + expect(result, isNotNull); + final output = controller.markdown; + controller.dispose(); + return output; +} + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + + test( + 'native fragment preserves formatting and structured blocks through JSON', + () { + const source = + '$_source\n- Parent\n - **Child**\n\n| A | B |\n| --- | --- |\n| one | **two** |\n\n```dart\nfinal x = 1;\n```\n'; + final decoded = WysiwygClipboardFragment.decode( + _fragment(source).encode(), + )!; + final output = _insert(decoded); + expect(output, contains('# Issues')); + expect(output, contains('**When**')); + expect(output, contains('- [ ] First task')); + expect(output, contains('- [x] Second task')); + expect(output, contains('**Child**')); + expect(output, contains('| one | **two** |')); + expect(output, contains('```dart\nfinal x = 1;\n```')); + }, + ); + + test( + 'fragment rejects invalid versions, ranges, kinds, and excessive nesting', + () { + for (final change in <void Function(Map<String, dynamic>)>[ + (map) => map['version'] = 99, + (map) => map['mode'] = 'nonexistent', + (map) => map['blocks'][0]['kind'] = 'nonexistent', + (map) => map['blocks'][0]['ranges'] = [ + {'start': -1, 'end': 500, 'kind': 'strong'}, + ], + (map) => map['blocks'][0]['completeBlock']['inlines'] = null, + ]) { + final map = + jsonDecode(_fragment(_source).encode()) as Map<String, dynamic>; + change(map); + expect(WysiwygClipboardFragment.decode(jsonEncode(map)), isNull); + } + expect( + WysiwygClipboardFragment.decode('${'[' * 200}0${']' * 200}'), + isNull, + ); + expect(WysiwygClipboardFragment.decode('not json'), isNull); + }, + ); + + test('relative links are rebased for another document', () { + final fragment = _fragment('[Guide](guide.md#section)\n'); + expect( + _insert(fragment.rebase('/destination/topic.md')), + contains('../source/guide.md#section'), + ); + expect(fragment.rebase('/source/topic.md'), same(fragment)); + }); + + test('inline images retain their source media path between projects', () { + final original = _fragment('Before ![Alt](diagram.png) after\n'); + final fragment = WysiwygClipboardFragment( + blocks: original.blocks, + mode: original.mode, + sourcePath: original.sourcePath, + mediaPaths: const {'diagram.png': '/source/images/diagram.png'}, + ); + final decoded = WysiwygClipboardFragment.decode(fragment.encode())!; + expect( + _insert(decoded.rebase('/destination/topic.md')), + contains('![Alt](/source/images/diagram.png)'), + ); + expect( + const WysiwygClipboardHtml().encode(decoded), + contains('src="file:///source/images/diagram.png"'), + ); + }); + + test('Writerside structure survives the fragment and insertion', () { + const source = + '<note><p>Keep <b>this</b> note.</p></note>\n\n' + '<tabs><tab title="First"><p>Tab content</p></tab></tabs>\n'; + final decoded = WysiwygClipboardFragment.decode( + _fragment(source).encode(), + )!; + final output = _insert(decoded); + expect(output, contains('<note>')); + expect(output, contains('this')); + expect(output, contains('<tabs>')); + expect(output, contains('title="First"')); + expect(output, contains('Tab content')); + }); + + test( + 'styled table-cell insertion preserves emphasis and table structure', + () { + final document = _parser + .parse( + filePath: '/destination/topic.md', + source: '| A | B |\n| --- | --- |\n| before after | keep |\n', + ) + .busyDocument; + final table = document.blocks.single; + final cell = table.children.last.children.first; + final controller = BusyMarkWysiwygDocumentController(document: document); + final offset = controller.insertStyledInlinesInTableCell( + tableBlockId: table.id, + cellId: cell.id, + selectionStart: 7, + selectionEnd: 7, + blocks: _fragment('**Bold**\n\n*Italic*\n').blocks, + ); + expect(offset, 18); + expect( + controller.markdown, + contains('| before **Bold** *Italic*after | keep |'), + ); + expect(controller.document.blocks.single.kind, BusyBlockKind.table); + controller.dispose(); + }, + ); + + test( + 'clipboard service serializes writes and reads the latest result', + () async { + const channel = MethodChannel('test/rich_clipboard_order'); + final messenger = + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger; + final gate = Completer<void>(); + final started = Completer<void>(); + final writes = <String>[]; + var data = <String, dynamic>{}; + messenger.setMockMethodCallHandler(channel, (call) async { + if (call.method == 'write') { + final value = Map<String, dynamic>.from(call.arguments as Map); + writes.add(value['text'] as String); + if (writes.length == 1) { + started.complete(); + await gate.future; + } + data = value; + return true; + } + return data; + }); + addTearDown(() => messenger.setMockMethodCallHandler(channel, null)); + final service = RichClipboardService(channel: channel); + final first = service.write(const RichClipboardData(text: 'first')); + await started.future; + final second = service.write( + const RichClipboardData(text: 'second', html: '<b>second</b>'), + ); + final read = service.read(); + expect(writes, ['first']); + gate.complete(); + expect(await first, isTrue); + expect(await second, isTrue); + expect((await read).html, '<b>second</b>'); + expect(writes, ['first', 'second']); + }, + ); + + test('clipboard HTML carries headings, emphasis, tasks, tables, and code', () { + const source = + '$_source\n| A | B |\n| --- | --- |\n| one | **two** |\n\n```dart\nx < 3\n```\n'; + final encoded = const WysiwygClipboardHtml().encode(_fragment(source)); + final dom = html.parse(encoded); + expect(dom.querySelector('h1')!.text, 'Issues'); + expect(dom.querySelector('strong')!.text, 'When'); + expect(dom.querySelector('em')!.text, 'formatting'); + expect(dom.querySelectorAll('li').map((e) => e.text), [ + '☐ First task', + '☑ Second task', + ]); + expect(dom.querySelectorAll('table'), hasLength(1)); + expect(dom.querySelector('pre code')!.text, 'x < 3'); + expect(dom.querySelectorAll('script,input'), isEmpty); + final decoded = const WysiwygClipboardHtml().decode( + encoded, + mode: MarkdownMode.writersideMarkdown, + )!; + expect(_insert(decoded), contains('- [x] Second task')); + }); + + test('HTML normalization preserves supported CSS and checkbox state safely', () { + const source = + '<html><head><style>p{color:red}</style></head><body>' + '<h1>Title</h1><p><span style="font-weight:700;font-style:italic;text-decoration:underline">Mixed</span>' + '<a href="javascript:alert(1)" onclick="alert(2)">label</a><script>bad()</script></p>' + '<ul><li><input type="checkbox" checked>Done</li></ul></body></html>'; + final decoded = const WysiwygClipboardHtml().decode( + source, + mode: MarkdownMode.gfm, + )!; + final output = _insert(decoded); + expect(output, contains('# Title')); + expect(output, contains('Mixed')); + expect(output, contains('- [x] Done')); + expect(output, isNot(contains('javascript'))); + expect(output, isNot(contains('bad()'))); + final ranges = decoded.blocks + .expand((block) => block.ranges) + .map((range) => range.kind) + .toSet(); + expect( + ranges, + containsAll([ + BusyInlineKind.strong, + BusyInlineKind.emphasis, + BusyInlineKind.underline, + ]), + ); + }); + + group('Editor clipboard', () { + late Map<String, dynamic> systemData; + late Completer<void>? readGate; + late Completer<void>? writeGate; + late bool failWrite; + const channel = MethodChannel(richClipboardChannelName); + setUp(() { + systemData = {}; + readGate = null; + writeGate = null; + failWrite = false; + final messenger = + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger; + messenger.setMockMethodCallHandler(channel, (call) async { + if (call.method == 'write') { + await writeGate?.future; + if (failWrite) throw PlatformException(code: 'clipboard.unavailable'); + systemData = Map<String, dynamic>.from(call.arguments as Map); + return true; + } + if (call.method == 'read') { + await readGate?.future; + return Map<String, dynamic>.from(systemData); + } + return null; + }); + messenger.setMockMethodCallHandler(SystemChannels.platform, (call) async { + if (call.method == 'Clipboard.setData') { + systemData = Map<String, dynamic>.from(call.arguments as Map); + } + if (call.method == 'Clipboard.getData') { + return {'text': systemData['text']}; + } + if (call.method == 'Clipboard.hasStrings') { + return {'value': systemData['text'] != null}; + } + return null; + }); + }); + tearDown(() { + final messenger = + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger; + messenger.setMockMethodCallHandler(channel, null); + messenger.setMockMethodCallHandler(SystemChannels.platform, null); + }); + + Future<void> key( + WidgetTester tester, + LogicalKeyboardKey key, { + bool shift = false, + }) async { + await tester.sendKeyDownEvent(LogicalKeyboardKey.controlLeft); + if (shift) await tester.sendKeyDownEvent(LogicalKeyboardKey.shiftLeft); + await tester.sendKeyEvent(key); + if (shift) await tester.sendKeyUpEvent(LogicalKeyboardKey.shiftLeft); + await tester.sendKeyUpEvent(LogicalKeyboardKey.controlLeft); + await tester.pump(); + } + + Future<void> mount( + WidgetTester tester, + String id, + String source, + ValueChanged<String> changed, + ) async { + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: BusyMarkWysiwygEditor( + key: ValueKey(id), + clipboardService: RichClipboardService(), + document: _parser + .parse( + filePath: '/$id.md', + source: source, + mode: MarkdownMode.writersideMarkdown, + ) + .busyDocument, + onSourceChanged: (_, value) => changed(value), + ), + ), + ), + ); + await tester.pumpAndSettle(); + final field = tester.widget<TextField>(find.byType(TextField).first); + field.focusNode!.requestFocus(); + field.controller!.selection = const TextSelection.collapsed(offset: 0); + await tester.pump(); + } + + Future<void> copyAll(WidgetTester tester, {String source = _source}) async { + await mount(tester, 'origin', source, (_) {}); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyC); + } + + testWidgets('fresh Editor restores system clipboard formatting and undo', ( + tester, + ) async { + await copyAll(tester); + expect(systemData.keys, containsAll(['text', 'html', 'fragment'])); + expect(systemData['text'], contains('[ ] First task')); + var result = ''; + await mount(tester, 'destination', 'Target\n', (value) => result = value); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyV); + expect(result, contains('# Issues')); + expect(result, contains('**When**')); + expect(result, contains('- [x] Second task')); + await key(tester, LogicalKeyboardKey.keyZ); + expect(result, 'Target\n'); + await key(tester, LogicalKeyboardKey.keyZ, shift: true); + expect(result, contains('**When**')); + }); + + testWidgets('copy all does not duplicate nested list children', ( + tester, + ) async { + await copyAll( + tester, + source: 'Before\n\n- Parent\n - **Child**\n\nAfter\n', + ); + var result = ''; + await mount(tester, 'destination', 'Target\n', (value) => result = value); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyV); + expect(RegExp('Child').allMatches(result), hasLength(1)); + expect(result, contains(' - **Child**')); + }); + + testWidgets('whole-document copy preserves a structured blockquote', ( + tester, + ) async { + await copyAll( + tester, + source: 'Before\n\n> First\n>\n> **Second**\n\nAfter\n', + ); + var result = ''; + await mount(tester, 'destination', 'Target\n', (value) => result = value); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyV); + expect(result, contains('> First')); + expect(result, contains('> **Second**')); + expect(RegExp('Second').allMatches(result), hasLength(1)); + }); + + testWidgets( + 'partial inline copy keeps formatting inside another paragraph', + (tester) async { + await mount(tester, 'origin', 'A **bold** word\n', (_) {}); + final field = tester.widget<TextField>(find.byType(TextField).first); + field.controller!.selection = const TextSelection( + baseOffset: 2, + extentOffset: 6, + ); + await key(tester, LogicalKeyboardKey.keyC); + var result = ''; + await mount( + tester, + 'destination', + 'Before after\n', + (value) => result = value, + ); + tester + .widget<TextField>(find.byType(TextField).first) + .controller! + .selection = const TextSelection.collapsed( + offset: 7, + ); + await key(tester, LogicalKeyboardKey.keyV); + expect(result, 'Before **bold**after\n'); + }, + ); + + testWidgets('malformed native fragment falls back to HTML', (tester) async { + systemData = { + 'fragment': '{"version":99}', + 'html': '<p><b>Fallback</b></p>', + 'text': 'Fallback', + }; + var result = ''; + await mount(tester, 'destination', 'Target\n', (value) => result = value); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyV); + expect(result, '**Fallback**\n'); + }); + + testWidgets('HTML-only clipboard imports into a fresh Editor', ( + tester, + ) async { + systemData = { + 'html': '<h1>Other app</h1><p><b>Bold</b></p>', + 'text': 'Other app\nBold', + }; + var result = ''; + await mount(tester, 'destination', 'Target\n', (value) => result = value); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyV); + expect(result, contains('# Other app')); + expect(result, contains('**Bold**')); + }); + + testWidgets( + 'plain paste and later plain copies never revive cached formatting', + (tester) async { + await copyAll(tester); + var result = ''; + await mount( + tester, + 'destination', + 'Target\n', + (value) => result = value, + ); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyV, shift: true); + expect(result, isNot(contains('# Issues'))); + expect(result, isNot(contains('**When**'))); + final sameText = systemData['text'] as String; + await Clipboard.setData(ClipboardData(text: sameText)); + await mount( + tester, + 'destination2', + 'Target\n', + (value) => result = value, + ); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyV); + expect(result, isNot(contains('**When**'))); + }, + ); + + testWidgets('failed clipboard write leaves cut selection intact', ( + tester, + ) async { + var result = _source; + await mount(tester, 'origin', _source, (value) => result = value); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyA); + failWrite = true; + await key(tester, LogicalKeyboardKey.keyX); + expect(result, _source); + expect(systemData, isEmpty); + }); + + testWidgets('paste does not edit a destination changed during the read', ( + tester, + ) async { + systemData = {'text': 'Pasted', 'html': '<p><b>Pasted</b></p>'}; + var result = 'Target\n'; + await mount(tester, 'destination', result, (value) => result = value); + readGate = Completer<void>(); + await key(tester, LogicalKeyboardKey.keyV); + await tester.enterText(find.byType(TextField).first, 'Changed'); + readGate!.complete(); + await tester.pumpAndSettle(); + expect(result, 'Changed\n'); + }); + + testWidgets('cut does not delete a selection changed during the write', ( + tester, + ) async { + var result = 'Target\n'; + await mount(tester, 'origin', result, (value) => result = value); + await key(tester, LogicalKeyboardKey.keyA); + writeGate = Completer<void>(); + await key(tester, LogicalKeyboardKey.keyX); + final field = tester.widget<TextField>(find.byType(TextField).first); + field.controller!.selection = const TextSelection.collapsed(offset: 0); + writeGate!.complete(); + await tester.pumpAndSettle(); + expect(result, 'Target\n'); + expect(systemData['text'], 'Target'); + }); + + testWidgets('paste is cancelled when the destination Editor is replaced', ( + tester, + ) async { + systemData = {'html': '<p><b>Pasted</b></p>', 'text': 'Pasted'}; + await mount(tester, 'destination', 'Target\n', (_) {}); + readGate = Completer<void>(); + await key(tester, LogicalKeyboardKey.keyV); + var result = 'Other\n'; + await mount(tester, 'other', result, (value) => result = value); + readGate!.complete(); + await tester.pumpAndSettle(); + expect(result, 'Other\n'); + }); + }); +} diff --git a/test/src/wysiwyg_structured_regression_test.dart b/test/src/wysiwyg_structured_regression_test.dart index 1f17d1a8..6b056520 100644 --- a/test/src/wysiwyg_structured_regression_test.dart +++ b/test/src/wysiwyg_structured_regression_test.dart @@ -13,6 +13,8 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import '../support/memory_rich_clipboard.dart'; + void main() { const parser = MarkdownParser(); @@ -239,6 +241,7 @@ void main() { await tester.pumpWidget( _app( BusyMarkWysiwygEditor( + clipboardService: MemoryRichClipboard(), document: document, onSourceChanged: (_, value) => markdown = value, ), diff --git a/test/support/memory_rich_clipboard.dart b/test/support/memory_rich_clipboard.dart new file mode 100644 index 00000000..2c1ef155 --- /dev/null +++ b/test/support/memory_rich_clipboard.dart @@ -0,0 +1,19 @@ +import 'package:busymark/src/platform/rich_clipboard_service.dart'; +import 'package:flutter/services.dart'; + +/// A test clipboard that exposes the OS text representation to existing mocks. +class MemoryRichClipboard extends RichClipboardService { + RichClipboardData data = const RichClipboardData(); + bool writeSucceeds = true; + + @override + Future<bool> write(RichClipboardData value) async { + if (!writeSucceeds) return false; + await Clipboard.setData(ClipboardData(text: value.text ?? '')); + data = value; + return true; + } + + @override + Future<RichClipboardData> read() async => data; +} diff --git a/tools/clipboard_smoke.dart b/tools/clipboard_smoke.dart new file mode 100644 index 00000000..1c7c5d0d --- /dev/null +++ b/tools/clipboard_smoke.dart @@ -0,0 +1,140 @@ +// Build with flutter build linux --debug -t tools/clipboard_smoke.dart. +// Run the resulting binary with: write|read|plain|html OUTPUT_DIRECTORY. +// Use a private display: this probe intentionally owns that display's clipboard. +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:busymark/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_clipboard_html.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_document_controller.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_inline_controller.dart'; +import 'package:busymark/src/markdown/markdown_parser.dart'; +import 'package:busymark/src/platform/rich_clipboard_service.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +const source = + '# Issues\n\n**When** selecting all\n\n- [ ] First task\n- [x] Second task\n'; + +void main(List<String> arguments) { + WidgetsFlutterBinding.ensureInitialized(); + if (arguments.length != 2) { + stderr.writeln('Usage: write|read|plain|html OUTPUT_DIRECTORY'); + exit(2); + } + runApp( + MaterialApp(home: Scaffold(body: Text('Clipboard ${arguments.first}'))), + ); + WidgetsBinding.instance.addPostFrameCallback((_) { + unawaited(run(arguments.first, Directory(arguments.last))); + }); +} + +Future<void> run(String operation, Directory output) async { + try { + if (Platform.environment['BUSYMARK_CLIPBOARD_WAIT_FOR_FOCUS'] == '1') { + await File('${output.path}/$operation.window').writeAsString('ready'); + while (!File('${output.path}/start-$operation').existsSync()) { + await Future<void>.delayed(const Duration(milliseconds: 100)); + } + } + final service = RichClipboardService(); + const parser = MarkdownParser(); + final document = parser + .parse(filePath: '/clipboard/source.md', source: source) + .busyDocument; + final fragment = WysiwygClipboardFragment( + mode: document.mode, + sourcePath: document.filePath, + blocks: [ + for (final block in document.blocks) + BusyWysiwygStyledBlock( + kind: block.kind, + text: block.plainText, + ranges: busyInlineStyleRanges(block.inlines), + attributes: block.attributes, + completeBlock: busyMarkWysiwygImmutableBlockSnapshot(block), + ), + ], + ); + const text = + 'Issues\n\nWhen selecting all\n\n[ ] First task\n\n[x] Second task'; + void check(bool condition, String reason) { + if (!condition) throw StateError(reason); + } + + if (operation == 'write' || operation == 'html') { + check( + await service.write( + RichClipboardData( + text: text, + html: const WysiwygClipboardHtml().encode(fragment), + fragment: operation == 'write' ? fragment.encode() : null, + ), + ), + 'Clipboard write failed', + ); + await File('${output.path}/$operation.ready').writeAsString('ready'); + Timer.periodic(const Duration(milliseconds: 100), (timer) { + if (File('${output.path}/stop').existsSync()) { + timer.cancel(); + unawaited(SystemNavigator.pop()); + } + }); + return; + } + if (operation == 'plain') { + await Clipboard.setData(const ClipboardData(text: text)); + } + final data = await service.read(); + check( + data.text == text, + 'Plain text did not survive transport: ${data.toMap().keys}', + ); + if (operation == 'plain') { + check( + data.fragment == null && data.html == null, + 'Plain copy retained stale rich representations', + ); + } else { + check( + data.html?.contains('<strong>When</strong>') == true, + 'HTML formatting missing', + ); + final decoded = WysiwygClipboardFragment.decode(data.fragment ?? ''); + check(decoded != null, 'Structured data missing'); + final target = parser + .parse(filePath: '/clipboard/destination.md', source: 'Target\n') + .busyDocument; + final controller = BusyMarkWysiwygDocumentController(document: target); + final inserted = controller.insertStyledBlocksAtSelection( + blockId: target.blocks.single.id, + selectionStart: 0, + selectionEnd: 6, + blocks: decoded!.blocks, + ); + final markdown = controller.markdown; + check( + inserted != null && + markdown.contains('# Issues') && + markdown.contains('**When** selecting all') && + markdown.contains('- [ ] First task') && + markdown.contains('- [x] Second task'), + 'Formatting changed during insertion: $markdown', + ); + controller.dispose(); + } + await File('${output.path}/$operation.json').writeAsString( + jsonEncode({'passed': true, 'formats': data.toMap().keys.toList()}), + ); + // Let native render hosts finish their first frame before closing the probe. + await Future<void>.delayed(const Duration(seconds: 1)); + await SystemNavigator.pop(); + } catch (error, stack) { + await File( + '${output.path}/$operation.error', + ).writeAsString('$error\n$stack'); + exit(1); + } +} From fa724c08974abc0382342a080da99e07c6e61ab5 Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Mon, 7 Sep 2026 15:15:40 -0700 Subject: [PATCH 12/37] Fixed the Editor right-click bug for document-wide selections --- docs/clipboard-fix-plan.md | 5 +- .../editor/wysiwyg/wysiwyg_block_widgets.dart | 31 +++- lib/src/editor/wysiwyg/wysiwyg_editor.dart | 158 +++++++++++++++--- test/src/wysiwyg_clipboard_test.dart | 30 ++++ 4 files changed, 193 insertions(+), 31 deletions(-) diff --git a/docs/clipboard-fix-plan.md b/docs/clipboard-fix-plan.md index 7859a9be..c40bbf0e 100644 --- a/docs/clipboard-fix-plan.md +++ b/docs/clipboard-fix-plan.md @@ -42,10 +42,13 @@ operation, and ordinary paste uses the richest supported representation. ## Validation -- 237 editor/model regression tests pass, including fresh Editor instances, +- 238 editor/model regression tests pass, including fresh Editor instances, same-Editor cut/paste, partial selections, nested lists, blockquotes, tasks, tables, code, Writerside, images, RTL, math, undo/redo, malformed fragments, serialized writes, failed cut, delayed paste, and a later plain-text copy. +- A document-wide selection has its own right-click menu for Cut, Copy, Paste, + Select all, and Refine with AI when available. The selected blocks stay active + while the menu opens, including when the pointer is over a table cell. - Both reported files, `issues.md` and `writerside-support.md`, passed a read-only codec and insertion probe. Heading, task, table, blockquote, and code content survived; exported HTML also imported successfully. diff --git a/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart b/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart index 0c838097..9c534123 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart @@ -169,6 +169,7 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { this.editRevision = 0, this.selected = false, this.selectionRange, + this.documentSelectionActive = false, this.onPointerDown, this.onPointerMove, this.onPointerUp, @@ -211,6 +212,7 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { final int editRevision; final bool selected; final BusyMarkWysiwygSelectionRange? selectionRange; + final bool documentSelectionActive; final ValueChanged<PointerDownEvent>? onPointerDown; final ValueChanged<PointerMoveEvent>? onPointerMove; final ValueChanged<PointerUpEvent>? onPointerUp; @@ -383,6 +385,7 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { cellFocusNode: tableCellFocusNode, cellKey: tableCellKey, onCellFocused: onTableCellFocused, + suppressContextMenu: documentSelectionActive, ), ); } @@ -531,15 +534,17 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { hoverColor: BusyMarkLinuxPalette.transparent, contentPadding: EdgeInsets.zero, ), - contextMenuBuilder: - (context, editableTextState) => - buildBusyMarkEditorTextContextMenu( - context, - editableTextState, - refineWithAiLabel: - context.l10n.aiRefineWithAi, - onRefineWithAi: onRefineWithAi, - ), + contextMenuBuilder: documentSelectionActive + ? (context, editableTextState) => + const SizedBox.shrink() + : (context, editableTextState) => + buildBusyMarkEditorTextContextMenu( + context, + editableTextState, + refineWithAiLabel: + context.l10n.aiRefineWithAi, + onRefineWithAi: onRefineWithAi, + ), onTap: onFocused, onChanged: onChanged, ), @@ -1451,6 +1456,7 @@ class _TableBlockEditor extends StatelessWidget { this.cellFocusNode, this.cellKey, this.onCellFocused, + this.suppressContextMenu = false, }); static const double _controlSize = BusyMarkSizes.tableControl; @@ -1473,6 +1479,7 @@ class _TableBlockEditor extends StatelessWidget { final FocusNode Function(BusyBlock cell)? cellFocusNode; final GlobalKey Function(String cellId)? cellKey; final ValueChanged<String>? onCellFocused; + final bool suppressContextMenu; @override Widget build(BuildContext context) { @@ -1556,6 +1563,7 @@ class _TableBlockEditor extends StatelessWidget { ? cellKey?.call(row.children[column].id) : null, onCellFocused: onCellFocused, + suppressContextMenu: suppressContextMenu, ), ], ), @@ -1800,6 +1808,7 @@ class _TableCellEditor extends StatefulWidget { this.focusNode, this.cellKey, this.onCellFocused, + this.suppressContextMenu = false, }); final BusyBlock? cell; @@ -1816,6 +1825,7 @@ class _TableCellEditor extends StatefulWidget { final FocusNode? focusNode; final GlobalKey? cellKey; final ValueChanged<String>? onCellFocused; + final bool suppressContextMenu; @override State<_TableCellEditor> createState() => _TableCellEditorState(); @@ -1989,6 +1999,9 @@ class _TableCellEditorState extends State<_TableCellEditor> { hintStyle: textStyle.copyWith(color: colors.mutedForeground), contentPadding: EdgeInsets.zero, ), + contextMenuBuilder: widget.suppressContextMenu + ? (context, editableTextState) => const SizedBox.shrink() + : null, onTap: () { final onCellFocused = widget.onCellFocused; if (onCellFocused == null) { diff --git a/lib/src/editor/wysiwyg/wysiwyg_editor.dart b/lib/src/editor/wysiwyg/wysiwyg_editor.dart index c21b579c..96c49e4e 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_editor.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_editor.dart @@ -175,6 +175,8 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { _ContinuousTextEdit? _continuousTextEdit; _DocumentTextSelection? _documentSelection; _DocumentTextPosition? _pointerSelectionAnchor; + int? _documentSelectionContextPointer; + _DocumentTextSelection? _documentSelectionContextSnapshot; VerticalCaretMovementRun? _verticalCaretMovement; String? _verticalCaretMovementBlockId; TextPosition? _verticalCaretMovementPosition; @@ -518,27 +520,34 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { return Stack( children: [ Positioned.fill( - child: GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () { - _clearBlockSelection(); - _focusActiveOrFirstBlock(); - }, - child: Focus( - focusNode: _selectionFocusNode, - child: ScrollablePositionedList.builder( - key: const ValueKey('wysiwyg-document-scroll'), - itemScrollController: _itemScrollController, - itemPositionsListener: _itemPositionsListener, - padding: documentLayout.scrollPadding, - itemCount: renderEntries.length, - itemBuilder: (context, index) => _buildRenderEntry( - context, - renderEntries[index], - documentLayout: documentLayout, - first: index == 0, - selectedBlockIds: selectedBlockIds, - selectionRangesByBlockId: selectionRangesByBlockId, + child: Listener( + onPointerDown: _handleDocumentSelectionContextPointerDown, + onPointerUp: _handleDocumentSelectionContextPointerUp, + onPointerCancel: + _handleDocumentSelectionContextPointerCancel, + child: GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + _clearBlockSelection(); + _focusActiveOrFirstBlock(); + }, + child: Focus( + focusNode: _selectionFocusNode, + child: ScrollablePositionedList.builder( + key: const ValueKey('wysiwyg-document-scroll'), + itemScrollController: _itemScrollController, + itemPositionsListener: _itemPositionsListener, + padding: documentLayout.scrollPadding, + itemCount: renderEntries.length, + itemBuilder: (context, index) => _buildRenderEntry( + context, + renderEntries[index], + documentLayout: documentLayout, + first: index == 0, + selectedBlockIds: selectedBlockIds, + selectionRangesByBlockId: + selectionRangesByBlockId, + ), ), ), ), @@ -853,6 +862,7 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { focusNode: _focusNodeFor(block), selected: selectedBlockIds.contains(block.id), selectionRange: selectionRangesByBlockId[block.id], + documentSelectionActive: _hasBlockSelection, onPointerDown: (event) => _handleBlockPointerDown(block.id, event), onPointerMove: _handleBlockPointerMove, onPointerUp: _handleBlockPointerUp, @@ -5433,6 +5443,110 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { ); } + void _handleDocumentSelectionContextPointerDown(PointerDownEvent event) { + _documentSelectionContextPointer = null; + _documentSelectionContextSnapshot = null; + if (event.buttons != kSecondaryMouseButton || !_hasBlockSelection) { + return; + } + _documentSelectionContextPointer = event.pointer; + _documentSelectionContextSnapshot = _documentSelection; + _preserveSelectionFocusCallbacks = math.max( + _preserveSelectionFocusCallbacks, + 2, + ); + } + + void _handleDocumentSelectionContextPointerUp(PointerUpEvent event) { + if (_documentSelectionContextPointer != event.pointer) { + return; + } + final snapshot = _documentSelectionContextSnapshot; + _documentSelectionContextPointer = null; + _documentSelectionContextSnapshot = null; + if (snapshot == null || snapshot != _documentSelection) { + return; + } + unawaited(_showDocumentSelectionContextMenu(event.position, snapshot)); + } + + void _handleDocumentSelectionContextPointerCancel(PointerCancelEvent event) { + if (_documentSelectionContextPointer == event.pointer) { + _documentSelectionContextPointer = null; + _documentSelectionContextSnapshot = null; + } + } + + Future<void> _showDocumentSelectionContextMenu( + Offset position, + _DocumentTextSelection snapshot, + ) async { + final commands = + BusyMarkCommandRegistryScope.maybeOf(context) ?? + BusyMarkCommandCatalog.metadata; + BusyMarkPopupMenuItem<_DocumentSelectionMenuAction> item( + _DocumentSelectionMenuAction action, + String commandId, + IconData icon, + ) { + final command = commands[commandId]!; + return BusyMarkPopupMenuItem( + value: action, + label: command.label(context), + icon: icon, + shortcut: command.shortcut?.label, + ); + } + + final action = await showBusyMarkContextMenu<_DocumentSelectionMenuAction>( + context, + position, + items: [ + item( + _DocumentSelectionMenuAction.cut, + BusyMarkCommandIds.textCut, + BusyMarkGlyphs.cut, + ), + item( + _DocumentSelectionMenuAction.copy, + BusyMarkCommandIds.textCopy, + BusyMarkGlyphs.copy, + ), + item( + _DocumentSelectionMenuAction.paste, + BusyMarkCommandIds.textPaste, + BusyMarkGlyphs.paste, + ), + item( + _DocumentSelectionMenuAction.selectAll, + BusyMarkCommandIds.textSelectAll, + BusyMarkGlyphs.selectAll, + ), + if (widget.onAiEdit != null) + item( + _DocumentSelectionMenuAction.refineWithAi, + BusyMarkCommandIds.editorRefineWithAi, + BusyMarkGlyphs.ai, + ), + ], + ); + if (!mounted || action == null || snapshot != _documentSelection) { + return; + } + switch (action) { + case _DocumentSelectionMenuAction.cut: + _cutBlockSelection(); + case _DocumentSelectionMenuAction.copy: + _copyBlockSelection(); + case _DocumentSelectionMenuAction.paste: + unawaited(_pasteIntoActiveBlock()); + case _DocumentSelectionMenuAction.selectAll: + _selectWholeDocumentText(); + case _DocumentSelectionMenuAction.refineWithAi: + unawaited(_runAiEdit()); + } + } + void _handleBlockPointerMove(PointerMoveEvent event) { if (_pointerSelectionAnchor == null || event.buttons != kPrimaryMouseButton) { @@ -6282,6 +6396,8 @@ class _ClipboardTarget { final TextSelection? textSelection; } +enum _DocumentSelectionMenuAction { cut, copy, paste, selectAll, refineWithAi } + class _ContinuousTextEdit { const _ContinuousTextEdit({ required this.targetId, diff --git a/test/src/wysiwyg_clipboard_test.dart b/test/src/wysiwyg_clipboard_test.dart index e145f343..d888b4b7 100644 --- a/test/src/wysiwyg_clipboard_test.dart +++ b/test/src/wysiwyg_clipboard_test.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:busymark/l10n/generated/app_localizations.dart'; +import 'package:busymark/src/app/busymark_design.dart'; import 'package:busymark/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart'; import 'package:busymark/src/editor/wysiwyg/wysiwyg_clipboard_html.dart'; import 'package:busymark/src/editor/wysiwyg/wysiwyg_document_controller.dart'; @@ -12,6 +13,7 @@ import 'package:busymark/src/markdown/markdown_model.dart'; import 'package:busymark/src/markdown/markdown_parser.dart'; import 'package:busymark/src/platform/rich_clipboard_service.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:html/parser.dart' as html; @@ -427,6 +429,34 @@ void main() { expect(RegExp('Second').allMatches(result), hasLength(1)); }); + testWidgets('right-click opens the menu for a whole-document selection', ( + tester, + ) async { + await mount(tester, 'issues', _source, (_) {}); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyA); + + await tester.tap( + find.widgetWithText(TextField, 'When selecting all, keep formatting.'), + buttons: kSecondaryMouseButton, + ); + await tester.pumpAndSettle(); + + for (final label in ['Cut', 'Copy', 'Paste', 'Select all']) { + expect( + find.byWidgetPredicate( + (widget) => + widget is BusyMarkPopupMenuItem && widget.label == label, + ), + findsOneWidget, + ); + } + await tester.tap(find.text('Copy')); + await tester.pumpAndSettle(); + expect(systemData.keys, containsAll(['text', 'html', 'fragment'])); + expect(systemData['text'], contains('[ ] First task')); + }); + testWidgets( 'partial inline copy keeps formatting inside another paragraph', (tester) async { From 370ae2e4aae6ec111363efd7fb238654204a42a7 Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Mon, 7 Sep 2026 16:38:24 -0700 Subject: [PATCH 13/37] Fixed a bug. Editor session restoration counted the top toolbar padding twice, moving the title from 58 px to 116 px after reopening Editor or switching from Source. --- lib/l10n/app_ar.arb | 4 ++ lib/l10n/app_de.arb | 4 ++ lib/l10n/app_en.arb | 2 + lib/l10n/app_es.arb | 4 ++ lib/l10n/app_et.arb | 4 ++ lib/l10n/app_fa.arb | 4 ++ lib/l10n/app_fr.arb | 4 ++ lib/l10n/app_hi.arb | 4 ++ lib/l10n/app_id.arb | 4 ++ lib/l10n/app_it.arb | 4 ++ lib/l10n/app_ja.arb | 4 ++ lib/l10n/app_ko.arb | 4 ++ lib/l10n/app_nb.arb | 4 ++ lib/l10n/app_nl.arb | 4 ++ lib/l10n/app_pl.arb | 4 ++ lib/l10n/app_pt_BR.arb | 4 ++ lib/l10n/app_ru.arb | 4 ++ lib/l10n/app_tr.arb | 4 ++ lib/l10n/app_uk.arb | 4 ++ lib/l10n/app_vi.arb | 4 ++ lib/l10n/app_zh_CN.arb | 4 ++ lib/l10n/generated/app_localizations.dart | 6 ++ lib/l10n/generated/app_localizations_ar.dart | 3 + lib/l10n/generated/app_localizations_de.dart | 3 + lib/l10n/generated/app_localizations_en.dart | 3 + lib/l10n/generated/app_localizations_es.dart | 3 + lib/l10n/generated/app_localizations_et.dart | 3 + lib/l10n/generated/app_localizations_fa.dart | 3 + lib/l10n/generated/app_localizations_fr.dart | 4 ++ lib/l10n/generated/app_localizations_hi.dart | 3 + lib/l10n/generated/app_localizations_id.dart | 3 + lib/l10n/generated/app_localizations_it.dart | 3 + lib/l10n/generated/app_localizations_ja.dart | 3 + lib/l10n/generated/app_localizations_ko.dart | 3 + lib/l10n/generated/app_localizations_nb.dart | 3 + lib/l10n/generated/app_localizations_nl.dart | 3 + lib/l10n/generated/app_localizations_pl.dart | 3 + lib/l10n/generated/app_localizations_pt.dart | 6 ++ lib/l10n/generated/app_localizations_ru.dart | 3 + lib/l10n/generated/app_localizations_tr.dart | 3 + lib/l10n/generated/app_localizations_uk.dart | 3 + lib/l10n/generated/app_localizations_vi.dart | 3 + lib/l10n/generated/app_localizations_zh.dart | 6 ++ lib/src/editor/wysiwyg/wysiwyg_editor.dart | 24 ++++++-- .../presentation/workspace_screen.dart | 49 ++++------------- test/src/app_smoke_test.dart | 8 ++- test/src/busymark_document_test.dart | 55 +++++++++++++++++++ 47 files changed, 249 insertions(+), 45 deletions(-) diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index fa97665b..23ec80a8 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -2478,6 +2478,10 @@ "@removeTocElement": { "description": "Action that removes a topic element from the selected table of contents." }, + "removeTocElements": "إزالة عناصر جدول المحتويات", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "مراجعة الاستخدامات", "@reviewUsages": { "description": "Action that opens the topic usage review." diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 4fdb355d..1e6c77b3 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -2478,6 +2478,10 @@ "@removeTocElement": { "description": "Action that removes a topic element from the selected table of contents." }, + "removeTocElements": "Inhaltsverzeichniselemente entfernen", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "Verwendungen prüfen", "@reviewUsages": { "description": "Action that opens the topic usage review." diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index cbab63d6..74bb04b2 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -759,6 +759,8 @@ "@safeDeleteTopicFile": {"description": "Writerside action that safely deletes a topic after checking usages."}, "removeTocElement": "Remove TOC Element", "@removeTocElement": {"description": "Writerside action and dialog title for removing a topic from one table of contents."}, + "removeTocElements": "Remove TOC Elements", + "@removeTocElements": {"description": "Action that removes multiple selected elements from one Writerside table of contents."}, "reviewUsages": "Review Usages", "@reviewUsages": {"description": "Action that opens the Writerside topic usages review."}, "deleteTopicFile": "Delete Topic File", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 48230a98..fd7714d4 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -2478,6 +2478,10 @@ "@removeTocElement": { "description": "Action that removes a topic element from the selected table of contents." }, + "removeTocElements": "Quitar elementos del índice", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "Revisar usos", "@reviewUsages": { "description": "Action that opens the topic usage review." diff --git a/lib/l10n/app_et.arb b/lib/l10n/app_et.arb index 32b5a9aa..174f2028 100644 --- a/lib/l10n/app_et.arb +++ b/lib/l10n/app_et.arb @@ -1410,6 +1410,10 @@ "@removeTocElement": { "description": "Writerside action and dialog title for removing a topic from one table of contents." }, + "removeTocElements": "Eemalda sisukorraelemendid", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "Vaata kasutuskohad üle", "@reviewUsages": { "description": "Action that opens the Writerside topic usages review." diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index 258b7c73..ba684b58 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -2517,6 +2517,10 @@ "@removeTocElement": { "description": "Action that removes a topic element from the selected table of contents." }, + "removeTocElements": "حذف عناصر فهرست مطالب", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "مرور موارد استفاده", "@reviewUsages": { "description": "Action that opens the topic usage review." diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 86498b4e..c912d89d 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -2478,6 +2478,10 @@ "@removeTocElement": { "description": "Action that removes a topic element from the selected table of contents." }, + "removeTocElements": "Retirer les éléments de la table des matières", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "Examiner les utilisations", "@reviewUsages": { "description": "Action that opens the topic usage review." diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index c8c5c68c..405d5c0f 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -2478,6 +2478,10 @@ "@removeTocElement": { "description": "Action that removes a topic element from the selected table of contents." }, + "removeTocElements": "TOC तत्व हटाएँ", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "उपयोगों की समीक्षा करें", "@reviewUsages": { "description": "Action that opens the topic usage review." diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index 288e3632..382c16cf 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -1498,6 +1498,10 @@ "@removeTocElement": { "description": "Writerside action and dialog title for removing a topic from one table of contents." }, + "removeTocElements": "Hapus elemen TOC", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "Tinjau penggunaan", "@reviewUsages": { "description": "Action that opens the Writerside topic usages review." diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 13bfa692..b435edb9 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -2478,6 +2478,10 @@ "@removeTocElement": { "description": "Action that removes a topic element from the selected table of contents." }, + "removeTocElements": "Rimuovi elementi dal TOC", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "Esamina utilizzi", "@reviewUsages": { "description": "Action that opens the topic usage review." diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 997cdc4c..63e921f3 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -1498,6 +1498,10 @@ "@removeTocElement": { "description": "Writerside action and dialog title for removing a topic from one table of contents." }, + "removeTocElements": "目次要素を削除", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "使用箇所を確認", "@reviewUsages": { "description": "Action that opens the Writerside topic usages review." diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index 3edae17f..b59d430d 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -1498,6 +1498,10 @@ "@removeTocElement": { "description": "Writerside action and dialog title for removing a topic from one table of contents." }, + "removeTocElements": "TOC 요소 제거", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "사용 검토", "@reviewUsages": { "description": "Action that opens the Writerside topic usages review." diff --git a/lib/l10n/app_nb.arb b/lib/l10n/app_nb.arb index 5b14d8e1..3f4c957b 100644 --- a/lib/l10n/app_nb.arb +++ b/lib/l10n/app_nb.arb @@ -2478,6 +2478,10 @@ "@removeTocElement": { "description": "Action that removes a topic element from the selected table of contents." }, + "removeTocElements": "Fjern elementer fra innholdsfortegnelsen", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "Se gjennom bruk", "@reviewUsages": { "description": "Action that opens the topic usage review." diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index d673b813..0b293e4d 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -1498,6 +1498,10 @@ "@removeTocElement": { "description": "Writerside action and dialog title for removing a topic from one table of contents." }, + "removeTocElements": "TOC-elementen verwijderen", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "Gebruik controleren", "@reviewUsages": { "description": "Action that opens the Writerside topic usages review." diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 5eb6b2fb..d3b3bb3d 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -2504,6 +2504,10 @@ "@removeTocElement": { "description": "Action that removes a topic element from the selected table of contents." }, + "removeTocElements": "Usuń elementy spisu treści", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "Przejrzyj użycia", "@reviewUsages": { "description": "Action that opens the topic usage review." diff --git a/lib/l10n/app_pt_BR.arb b/lib/l10n/app_pt_BR.arb index 168a2064..3ea34ee2 100644 --- a/lib/l10n/app_pt_BR.arb +++ b/lib/l10n/app_pt_BR.arb @@ -2478,6 +2478,10 @@ "@removeTocElement": { "description": "Action that removes a topic element from the selected table of contents." }, + "removeTocElements": "Remover elementos do TOC", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "Revisar usos", "@reviewUsages": { "description": "Action that opens the topic usage review." diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index de81f71c..479238cc 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -2504,6 +2504,10 @@ "@removeTocElement": { "description": "Action that removes a topic element from the selected table of contents." }, + "removeTocElements": "Удалить элементы оглавления", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "Просмотреть использования", "@reviewUsages": { "description": "Action that opens the topic usage review." diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 96b14eaf..d25ff535 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -1498,6 +1498,10 @@ "@removeTocElement": { "description": "Writerside action and dialog title for removing a topic from one table of contents." }, + "removeTocElements": "TOC öğelerini kaldır", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "Kullanımları incele", "@reviewUsages": { "description": "Action that opens the Writerside topic usages review." diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 458944a5..9d45f769 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -2504,6 +2504,10 @@ "@removeTocElement": { "description": "Action that removes a topic element from the selected table of contents." }, + "removeTocElements": "Вилучити елементи змісту", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "Переглянути використання", "@reviewUsages": { "description": "Action that opens the topic usage review." diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index 1f1b5709..1efa18ff 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -1498,6 +1498,10 @@ "@removeTocElement": { "description": "Writerside action and dialog title for removing a topic from one table of contents." }, + "removeTocElements": "Xóa các phần tử mục lục", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "Xem lại các tham chiếu", "@reviewUsages": { "description": "Action that opens the Writerside topic usages review." diff --git a/lib/l10n/app_zh_CN.arb b/lib/l10n/app_zh_CN.arb index cb36af3e..0007e82a 100644 --- a/lib/l10n/app_zh_CN.arb +++ b/lib/l10n/app_zh_CN.arb @@ -1498,6 +1498,10 @@ "@removeTocElement": { "description": "Writerside action and dialog title for removing a topic from one table of contents." }, + "removeTocElements": "移除目录元素", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, "reviewUsages": "查看使用情况", "@reviewUsages": { "description": "Action that opens the Writerside topic usages review." diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index e4cd8712..591685ff 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -2299,6 +2299,12 @@ abstract class AppLocalizations { /// **'Remove TOC Element'** String get removeTocElement; + /// Action that removes multiple selected elements from one Writerside table of contents. + /// + /// In en, this message translates to: + /// **'Remove TOC Elements'** + String get removeTocElements; + /// Action that opens the Writerside topic usages review. /// /// In en, this message translates to: diff --git a/lib/l10n/generated/app_localizations_ar.dart b/lib/l10n/generated/app_localizations_ar.dart index c4c9f117..8c3ab3fd 100644 --- a/lib/l10n/generated/app_localizations_ar.dart +++ b/lib/l10n/generated/app_localizations_ar.dart @@ -1211,6 +1211,9 @@ class AppLocalizationsAr extends AppLocalizations { @override String get removeTocElement => 'إزالة عنصر جدول المحتويات'; + @override + String get removeTocElements => 'إزالة عناصر جدول المحتويات'; + @override String get reviewUsages => 'مراجعة الاستخدامات'; diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index dcf74d0a..37714fad 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -1224,6 +1224,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get removeTocElement => 'Inhaltsverzeichniselement entfernen'; + @override + String get removeTocElements => 'Inhaltsverzeichniselemente entfernen'; + @override String get reviewUsages => 'Verwendungen prüfen'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 7464d107..e61f547b 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -1204,6 +1204,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get removeTocElement => 'Remove TOC Element'; + @override + String get removeTocElements => 'Remove TOC Elements'; + @override String get reviewUsages => 'Review Usages'; diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart index 1343c9a3..088c1937 100644 --- a/lib/l10n/generated/app_localizations_es.dart +++ b/lib/l10n/generated/app_localizations_es.dart @@ -1224,6 +1224,9 @@ class AppLocalizationsEs extends AppLocalizations { @override String get removeTocElement => 'Quitar elemento del índice'; + @override + String get removeTocElements => 'Quitar elementos del índice'; + @override String get reviewUsages => 'Revisar usos'; diff --git a/lib/l10n/generated/app_localizations_et.dart b/lib/l10n/generated/app_localizations_et.dart index 5c2ea647..c535eb05 100644 --- a/lib/l10n/generated/app_localizations_et.dart +++ b/lib/l10n/generated/app_localizations_et.dart @@ -1209,6 +1209,9 @@ class AppLocalizationsEt extends AppLocalizations { @override String get removeTocElement => 'Eemalda sisukorraelement'; + @override + String get removeTocElements => 'Eemalda sisukorraelemendid'; + @override String get reviewUsages => 'Vaata kasutuskohad üle'; diff --git a/lib/l10n/generated/app_localizations_fa.dart b/lib/l10n/generated/app_localizations_fa.dart index 33a7f95f..fe4ff4d7 100644 --- a/lib/l10n/generated/app_localizations_fa.dart +++ b/lib/l10n/generated/app_localizations_fa.dart @@ -1232,6 +1232,9 @@ class AppLocalizationsFa extends AppLocalizations { @override String get removeTocElement => 'حذف عنصر فهرست مطالب'; + @override + String get removeTocElements => 'حذف عناصر فهرست مطالب'; + @override String get reviewUsages => 'مرور موارد استفاده'; diff --git a/lib/l10n/generated/app_localizations_fr.dart b/lib/l10n/generated/app_localizations_fr.dart index a3c66db9..39b9f46d 100644 --- a/lib/l10n/generated/app_localizations_fr.dart +++ b/lib/l10n/generated/app_localizations_fr.dart @@ -1222,6 +1222,10 @@ class AppLocalizationsFr extends AppLocalizations { @override String get removeTocElement => 'Retirer l’élément de la table des matières'; + @override + String get removeTocElements => + 'Retirer les éléments de la table des matières'; + @override String get reviewUsages => 'Examiner les utilisations'; diff --git a/lib/l10n/generated/app_localizations_hi.dart b/lib/l10n/generated/app_localizations_hi.dart index 50c0ad22..19f4cd09 100644 --- a/lib/l10n/generated/app_localizations_hi.dart +++ b/lib/l10n/generated/app_localizations_hi.dart @@ -1200,6 +1200,9 @@ class AppLocalizationsHi extends AppLocalizations { @override String get removeTocElement => 'TOC तत्व हटाएँ'; + @override + String get removeTocElements => 'TOC तत्व हटाएँ'; + @override String get reviewUsages => 'उपयोगों की समीक्षा करें'; diff --git a/lib/l10n/generated/app_localizations_id.dart b/lib/l10n/generated/app_localizations_id.dart index e31761d2..d994d60b 100644 --- a/lib/l10n/generated/app_localizations_id.dart +++ b/lib/l10n/generated/app_localizations_id.dart @@ -1210,6 +1210,9 @@ class AppLocalizationsId extends AppLocalizations { @override String get removeTocElement => 'Hapus elemen TOC'; + @override + String get removeTocElements => 'Hapus elemen TOC'; + @override String get reviewUsages => 'Tinjau penggunaan'; diff --git a/lib/l10n/generated/app_localizations_it.dart b/lib/l10n/generated/app_localizations_it.dart index 3971a211..f57a677c 100644 --- a/lib/l10n/generated/app_localizations_it.dart +++ b/lib/l10n/generated/app_localizations_it.dart @@ -1219,6 +1219,9 @@ class AppLocalizationsIt extends AppLocalizations { @override String get removeTocElement => 'Rimuovi elemento dal TOC'; + @override + String get removeTocElements => 'Rimuovi elementi dal TOC'; + @override String get reviewUsages => 'Esamina utilizzi'; diff --git a/lib/l10n/generated/app_localizations_ja.dart b/lib/l10n/generated/app_localizations_ja.dart index 25a11b95..069f8cba 100644 --- a/lib/l10n/generated/app_localizations_ja.dart +++ b/lib/l10n/generated/app_localizations_ja.dart @@ -1171,6 +1171,9 @@ class AppLocalizationsJa extends AppLocalizations { @override String get removeTocElement => '目次要素を削除'; + @override + String get removeTocElements => '目次要素を削除'; + @override String get reviewUsages => '使用箇所を確認'; diff --git a/lib/l10n/generated/app_localizations_ko.dart b/lib/l10n/generated/app_localizations_ko.dart index 44061bdf..519241fd 100644 --- a/lib/l10n/generated/app_localizations_ko.dart +++ b/lib/l10n/generated/app_localizations_ko.dart @@ -1169,6 +1169,9 @@ class AppLocalizationsKo extends AppLocalizations { @override String get removeTocElement => 'TOC 요소 제거'; + @override + String get removeTocElements => 'TOC 요소 제거'; + @override String get reviewUsages => '사용 검토'; diff --git a/lib/l10n/generated/app_localizations_nb.dart b/lib/l10n/generated/app_localizations_nb.dart index 627fe8a5..cbad9a34 100644 --- a/lib/l10n/generated/app_localizations_nb.dart +++ b/lib/l10n/generated/app_localizations_nb.dart @@ -1209,6 +1209,9 @@ class AppLocalizationsNb extends AppLocalizations { @override String get removeTocElement => 'Fjern element fra innholdsfortegnelsen'; + @override + String get removeTocElements => 'Fjern elementer fra innholdsfortegnelsen'; + @override String get reviewUsages => 'Se gjennom bruk'; diff --git a/lib/l10n/generated/app_localizations_nl.dart b/lib/l10n/generated/app_localizations_nl.dart index 1a2dbb5d..f120cb86 100644 --- a/lib/l10n/generated/app_localizations_nl.dart +++ b/lib/l10n/generated/app_localizations_nl.dart @@ -1210,6 +1210,9 @@ class AppLocalizationsNl extends AppLocalizations { @override String get removeTocElement => 'TOC-element verwijderen'; + @override + String get removeTocElements => 'TOC-elementen verwijderen'; + @override String get reviewUsages => 'Gebruik controleren'; diff --git a/lib/l10n/generated/app_localizations_pl.dart b/lib/l10n/generated/app_localizations_pl.dart index 177ef81d..aaa835ec 100644 --- a/lib/l10n/generated/app_localizations_pl.dart +++ b/lib/l10n/generated/app_localizations_pl.dart @@ -1229,6 +1229,9 @@ class AppLocalizationsPl extends AppLocalizations { @override String get removeTocElement => 'Usuń element spisu treści'; + @override + String get removeTocElements => 'Usuń elementy spisu treści'; + @override String get reviewUsages => 'Przejrzyj użycia'; diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart index a88eacdb..a548feac 100644 --- a/lib/l10n/generated/app_localizations_pt.dart +++ b/lib/l10n/generated/app_localizations_pt.dart @@ -1205,6 +1205,9 @@ class AppLocalizationsPt extends AppLocalizations { @override String get removeTocElement => 'Remove TOC Element'; + @override + String get removeTocElements => 'Remove TOC Elements'; + @override String get reviewUsages => 'Review Usages'; @@ -5128,6 +5131,9 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { @override String get removeTocElement => 'Remover elemento do TOC'; + @override + String get removeTocElements => 'Remover elementos do TOC'; + @override String get reviewUsages => 'Revisar usos'; diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart index f751c192..a1db8f45 100644 --- a/lib/l10n/generated/app_localizations_ru.dart +++ b/lib/l10n/generated/app_localizations_ru.dart @@ -1225,6 +1225,9 @@ class AppLocalizationsRu extends AppLocalizations { @override String get removeTocElement => 'Удалить элемент оглавления'; + @override + String get removeTocElements => 'Удалить элементы оглавления'; + @override String get reviewUsages => 'Просмотреть использования'; diff --git a/lib/l10n/generated/app_localizations_tr.dart b/lib/l10n/generated/app_localizations_tr.dart index 73b2eb45..4e0cc6d0 100644 --- a/lib/l10n/generated/app_localizations_tr.dart +++ b/lib/l10n/generated/app_localizations_tr.dart @@ -1211,6 +1211,9 @@ class AppLocalizationsTr extends AppLocalizations { @override String get removeTocElement => 'TOC öğesini kaldır'; + @override + String get removeTocElements => 'TOC öğelerini kaldır'; + @override String get reviewUsages => 'Kullanımları incele'; diff --git a/lib/l10n/generated/app_localizations_uk.dart b/lib/l10n/generated/app_localizations_uk.dart index 1f2d279b..794beacc 100644 --- a/lib/l10n/generated/app_localizations_uk.dart +++ b/lib/l10n/generated/app_localizations_uk.dart @@ -1232,6 +1232,9 @@ class AppLocalizationsUk extends AppLocalizations { @override String get removeTocElement => 'Вилучити елемент змісту'; + @override + String get removeTocElements => 'Вилучити елементи змісту'; + @override String get reviewUsages => 'Переглянути використання'; diff --git a/lib/l10n/generated/app_localizations_vi.dart b/lib/l10n/generated/app_localizations_vi.dart index 8e185a67..0c55b9c5 100644 --- a/lib/l10n/generated/app_localizations_vi.dart +++ b/lib/l10n/generated/app_localizations_vi.dart @@ -1203,6 +1203,9 @@ class AppLocalizationsVi extends AppLocalizations { @override String get removeTocElement => 'Xóa phần tử mục lục'; + @override + String get removeTocElements => 'Xóa các phần tử mục lục'; + @override String get reviewUsages => 'Xem lại các tham chiếu'; diff --git a/lib/l10n/generated/app_localizations_zh.dart b/lib/l10n/generated/app_localizations_zh.dart index 7ab5ae1d..f85f8f71 100644 --- a/lib/l10n/generated/app_localizations_zh.dart +++ b/lib/l10n/generated/app_localizations_zh.dart @@ -1204,6 +1204,9 @@ class AppLocalizationsZh extends AppLocalizations { @override String get removeTocElement => 'Remove TOC Element'; + @override + String get removeTocElements => 'Remove TOC Elements'; + @override String get reviewUsages => 'Review Usages'; @@ -5051,6 +5054,9 @@ class AppLocalizationsZhCn extends AppLocalizationsZh { @override String get removeTocElement => '移除目录元素'; + @override + String get removeTocElements => '移除目录元素'; + @override String get reviewUsages => '查看使用情况'; diff --git a/lib/src/editor/wysiwyg/wysiwyg_editor.dart b/lib/src/editor/wysiwyg/wysiwyg_editor.dart index 96c49e4e..94bfc921 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_editor.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_editor.dart @@ -188,6 +188,7 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { var _toolbarVisible = true; var _documentGeneration = 0; bool _sessionReportScheduled = false; + double? _viewportHeight; String get _documentId => widget.documentId ?? widget.document.filePath; @@ -516,6 +517,9 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { decoration: BoxDecoration(color: colors.view), child: LayoutBuilder( builder: (context, constraints) { + _viewportHeight = constraints.maxHeight.isFinite + ? constraints.maxHeight + : null; final documentLayout = _documentLayout; return Stack( children: [ @@ -1788,10 +1792,22 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { } final viewportBlockId = session.viewportBlockId; if (viewportBlockId != null) { - _jumpToBlock( - viewportBlockId, - alignment: session.viewportAlignment.clamp(0.0, 1.0), - ); + var alignment = session.viewportAlignment.clamp(0.0, 1.0).toDouble(); + final firstViewportBlockId = _editorRenderEntries( + _documentController.document.blocks, + ).firstOrNull?.block.id; + final viewportHeight = _viewportHeight; + if (viewportBlockId == firstViewportBlockId && + viewportHeight != null && + viewportHeight > 0) { + // ItemPosition includes the leading scroll padding for item zero, + // while jumpTo applies that padding again during restoration. + alignment = math.max( + 0, + alignment - _documentLayout.scrollPadding.top / viewportHeight, + ); + } + _jumpToBlock(viewportBlockId, alignment: alignment); } final activeCellId = _activeCellId; if (activeCellId != null) { diff --git a/lib/src/workspace/presentation/workspace_screen.dart b/lib/src/workspace/presentation/workspace_screen.dart index aa51ba59..8841d3cb 100644 --- a/lib/src/workspace/presentation/workspace_screen.dart +++ b/lib/src/workspace/presentation/workspace_screen.dart @@ -5578,7 +5578,7 @@ class _TocTabState extends ConsumerState<_TocTab> { if (canRefineSelection) { await _refineTocTopicsWithAi(context, selectedTopics); } - case _TocTreeAction.deleteSelection: + case _TocTreeAction.removeSelection: if (canEditSelection) { await _removeTocEntries( context, @@ -5737,26 +5737,6 @@ class _TocTabState extends ConsumerState<_TocTab> { instanceTreePath: instanceTreePath, entry: entry, ); - case _TocTreeAction.delete: - final path = topicPath; - if (path == null) { - return; - } - final result = await widget.onRequestTopicRemoval( - _WritersideTopicRemovalTarget( - mode: WritersideTopicRemovalMode.safeDeleteFile, - topicPath: path, - ), - ); - if (mounted && result != null) { - setState(() { - _cutEntries = []; - _selectedNodePathKey = null; - _selectedNodePathKeys = {}; - _selectionAnchorPathKey = null; - }); - _clearGitDetailSelection(ref); - } case _TocTreeAction.addToGit: final relativePath = gitRelativePath; if (relativePath != null) { @@ -5928,11 +5908,10 @@ enum _TocTreeAction { rename, cut, refineWithAi, - deleteSelection, + removeSelection, pasteAfter, pasteAsChild, removeFromToc, - delete, addToGit, copyName, copyPath, @@ -5976,9 +5955,15 @@ Future<_TocTreeAction?> _showTocTreeMenu( ), const PopupMenuDivider(height: BusyMarkSpacing.sm), BusyMarkPopupMenuItem( - value: _TocTreeAction.deleteSelection, - label: context.l10n.delete, - icon: BusyMarkGlyphs.delete, + value: _TocTreeAction.removeSelection, + label: context.l10n.removeTocElements, + icon: BusyMarkGlyphs.outdentFor(Directionality.of(context)), + shortcut: + (BusyMarkCommandRegistryScope.read(context) ?? + BusyMarkCommandCatalog.metadata)[BusyMarkCommandIds + .treeDeleteSelection] + ?.shortcut + ?.label, enabled: canEditSelection, ), ] else ...[ @@ -6054,18 +6039,6 @@ Future<_TocTreeAction?> _showTocTreeMenu( ?.label, enabled: canEditStructure, ), - BusyMarkPopupMenuItem( - value: _TocTreeAction.delete, - label: context.l10n.safeDeleteTopicFile, - icon: BusyMarkGlyphs.delete, - enabled: hasTopicFile, - ), - BusyMarkPopupMenuItem( - value: _TocTreeAction.deleteSelection, - label: context.l10n.delete, - icon: BusyMarkGlyphs.delete, - enabled: canEditSelection, - ), const PopupMenuDivider(height: BusyMarkSpacing.sm), BusyMarkPopupMenuItem( value: _TocTreeAction.openInFiles, diff --git a/test/src/app_smoke_test.dart b/test/src/app_smoke_test.dart index f099bb21..b80b7d82 100644 --- a/test/src/app_smoke_test.dart +++ b/test/src/app_smoke_test.dart @@ -2059,8 +2059,6 @@ void main() { l10n.pasteAfterTopic, l10n.pasteAsChildTopic, l10n.removeTocElement, - l10n.safeDeleteTopicFile, - l10n.delete, l10n.copyName, l10n.copyPath, l10n.openInFiles, @@ -2069,6 +2067,8 @@ void main() { ]) { expect(popupMenuItem(label), findsOneWidget); } + expect(popupMenuItem(l10n.safeDeleteTopicFile), findsNothing); + expect(popupMenuItem(l10n.delete), findsNothing); await tester.tap(find.text(l10n.newChildTopic)); await tester.pump(const Duration(milliseconds: 300)); @@ -2115,10 +2115,12 @@ void main() { l10n.copy, l10n.cut, l10n.aiRefineWithAi, - l10n.delete, + l10n.removeTocElements, ]) { expect(popupMenuItem(label), findsOneWidget); } + expect(popupMenuItem(l10n.delete), findsNothing); + expect(popupMenuItem(l10n.safeDeleteTopicFile), findsNothing); expect(find.text(l10n.newSiblingTopic), findsNothing); expect(find.text(l10n.copyName), findsNothing); await tester.sendKeyEvent(LogicalKeyboardKey.escape); diff --git a/test/src/busymark_document_test.dart b/test/src/busymark_document_test.dart index cedfe61e..dbdea9d6 100644 --- a/test/src/busymark_document_test.dart +++ b/test/src/busymark_document_test.dart @@ -22,6 +22,7 @@ import 'package:busymark/src/editor/wysiwyg/wysiwyg_commands.dart'; import 'package:busymark/src/editor/wysiwyg/wysiwyg_document_controller.dart'; import 'package:busymark/src/editor/wysiwyg/wysiwyg_editor.dart'; import 'package:busymark/src/editor/wysiwyg/wysiwyg_inline_controller.dart'; +import 'package:busymark/src/editor/wysiwyg/wysiwyg_session_state.dart'; import 'package:busymark/src/editor/wysiwyg/wysiwyg_toolbar.dart'; import 'package:busymark/src/markdown/busymark_document.dart'; import 'package:busymark/src/markdown/busymark_markdown_serializer.dart'; @@ -3417,6 +3418,60 @@ void main() {} } }); + testWidgets( + 'restoring the first block does not duplicate the Editor top inset', + (tester) async { + tester.view.physicalSize = const Size(900, 640); + tester.view.devicePixelRatio = 1; + addTearDown(() { + tester.view.resetPhysicalSize(); + tester.view.resetDevicePixelRatio(); + }); + final document = parser + .parse( + filePath: 'new-topic.md', + source: '''# New topic + +> Advice. +{style="note"} +''', + mode: MarkdownMode.writersideMarkdown, + validateLocalReferences: false, + ) + .busyDocument; + var session = const WysiwygEditorSessionState(); + + Future<double> pumpEditor(Key key) async { + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: BusyMarkWysiwygEditor( + key: key, + document: document, + initialSessionState: session, + onSessionChanged: (_, next) => session = next, + onSourceChanged: (_, _) {}, + ), + ), + ), + ); + await tester.pumpAndSettle(); + await tester.pump(); + return tester.getRect(find.byType(TextField).first).top; + } + + final initialTitleTop = await pumpEditor(const ValueKey('initial')); + expect(session.viewportBlockId, isNotNull); + expect(session.viewportAlignment, greaterThan(0)); + + final restoredTitleTop = await pumpEditor(const ValueKey('restored')); + + expect(restoredTitleTop, closeTo(initialTitleTop, 0.1)); + }, + ); + testWidgets('vertical WYSIWYG toolbar is bounded and extends from its edge', ( tester, ) async { From de18b6d68e1baaf114d4eddf9ae2419ce3059dfb Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Mon, 7 Sep 2026 17:34:20 -0700 Subject: [PATCH 14/37] Add Copy as Markdown to the Editor --- lib/l10n/app_ar.arb | 1 + lib/l10n/app_de.arb | 1 + lib/l10n/app_en.arb | 2 + lib/l10n/app_es.arb | 1 + lib/l10n/app_et.arb | 1 + lib/l10n/app_fa.arb | 1 + lib/l10n/app_fr.arb | 1 + lib/l10n/app_hi.arb | 1 + lib/l10n/app_id.arb | 1 + lib/l10n/app_it.arb | 1 + lib/l10n/app_ja.arb | 1 + lib/l10n/app_ko.arb | 1 + lib/l10n/app_nb.arb | 1 + lib/l10n/app_nl.arb | 1 + lib/l10n/app_pl.arb | 1 + lib/l10n/app_pt_BR.arb | 1 + lib/l10n/app_ru.arb | 1 + lib/l10n/app_tr.arb | 1 + lib/l10n/app_uk.arb | 1 + lib/l10n/app_vi.arb | 1 + lib/l10n/app_zh_CN.arb | 1 + lib/l10n/generated/app_localizations.dart | 6 ++ lib/l10n/generated/app_localizations_ar.dart | 3 + lib/l10n/generated/app_localizations_de.dart | 3 + lib/l10n/generated/app_localizations_en.dart | 3 + lib/l10n/generated/app_localizations_es.dart | 3 + lib/l10n/generated/app_localizations_et.dart | 3 + lib/l10n/generated/app_localizations_fa.dart | 3 + lib/l10n/generated/app_localizations_fr.dart | 3 + lib/l10n/generated/app_localizations_hi.dart | 3 + lib/l10n/generated/app_localizations_id.dart | 3 + lib/l10n/generated/app_localizations_it.dart | 3 + lib/l10n/generated/app_localizations_ja.dart | 3 + lib/l10n/generated/app_localizations_ko.dart | 3 + lib/l10n/generated/app_localizations_nb.dart | 3 + lib/l10n/generated/app_localizations_nl.dart | 3 + lib/l10n/generated/app_localizations_pl.dart | 3 + lib/l10n/generated/app_localizations_pt.dart | 6 ++ lib/l10n/generated/app_localizations_ru.dart | 3 + lib/l10n/generated/app_localizations_tr.dart | 3 + lib/l10n/generated/app_localizations_uk.dart | 3 + lib/l10n/generated/app_localizations_vi.dart | 3 + lib/l10n/generated/app_localizations_zh.dart | 6 ++ lib/src/app/busymark_design.dart | 1 + lib/src/app/busymark_shortcuts.dart | 12 ++++ lib/src/app/command_registry.dart | 5 ++ lib/src/editor/editor_text_context_menu.dart | 60 ++++++++++++++----- lib/src/editor/source/source_editor.dart | 11 ++++ .../editor/wysiwyg/wysiwyg_block_widgets.dart | 27 ++++++++- .../wysiwyg/wysiwyg_clipboard_fragment.dart | 5 ++ lib/src/editor/wysiwyg/wysiwyg_editor.dart | 54 ++++++++++++++++- test/src/app_smoke_test.dart | 1 + test/src/wysiwyg_clipboard_test.dart | 45 +++++++++++++- 53 files changed, 301 insertions(+), 17 deletions(-) diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index 23ec80a8..b08c791d 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -94,6 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "نسخ", + "copyAsMarkdown": "نسخ كـ Markdown", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 1e6c77b3..3f94e819 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -94,6 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Kopieren", + "copyAsMarkdown": "Als Markdown kopieren", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 74bb04b2..82f1ed7e 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -90,6 +90,8 @@ "chooseLocation": "Choose location", "@chooseLocation": {"description": "File picker confirmation label for choosing a directory."}, "copy": "Copy", + "copyAsMarkdown": "Copy as Markdown", + "@copyAsMarkdown": {"description": "Copies the Editor selection as Markdown source."}, "clipboardCopyFailed": "Could not copy the selection to the clipboard.", "@clipboardCopyFailed": {"description": "Shown when Editor copy or cut cannot write the clipboard; cut leaves the document intact."}, "@copy": {"description": "Copy command label."}, diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index fd7714d4..18035794 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -94,6 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Copiar", + "copyAsMarkdown": "Copiar como Markdown", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_et.arb b/lib/l10n/app_et.arb index 174f2028..7204add1 100644 --- a/lib/l10n/app_et.arb +++ b/lib/l10n/app_et.arb @@ -178,6 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Kopeeri", + "copyAsMarkdown": "Kopeeri Markdownina", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index ba684b58..cc9c94be 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -94,6 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "کپی", + "copyAsMarkdown": "کپی به‌صورت Markdown", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index c912d89d..c8fecda9 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -94,6 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Copier", + "copyAsMarkdown": "Copier en Markdown", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index 405d5c0f..cc9b882e 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -94,6 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "कॉपी करें", + "copyAsMarkdown": "Markdown के रूप में कॉपी करें", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index 382c16cf..3bd8b2d8 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -178,6 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Salin", + "copyAsMarkdown": "Salin sebagai Markdown", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index b435edb9..a5bdfdd8 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -94,6 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Copia", + "copyAsMarkdown": "Copia come Markdown", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 63e921f3..bc660dce 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -178,6 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "コピー", + "copyAsMarkdown": "Markdown としてコピー", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index b59d430d..5f942163 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -178,6 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "복사", + "copyAsMarkdown": "Markdown으로 복사", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_nb.arb b/lib/l10n/app_nb.arb index 3f4c957b..c7188f8c 100644 --- a/lib/l10n/app_nb.arb +++ b/lib/l10n/app_nb.arb @@ -94,6 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Kopier", + "copyAsMarkdown": "Kopier som Markdown", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 0b293e4d..e73d4c86 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -178,6 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Kopiëren", + "copyAsMarkdown": "Kopiëren als Markdown", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index d3b3bb3d..e12f5dd4 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -94,6 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Kopiuj", + "copyAsMarkdown": "Kopiuj jako Markdown", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_pt_BR.arb b/lib/l10n/app_pt_BR.arb index 3ea34ee2..83f989c1 100644 --- a/lib/l10n/app_pt_BR.arb +++ b/lib/l10n/app_pt_BR.arb @@ -94,6 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Copiar", + "copyAsMarkdown": "Copiar como Markdown", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 479238cc..1f6c8af9 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -94,6 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Копировать", + "copyAsMarkdown": "Копировать как Markdown", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index d25ff535..819660e0 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -178,6 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Kopyala", + "copyAsMarkdown": "Markdown olarak kopyala", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 9d45f769..f53d261f 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -94,6 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Копіювати", + "copyAsMarkdown": "Копіювати як Markdown", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index 1efa18ff..bec87976 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -178,6 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Sao chép", + "copyAsMarkdown": "Sao chép dưới dạng Markdown", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_zh_CN.arb b/lib/l10n/app_zh_CN.arb index 0007e82a..07a54c96 100644 --- a/lib/l10n/app_zh_CN.arb +++ b/lib/l10n/app_zh_CN.arb @@ -178,6 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "复制", + "copyAsMarkdown": "复制为 Markdown", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index 591685ff..ee3bc7ca 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -403,6 +403,12 @@ abstract class AppLocalizations { /// **'Copy'** String get copy; + /// Copies the Editor selection as Markdown source. + /// + /// In en, this message translates to: + /// **'Copy as Markdown'** + String get copyAsMarkdown; + /// Shown when Editor copy or cut cannot write the clipboard; cut leaves the document intact. /// /// In en, this message translates to: diff --git a/lib/l10n/generated/app_localizations_ar.dart b/lib/l10n/generated/app_localizations_ar.dart index 8c3ab3fd..91ff4af6 100644 --- a/lib/l10n/generated/app_localizations_ar.dart +++ b/lib/l10n/generated/app_localizations_ar.dart @@ -152,6 +152,9 @@ class AppLocalizationsAr extends AppLocalizations { @override String get copy => 'نسخ'; + @override + String get copyAsMarkdown => 'نسخ كـ Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 37714fad..36b0e620 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -156,6 +156,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get copy => 'Kopieren'; + @override + String get copyAsMarkdown => 'Als Markdown kopieren'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index e61f547b..9c739f42 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -153,6 +153,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get copy => 'Copy'; + @override + String get copyAsMarkdown => 'Copy as Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart index 088c1937..89d28b0e 100644 --- a/lib/l10n/generated/app_localizations_es.dart +++ b/lib/l10n/generated/app_localizations_es.dart @@ -155,6 +155,9 @@ class AppLocalizationsEs extends AppLocalizations { @override String get copy => 'Copiar'; + @override + String get copyAsMarkdown => 'Copiar como Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_et.dart b/lib/l10n/generated/app_localizations_et.dart index c535eb05..559c6533 100644 --- a/lib/l10n/generated/app_localizations_et.dart +++ b/lib/l10n/generated/app_localizations_et.dart @@ -152,6 +152,9 @@ class AppLocalizationsEt extends AppLocalizations { @override String get copy => 'Kopeeri'; + @override + String get copyAsMarkdown => 'Kopeeri Markdownina'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_fa.dart b/lib/l10n/generated/app_localizations_fa.dart index fe4ff4d7..158398c2 100644 --- a/lib/l10n/generated/app_localizations_fa.dart +++ b/lib/l10n/generated/app_localizations_fa.dart @@ -152,6 +152,9 @@ class AppLocalizationsFa extends AppLocalizations { @override String get copy => 'کپی'; + @override + String get copyAsMarkdown => 'کپی به‌صورت Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_fr.dart b/lib/l10n/generated/app_localizations_fr.dart index 39b9f46d..a0afbadf 100644 --- a/lib/l10n/generated/app_localizations_fr.dart +++ b/lib/l10n/generated/app_localizations_fr.dart @@ -155,6 +155,9 @@ class AppLocalizationsFr extends AppLocalizations { @override String get copy => 'Copier'; + @override + String get copyAsMarkdown => 'Copier en Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_hi.dart b/lib/l10n/generated/app_localizations_hi.dart index 19f4cd09..2b54fa60 100644 --- a/lib/l10n/generated/app_localizations_hi.dart +++ b/lib/l10n/generated/app_localizations_hi.dart @@ -154,6 +154,9 @@ class AppLocalizationsHi extends AppLocalizations { @override String get copy => 'कॉपी करें'; + @override + String get copyAsMarkdown => 'Markdown के रूप में कॉपी करें'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_id.dart b/lib/l10n/generated/app_localizations_id.dart index d994d60b..22af6984 100644 --- a/lib/l10n/generated/app_localizations_id.dart +++ b/lib/l10n/generated/app_localizations_id.dart @@ -154,6 +154,9 @@ class AppLocalizationsId extends AppLocalizations { @override String get copy => 'Salin'; + @override + String get copyAsMarkdown => 'Salin sebagai Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_it.dart b/lib/l10n/generated/app_localizations_it.dart index f57a677c..b7d8c6a3 100644 --- a/lib/l10n/generated/app_localizations_it.dart +++ b/lib/l10n/generated/app_localizations_it.dart @@ -154,6 +154,9 @@ class AppLocalizationsIt extends AppLocalizations { @override String get copy => 'Copia'; + @override + String get copyAsMarkdown => 'Copia come Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_ja.dart b/lib/l10n/generated/app_localizations_ja.dart index 069f8cba..9ce79ac1 100644 --- a/lib/l10n/generated/app_localizations_ja.dart +++ b/lib/l10n/generated/app_localizations_ja.dart @@ -149,6 +149,9 @@ class AppLocalizationsJa extends AppLocalizations { @override String get copy => 'コピー'; + @override + String get copyAsMarkdown => 'Markdown としてコピー'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_ko.dart b/lib/l10n/generated/app_localizations_ko.dart index 519241fd..dfa6a8db 100644 --- a/lib/l10n/generated/app_localizations_ko.dart +++ b/lib/l10n/generated/app_localizations_ko.dart @@ -148,6 +148,9 @@ class AppLocalizationsKo extends AppLocalizations { @override String get copy => '복사'; + @override + String get copyAsMarkdown => 'Markdown으로 복사'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_nb.dart b/lib/l10n/generated/app_localizations_nb.dart index cbad9a34..425560f1 100644 --- a/lib/l10n/generated/app_localizations_nb.dart +++ b/lib/l10n/generated/app_localizations_nb.dart @@ -155,6 +155,9 @@ class AppLocalizationsNb extends AppLocalizations { @override String get copy => 'Kopier'; + @override + String get copyAsMarkdown => 'Kopier som Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_nl.dart b/lib/l10n/generated/app_localizations_nl.dart index f120cb86..e3b3f2c6 100644 --- a/lib/l10n/generated/app_localizations_nl.dart +++ b/lib/l10n/generated/app_localizations_nl.dart @@ -155,6 +155,9 @@ class AppLocalizationsNl extends AppLocalizations { @override String get copy => 'Kopiëren'; + @override + String get copyAsMarkdown => 'Kopiëren als Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_pl.dart b/lib/l10n/generated/app_localizations_pl.dart index aaa835ec..1f0cb0e7 100644 --- a/lib/l10n/generated/app_localizations_pl.dart +++ b/lib/l10n/generated/app_localizations_pl.dart @@ -154,6 +154,9 @@ class AppLocalizationsPl extends AppLocalizations { @override String get copy => 'Kopiuj'; + @override + String get copyAsMarkdown => 'Kopiuj jako Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart index a548feac..80b4c835 100644 --- a/lib/l10n/generated/app_localizations_pt.dart +++ b/lib/l10n/generated/app_localizations_pt.dart @@ -153,6 +153,9 @@ class AppLocalizationsPt extends AppLocalizations { @override String get copy => 'Copy'; + @override + String get copyAsMarkdown => 'Copy as Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; @@ -4071,6 +4074,9 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { @override String get copy => 'Copiar'; + @override + String get copyAsMarkdown => 'Copiar como Markdown'; + @override String get copyName => 'Copiar nome'; diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart index a1db8f45..eb3b3464 100644 --- a/lib/l10n/generated/app_localizations_ru.dart +++ b/lib/l10n/generated/app_localizations_ru.dart @@ -155,6 +155,9 @@ class AppLocalizationsRu extends AppLocalizations { @override String get copy => 'Копировать'; + @override + String get copyAsMarkdown => 'Копировать как Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_tr.dart b/lib/l10n/generated/app_localizations_tr.dart index 4e0cc6d0..0e6c3372 100644 --- a/lib/l10n/generated/app_localizations_tr.dart +++ b/lib/l10n/generated/app_localizations_tr.dart @@ -155,6 +155,9 @@ class AppLocalizationsTr extends AppLocalizations { @override String get copy => 'Kopyala'; + @override + String get copyAsMarkdown => 'Markdown olarak kopyala'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_uk.dart b/lib/l10n/generated/app_localizations_uk.dart index 794beacc..fa8b4eb1 100644 --- a/lib/l10n/generated/app_localizations_uk.dart +++ b/lib/l10n/generated/app_localizations_uk.dart @@ -154,6 +154,9 @@ class AppLocalizationsUk extends AppLocalizations { @override String get copy => 'Копіювати'; + @override + String get copyAsMarkdown => 'Копіювати як Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_vi.dart b/lib/l10n/generated/app_localizations_vi.dart index 0c55b9c5..6ab1f7d8 100644 --- a/lib/l10n/generated/app_localizations_vi.dart +++ b/lib/l10n/generated/app_localizations_vi.dart @@ -153,6 +153,9 @@ class AppLocalizationsVi extends AppLocalizations { @override String get copy => 'Sao chép'; + @override + String get copyAsMarkdown => 'Sao chép dưới dạng Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; diff --git a/lib/l10n/generated/app_localizations_zh.dart b/lib/l10n/generated/app_localizations_zh.dart index f85f8f71..300ff598 100644 --- a/lib/l10n/generated/app_localizations_zh.dart +++ b/lib/l10n/generated/app_localizations_zh.dart @@ -153,6 +153,9 @@ class AppLocalizationsZh extends AppLocalizations { @override String get copy => 'Copy'; + @override + String get copyAsMarkdown => 'Copy as Markdown'; + @override String get clipboardCopyFailed => 'Could not copy the selection to the clipboard.'; @@ -4047,6 +4050,9 @@ class AppLocalizationsZhCn extends AppLocalizationsZh { @override String get copy => '复制'; + @override + String get copyAsMarkdown => '复制为 Markdown'; + @override String get copyName => '复制名称'; diff --git a/lib/src/app/busymark_design.dart b/lib/src/app/busymark_design.dart index 6de6a43b..6dbff7cd 100644 --- a/lib/src/app/busymark_design.dart +++ b/lib/src/app/busymark_design.dart @@ -72,6 +72,7 @@ abstract final class BusyMarkSizes { static const double dialogCompact = 460; static const double dialogWide = 560; static const double popupMenuMinWidth = 180; + static const double editorContextMenuWidth = 260; static const double languagePopupMinWidth = 220; static const double languagePopupMaxWidth = 280; static const double languageButtonMaxWidth = 256; diff --git a/lib/src/app/busymark_shortcuts.dart b/lib/src/app/busymark_shortcuts.dart index eb9d0936..b9167f76 100644 --- a/lib/src/app/busymark_shortcuts.dart +++ b/lib/src/app/busymark_shortcuts.dart @@ -502,6 +502,7 @@ abstract final class BusyMarkTextEditingShortcutActivators { enum BusyMarkEditorShortcutAction { refineWithAi, + copyAsMarkdown, bold, italic, underline, @@ -537,6 +538,7 @@ abstract final class BusyMarkEditorShortcuts { const BusyMarkEditorShortcuts._(); static const refineWithAiLabel = 'Ctrl+G'; + static const copyAsMarkdownLabel = 'Ctrl+Shift+C'; static const textStyleLabel = 'Ctrl+Alt+0-6'; static const boldLabel = 'Ctrl+B'; static const italicLabel = 'Ctrl+I'; @@ -565,6 +567,14 @@ abstract final class BusyMarkEditorShortcuts { label: refineWithAiLabel, activator: SingleActivator(LogicalKeyboardKey.keyG, control: true), ); + static const copyAsMarkdown = BusyMarkShortcutDefinition( + label: copyAsMarkdownLabel, + activator: SingleActivator( + LogicalKeyboardKey.keyC, + control: true, + shift: true, + ), + ); static const bold = BusyMarkShortcutDefinition( label: boldLabel, activator: SingleActivator(LogicalKeyboardKey.keyB, control: true), @@ -718,6 +728,7 @@ abstract final class BusyMarkEditorShortcuts { static const definitions = <BusyMarkEditorShortcutAction, BusyMarkShortcutDefinition>{ BusyMarkEditorShortcutAction.refineWithAi: refineWithAi, + BusyMarkEditorShortcutAction.copyAsMarkdown: copyAsMarkdown, BusyMarkEditorShortcutAction.bold: bold, BusyMarkEditorShortcutAction.italic: italic, BusyMarkEditorShortcutAction.underline: underline, @@ -748,6 +759,7 @@ abstract final class BusyMarkEditorShortcutLabels { const BusyMarkEditorShortcutLabels._(); static const refineWithAi = BusyMarkEditorShortcuts.refineWithAiLabel; + static const copyAsMarkdown = BusyMarkEditorShortcuts.copyAsMarkdownLabel; static const textStyle = BusyMarkEditorShortcuts.textStyleLabel; static const bold = BusyMarkEditorShortcuts.boldLabel; static const italic = BusyMarkEditorShortcuts.italicLabel; diff --git a/lib/src/app/command_registry.dart b/lib/src/app/command_registry.dart index 2bd874cb..3c8fdcba 100644 --- a/lib/src/app/command_registry.dart +++ b/lib/src/app/command_registry.dart @@ -265,6 +265,7 @@ abstract final class BusyMarkCommandIds { static const textSelectAll = 'text.selectAll'; static const textCut = 'text.cut'; static const textCopy = 'text.copy'; + static const editorCopyAsMarkdown = 'editor.copyAsMarkdown'; static const textPaste = 'text.paste'; static const textPastePlainText = 'text.pastePlainText'; static const textUndo = 'text.undo'; @@ -512,6 +513,7 @@ abstract final class BusyMarkCommandCatalog { BusyMarkEditorShortcutAction action, ) => switch (action) { BusyMarkEditorShortcutAction.refineWithAi => context.l10n.aiRefineWithAi, + BusyMarkEditorShortcutAction.copyAsMarkdown => context.l10n.copyAsMarkdown, BusyMarkEditorShortcutAction.bold => context.l10n.bold, BusyMarkEditorShortcutAction.italic => context.l10n.italic, BusyMarkEditorShortcutAction.underline => context.l10n.underline, @@ -611,6 +613,9 @@ abstract final class BusyMarkCommandCatalog { BuildContext context, BusyMarkEditorShortcutAction action, ) => switch (action) { + BusyMarkEditorShortcutAction.copyAsMarkdown || + BusyMarkEditorShortcutAction.pastePlainText => + context.l10n.shortcutGroupTextEditing, BusyMarkEditorShortcutAction.bold || BusyMarkEditorShortcutAction.italic || BusyMarkEditorShortcutAction.underline || diff --git a/lib/src/editor/editor_text_context_menu.dart b/lib/src/editor/editor_text_context_menu.dart index 9482657f..40584e87 100644 --- a/lib/src/editor/editor_text_context_menu.dart +++ b/lib/src/editor/editor_text_context_menu.dart @@ -11,12 +11,16 @@ Widget buildBusyMarkEditorTextContextMenu( EditableTextState editableTextState, { required String refineWithAiLabel, VoidCallback? onRefineWithAi, + VoidCallback? onCopy, + VoidCallback? onCopyAsMarkdown, List<PopupMenuEntry<VoidCallback>> additionalItems = const [], }) { return _BusyMarkEditorTextContextMenu( editableTextState: editableTextState, refineWithAiLabel: refineWithAiLabel, onRefineWithAi: onRefineWithAi, + onCopy: onCopy, + onCopyAsMarkdown: onCopyAsMarkdown, additionalItems: additionalItems, ); } @@ -26,12 +30,16 @@ class _BusyMarkEditorTextContextMenu extends StatefulWidget { required this.editableTextState, required this.refineWithAiLabel, required this.onRefineWithAi, + required this.onCopy, + required this.onCopyAsMarkdown, required this.additionalItems, }); final EditableTextState editableTextState; final String refineWithAiLabel; final VoidCallback? onRefineWithAi; + final VoidCallback? onCopy; + final VoidCallback? onCopyAsMarkdown; final List<PopupMenuEntry<VoidCallback>> additionalItems; @override @@ -79,7 +87,9 @@ class _BusyMarkEditorTextContextMenuState anchorPoint: widget.editableTextState.contextMenuAnchors.primaryAnchor, items: _menuItems(context), session: _menuSession, - width: BusyMarkSizes.popupMenuMinWidth, + width: widget.onCopyAsMarkdown == null + ? BusyMarkSizes.popupMenuMinWidth + : BusyMarkSizes.editorContextMenuWidth, ); if (!mounted || _menuSession.dismissed) { return; @@ -93,28 +103,50 @@ class _BusyMarkEditorTextContextMenuState final commands = BusyMarkCommandRegistryScope.maybeOf(context) ?? BusyMarkCommandCatalog.metadata; - final items = <PopupMenuEntry<VoidCallback>>[ - for (final item in editable.contextMenuButtonItems) ...[ - if (_commandIdFor(item.type) case final commandId?) + final selection = editable.textEditingValue.selection; + final hasSelection = selection.isValid && !selection.isCollapsed; + final items = <PopupMenuEntry<VoidCallback>>[]; + for (final item in editable.contextMenuButtonItems) { + final callback = item.type == ContextMenuButtonType.copy + ? widget.onCopy ?? item.onPressed + : item.onPressed; + if (_commandIdFor(item.type) case final commandId?) { + items.add( BusyMarkPopupMenuItem<VoidCallback>( - value: item.onPressed ?? () {}, + value: callback ?? () {}, label: commands[commandId]!.label(context), icon: _iconFor(item.type), shortcut: commands[commandId]!.shortcut?.label, - enabled: item.onPressed != null, - ) - else + enabled: callback != null, + ), + ); + } else { + items.add( BusyMarkPopupMenuItem<VoidCallback>( - value: item.onPressed ?? () {}, + value: callback ?? () {}, label: AdaptiveTextSelectionToolbar.getButtonLabel(context, item), icon: _iconFor(item.type), - enabled: item.onPressed != null, + enabled: callback != null, ), - ], - ]; - final selection = editable.textEditingValue.selection; + ); + } + final copyAsMarkdown = widget.onCopyAsMarkdown; + if (item.type == ContextMenuButtonType.copy && + copyAsMarkdown != null && + hasSelection) { + final command = commands[BusyMarkCommandIds.editorCopyAsMarkdown]!; + items.add( + BusyMarkPopupMenuItem<VoidCallback>( + value: copyAsMarkdown, + label: command.label(context), + icon: BusyMarkGlyphs.copy, + shortcut: command.shortcut?.label, + ), + ); + } + } final refineWithAi = widget.onRefineWithAi; - if (refineWithAi != null && selection.isValid && !selection.isCollapsed) { + if (refineWithAi != null && hasSelection) { items.add( BusyMarkPopupMenuItem<VoidCallback>( value: refineWithAi, diff --git a/lib/src/editor/source/source_editor.dart b/lib/src/editor/source/source_editor.dart index 28c1569b..2f6e902e 100644 --- a/lib/src/editor/source/source_editor.dart +++ b/lib/src/editor/source/source_editor.dart @@ -1414,6 +1414,17 @@ class BusyMarkSourceEditorState extends State<BusyMarkSourceEditor> { case BusyMarkEditorShortcutAction.refineWithAi: unawaited(_runAiEdit()); break; + case BusyMarkEditorShortcutAction.copyAsMarkdown: + final value = _fullEditingValue(); + final selection = value.selection; + if (selection.isValid && !selection.isCollapsed) { + unawaited( + Clipboard.setData( + ClipboardData(text: selection.textInside(value.text)), + ), + ); + } + break; case BusyMarkEditorShortcutAction.bold: _applyInlineCommand(SourceInlineCommand.bold); break; diff --git a/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart b/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart index 9c534123..2dc18266 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart @@ -165,6 +165,8 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { required this.onHtmlEditRequested, required this.onTaskChanged, required this.onFocused, + this.onCopy, + this.onCopyAsMarkdown, this.onRefineWithAi, this.editRevision = 0, this.selected = false, @@ -208,6 +210,8 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { final VoidCallback onHtmlEditRequested; final ValueChanged<bool> onTaskChanged; final VoidCallback onFocused; + final VoidCallback? onCopy; + final VoidCallback? onCopyAsMarkdown; final VoidCallback? onRefineWithAi; final int editRevision; final bool selected; @@ -386,6 +390,8 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { cellKey: tableCellKey, onCellFocused: onTableCellFocused, suppressContextMenu: documentSelectionActive, + onCopy: onCopy, + onCopyAsMarkdown: onCopyAsMarkdown, ), ); } @@ -544,6 +550,8 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { refineWithAiLabel: context.l10n.aiRefineWithAi, onRefineWithAi: onRefineWithAi, + onCopy: onCopy, + onCopyAsMarkdown: onCopyAsMarkdown, ), onTap: onFocused, onChanged: onChanged, @@ -1457,6 +1465,8 @@ class _TableBlockEditor extends StatelessWidget { this.cellKey, this.onCellFocused, this.suppressContextMenu = false, + this.onCopy, + this.onCopyAsMarkdown, }); static const double _controlSize = BusyMarkSizes.tableControl; @@ -1480,6 +1490,8 @@ class _TableBlockEditor extends StatelessWidget { final GlobalKey Function(String cellId)? cellKey; final ValueChanged<String>? onCellFocused; final bool suppressContextMenu; + final VoidCallback? onCopy; + final VoidCallback? onCopyAsMarkdown; @override Widget build(BuildContext context) { @@ -1564,6 +1576,8 @@ class _TableBlockEditor extends StatelessWidget { : null, onCellFocused: onCellFocused, suppressContextMenu: suppressContextMenu, + onCopy: onCopy, + onCopyAsMarkdown: onCopyAsMarkdown, ), ], ), @@ -1809,6 +1823,8 @@ class _TableCellEditor extends StatefulWidget { this.cellKey, this.onCellFocused, this.suppressContextMenu = false, + this.onCopy, + this.onCopyAsMarkdown, }); final BusyBlock? cell; @@ -1826,6 +1842,8 @@ class _TableCellEditor extends StatefulWidget { final GlobalKey? cellKey; final ValueChanged<String>? onCellFocused; final bool suppressContextMenu; + final VoidCallback? onCopy; + final VoidCallback? onCopyAsMarkdown; @override State<_TableCellEditor> createState() => _TableCellEditorState(); @@ -2001,7 +2019,14 @@ class _TableCellEditorState extends State<_TableCellEditor> { ), contextMenuBuilder: widget.suppressContextMenu ? (context, editableTextState) => const SizedBox.shrink() - : null, + : (context, editableTextState) => + buildBusyMarkEditorTextContextMenu( + context, + editableTextState, + refineWithAiLabel: context.l10n.aiRefineWithAi, + onCopy: widget.onCopy, + onCopyAsMarkdown: widget.onCopyAsMarkdown, + ), onTap: () { final onCellFocused = widget.onCellFocused; if (onCellFocused == null) { diff --git a/lib/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart b/lib/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart index 49d5a439..7f83f52e 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_clipboard_fragment.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:path/path.dart' as p; import '../../markdown/busymark_document.dart'; +import '../../markdown/busymark_markdown_serializer.dart'; import '../../markdown/markdown_model.dart'; import '../../platform/rich_clipboard_service.dart'; import 'wysiwyg_document_controller.dart'; @@ -28,6 +29,10 @@ class WysiwygClipboardFragment { for (final block in blocks) busyMarkWysiwygClipboardBlock(block), ]; + String get markdown => const BusyMarkMarkdownSerializer().serialize( + BusyDocument(filePath: sourcePath, mode: mode, blocks: documentBlocks), + ); + String encode() => jsonEncode({ 'version': 1, 'mode': mode.name, diff --git a/lib/src/editor/wysiwyg/wysiwyg_editor.dart b/lib/src/editor/wysiwyg/wysiwyg_editor.dart index 94bfc921..6e14b60a 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_editor.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_editor.dart @@ -871,6 +871,8 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { onPointerMove: _handleBlockPointerMove, onPointerUp: _handleBlockPointerUp, onFocused: () => _handleBlockFocused(block.id), + onCopy: _copyCurrentSelection, + onCopyAsMarkdown: _copyCurrentSelectionAsMarkdown, onRefineWithAi: widget.onAiEdit == null ? null : () => unawaited(_runAiEdit(blockId: block.id)), @@ -3528,6 +3530,9 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { case BusyMarkEditorShortcutAction.refineWithAi: unawaited(_runAiEdit()); break; + case BusyMarkEditorShortcutAction.copyAsMarkdown: + _copyCurrentSelectionAsMarkdown(); + break; case BusyMarkEditorShortcutAction.bold: _applyInlineCommand(BusyWysiwygInlineCommand.bold); break; @@ -5517,6 +5522,7 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { final action = await showBusyMarkContextMenu<_DocumentSelectionMenuAction>( context, position, + width: BusyMarkSizes.editorContextMenuWidth, items: [ item( _DocumentSelectionMenuAction.cut, @@ -5528,6 +5534,11 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { BusyMarkCommandIds.textCopy, BusyMarkGlyphs.copy, ), + item( + _DocumentSelectionMenuAction.copyAsMarkdown, + BusyMarkCommandIds.editorCopyAsMarkdown, + BusyMarkGlyphs.copy, + ), item( _DocumentSelectionMenuAction.paste, BusyMarkCommandIds.textPaste, @@ -5554,6 +5565,8 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { _cutBlockSelection(); case _DocumentSelectionMenuAction.copy: _copyBlockSelection(); + case _DocumentSelectionMenuAction.copyAsMarkdown: + _copyCurrentSelectionAsMarkdown(); case _DocumentSelectionMenuAction.paste: unawaited(_pasteIntoActiveBlock()); case _DocumentSelectionMenuAction.selectAll: @@ -5902,6 +5915,29 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { bool _copyCurrentSelection() => _copyOrCutSelection(cut: false); + bool _copyCurrentSelectionAsMarkdown() { + final documentSelection = _hasBlockSelection; + final allRanges = documentSelection + ? _selectedTextRanges(null, true) + : _currentSelectionRanges(); + if (allRanges.isEmpty) return false; + final ranges = documentSelection + ? _withoutEmptySelectionEndpoints(allRanges) + : allRanges + .where((range) => _copyTextForRange(range).trim().isNotEmpty) + .toList(); + if (ranges.isEmpty) return false; + final fragment = WysiwygClipboardFragment( + mode: _documentController.document.mode, + sourcePath: _documentController.document.filePath, + blocks: _clipboardBlocksForRanges(ranges), + ); + final markdown = fragment.markdown; + if (markdown.isEmpty) return false; + unawaited(_writeMarkdownClipboard(markdown)); + return true; + } + bool _cutCurrentSelection() => _copyOrCutSelection(cut: true); bool _copyOrCutSelection({required bool cut}) { @@ -5972,6 +6008,15 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { } } + Future<void> _writeMarkdownClipboard(String markdown) async { + final success = await _clipboard.write(RichClipboardData(text: markdown)); + if (!mounted || success) return; + BusyMarkToastOverlay.show( + context, + message: context.l10n.clipboardCopyFailed, + ); + } + List<BusyWysiwygStyledBlock> _clipboardBlocksForRanges( List<_SelectedTextRange> ranges, ) { @@ -6412,7 +6457,14 @@ class _ClipboardTarget { final TextSelection? textSelection; } -enum _DocumentSelectionMenuAction { cut, copy, paste, selectAll, refineWithAi } +enum _DocumentSelectionMenuAction { + cut, + copy, + copyAsMarkdown, + paste, + selectAll, + refineWithAi, +} class _ContinuousTextEdit { const _ContinuousTextEdit({ diff --git a/test/src/app_smoke_test.dart b/test/src/app_smoke_test.dart index b80b7d82..f51f9ca3 100644 --- a/test/src/app_smoke_test.dart +++ b/test/src/app_smoke_test.dart @@ -74,6 +74,7 @@ void main() { }, { BusyMarkEditorShortcutAction.refineWithAi: 'Ctrl+G', + BusyMarkEditorShortcutAction.copyAsMarkdown: 'Ctrl+Shift+C', BusyMarkEditorShortcutAction.bold: 'Ctrl+B', BusyMarkEditorShortcutAction.italic: 'Ctrl+I', BusyMarkEditorShortcutAction.underline: 'Ctrl+U', diff --git a/test/src/wysiwyg_clipboard_test.dart b/test/src/wysiwyg_clipboard_test.dart index d888b4b7..e021b969 100644 --- a/test/src/wysiwyg_clipboard_test.dart +++ b/test/src/wysiwyg_clipboard_test.dart @@ -250,6 +250,14 @@ void main() { expect(_insert(decoded), contains('- [x] Second task')); }); + test('clipboard fragment serializes its selected structure as Markdown', () { + final markdown = _fragment(_source).markdown; + expect(markdown, contains('# Issues')); + expect(markdown, contains('**When**')); + expect(markdown, contains('- [ ] First task')); + expect(markdown, contains('- [x] Second task')); + }); + test('HTML normalization preserves supported CSS and checkbox state safely', () { const source = '<html><head><style>p{color:red}</style></head><body>' @@ -442,7 +450,13 @@ void main() { ); await tester.pumpAndSettle(); - for (final label in ['Cut', 'Copy', 'Paste', 'Select all']) { + for (final label in [ + 'Cut', + 'Copy', + 'Copy as Markdown', + 'Paste', + 'Select all', + ]) { expect( find.byWidgetPredicate( (widget) => @@ -457,6 +471,35 @@ void main() { expect(systemData['text'], contains('[ ] First task')); }); + testWidgets('Copy as Markdown writes only Markdown source', (tester) async { + await mount(tester, 'issues', _source, (_) {}); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyC, shift: true); + + expect(systemData.keys, ['text']); + expect(systemData['text'], startsWith('# Issues')); + expect(systemData['text'], contains('**When**')); + expect(systemData['text'], contains('- [ ] First task')); + }); + + testWidgets('document selection menu can copy as Markdown', (tester) async { + await mount(tester, 'issues', _source, (_) {}); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyA); + await tester.tap( + find.widgetWithText(TextField, 'When selecting all, keep formatting.'), + buttons: kSecondaryMouseButton, + ); + await tester.pumpAndSettle(); + + await tester.tap(find.text('Copy as Markdown')); + await tester.pumpAndSettle(); + expect(systemData.keys, ['text']); + expect(systemData['text'], startsWith('# Issues')); + expect(systemData['text'], contains('**When**')); + }); + testWidgets( 'partial inline copy keeps formatting inside another paragraph', (tester) async { From 4d74e16fa4e32d45e01175a824e772b1c3662d31 Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Mon, 7 Sep 2026 17:39:14 -0700 Subject: [PATCH 15/37] Preserve formatting when pasting Markdown into Editor --- lib/src/editor/wysiwyg/wysiwyg_editor.dart | 11 ++++-- test/src/wysiwyg_clipboard_test.dart | 40 ++++++++++++++++------ 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/lib/src/editor/wysiwyg/wysiwyg_editor.dart b/lib/src/editor/wysiwyg/wysiwyg_editor.dart index 6e14b60a..7a4cea3b 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_editor.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_editor.dart @@ -5934,7 +5934,7 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { ); final markdown = fragment.markdown; if (markdown.isEmpty) return false; - unawaited(_writeMarkdownClipboard(markdown)); + unawaited(_writeMarkdownClipboard(markdown, fragment)); return true; } @@ -6008,8 +6008,13 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { } } - Future<void> _writeMarkdownClipboard(String markdown) async { - final success = await _clipboard.write(RichClipboardData(text: markdown)); + Future<void> _writeMarkdownClipboard( + String markdown, + WysiwygClipboardFragment fragment, + ) async { + final success = await _clipboard.write( + RichClipboardData(text: markdown, fragment: fragment.encode()), + ); if (!mounted || success) return; BusyMarkToastOverlay.show( context, diff --git a/test/src/wysiwyg_clipboard_test.dart b/test/src/wysiwyg_clipboard_test.dart index e021b969..49d48f00 100644 --- a/test/src/wysiwyg_clipboard_test.dart +++ b/test/src/wysiwyg_clipboard_test.dart @@ -471,17 +471,34 @@ void main() { expect(systemData['text'], contains('[ ] First task')); }); - testWidgets('Copy as Markdown writes only Markdown source', (tester) async { - await mount(tester, 'issues', _source, (_) {}); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyC, shift: true); + testWidgets( + 'Copy as Markdown serves source externally and structure internally', + (tester) async { + await mount(tester, 'issues', _source, (_) {}); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyC, shift: true); - expect(systemData.keys, ['text']); - expect(systemData['text'], startsWith('# Issues')); - expect(systemData['text'], contains('**When**')); - expect(systemData['text'], contains('- [ ] First task')); - }); + expect(systemData.keys, containsAll(['text', 'fragment'])); + expect(systemData, isNot(contains('html'))); + expect(systemData['text'], startsWith('# Issues')); + expect(systemData['text'], contains('**When**')); + expect(systemData['text'], contains('- [ ] First task')); + + var result = ''; + await mount( + tester, + 'destination', + 'Target\n', + (value) => result = value, + ); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyV); + expect(result, contains('# Issues')); + expect(result, contains('**When**')); + expect(result, contains('- [x] Second task')); + }, + ); testWidgets('document selection menu can copy as Markdown', (tester) async { await mount(tester, 'issues', _source, (_) {}); @@ -495,7 +512,8 @@ void main() { await tester.tap(find.text('Copy as Markdown')); await tester.pumpAndSettle(); - expect(systemData.keys, ['text']); + expect(systemData.keys, containsAll(['text', 'fragment'])); + expect(systemData, isNot(contains('html'))); expect(systemData['text'], startsWith('# Issues')); expect(systemData['text'], contains('**When**')); }); From 176e43834d18227215a4e89515ef237d5da418ac Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Mon, 7 Sep 2026 17:49:44 -0700 Subject: [PATCH 16/37] Defer Editor session updates during rebuilds --- lib/src/editor/wysiwyg/wysiwyg_editor.dart | 38 ++++++++++++------ test/src/wysiwyg_session_test.dart | 46 ++++++++++++++++++++++ 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/lib/src/editor/wysiwyg/wysiwyg_editor.dart b/lib/src/editor/wysiwyg/wysiwyg_editor.dart index 7a4cea3b..ce7e91fb 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_editor.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_editor.dart @@ -6,6 +6,7 @@ import 'package:file_selector/file_selector.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:html/parser.dart' as html_parser; import 'package:path/path.dart' as p; @@ -1885,19 +1886,27 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { viewportBlockId = _viewportBlockIds[positions.first.index]; viewportAlignment = positions.first.itemLeadingEdge.clamp(0.0, 1.0); } - report( - documentId ?? _documentId, - WysiwygEditorSessionState( - activeBlockId: _activeBlockId, - activeCellId: _activeCellId, - anchorBlockId: anchorBlockId, - anchorOffset: anchorOffset, - extentBlockId: extentBlockId, - extentOffset: extentOffset, - viewportBlockId: viewportBlockId, - viewportAlignment: viewportAlignment, - ), - ); + final targetDocumentId = documentId ?? _documentId; + final session = WysiwygEditorSessionState( + activeBlockId: _activeBlockId, + activeCellId: _activeCellId, + anchorBlockId: anchorBlockId, + anchorOffset: anchorOffset, + extentBlockId: extentBlockId, + extentOffset: extentOffset, + viewportBlockId: viewportBlockId, + viewportAlignment: viewportAlignment, + ); + if (SchedulerBinding.instance.schedulerPhase == + SchedulerPhase.persistentCallbacks) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) { + report(targetDocumentId, session); + } + }); + return; + } + report(targetDocumentId, session); } void _scheduleHeadingScroll() { @@ -2445,6 +2454,9 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { } KeyEventResult _handleBlockKeyEvent(String blockId, KeyEvent event) { + if (event is! KeyDownEvent && event is! KeyRepeatEvent) { + return KeyEventResult.ignored; + } final keyboard = HardwareKeyboard.instance; final key = event.logicalKey; final commands = diff --git a/test/src/wysiwyg_session_test.dart b/test/src/wysiwyg_session_test.dart index 0a519a07..490887ca 100644 --- a/test/src/wysiwyg_session_test.dart +++ b/test/src/wysiwyg_session_test.dart @@ -1,10 +1,23 @@ import 'package:busymark/l10n/generated/app_localizations.dart'; import 'package:busymark/src/editor/wysiwyg/wysiwyg_editor.dart'; import 'package:busymark/src/editor/wysiwyg/wysiwyg_session_state.dart'; +import 'package:busymark/src/markdown/busymark_document.dart'; import 'package:busymark/src/markdown/markdown_parser.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +final _sessionReportProvider = NotifierProvider<_SessionReportNotifier, int>( + _SessionReportNotifier.new, +); + +class _SessionReportNotifier extends Notifier<int> { + @override + int build() => 0; + + void record() => state += 1; +} void main() { const parser = MarkdownParser(); @@ -79,6 +92,39 @@ void main() { expect(sessions['one']?.extentOffset, 4); }); + testWidgets('defers session provider updates until document rebuild ends', ( + tester, + ) async { + final populated = parser + .parse(filePath: 'topic.md', source: '# Topic\n\nContent\n') + .busyDocument; + final empty = parser.parse(filePath: 'topic.md', source: '').busyDocument; + + Widget editor(String id, BusyDocument document) => ProviderScope( + child: Consumer( + builder: (context, ref, _) { + ref.watch(_sessionReportProvider); + return _app( + BusyMarkWysiwygEditor( + document: document, + documentId: id, + onSessionChanged: (_, _) => + ref.read(_sessionReportProvider.notifier).record(), + onSourceChanged: (_, _) {}, + ), + ); + }, + ), + ); + + await tester.pumpWidget(editor('populated', populated)); + await tester.pump(); + await tester.pumpWidget(editor('empty', empty)); + await tester.pump(); + + expect(tester.takeException(), isNull); + }); + testWidgets('workspace mode delegates WYSIWYG undo to buffer history', ( tester, ) async { From 42b1f95ea304100c201aa01a14b3b33a9f5a1ce1 Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Mon, 7 Sep 2026 17:53:25 -0700 Subject: [PATCH 17/37] Use rich clipboard for Editor Cut --- lib/src/editor/editor_text_context_menu.dart | 12 +++++-- .../editor/wysiwyg/wysiwyg_block_widgets.dart | 10 ++++++ lib/src/editor/wysiwyg/wysiwyg_editor.dart | 1 + test/src/wysiwyg_clipboard_test.dart | 36 +++++++++++++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) diff --git a/lib/src/editor/editor_text_context_menu.dart b/lib/src/editor/editor_text_context_menu.dart index 40584e87..9ad5e240 100644 --- a/lib/src/editor/editor_text_context_menu.dart +++ b/lib/src/editor/editor_text_context_menu.dart @@ -11,6 +11,7 @@ Widget buildBusyMarkEditorTextContextMenu( EditableTextState editableTextState, { required String refineWithAiLabel, VoidCallback? onRefineWithAi, + VoidCallback? onCut, VoidCallback? onCopy, VoidCallback? onCopyAsMarkdown, List<PopupMenuEntry<VoidCallback>> additionalItems = const [], @@ -19,6 +20,7 @@ Widget buildBusyMarkEditorTextContextMenu( editableTextState: editableTextState, refineWithAiLabel: refineWithAiLabel, onRefineWithAi: onRefineWithAi, + onCut: onCut, onCopy: onCopy, onCopyAsMarkdown: onCopyAsMarkdown, additionalItems: additionalItems, @@ -30,6 +32,7 @@ class _BusyMarkEditorTextContextMenu extends StatefulWidget { required this.editableTextState, required this.refineWithAiLabel, required this.onRefineWithAi, + required this.onCut, required this.onCopy, required this.onCopyAsMarkdown, required this.additionalItems, @@ -38,6 +41,7 @@ class _BusyMarkEditorTextContextMenu extends StatefulWidget { final EditableTextState editableTextState; final String refineWithAiLabel; final VoidCallback? onRefineWithAi; + final VoidCallback? onCut; final VoidCallback? onCopy; final VoidCallback? onCopyAsMarkdown; final List<PopupMenuEntry<VoidCallback>> additionalItems; @@ -107,9 +111,11 @@ class _BusyMarkEditorTextContextMenuState final hasSelection = selection.isValid && !selection.isCollapsed; final items = <PopupMenuEntry<VoidCallback>>[]; for (final item in editable.contextMenuButtonItems) { - final callback = item.type == ContextMenuButtonType.copy - ? widget.onCopy ?? item.onPressed - : item.onPressed; + final callback = switch (item.type) { + ContextMenuButtonType.cut => widget.onCut ?? item.onPressed, + ContextMenuButtonType.copy => widget.onCopy ?? item.onPressed, + _ => item.onPressed, + }; if (_commandIdFor(item.type) case final commandId?) { items.add( BusyMarkPopupMenuItem<VoidCallback>( diff --git a/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart b/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart index 2dc18266..2c089534 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart @@ -165,6 +165,7 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { required this.onHtmlEditRequested, required this.onTaskChanged, required this.onFocused, + this.onCut, this.onCopy, this.onCopyAsMarkdown, this.onRefineWithAi, @@ -210,6 +211,7 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { final VoidCallback onHtmlEditRequested; final ValueChanged<bool> onTaskChanged; final VoidCallback onFocused; + final VoidCallback? onCut; final VoidCallback? onCopy; final VoidCallback? onCopyAsMarkdown; final VoidCallback? onRefineWithAi; @@ -390,6 +392,7 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { cellKey: tableCellKey, onCellFocused: onTableCellFocused, suppressContextMenu: documentSelectionActive, + onCut: onCut, onCopy: onCopy, onCopyAsMarkdown: onCopyAsMarkdown, ), @@ -550,6 +553,7 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { refineWithAiLabel: context.l10n.aiRefineWithAi, onRefineWithAi: onRefineWithAi, + onCut: onCut, onCopy: onCopy, onCopyAsMarkdown: onCopyAsMarkdown, ), @@ -1465,6 +1469,7 @@ class _TableBlockEditor extends StatelessWidget { this.cellKey, this.onCellFocused, this.suppressContextMenu = false, + this.onCut, this.onCopy, this.onCopyAsMarkdown, }); @@ -1490,6 +1495,7 @@ class _TableBlockEditor extends StatelessWidget { final GlobalKey Function(String cellId)? cellKey; final ValueChanged<String>? onCellFocused; final bool suppressContextMenu; + final VoidCallback? onCut; final VoidCallback? onCopy; final VoidCallback? onCopyAsMarkdown; @@ -1576,6 +1582,7 @@ class _TableBlockEditor extends StatelessWidget { : null, onCellFocused: onCellFocused, suppressContextMenu: suppressContextMenu, + onCut: onCut, onCopy: onCopy, onCopyAsMarkdown: onCopyAsMarkdown, ), @@ -1823,6 +1830,7 @@ class _TableCellEditor extends StatefulWidget { this.cellKey, this.onCellFocused, this.suppressContextMenu = false, + this.onCut, this.onCopy, this.onCopyAsMarkdown, }); @@ -1842,6 +1850,7 @@ class _TableCellEditor extends StatefulWidget { final GlobalKey? cellKey; final ValueChanged<String>? onCellFocused; final bool suppressContextMenu; + final VoidCallback? onCut; final VoidCallback? onCopy; final VoidCallback? onCopyAsMarkdown; @@ -2024,6 +2033,7 @@ class _TableCellEditorState extends State<_TableCellEditor> { context, editableTextState, refineWithAiLabel: context.l10n.aiRefineWithAi, + onCut: widget.onCut, onCopy: widget.onCopy, onCopyAsMarkdown: widget.onCopyAsMarkdown, ), diff --git a/lib/src/editor/wysiwyg/wysiwyg_editor.dart b/lib/src/editor/wysiwyg/wysiwyg_editor.dart index ce7e91fb..bcab0cae 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_editor.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_editor.dart @@ -872,6 +872,7 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { onPointerMove: _handleBlockPointerMove, onPointerUp: _handleBlockPointerUp, onFocused: () => _handleBlockFocused(block.id), + onCut: _cutCurrentSelection, onCopy: _copyCurrentSelection, onCopyAsMarkdown: _copyCurrentSelectionAsMarkdown, onRefineWithAi: widget.onAiEdit == null diff --git a/test/src/wysiwyg_clipboard_test.dart b/test/src/wysiwyg_clipboard_test.dart index 49d48f00..48d7b38e 100644 --- a/test/src/wysiwyg_clipboard_test.dart +++ b/test/src/wysiwyg_clipboard_test.dart @@ -546,6 +546,42 @@ void main() { }, ); + testWidgets('cut transfers formatting before deleting the selection', ( + tester, + ) async { + var origin = 'A **bold** word\n'; + await mount(tester, 'origin', origin, (value) => origin = value); + tester + .widget<TextField>(find.byType(TextField).first) + .controller! + .selection = const TextSelection( + baseOffset: 2, + extentOffset: 6, + ); + + await key(tester, LogicalKeyboardKey.keyX); + expect(origin, 'A word\n'); + expect(systemData.keys, containsAll(['text', 'html', 'fragment'])); + expect(systemData['text'], 'bold'); + expect(systemData['html'], contains('<strong>bold</strong>')); + + var destination = ''; + await mount( + tester, + 'destination', + 'Before after\n', + (value) => destination = value, + ); + tester + .widget<TextField>(find.byType(TextField).first) + .controller! + .selection = const TextSelection.collapsed( + offset: 7, + ); + await key(tester, LogicalKeyboardKey.keyV); + expect(destination, 'Before **bold**after\n'); + }); + testWidgets('malformed native fragment falls back to HTML', (tester) async { systemData = { 'fragment': '{"version":99}', From dcb46cbe83e22029f3e598e9158f62d6353142ee Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Mon, 7 Sep 2026 18:07:14 -0700 Subject: [PATCH 18/37] Make standard Editor Copy plain text --- lib/src/editor/wysiwyg/wysiwyg_editor.dart | 17 +++- test/src/wysiwyg_clipboard_test.dart | 101 +++++++++++++-------- 2 files changed, 76 insertions(+), 42 deletions(-) diff --git a/lib/src/editor/wysiwyg/wysiwyg_editor.dart b/lib/src/editor/wysiwyg/wysiwyg_editor.dart index bcab0cae..b8b99ae5 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_editor.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_editor.dart @@ -5965,6 +5965,11 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { .where((range) => _copyTextForRange(range).trim().isNotEmpty) .toList(); if (ranges.isEmpty) return false; + final text = ranges.map(_copyTextForRange).join('\n\n'); + if (!cut) { + unawaited(_writePlainClipboard(text)); + return true; + } final target = _captureClipboardTarget(); final blocks = _clipboardBlocksForRanges(ranges); final fragment = WysiwygClipboardFragment( @@ -5973,13 +5978,12 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { blocks: blocks, mediaPaths: _clipboardMediaPaths(blocks), ); - final text = ranges.map(_copyTextForRange).join('\n\n'); unawaited( _writeClipboardSelection( fragment: fragment, text: text, onWritten: () { - if (!cut || !_isClipboardTargetCurrent(target)) return; + if (!_isClipboardTargetCurrent(target)) return; if (documentSelection) { _deleteBlockSelection(); } else { @@ -5991,6 +5995,15 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { return true; } + Future<void> _writePlainClipboard(String text) async { + final success = await _clipboard.write(RichClipboardData(text: text)); + if (!mounted || success) return; + BusyMarkToastOverlay.show( + context, + message: context.l10n.clipboardCopyFailed, + ); + } + Future<void> _writeClipboardSelection({ required WysiwygClipboardFragment fragment, required String text, diff --git a/test/src/wysiwyg_clipboard_test.dart b/test/src/wysiwyg_clipboard_test.dart index 48d7b38e..dad33eaf 100644 --- a/test/src/wysiwyg_clipboard_test.dart +++ b/test/src/wysiwyg_clipboard_test.dart @@ -387,29 +387,48 @@ void main() { await key(tester, LogicalKeyboardKey.keyC); } - testWidgets('fresh Editor restores system clipboard formatting and undo', ( + Future<void> copyAllAsMarkdown( + WidgetTester tester, { + String source = _source, + }) async { + await mount(tester, 'origin', source, (_) {}); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyC, shift: true); + } + + testWidgets('regular Copy stays plain when pasted into a fresh Editor', ( tester, ) async { await copyAll(tester); - expect(systemData.keys, containsAll(['text', 'html', 'fragment'])); + expect(systemData.keys, ['text']); + expect(systemData['text'], startsWith('Issues')); + expect( + systemData['text'], + contains('When selecting all, keep formatting.'), + ); expect(systemData['text'], contains('[ ] First task')); + expect(systemData['text'], isNot(contains('# Issues'))); + expect(systemData['text'], isNot(contains('**When**'))); var result = ''; await mount(tester, 'destination', 'Target\n', (value) => result = value); await key(tester, LogicalKeyboardKey.keyA); await key(tester, LogicalKeyboardKey.keyV); - expect(result, contains('# Issues')); - expect(result, contains('**When**')); - expect(result, contains('- [x] Second task')); + expect(result, contains('Issues')); + expect(result, contains('When selecting all, keep formatting.')); + expect(result, isNot(contains('# Issues'))); + expect(result, isNot(contains('**When**'))); + expect(result, isNot(contains('- [x] Second task'))); await key(tester, LogicalKeyboardKey.keyZ); expect(result, 'Target\n'); await key(tester, LogicalKeyboardKey.keyZ, shift: true); - expect(result, contains('**When**')); + expect(result, contains('When selecting all, keep formatting.')); }); testWidgets('copy all does not duplicate nested list children', ( tester, ) async { - await copyAll( + await copyAllAsMarkdown( tester, source: 'Before\n\n- Parent\n - **Child**\n\nAfter\n', ); @@ -424,7 +443,7 @@ void main() { testWidgets('whole-document copy preserves a structured blockquote', ( tester, ) async { - await copyAll( + await copyAllAsMarkdown( tester, source: 'Before\n\n> First\n>\n> **Second**\n\nAfter\n', ); @@ -467,8 +486,9 @@ void main() { } await tester.tap(find.text('Copy')); await tester.pumpAndSettle(); - expect(systemData.keys, containsAll(['text', 'html', 'fragment'])); + expect(systemData.keys, ['text']); expect(systemData['text'], contains('[ ] First task')); + expect(systemData['text'], isNot(contains('**When**'))); }); testWidgets( @@ -518,33 +538,33 @@ void main() { expect(systemData['text'], contains('**When**')); }); - testWidgets( - 'partial inline copy keeps formatting inside another paragraph', - (tester) async { - await mount(tester, 'origin', 'A **bold** word\n', (_) {}); - final field = tester.widget<TextField>(find.byType(TextField).first); - field.controller!.selection = const TextSelection( - baseOffset: 2, - extentOffset: 6, - ); - await key(tester, LogicalKeyboardKey.keyC); - var result = ''; - await mount( - tester, - 'destination', - 'Before after\n', - (value) => result = value, - ); - tester - .widget<TextField>(find.byType(TextField).first) - .controller! - .selection = const TextSelection.collapsed( - offset: 7, - ); - await key(tester, LogicalKeyboardKey.keyV); - expect(result, 'Before **bold**after\n'); - }, - ); + testWidgets('partial inline Copy remains plain inside another paragraph', ( + tester, + ) async { + await mount(tester, 'origin', 'A **bold** word\n', (_) {}); + final field = tester.widget<TextField>(find.byType(TextField).first); + field.controller!.selection = const TextSelection( + baseOffset: 2, + extentOffset: 6, + ); + await key(tester, LogicalKeyboardKey.keyC); + expect(systemData, {'text': 'bold'}); + var result = ''; + await mount( + tester, + 'destination', + 'Before after\n', + (value) => result = value, + ); + tester + .widget<TextField>(find.byType(TextField).first) + .controller! + .selection = const TextSelection.collapsed( + offset: 7, + ); + await key(tester, LogicalKeyboardKey.keyV); + expect(result, 'Before boldafter\n'); + }); testWidgets('cut transfers formatting before deleting the selection', ( tester, @@ -613,7 +633,7 @@ void main() { testWidgets( 'plain paste and later plain copies never revive cached formatting', (tester) async { - await copyAll(tester); + await copyAllAsMarkdown(tester); var result = ''; await mount( tester, @@ -623,8 +643,8 @@ void main() { ); await key(tester, LogicalKeyboardKey.keyA); await key(tester, LogicalKeyboardKey.keyV, shift: true); - expect(result, isNot(contains('# Issues'))); - expect(result, isNot(contains('**When**'))); + expect(result, contains(r'\# Issues')); + expect(result, contains(r'\*\*When\*\*')); final sameText = systemData['text'] as String; await Clipboard.setData(ClipboardData(text: sameText)); await mount( @@ -635,7 +655,8 @@ void main() { ); await key(tester, LogicalKeyboardKey.keyA); await key(tester, LogicalKeyboardKey.keyV); - expect(result, isNot(contains('**When**'))); + expect(result, contains(r'\# Issues')); + expect(result, contains(r'\*\*When\*\*')); }, ); From ff37af32361748f7481a35864b06c923d02012b2 Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Mon, 7 Sep 2026 18:25:07 -0700 Subject: [PATCH 19/37] Restore standard rich Editor copy --- lib/src/editor/wysiwyg/wysiwyg_editor.dart | 17 +--- test/src/wysiwyg_clipboard_test.dart | 101 ++++++++------------- 2 files changed, 42 insertions(+), 76 deletions(-) diff --git a/lib/src/editor/wysiwyg/wysiwyg_editor.dart b/lib/src/editor/wysiwyg/wysiwyg_editor.dart index b8b99ae5..bcab0cae 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_editor.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_editor.dart @@ -5965,11 +5965,6 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { .where((range) => _copyTextForRange(range).trim().isNotEmpty) .toList(); if (ranges.isEmpty) return false; - final text = ranges.map(_copyTextForRange).join('\n\n'); - if (!cut) { - unawaited(_writePlainClipboard(text)); - return true; - } final target = _captureClipboardTarget(); final blocks = _clipboardBlocksForRanges(ranges); final fragment = WysiwygClipboardFragment( @@ -5978,12 +5973,13 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { blocks: blocks, mediaPaths: _clipboardMediaPaths(blocks), ); + final text = ranges.map(_copyTextForRange).join('\n\n'); unawaited( _writeClipboardSelection( fragment: fragment, text: text, onWritten: () { - if (!_isClipboardTargetCurrent(target)) return; + if (!cut || !_isClipboardTargetCurrent(target)) return; if (documentSelection) { _deleteBlockSelection(); } else { @@ -5995,15 +5991,6 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { return true; } - Future<void> _writePlainClipboard(String text) async { - final success = await _clipboard.write(RichClipboardData(text: text)); - if (!mounted || success) return; - BusyMarkToastOverlay.show( - context, - message: context.l10n.clipboardCopyFailed, - ); - } - Future<void> _writeClipboardSelection({ required WysiwygClipboardFragment fragment, required String text, diff --git a/test/src/wysiwyg_clipboard_test.dart b/test/src/wysiwyg_clipboard_test.dart index dad33eaf..48d7b38e 100644 --- a/test/src/wysiwyg_clipboard_test.dart +++ b/test/src/wysiwyg_clipboard_test.dart @@ -387,48 +387,29 @@ void main() { await key(tester, LogicalKeyboardKey.keyC); } - Future<void> copyAllAsMarkdown( - WidgetTester tester, { - String source = _source, - }) async { - await mount(tester, 'origin', source, (_) {}); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyC, shift: true); - } - - testWidgets('regular Copy stays plain when pasted into a fresh Editor', ( + testWidgets('fresh Editor restores system clipboard formatting and undo', ( tester, ) async { await copyAll(tester); - expect(systemData.keys, ['text']); - expect(systemData['text'], startsWith('Issues')); - expect( - systemData['text'], - contains('When selecting all, keep formatting.'), - ); + expect(systemData.keys, containsAll(['text', 'html', 'fragment'])); expect(systemData['text'], contains('[ ] First task')); - expect(systemData['text'], isNot(contains('# Issues'))); - expect(systemData['text'], isNot(contains('**When**'))); var result = ''; await mount(tester, 'destination', 'Target\n', (value) => result = value); await key(tester, LogicalKeyboardKey.keyA); await key(tester, LogicalKeyboardKey.keyV); - expect(result, contains('Issues')); - expect(result, contains('When selecting all, keep formatting.')); - expect(result, isNot(contains('# Issues'))); - expect(result, isNot(contains('**When**'))); - expect(result, isNot(contains('- [x] Second task'))); + expect(result, contains('# Issues')); + expect(result, contains('**When**')); + expect(result, contains('- [x] Second task')); await key(tester, LogicalKeyboardKey.keyZ); expect(result, 'Target\n'); await key(tester, LogicalKeyboardKey.keyZ, shift: true); - expect(result, contains('When selecting all, keep formatting.')); + expect(result, contains('**When**')); }); testWidgets('copy all does not duplicate nested list children', ( tester, ) async { - await copyAllAsMarkdown( + await copyAll( tester, source: 'Before\n\n- Parent\n - **Child**\n\nAfter\n', ); @@ -443,7 +424,7 @@ void main() { testWidgets('whole-document copy preserves a structured blockquote', ( tester, ) async { - await copyAllAsMarkdown( + await copyAll( tester, source: 'Before\n\n> First\n>\n> **Second**\n\nAfter\n', ); @@ -486,9 +467,8 @@ void main() { } await tester.tap(find.text('Copy')); await tester.pumpAndSettle(); - expect(systemData.keys, ['text']); + expect(systemData.keys, containsAll(['text', 'html', 'fragment'])); expect(systemData['text'], contains('[ ] First task')); - expect(systemData['text'], isNot(contains('**When**'))); }); testWidgets( @@ -538,33 +518,33 @@ void main() { expect(systemData['text'], contains('**When**')); }); - testWidgets('partial inline Copy remains plain inside another paragraph', ( - tester, - ) async { - await mount(tester, 'origin', 'A **bold** word\n', (_) {}); - final field = tester.widget<TextField>(find.byType(TextField).first); - field.controller!.selection = const TextSelection( - baseOffset: 2, - extentOffset: 6, - ); - await key(tester, LogicalKeyboardKey.keyC); - expect(systemData, {'text': 'bold'}); - var result = ''; - await mount( - tester, - 'destination', - 'Before after\n', - (value) => result = value, - ); - tester - .widget<TextField>(find.byType(TextField).first) - .controller! - .selection = const TextSelection.collapsed( - offset: 7, - ); - await key(tester, LogicalKeyboardKey.keyV); - expect(result, 'Before boldafter\n'); - }); + testWidgets( + 'partial inline copy keeps formatting inside another paragraph', + (tester) async { + await mount(tester, 'origin', 'A **bold** word\n', (_) {}); + final field = tester.widget<TextField>(find.byType(TextField).first); + field.controller!.selection = const TextSelection( + baseOffset: 2, + extentOffset: 6, + ); + await key(tester, LogicalKeyboardKey.keyC); + var result = ''; + await mount( + tester, + 'destination', + 'Before after\n', + (value) => result = value, + ); + tester + .widget<TextField>(find.byType(TextField).first) + .controller! + .selection = const TextSelection.collapsed( + offset: 7, + ); + await key(tester, LogicalKeyboardKey.keyV); + expect(result, 'Before **bold**after\n'); + }, + ); testWidgets('cut transfers formatting before deleting the selection', ( tester, @@ -633,7 +613,7 @@ void main() { testWidgets( 'plain paste and later plain copies never revive cached formatting', (tester) async { - await copyAllAsMarkdown(tester); + await copyAll(tester); var result = ''; await mount( tester, @@ -643,8 +623,8 @@ void main() { ); await key(tester, LogicalKeyboardKey.keyA); await key(tester, LogicalKeyboardKey.keyV, shift: true); - expect(result, contains(r'\# Issues')); - expect(result, contains(r'\*\*When\*\*')); + expect(result, isNot(contains('# Issues'))); + expect(result, isNot(contains('**When**'))); final sameText = systemData['text'] as String; await Clipboard.setData(ClipboardData(text: sameText)); await mount( @@ -655,8 +635,7 @@ void main() { ); await key(tester, LogicalKeyboardKey.keyA); await key(tester, LogicalKeyboardKey.keyV); - expect(result, contains(r'\# Issues')); - expect(result, contains(r'\*\*When\*\*')); + expect(result, isNot(contains('**When**'))); }, ); From eaebdd28fa5b6fa2901ca273081a499c4edd6934 Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Mon, 7 Sep 2026 20:06:03 -0700 Subject: [PATCH 20/37] Refactor copy/paste - distinguish between copying with formatting and plain text only. --- lib/l10n/app_ar.arb | 6 +- lib/l10n/app_de.arb | 6 +- lib/l10n/app_en.arb | 6 +- lib/l10n/app_es.arb | 6 +- lib/l10n/app_et.arb | 6 +- lib/l10n/app_fa.arb | 6 +- lib/l10n/app_fr.arb | 6 +- lib/l10n/app_hi.arb | 6 +- lib/l10n/app_id.arb | 6 +- lib/l10n/app_it.arb | 6 +- lib/l10n/app_ja.arb | 6 +- lib/l10n/app_ko.arb | 6 +- lib/l10n/app_nb.arb | 6 +- lib/l10n/app_nl.arb | 6 +- lib/l10n/app_pl.arb | 6 +- lib/l10n/app_pt_BR.arb | 6 +- lib/l10n/app_ru.arb | 6 +- lib/l10n/app_tr.arb | 6 +- lib/l10n/app_uk.arb | 6 +- lib/l10n/app_vi.arb | 6 +- lib/l10n/app_zh_CN.arb | 6 +- lib/l10n/generated/app_localizations.dart | 12 +-- lib/l10n/generated/app_localizations_ar.dart | 5 +- lib/l10n/generated/app_localizations_de.dart | 5 +- lib/l10n/generated/app_localizations_en.dart | 5 +- lib/l10n/generated/app_localizations_es.dart | 5 +- lib/l10n/generated/app_localizations_et.dart | 5 +- lib/l10n/generated/app_localizations_fa.dart | 5 +- lib/l10n/generated/app_localizations_fr.dart | 5 +- lib/l10n/generated/app_localizations_hi.dart | 5 +- lib/l10n/generated/app_localizations_id.dart | 5 +- lib/l10n/generated/app_localizations_it.dart | 5 +- lib/l10n/generated/app_localizations_ja.dart | 5 +- lib/l10n/generated/app_localizations_ko.dart | 5 +- lib/l10n/generated/app_localizations_nb.dart | 5 +- lib/l10n/generated/app_localizations_nl.dart | 5 +- lib/l10n/generated/app_localizations_pl.dart | 5 +- lib/l10n/generated/app_localizations_pt.dart | 10 +- lib/l10n/generated/app_localizations_ru.dart | 5 +- lib/l10n/generated/app_localizations_tr.dart | 5 +- lib/l10n/generated/app_localizations_uk.dart | 5 +- lib/l10n/generated/app_localizations_vi.dart | 5 +- lib/l10n/generated/app_localizations_zh.dart | 10 +- lib/src/app/busymark_dialogs.dart | 9 -- lib/src/app/busymark_shortcuts.dart | 35 ++---- lib/src/app/command_registry.dart | 14 +-- lib/src/editor/editor_text_context_menu.dart | 18 ++-- lib/src/editor/source/source_editor.dart | 27 +---- .../editor/wysiwyg/wysiwyg_block_widgets.dart | 20 ++-- lib/src/editor/wysiwyg/wysiwyg_editor.dart | 58 ++++------ test/src/app_smoke_test.dart | 9 +- test/src/wysiwyg_clipboard_test.dart | 101 +++++++----------- 52 files changed, 145 insertions(+), 399 deletions(-) diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index b08c791d..e8c62a35 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -94,7 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "نسخ", - "copyAsMarkdown": "نسخ كـ Markdown", + "copyPlainText": "نسخ كنص عادي", "@copy": { "description": "Copy command label." }, @@ -200,10 +200,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "لصق بدون تنسيق", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "وضع القراءة", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 3f94e819..aeb2f0da 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -94,7 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Kopieren", - "copyAsMarkdown": "Als Markdown kopieren", + "copyPlainText": "Als Nur-Text kopieren", "@copy": { "description": "Copy command label." }, @@ -200,10 +200,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "Ohne Formatierung einfügen", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "Leseansicht", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 82f1ed7e..81d4048a 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -90,8 +90,8 @@ "chooseLocation": "Choose location", "@chooseLocation": {"description": "File picker confirmation label for choosing a directory."}, "copy": "Copy", - "copyAsMarkdown": "Copy as Markdown", - "@copyAsMarkdown": {"description": "Copies the Editor selection as Markdown source."}, + "copyPlainText": "Copy Plain Text", + "@copyPlainText": {"description": "Copies the Editor selection without formatting or Markdown syntax."}, "clipboardCopyFailed": "Could not copy the selection to the clipboard.", "@clipboardCopyFailed": {"description": "Shown when Editor copy or cut cannot write the clipboard; cut leaves the document intact."}, "@copy": {"description": "Copy command label."}, @@ -168,8 +168,6 @@ "@overwrite": {"description": "Button label for overwriting a changed file."}, "paste": "Paste", "@paste": {"description": "Paste command label."}, - "pasteWithoutFormatting": "Paste without formatting", - "@pasteWithoutFormatting": {"description": "Plain text paste command label."}, "reading": "Reading", "@reading": {"description": "Reading view label."}, "removeFromRecent": "Remove from Recent", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 18035794..d5679b4a 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -94,7 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Copiar", - "copyAsMarkdown": "Copiar como Markdown", + "copyPlainText": "Copiar como texto sin formato", "@copy": { "description": "Copy command label." }, @@ -200,10 +200,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "Pegar sin formatear", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "Lectura", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_et.arb b/lib/l10n/app_et.arb index 7204add1..a58f844e 100644 --- a/lib/l10n/app_et.arb +++ b/lib/l10n/app_et.arb @@ -178,7 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Kopeeri", - "copyAsMarkdown": "Kopeeri Markdownina", + "copyPlainText": "Kopeeri lihttekstina", "@copy": { "description": "Copy command label." }, @@ -288,10 +288,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "Aseta vorminduseta", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "Lugemisvaade", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index cc9c94be..7d9da90f 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -94,7 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "کپی", - "copyAsMarkdown": "کپی به‌صورت Markdown", + "copyPlainText": "کپی به‌صورت متن ساده", "@copy": { "description": "Copy command label." }, @@ -200,10 +200,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "جای‌گذاری بدون قالب‌بندی", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "حالت مطالعه", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index c8fecda9..a1747150 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -94,7 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Copier", - "copyAsMarkdown": "Copier en Markdown", + "copyPlainText": "Copier en texte brut", "@copy": { "description": "Copy command label." }, @@ -200,10 +200,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "Coller sans mise en forme", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "Lecture", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index cc9b882e..b801bbb5 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -94,7 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "कॉपी करें", - "copyAsMarkdown": "Markdown के रूप में कॉपी करें", + "copyPlainText": "सादे पाठ के रूप में कॉपी करें", "@copy": { "description": "Copy command label." }, @@ -200,10 +200,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "बिना फ़ॉर्मेटिंग पेस्ट करें", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "पठन दृश्य", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index 3bd8b2d8..6b949b98 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -178,7 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Salin", - "copyAsMarkdown": "Salin sebagai Markdown", + "copyPlainText": "Salin sebagai teks biasa", "@copy": { "description": "Copy command label." }, @@ -327,10 +327,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "Tempel tanpa memformat", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "Membaca", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index a5bdfdd8..983fb496 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -94,7 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Copia", - "copyAsMarkdown": "Copia come Markdown", + "copyPlainText": "Copia come testo semplice", "@copy": { "description": "Copy command label." }, @@ -200,10 +200,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "Incolla senza formattazione", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "Lettura", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index bc660dce..6f53ce50 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -178,7 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "コピー", - "copyAsMarkdown": "Markdown としてコピー", + "copyPlainText": "プレーンテキストとしてコピー", "@copy": { "description": "Copy command label." }, @@ -327,10 +327,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "書式なしで貼り付け", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "閲覧", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index 5f942163..c9bf22d3 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -178,7 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "복사", - "copyAsMarkdown": "Markdown으로 복사", + "copyPlainText": "일반 텍스트로 복사", "@copy": { "description": "Copy command label." }, @@ -327,10 +327,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "서식 없이 붙여넣기", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "읽기", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_nb.arb b/lib/l10n/app_nb.arb index c7188f8c..f9d90f5d 100644 --- a/lib/l10n/app_nb.arb +++ b/lib/l10n/app_nb.arb @@ -94,7 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Kopier", - "copyAsMarkdown": "Kopier som Markdown", + "copyPlainText": "Kopier som ren tekst", "@copy": { "description": "Copy command label." }, @@ -200,10 +200,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "Lim inn uten formatering", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "Lesevisning", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index e73d4c86..4d8cdd88 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -178,7 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Kopiëren", - "copyAsMarkdown": "Kopiëren als Markdown", + "copyPlainText": "Kopiëren als platte tekst", "@copy": { "description": "Copy command label." }, @@ -327,10 +327,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "Plakken zonder opmaak", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "Lezen", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index e12f5dd4..5171f52f 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -94,7 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Kopiuj", - "copyAsMarkdown": "Kopiuj jako Markdown", + "copyPlainText": "Kopiuj jako zwykły tekst", "@copy": { "description": "Copy command label." }, @@ -200,10 +200,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "Wklej bez formatowania", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "Widok do czytania", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_pt_BR.arb b/lib/l10n/app_pt_BR.arb index 83f989c1..5bbe3c10 100644 --- a/lib/l10n/app_pt_BR.arb +++ b/lib/l10n/app_pt_BR.arb @@ -94,7 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Copiar", - "copyAsMarkdown": "Copiar como Markdown", + "copyPlainText": "Copiar como texto simples", "@copy": { "description": "Copy command label." }, @@ -200,10 +200,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "Colar sem formatar", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "Leitura", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 1f6c8af9..9a1a1b22 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -94,7 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Копировать", - "copyAsMarkdown": "Копировать как Markdown", + "copyPlainText": "Копировать как обычный текст", "@copy": { "description": "Copy command label." }, @@ -200,10 +200,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "Вставить без форматирования", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "Режим чтения", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 819660e0..394ec723 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -178,7 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Kopyala", - "copyAsMarkdown": "Markdown olarak kopyala", + "copyPlainText": "Düz metin olarak kopyala", "@copy": { "description": "Copy command label." }, @@ -327,10 +327,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "Biçimlendirmeden yapıştır", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "Okuma", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index f53d261f..a559ec3d 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -94,7 +94,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Копіювати", - "copyAsMarkdown": "Копіювати як Markdown", + "copyPlainText": "Копіювати як звичайний текст", "@copy": { "description": "Copy command label." }, @@ -200,10 +200,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "Вставити без форматування", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "Режим читання", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index bec87976..c9977647 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -178,7 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "Sao chép", - "copyAsMarkdown": "Sao chép dưới dạng Markdown", + "copyPlainText": "Sao chép dưới dạng văn bản thuần", "@copy": { "description": "Copy command label." }, @@ -327,10 +327,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "Dán không định dạng", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "Đọc", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/app_zh_CN.arb b/lib/l10n/app_zh_CN.arb index 07a54c96..269baadc 100644 --- a/lib/l10n/app_zh_CN.arb +++ b/lib/l10n/app_zh_CN.arb @@ -178,7 +178,7 @@ "description": "File picker confirmation label for choosing a directory." }, "copy": "复制", - "copyAsMarkdown": "复制为 Markdown", + "copyPlainText": "复制为纯文本", "@copy": { "description": "Copy command label." }, @@ -327,10 +327,6 @@ "@paste": { "description": "Paste command label." }, - "pasteWithoutFormatting": "粘贴为无格式文本", - "@pasteWithoutFormatting": { - "description": "Plain text paste command label." - }, "reading": "阅读", "@reading": { "description": "Reading view label." diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index ee3bc7ca..c6d1403c 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -403,11 +403,11 @@ abstract class AppLocalizations { /// **'Copy'** String get copy; - /// Copies the Editor selection as Markdown source. + /// Copies the Editor selection without formatting or Markdown syntax. /// /// In en, this message translates to: - /// **'Copy as Markdown'** - String get copyAsMarkdown; + /// **'Copy Plain Text'** + String get copyPlainText; /// Shown when Editor copy or cut cannot write the clipboard; cut leaves the document intact. /// @@ -625,12 +625,6 @@ abstract class AppLocalizations { /// **'Paste'** String get paste; - /// Plain text paste command label. - /// - /// In en, this message translates to: - /// **'Paste without formatting'** - String get pasteWithoutFormatting; - /// Reading view label. /// /// In en, this message translates to: diff --git a/lib/l10n/generated/app_localizations_ar.dart b/lib/l10n/generated/app_localizations_ar.dart index 91ff4af6..83ce3337 100644 --- a/lib/l10n/generated/app_localizations_ar.dart +++ b/lib/l10n/generated/app_localizations_ar.dart @@ -153,7 +153,7 @@ class AppLocalizationsAr extends AppLocalizations { String get copy => 'نسخ'; @override - String get copyAsMarkdown => 'نسخ كـ Markdown'; + String get copyPlainText => 'نسخ كنص عادي'; @override String get clipboardCopyFailed => @@ -267,9 +267,6 @@ class AppLocalizationsAr extends AppLocalizations { @override String get paste => 'لصق'; - @override - String get pasteWithoutFormatting => 'لصق بدون تنسيق'; - @override String get reading => 'وضع القراءة'; diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 36b0e620..9fbaa04d 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -157,7 +157,7 @@ class AppLocalizationsDe extends AppLocalizations { String get copy => 'Kopieren'; @override - String get copyAsMarkdown => 'Als Markdown kopieren'; + String get copyPlainText => 'Als Nur-Text kopieren'; @override String get clipboardCopyFailed => @@ -271,9 +271,6 @@ class AppLocalizationsDe extends AppLocalizations { @override String get paste => 'Einfügen'; - @override - String get pasteWithoutFormatting => 'Ohne Formatierung einfügen'; - @override String get reading => 'Leseansicht'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 9c739f42..7513dbaf 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -154,7 +154,7 @@ class AppLocalizationsEn extends AppLocalizations { String get copy => 'Copy'; @override - String get copyAsMarkdown => 'Copy as Markdown'; + String get copyPlainText => 'Copy Plain Text'; @override String get clipboardCopyFailed => @@ -268,9 +268,6 @@ class AppLocalizationsEn extends AppLocalizations { @override String get paste => 'Paste'; - @override - String get pasteWithoutFormatting => 'Paste without formatting'; - @override String get reading => 'Reading'; diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart index 89d28b0e..e070e427 100644 --- a/lib/l10n/generated/app_localizations_es.dart +++ b/lib/l10n/generated/app_localizations_es.dart @@ -156,7 +156,7 @@ class AppLocalizationsEs extends AppLocalizations { String get copy => 'Copiar'; @override - String get copyAsMarkdown => 'Copiar como Markdown'; + String get copyPlainText => 'Copiar como texto sin formato'; @override String get clipboardCopyFailed => @@ -270,9 +270,6 @@ class AppLocalizationsEs extends AppLocalizations { @override String get paste => 'Pegar'; - @override - String get pasteWithoutFormatting => 'Pegar sin formatear'; - @override String get reading => 'Lectura'; diff --git a/lib/l10n/generated/app_localizations_et.dart b/lib/l10n/generated/app_localizations_et.dart index 559c6533..acadc20f 100644 --- a/lib/l10n/generated/app_localizations_et.dart +++ b/lib/l10n/generated/app_localizations_et.dart @@ -153,7 +153,7 @@ class AppLocalizationsEt extends AppLocalizations { String get copy => 'Kopeeri'; @override - String get copyAsMarkdown => 'Kopeeri Markdownina'; + String get copyPlainText => 'Kopeeri lihttekstina'; @override String get clipboardCopyFailed => @@ -267,9 +267,6 @@ class AppLocalizationsEt extends AppLocalizations { @override String get paste => 'Aseta'; - @override - String get pasteWithoutFormatting => 'Aseta vorminduseta'; - @override String get reading => 'Lugemisvaade'; diff --git a/lib/l10n/generated/app_localizations_fa.dart b/lib/l10n/generated/app_localizations_fa.dart index 158398c2..b1a30ac5 100644 --- a/lib/l10n/generated/app_localizations_fa.dart +++ b/lib/l10n/generated/app_localizations_fa.dart @@ -153,7 +153,7 @@ class AppLocalizationsFa extends AppLocalizations { String get copy => 'کپی'; @override - String get copyAsMarkdown => 'کپی به‌صورت Markdown'; + String get copyPlainText => 'کپی به‌صورت متن ساده'; @override String get clipboardCopyFailed => @@ -267,9 +267,6 @@ class AppLocalizationsFa extends AppLocalizations { @override String get paste => 'جای‌گذاری'; - @override - String get pasteWithoutFormatting => 'جای‌گذاری بدون قالب‌بندی'; - @override String get reading => 'حالت مطالعه'; diff --git a/lib/l10n/generated/app_localizations_fr.dart b/lib/l10n/generated/app_localizations_fr.dart index a0afbadf..e4d0eb8b 100644 --- a/lib/l10n/generated/app_localizations_fr.dart +++ b/lib/l10n/generated/app_localizations_fr.dart @@ -156,7 +156,7 @@ class AppLocalizationsFr extends AppLocalizations { String get copy => 'Copier'; @override - String get copyAsMarkdown => 'Copier en Markdown'; + String get copyPlainText => 'Copier en texte brut'; @override String get clipboardCopyFailed => @@ -270,9 +270,6 @@ class AppLocalizationsFr extends AppLocalizations { @override String get paste => 'Coller'; - @override - String get pasteWithoutFormatting => 'Coller sans mise en forme'; - @override String get reading => 'Lecture'; diff --git a/lib/l10n/generated/app_localizations_hi.dart b/lib/l10n/generated/app_localizations_hi.dart index 2b54fa60..8dd264b2 100644 --- a/lib/l10n/generated/app_localizations_hi.dart +++ b/lib/l10n/generated/app_localizations_hi.dart @@ -155,7 +155,7 @@ class AppLocalizationsHi extends AppLocalizations { String get copy => 'कॉपी करें'; @override - String get copyAsMarkdown => 'Markdown के रूप में कॉपी करें'; + String get copyPlainText => 'सादे पाठ के रूप में कॉपी करें'; @override String get clipboardCopyFailed => @@ -269,9 +269,6 @@ class AppLocalizationsHi extends AppLocalizations { @override String get paste => 'पेस्ट करें'; - @override - String get pasteWithoutFormatting => 'बिना फ़ॉर्मेटिंग पेस्ट करें'; - @override String get reading => 'पठन दृश्य'; diff --git a/lib/l10n/generated/app_localizations_id.dart b/lib/l10n/generated/app_localizations_id.dart index 22af6984..41530a15 100644 --- a/lib/l10n/generated/app_localizations_id.dart +++ b/lib/l10n/generated/app_localizations_id.dart @@ -155,7 +155,7 @@ class AppLocalizationsId extends AppLocalizations { String get copy => 'Salin'; @override - String get copyAsMarkdown => 'Salin sebagai Markdown'; + String get copyPlainText => 'Salin sebagai teks biasa'; @override String get clipboardCopyFailed => @@ -269,9 +269,6 @@ class AppLocalizationsId extends AppLocalizations { @override String get paste => 'Tempel'; - @override - String get pasteWithoutFormatting => 'Tempel tanpa memformat'; - @override String get reading => 'Membaca'; diff --git a/lib/l10n/generated/app_localizations_it.dart b/lib/l10n/generated/app_localizations_it.dart index b7d8c6a3..85370c8d 100644 --- a/lib/l10n/generated/app_localizations_it.dart +++ b/lib/l10n/generated/app_localizations_it.dart @@ -155,7 +155,7 @@ class AppLocalizationsIt extends AppLocalizations { String get copy => 'Copia'; @override - String get copyAsMarkdown => 'Copia come Markdown'; + String get copyPlainText => 'Copia come testo semplice'; @override String get clipboardCopyFailed => @@ -269,9 +269,6 @@ class AppLocalizationsIt extends AppLocalizations { @override String get paste => 'Incolla'; - @override - String get pasteWithoutFormatting => 'Incolla senza formattazione'; - @override String get reading => 'Lettura'; diff --git a/lib/l10n/generated/app_localizations_ja.dart b/lib/l10n/generated/app_localizations_ja.dart index 9ce79ac1..fef2fd05 100644 --- a/lib/l10n/generated/app_localizations_ja.dart +++ b/lib/l10n/generated/app_localizations_ja.dart @@ -150,7 +150,7 @@ class AppLocalizationsJa extends AppLocalizations { String get copy => 'コピー'; @override - String get copyAsMarkdown => 'Markdown としてコピー'; + String get copyPlainText => 'プレーンテキストとしてコピー'; @override String get clipboardCopyFailed => @@ -263,9 +263,6 @@ class AppLocalizationsJa extends AppLocalizations { @override String get paste => '貼り付け'; - @override - String get pasteWithoutFormatting => '書式なしで貼り付け'; - @override String get reading => '閲覧'; diff --git a/lib/l10n/generated/app_localizations_ko.dart b/lib/l10n/generated/app_localizations_ko.dart index dfa6a8db..dbb8fd10 100644 --- a/lib/l10n/generated/app_localizations_ko.dart +++ b/lib/l10n/generated/app_localizations_ko.dart @@ -149,7 +149,7 @@ class AppLocalizationsKo extends AppLocalizations { String get copy => '복사'; @override - String get copyAsMarkdown => 'Markdown으로 복사'; + String get copyPlainText => '일반 텍스트로 복사'; @override String get clipboardCopyFailed => @@ -262,9 +262,6 @@ class AppLocalizationsKo extends AppLocalizations { @override String get paste => '붙여넣기'; - @override - String get pasteWithoutFormatting => '서식 없이 붙여넣기'; - @override String get reading => '읽기'; diff --git a/lib/l10n/generated/app_localizations_nb.dart b/lib/l10n/generated/app_localizations_nb.dart index 425560f1..9f8197a3 100644 --- a/lib/l10n/generated/app_localizations_nb.dart +++ b/lib/l10n/generated/app_localizations_nb.dart @@ -156,7 +156,7 @@ class AppLocalizationsNb extends AppLocalizations { String get copy => 'Kopier'; @override - String get copyAsMarkdown => 'Kopier som Markdown'; + String get copyPlainText => 'Kopier som ren tekst'; @override String get clipboardCopyFailed => @@ -270,9 +270,6 @@ class AppLocalizationsNb extends AppLocalizations { @override String get paste => 'Lim inn'; - @override - String get pasteWithoutFormatting => 'Lim inn uten formatering'; - @override String get reading => 'Lesevisning'; diff --git a/lib/l10n/generated/app_localizations_nl.dart b/lib/l10n/generated/app_localizations_nl.dart index e3b3f2c6..6607dad2 100644 --- a/lib/l10n/generated/app_localizations_nl.dart +++ b/lib/l10n/generated/app_localizations_nl.dart @@ -156,7 +156,7 @@ class AppLocalizationsNl extends AppLocalizations { String get copy => 'Kopiëren'; @override - String get copyAsMarkdown => 'Kopiëren als Markdown'; + String get copyPlainText => 'Kopiëren als platte tekst'; @override String get clipboardCopyFailed => @@ -270,9 +270,6 @@ class AppLocalizationsNl extends AppLocalizations { @override String get paste => 'Plakken'; - @override - String get pasteWithoutFormatting => 'Plakken zonder opmaak'; - @override String get reading => 'Lezen'; diff --git a/lib/l10n/generated/app_localizations_pl.dart b/lib/l10n/generated/app_localizations_pl.dart index 1f0cb0e7..17ef5fb5 100644 --- a/lib/l10n/generated/app_localizations_pl.dart +++ b/lib/l10n/generated/app_localizations_pl.dart @@ -155,7 +155,7 @@ class AppLocalizationsPl extends AppLocalizations { String get copy => 'Kopiuj'; @override - String get copyAsMarkdown => 'Kopiuj jako Markdown'; + String get copyPlainText => 'Kopiuj jako zwykły tekst'; @override String get clipboardCopyFailed => @@ -269,9 +269,6 @@ class AppLocalizationsPl extends AppLocalizations { @override String get paste => 'Wklej'; - @override - String get pasteWithoutFormatting => 'Wklej bez formatowania'; - @override String get reading => 'Widok do czytania'; diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart index 80b4c835..5700c21d 100644 --- a/lib/l10n/generated/app_localizations_pt.dart +++ b/lib/l10n/generated/app_localizations_pt.dart @@ -154,7 +154,7 @@ class AppLocalizationsPt extends AppLocalizations { String get copy => 'Copy'; @override - String get copyAsMarkdown => 'Copy as Markdown'; + String get copyPlainText => 'Copy Plain Text'; @override String get clipboardCopyFailed => @@ -268,9 +268,6 @@ class AppLocalizationsPt extends AppLocalizations { @override String get paste => 'Paste'; - @override - String get pasteWithoutFormatting => 'Paste without formatting'; - @override String get reading => 'Reading'; @@ -4075,7 +4072,7 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { String get copy => 'Copiar'; @override - String get copyAsMarkdown => 'Copiar como Markdown'; + String get copyPlainText => 'Copiar como texto simples'; @override String get copyName => 'Copiar nome'; @@ -4185,9 +4182,6 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { @override String get paste => 'Colar'; - @override - String get pasteWithoutFormatting => 'Colar sem formatar'; - @override String get reading => 'Leitura'; diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart index eb3b3464..80b96f87 100644 --- a/lib/l10n/generated/app_localizations_ru.dart +++ b/lib/l10n/generated/app_localizations_ru.dart @@ -156,7 +156,7 @@ class AppLocalizationsRu extends AppLocalizations { String get copy => 'Копировать'; @override - String get copyAsMarkdown => 'Копировать как Markdown'; + String get copyPlainText => 'Копировать как обычный текст'; @override String get clipboardCopyFailed => @@ -270,9 +270,6 @@ class AppLocalizationsRu extends AppLocalizations { @override String get paste => 'Вставить'; - @override - String get pasteWithoutFormatting => 'Вставить без форматирования'; - @override String get reading => 'Режим чтения'; diff --git a/lib/l10n/generated/app_localizations_tr.dart b/lib/l10n/generated/app_localizations_tr.dart index 0e6c3372..1b0c3b6a 100644 --- a/lib/l10n/generated/app_localizations_tr.dart +++ b/lib/l10n/generated/app_localizations_tr.dart @@ -156,7 +156,7 @@ class AppLocalizationsTr extends AppLocalizations { String get copy => 'Kopyala'; @override - String get copyAsMarkdown => 'Markdown olarak kopyala'; + String get copyPlainText => 'Düz metin olarak kopyala'; @override String get clipboardCopyFailed => @@ -270,9 +270,6 @@ class AppLocalizationsTr extends AppLocalizations { @override String get paste => 'Yapıştır'; - @override - String get pasteWithoutFormatting => 'Biçimlendirmeden yapıştır'; - @override String get reading => 'Okuma'; diff --git a/lib/l10n/generated/app_localizations_uk.dart b/lib/l10n/generated/app_localizations_uk.dart index fa8b4eb1..e06eb62f 100644 --- a/lib/l10n/generated/app_localizations_uk.dart +++ b/lib/l10n/generated/app_localizations_uk.dart @@ -155,7 +155,7 @@ class AppLocalizationsUk extends AppLocalizations { String get copy => 'Копіювати'; @override - String get copyAsMarkdown => 'Копіювати як Markdown'; + String get copyPlainText => 'Копіювати як звичайний текст'; @override String get clipboardCopyFailed => @@ -269,9 +269,6 @@ class AppLocalizationsUk extends AppLocalizations { @override String get paste => 'Вставити'; - @override - String get pasteWithoutFormatting => 'Вставити без форматування'; - @override String get reading => 'Режим читання'; diff --git a/lib/l10n/generated/app_localizations_vi.dart b/lib/l10n/generated/app_localizations_vi.dart index 6ab1f7d8..2e55517e 100644 --- a/lib/l10n/generated/app_localizations_vi.dart +++ b/lib/l10n/generated/app_localizations_vi.dart @@ -154,7 +154,7 @@ class AppLocalizationsVi extends AppLocalizations { String get copy => 'Sao chép'; @override - String get copyAsMarkdown => 'Sao chép dưới dạng Markdown'; + String get copyPlainText => 'Sao chép dưới dạng văn bản thuần'; @override String get clipboardCopyFailed => @@ -268,9 +268,6 @@ class AppLocalizationsVi extends AppLocalizations { @override String get paste => 'Dán'; - @override - String get pasteWithoutFormatting => 'Dán không định dạng'; - @override String get reading => 'Đọc'; diff --git a/lib/l10n/generated/app_localizations_zh.dart b/lib/l10n/generated/app_localizations_zh.dart index 300ff598..e4b1a00f 100644 --- a/lib/l10n/generated/app_localizations_zh.dart +++ b/lib/l10n/generated/app_localizations_zh.dart @@ -154,7 +154,7 @@ class AppLocalizationsZh extends AppLocalizations { String get copy => 'Copy'; @override - String get copyAsMarkdown => 'Copy as Markdown'; + String get copyPlainText => 'Copy Plain Text'; @override String get clipboardCopyFailed => @@ -268,9 +268,6 @@ class AppLocalizationsZh extends AppLocalizations { @override String get paste => 'Paste'; - @override - String get pasteWithoutFormatting => 'Paste without formatting'; - @override String get reading => 'Reading'; @@ -4051,7 +4048,7 @@ class AppLocalizationsZhCn extends AppLocalizationsZh { String get copy => '复制'; @override - String get copyAsMarkdown => '复制为 Markdown'; + String get copyPlainText => '复制为纯文本'; @override String get copyName => '复制名称'; @@ -4160,9 +4157,6 @@ class AppLocalizationsZhCn extends AppLocalizationsZh { @override String get paste => '粘贴'; - @override - String get pasteWithoutFormatting => '粘贴为无格式文本'; - @override String get reading => '阅读'; diff --git a/lib/src/app/busymark_dialogs.dart b/lib/src/app/busymark_dialogs.dart index 28f78194..2924d003 100644 --- a/lib/src/app/busymark_dialogs.dart +++ b/lib/src/app/busymark_dialogs.dart @@ -80,7 +80,6 @@ class _DismissBusyMarkModalIntent extends Intent { final _busyMarkModalShortcuts = <ShortcutActivator, Intent>{ for (final command in BusyMarkCommandCatalog.metadata.commands) if (command.shortcut != null && - command.id != BusyMarkCommandIds.textPastePlainText && command.scope != BusyMarkCommandScope.tree && command.scope != BusyMarkCommandScope.textEditing) command.shortcut!.activator: const DoNothingAndStopPropagationIntent(), @@ -661,14 +660,6 @@ void showLegacyBusyMarkKeyboardShortcutsDialog(BuildContext context) { BusyMarkTextEditingShortcutLabels.paste, ), ), - BusyMarkActionRow( - title: context.l10n.pasteWithoutFormatting, - subtitle: context.l10n.shortcutPastePlainTextDescription, - leading: const Icon(BusyMarkGlyphs.paste), - trailing: const _KeyboardShortcutBadge( - BusyMarkTextEditingShortcutLabels.pastePlainText, - ), - ), BusyMarkActionRow( title: context.l10n.undo, subtitle: context.l10n.shortcutUndoDescription, diff --git a/lib/src/app/busymark_shortcuts.dart b/lib/src/app/busymark_shortcuts.dart index b9167f76..1d1f67eb 100644 --- a/lib/src/app/busymark_shortcuts.dart +++ b/lib/src/app/busymark_shortcuts.dart @@ -372,7 +372,6 @@ enum BusyMarkTextEditingShortcutAction { cut, copy, paste, - pastePlainText, undo, redo, insertIndentation, @@ -387,7 +386,6 @@ abstract final class BusyMarkTextEditingShortcuts { static const cutLabel = 'Ctrl+X'; static const copyLabel = 'Ctrl+C'; static const pasteLabel = 'Ctrl+V'; - static const pastePlainTextLabel = 'Ctrl+Shift+V'; static const undoLabel = 'Ctrl+Z'; static const redoLabel = 'Ctrl+Shift+Z'; static const insertIndentationLabel = 'Tab'; @@ -410,14 +408,6 @@ abstract final class BusyMarkTextEditingShortcuts { label: pasteLabel, activator: SingleActivator(LogicalKeyboardKey.keyV, control: true), ); - static const pastePlainText = BusyMarkShortcutDefinition( - label: pastePlainTextLabel, - activator: SingleActivator( - LogicalKeyboardKey.keyV, - control: true, - shift: true, - ), - ); static const undo = BusyMarkShortcutDefinition( label: undoLabel, activator: SingleActivator(LogicalKeyboardKey.keyZ, control: true), @@ -449,7 +439,6 @@ abstract final class BusyMarkTextEditingShortcuts { BusyMarkTextEditingShortcutAction.cut: cut, BusyMarkTextEditingShortcutAction.copy: copy, BusyMarkTextEditingShortcutAction.paste: paste, - BusyMarkTextEditingShortcutAction.pastePlainText: pastePlainText, BusyMarkTextEditingShortcutAction.undo: undo, BusyMarkTextEditingShortcutAction.redo: redo, BusyMarkTextEditingShortcutAction.insertIndentation: insertIndentation, @@ -465,8 +454,6 @@ abstract final class BusyMarkTextEditingShortcutLabels { static const cut = BusyMarkTextEditingShortcuts.cutLabel; static const copy = BusyMarkTextEditingShortcuts.copyLabel; static const paste = BusyMarkTextEditingShortcuts.pasteLabel; - static const pastePlainText = - BusyMarkTextEditingShortcuts.pastePlainTextLabel; static const undo = BusyMarkTextEditingShortcuts.undoLabel; static const redo = BusyMarkTextEditingShortcuts.redoLabel; static const insertIndentation = @@ -486,8 +473,6 @@ abstract final class BusyMarkTextEditingShortcutActivators { BusyMarkTextEditingShortcuts.copy.activator; static ShortcutActivator get paste => BusyMarkTextEditingShortcuts.paste.activator; - static ShortcutActivator get pastePlainText => - BusyMarkTextEditingShortcuts.pastePlainText.activator; static ShortcutActivator get undo => BusyMarkTextEditingShortcuts.undo.activator; static ShortcutActivator get redo => @@ -502,7 +487,7 @@ abstract final class BusyMarkTextEditingShortcutActivators { enum BusyMarkEditorShortcutAction { refineWithAi, - copyAsMarkdown, + copyPlainText, bold, italic, underline, @@ -531,14 +516,13 @@ enum BusyMarkEditorShortcutAction { htmlBlock, thematicBreak, hardLineBreak, - pastePlainText, } abstract final class BusyMarkEditorShortcuts { const BusyMarkEditorShortcuts._(); static const refineWithAiLabel = 'Ctrl+G'; - static const copyAsMarkdownLabel = 'Ctrl+Shift+C'; + static const copyPlainTextLabel = 'Ctrl+Shift+C'; static const textStyleLabel = 'Ctrl+Alt+0-6'; static const boldLabel = 'Ctrl+B'; static const italicLabel = 'Ctrl+I'; @@ -567,8 +551,8 @@ abstract final class BusyMarkEditorShortcuts { label: refineWithAiLabel, activator: SingleActivator(LogicalKeyboardKey.keyG, control: true), ); - static const copyAsMarkdown = BusyMarkShortcutDefinition( - label: copyAsMarkdownLabel, + static const copyPlainText = BusyMarkShortcutDefinition( + label: copyPlainTextLabel, activator: SingleActivator( LogicalKeyboardKey.keyC, control: true, @@ -723,12 +707,10 @@ abstract final class BusyMarkEditorShortcuts { label: hardLineBreakLabel, activator: SingleActivator(LogicalKeyboardKey.enter, shift: true), ); - static const pastePlainText = BusyMarkTextEditingShortcuts.pastePlainText; - static const definitions = <BusyMarkEditorShortcutAction, BusyMarkShortcutDefinition>{ BusyMarkEditorShortcutAction.refineWithAi: refineWithAi, - BusyMarkEditorShortcutAction.copyAsMarkdown: copyAsMarkdown, + BusyMarkEditorShortcutAction.copyPlainText: copyPlainText, BusyMarkEditorShortcutAction.bold: bold, BusyMarkEditorShortcutAction.italic: italic, BusyMarkEditorShortcutAction.underline: underline, @@ -751,7 +733,6 @@ abstract final class BusyMarkEditorShortcuts { BusyMarkEditorShortcutAction.codeBlock: codeBlock, BusyMarkEditorShortcutAction.image: image, BusyMarkEditorShortcutAction.hardLineBreak: hardLineBreak, - BusyMarkEditorShortcutAction.pastePlainText: pastePlainText, }; } @@ -759,7 +740,7 @@ abstract final class BusyMarkEditorShortcutLabels { const BusyMarkEditorShortcutLabels._(); static const refineWithAi = BusyMarkEditorShortcuts.refineWithAiLabel; - static const copyAsMarkdown = BusyMarkEditorShortcuts.copyAsMarkdownLabel; + static const copyPlainText = BusyMarkEditorShortcuts.copyPlainTextLabel; static const textStyle = BusyMarkEditorShortcuts.textStyleLabel; static const bold = BusyMarkEditorShortcuts.boldLabel; static const italic = BusyMarkEditorShortcuts.italicLabel; @@ -783,8 +764,6 @@ abstract final class BusyMarkEditorShortcutLabels { static const codeBlock = BusyMarkEditorShortcuts.codeBlockLabel; static const image = BusyMarkEditorShortcuts.imageLabel; static const hardLineBreak = BusyMarkEditorShortcuts.hardLineBreakLabel; - static const pastePlainText = - BusyMarkTextEditingShortcuts.pastePlainTextLabel; } abstract final class BusyMarkEditorShortcutActivators { @@ -857,8 +836,6 @@ abstract final class BusyMarkEditorShortcutActivators { static ShortcutActivator get image => BusyMarkEditorShortcuts.image.activator; static ShortcutActivator get hardLineBreak => BusyMarkEditorShortcuts.hardLineBreak.activator; - static ShortcutActivator get pastePlainText => - BusyMarkEditorShortcuts.pastePlainText.activator; } enum BusyMarkSidebarShortcutAction { files, toc, outline, git } diff --git a/lib/src/app/command_registry.dart b/lib/src/app/command_registry.dart index 3c8fdcba..618ae37f 100644 --- a/lib/src/app/command_registry.dart +++ b/lib/src/app/command_registry.dart @@ -265,9 +265,8 @@ abstract final class BusyMarkCommandIds { static const textSelectAll = 'text.selectAll'; static const textCut = 'text.cut'; static const textCopy = 'text.copy'; - static const editorCopyAsMarkdown = 'editor.copyAsMarkdown'; + static const editorCopyPlainText = 'editor.copyPlainText'; static const textPaste = 'text.paste'; - static const textPastePlainText = 'text.pastePlainText'; static const textUndo = 'text.undo'; static const textRedo = 'text.redo'; static const textInsertIndentation = 'text.insertIndentation'; @@ -497,8 +496,6 @@ abstract final class BusyMarkCommandCatalog { BusyMarkTextEditingShortcutAction.cut => context.l10n.cut, BusyMarkTextEditingShortcutAction.copy => context.l10n.copy, BusyMarkTextEditingShortcutAction.paste => context.l10n.paste, - BusyMarkTextEditingShortcutAction.pastePlainText => - context.l10n.pasteWithoutFormatting, BusyMarkTextEditingShortcutAction.undo => context.l10n.undo, BusyMarkTextEditingShortcutAction.redo => context.l10n.redo, BusyMarkTextEditingShortcutAction.insertIndentation => @@ -513,7 +510,7 @@ abstract final class BusyMarkCommandCatalog { BusyMarkEditorShortcutAction action, ) => switch (action) { BusyMarkEditorShortcutAction.refineWithAi => context.l10n.aiRefineWithAi, - BusyMarkEditorShortcutAction.copyAsMarkdown => context.l10n.copyAsMarkdown, + BusyMarkEditorShortcutAction.copyPlainText => context.l10n.copyPlainText, BusyMarkEditorShortcutAction.bold => context.l10n.bold, BusyMarkEditorShortcutAction.italic => context.l10n.italic, BusyMarkEditorShortcutAction.underline => context.l10n.underline, @@ -542,8 +539,6 @@ abstract final class BusyMarkCommandCatalog { BusyMarkEditorShortcutAction.htmlBlock => context.l10n.htmlBlock, BusyMarkEditorShortcutAction.thematicBreak => context.l10n.thematicBreak, BusyMarkEditorShortcutAction.hardLineBreak => context.l10n.hardLineBreak, - BusyMarkEditorShortcutAction.pastePlainText => - context.l10n.pasteWithoutFormatting, }; static String? _textDescription( @@ -558,8 +553,6 @@ abstract final class BusyMarkCommandCatalog { context.l10n.shortcutCopyDescription, BusyMarkTextEditingShortcutAction.paste => context.l10n.shortcutPasteDescription, - BusyMarkTextEditingShortcutAction.pastePlainText => - context.l10n.shortcutPastePlainTextDescription, BusyMarkTextEditingShortcutAction.undo => context.l10n.shortcutUndoDescription, BusyMarkTextEditingShortcutAction.redo => @@ -613,8 +606,7 @@ abstract final class BusyMarkCommandCatalog { BuildContext context, BusyMarkEditorShortcutAction action, ) => switch (action) { - BusyMarkEditorShortcutAction.copyAsMarkdown || - BusyMarkEditorShortcutAction.pastePlainText => + BusyMarkEditorShortcutAction.copyPlainText => context.l10n.shortcutGroupTextEditing, BusyMarkEditorShortcutAction.bold || BusyMarkEditorShortcutAction.italic || diff --git a/lib/src/editor/editor_text_context_menu.dart b/lib/src/editor/editor_text_context_menu.dart index 9ad5e240..c9e24bc8 100644 --- a/lib/src/editor/editor_text_context_menu.dart +++ b/lib/src/editor/editor_text_context_menu.dart @@ -13,7 +13,7 @@ Widget buildBusyMarkEditorTextContextMenu( VoidCallback? onRefineWithAi, VoidCallback? onCut, VoidCallback? onCopy, - VoidCallback? onCopyAsMarkdown, + VoidCallback? onCopyPlainText, List<PopupMenuEntry<VoidCallback>> additionalItems = const [], }) { return _BusyMarkEditorTextContextMenu( @@ -22,7 +22,7 @@ Widget buildBusyMarkEditorTextContextMenu( onRefineWithAi: onRefineWithAi, onCut: onCut, onCopy: onCopy, - onCopyAsMarkdown: onCopyAsMarkdown, + onCopyPlainText: onCopyPlainText, additionalItems: additionalItems, ); } @@ -34,7 +34,7 @@ class _BusyMarkEditorTextContextMenu extends StatefulWidget { required this.onRefineWithAi, required this.onCut, required this.onCopy, - required this.onCopyAsMarkdown, + required this.onCopyPlainText, required this.additionalItems, }); @@ -43,7 +43,7 @@ class _BusyMarkEditorTextContextMenu extends StatefulWidget { final VoidCallback? onRefineWithAi; final VoidCallback? onCut; final VoidCallback? onCopy; - final VoidCallback? onCopyAsMarkdown; + final VoidCallback? onCopyPlainText; final List<PopupMenuEntry<VoidCallback>> additionalItems; @override @@ -91,7 +91,7 @@ class _BusyMarkEditorTextContextMenuState anchorPoint: widget.editableTextState.contextMenuAnchors.primaryAnchor, items: _menuItems(context), session: _menuSession, - width: widget.onCopyAsMarkdown == null + width: widget.onCopyPlainText == null ? BusyMarkSizes.popupMenuMinWidth : BusyMarkSizes.editorContextMenuWidth, ); @@ -136,14 +136,14 @@ class _BusyMarkEditorTextContextMenuState ), ); } - final copyAsMarkdown = widget.onCopyAsMarkdown; + final copyPlainText = widget.onCopyPlainText; if (item.type == ContextMenuButtonType.copy && - copyAsMarkdown != null && + copyPlainText != null && hasSelection) { - final command = commands[BusyMarkCommandIds.editorCopyAsMarkdown]!; + final command = commands[BusyMarkCommandIds.editorCopyPlainText]!; items.add( BusyMarkPopupMenuItem<VoidCallback>( - value: copyAsMarkdown, + value: copyPlainText, label: command.label(context), icon: BusyMarkGlyphs.copy, shortcut: command.shortcut?.label, diff --git a/lib/src/editor/source/source_editor.dart b/lib/src/editor/source/source_editor.dart index 2f6e902e..9dec96e5 100644 --- a/lib/src/editor/source/source_editor.dart +++ b/lib/src/editor/source/source_editor.dart @@ -1414,7 +1414,7 @@ class BusyMarkSourceEditorState extends State<BusyMarkSourceEditor> { case BusyMarkEditorShortcutAction.refineWithAi: unawaited(_runAiEdit()); break; - case BusyMarkEditorShortcutAction.copyAsMarkdown: + case BusyMarkEditorShortcutAction.copyPlainText: final value = _fullEditingValue(); final selection = value.selection; if (selection.isValid && !selection.isCollapsed) { @@ -1540,9 +1540,6 @@ class BusyMarkSourceEditorState extends State<BusyMarkSourceEditor> { SourceCommands.insertBlock(_fullEditingValue(), ' \n'), ); break; - case BusyMarkEditorShortcutAction.pastePlainText: - unawaited(_pastePlainText()); - break; } } @@ -1588,28 +1585,6 @@ class BusyMarkSourceEditorState extends State<BusyMarkSourceEditor> { _applyFullEditingValue(SourceCommands.insertTab(_fullEditingValue())); } - Future<void> _pastePlainText() async { - final data = await Clipboard.getData(Clipboard.kTextPlain); - final text = data?.text; - if (text == null || text.isEmpty) { - return; - } - final value = _fullEditingValue(); - final selection = value.selection; - final nextText = - selection.textBefore(value.text) + - text + - selection.textAfter(value.text); - _applyFullEditingValue( - TextEditingValue( - text: nextText, - selection: TextSelection.collapsed( - offset: selection.start + text.length, - ), - ), - ); - } - void _replaceController({ required String text, required SourceSyntaxLanguage language, diff --git a/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart b/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart index 2c089534..a16e9ee0 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart @@ -167,7 +167,7 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { required this.onFocused, this.onCut, this.onCopy, - this.onCopyAsMarkdown, + this.onCopyPlainText, this.onRefineWithAi, this.editRevision = 0, this.selected = false, @@ -213,7 +213,7 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { final VoidCallback onFocused; final VoidCallback? onCut; final VoidCallback? onCopy; - final VoidCallback? onCopyAsMarkdown; + final VoidCallback? onCopyPlainText; final VoidCallback? onRefineWithAi; final int editRevision; final bool selected; @@ -394,7 +394,7 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { suppressContextMenu: documentSelectionActive, onCut: onCut, onCopy: onCopy, - onCopyAsMarkdown: onCopyAsMarkdown, + onCopyPlainText: onCopyPlainText, ), ); } @@ -555,7 +555,7 @@ class BusyMarkWysiwygBlockField extends StatelessWidget { onRefineWithAi: onRefineWithAi, onCut: onCut, onCopy: onCopy, - onCopyAsMarkdown: onCopyAsMarkdown, + onCopyPlainText: onCopyPlainText, ), onTap: onFocused, onChanged: onChanged, @@ -1471,7 +1471,7 @@ class _TableBlockEditor extends StatelessWidget { this.suppressContextMenu = false, this.onCut, this.onCopy, - this.onCopyAsMarkdown, + this.onCopyPlainText, }); static const double _controlSize = BusyMarkSizes.tableControl; @@ -1497,7 +1497,7 @@ class _TableBlockEditor extends StatelessWidget { final bool suppressContextMenu; final VoidCallback? onCut; final VoidCallback? onCopy; - final VoidCallback? onCopyAsMarkdown; + final VoidCallback? onCopyPlainText; @override Widget build(BuildContext context) { @@ -1584,7 +1584,7 @@ class _TableBlockEditor extends StatelessWidget { suppressContextMenu: suppressContextMenu, onCut: onCut, onCopy: onCopy, - onCopyAsMarkdown: onCopyAsMarkdown, + onCopyPlainText: onCopyPlainText, ), ], ), @@ -1832,7 +1832,7 @@ class _TableCellEditor extends StatefulWidget { this.suppressContextMenu = false, this.onCut, this.onCopy, - this.onCopyAsMarkdown, + this.onCopyPlainText, }); final BusyBlock? cell; @@ -1852,7 +1852,7 @@ class _TableCellEditor extends StatefulWidget { final bool suppressContextMenu; final VoidCallback? onCut; final VoidCallback? onCopy; - final VoidCallback? onCopyAsMarkdown; + final VoidCallback? onCopyPlainText; @override State<_TableCellEditor> createState() => _TableCellEditorState(); @@ -2035,7 +2035,7 @@ class _TableCellEditorState extends State<_TableCellEditor> { refineWithAiLabel: context.l10n.aiRefineWithAi, onCut: widget.onCut, onCopy: widget.onCopy, - onCopyAsMarkdown: widget.onCopyAsMarkdown, + onCopyPlainText: widget.onCopyPlainText, ), onTap: () { final onCellFocused = widget.onCellFocused; diff --git a/lib/src/editor/wysiwyg/wysiwyg_editor.dart b/lib/src/editor/wysiwyg/wysiwyg_editor.dart index bcab0cae..2a2eedbe 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_editor.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_editor.dart @@ -874,7 +874,7 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { onFocused: () => _handleBlockFocused(block.id), onCut: _cutCurrentSelection, onCopy: _copyCurrentSelection, - onCopyAsMarkdown: _copyCurrentSelectionAsMarkdown, + onCopyPlainText: _copyCurrentSelectionAsPlainText, onRefineWithAi: widget.onAiEdit == null ? null : () => unawaited(_runAiEdit(blockId: block.id)), @@ -3543,8 +3543,8 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { case BusyMarkEditorShortcutAction.refineWithAi: unawaited(_runAiEdit()); break; - case BusyMarkEditorShortcutAction.copyAsMarkdown: - _copyCurrentSelectionAsMarkdown(); + case BusyMarkEditorShortcutAction.copyPlainText: + _copyCurrentSelectionAsPlainText(); break; case BusyMarkEditorShortcutAction.bold: _applyInlineCommand(BusyWysiwygInlineCommand.bold); @@ -3630,9 +3630,6 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { case BusyMarkEditorShortcutAction.hardLineBreak: _applyHardBreakCommand(); break; - case BusyMarkEditorShortcutAction.pastePlainText: - unawaited(_pastePlainTextIntoActiveBlock()); - break; } } @@ -3648,7 +3645,6 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { BusyMarkCommandIds.textCut || BusyMarkCommandIds.textCopy || BusyMarkCommandIds.textPaste || - 'text.pastePlainText' || 'text.undo' || 'text.redo' => true, _ => false, @@ -3675,8 +3671,6 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { _copyCurrentSelection(); case BusyMarkCommandIds.textPaste: unawaited(_pasteIntoActiveBlock()); - case 'text.pastePlainText': - unawaited(_pastePlainTextIntoActiveBlock()); case 'text.undo': if (widget.useExternalUndoHistory || !_undoEditorChange()) { widget.onUndo?.call(); @@ -5548,8 +5542,8 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { BusyMarkGlyphs.copy, ), item( - _DocumentSelectionMenuAction.copyAsMarkdown, - BusyMarkCommandIds.editorCopyAsMarkdown, + _DocumentSelectionMenuAction.copyPlainText, + BusyMarkCommandIds.editorCopyPlainText, BusyMarkGlyphs.copy, ), item( @@ -5578,8 +5572,8 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { _cutBlockSelection(); case _DocumentSelectionMenuAction.copy: _copyBlockSelection(); - case _DocumentSelectionMenuAction.copyAsMarkdown: - _copyCurrentSelectionAsMarkdown(); + case _DocumentSelectionMenuAction.copyPlainText: + _copyCurrentSelectionAsPlainText(); case _DocumentSelectionMenuAction.paste: unawaited(_pasteIntoActiveBlock()); case _DocumentSelectionMenuAction.selectAll: @@ -5928,7 +5922,7 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { bool _copyCurrentSelection() => _copyOrCutSelection(cut: false); - bool _copyCurrentSelectionAsMarkdown() { + bool _copyCurrentSelectionAsPlainText() { final documentSelection = _hasBlockSelection; final allRanges = documentSelection ? _selectedTextRanges(null, true) @@ -5940,14 +5934,9 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { .where((range) => _copyTextForRange(range).trim().isNotEmpty) .toList(); if (ranges.isEmpty) return false; - final fragment = WysiwygClipboardFragment( - mode: _documentController.document.mode, - sourcePath: _documentController.document.filePath, - blocks: _clipboardBlocksForRanges(ranges), - ); - final markdown = fragment.markdown; - if (markdown.isEmpty) return false; - unawaited(_writeMarkdownClipboard(markdown, fragment)); + final text = ranges.map(_copyTextForRange).join('\n\n'); + if (text.isEmpty) return false; + unawaited(_writePlainClipboard(text)); return true; } @@ -5991,6 +5980,15 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { return true; } + Future<void> _writePlainClipboard(String text) async { + final success = await _clipboard.write(RichClipboardData(text: text)); + if (!mounted || success) return; + BusyMarkToastOverlay.show( + context, + message: context.l10n.clipboardCopyFailed, + ); + } + Future<void> _writeClipboardSelection({ required WysiwygClipboardFragment fragment, required String text, @@ -6021,20 +6019,6 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { } } - Future<void> _writeMarkdownClipboard( - String markdown, - WysiwygClipboardFragment fragment, - ) async { - final success = await _clipboard.write( - RichClipboardData(text: markdown, fragment: fragment.encode()), - ); - if (!mounted || success) return; - BusyMarkToastOverlay.show( - context, - message: context.l10n.clipboardCopyFailed, - ); - } - List<BusyWysiwygStyledBlock> _clipboardBlocksForRanges( List<_SelectedTextRange> ranges, ) { @@ -6478,7 +6462,7 @@ class _ClipboardTarget { enum _DocumentSelectionMenuAction { cut, copy, - copyAsMarkdown, + copyPlainText, paste, selectAll, refineWithAi, diff --git a/test/src/app_smoke_test.dart b/test/src/app_smoke_test.dart index f51f9ca3..b33ac67c 100644 --- a/test/src/app_smoke_test.dart +++ b/test/src/app_smoke_test.dart @@ -74,7 +74,7 @@ void main() { }, { BusyMarkEditorShortcutAction.refineWithAi: 'Ctrl+G', - BusyMarkEditorShortcutAction.copyAsMarkdown: 'Ctrl+Shift+C', + BusyMarkEditorShortcutAction.copyPlainText: 'Ctrl+Shift+C', BusyMarkEditorShortcutAction.bold: 'Ctrl+B', BusyMarkEditorShortcutAction.italic: 'Ctrl+I', BusyMarkEditorShortcutAction.underline: 'Ctrl+U', @@ -97,9 +97,14 @@ void main() { BusyMarkEditorShortcutAction.codeBlock: 'Ctrl+Shift+K', BusyMarkEditorShortcutAction.image: 'Ctrl+Shift+I', BusyMarkEditorShortcutAction.hardLineBreak: 'Shift+Enter', - BusyMarkEditorShortcutAction.pastePlainText: 'Ctrl+Shift+V', }, ); + expect( + BusyMarkTextEditingShortcuts.definitions.values.map( + (definition) => definition.label, + ), + isNot(contains('Ctrl+Shift+V')), + ); }); test('document view shortcuts are distinct from existing commands', () { diff --git a/test/src/wysiwyg_clipboard_test.dart b/test/src/wysiwyg_clipboard_test.dart index 48d7b38e..e2941f19 100644 --- a/test/src/wysiwyg_clipboard_test.dart +++ b/test/src/wysiwyg_clipboard_test.dart @@ -453,7 +453,7 @@ void main() { for (final label in [ 'Cut', 'Copy', - 'Copy as Markdown', + 'Copy Plain Text', 'Paste', 'Select all', ]) { @@ -471,36 +471,36 @@ void main() { expect(systemData['text'], contains('[ ] First task')); }); - testWidgets( - 'Copy as Markdown serves source externally and structure internally', - (tester) async { - await mount(tester, 'issues', _source, (_) {}); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyC, shift: true); + testWidgets('Copy Plain Text strips formatting in another Editor', ( + tester, + ) async { + await mount(tester, 'issues', _source, (_) {}); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyC, shift: true); - expect(systemData.keys, containsAll(['text', 'fragment'])); - expect(systemData, isNot(contains('html'))); - expect(systemData['text'], startsWith('# Issues')); - expect(systemData['text'], contains('**When**')); - expect(systemData['text'], contains('- [ ] First task')); + expect(systemData.keys, ['text']); + expect(systemData['text'], startsWith('Issues')); + expect( + systemData['text'], + contains('When selecting all, keep formatting.'), + ); + expect(systemData['text'], contains('[ ] First task')); + expect(systemData['text'], isNot(contains('# Issues'))); + expect(systemData['text'], isNot(contains('**When**'))); - var result = ''; - await mount( - tester, - 'destination', - 'Target\n', - (value) => result = value, - ); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyV); - expect(result, contains('# Issues')); - expect(result, contains('**When**')); - expect(result, contains('- [x] Second task')); - }, - ); + var result = ''; + await mount(tester, 'destination', 'Target\n', (value) => result = value); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyV); + expect(result, contains('Issues')); + expect(result, contains('When selecting all, keep formatting.')); + expect(result, isNot(contains('# Issues'))); + expect(result, isNot(contains('**When**'))); + expect(result, isNot(contains('- [x] Second task'))); + }); - testWidgets('document selection menu can copy as Markdown', (tester) async { + testWidgets('document selection menu can copy plain text', (tester) async { await mount(tester, 'issues', _source, (_) {}); await key(tester, LogicalKeyboardKey.keyA); await key(tester, LogicalKeyboardKey.keyA); @@ -510,12 +510,11 @@ void main() { ); await tester.pumpAndSettle(); - await tester.tap(find.text('Copy as Markdown')); + await tester.tap(find.text('Copy Plain Text')); await tester.pumpAndSettle(); - expect(systemData.keys, containsAll(['text', 'fragment'])); - expect(systemData, isNot(contains('html'))); - expect(systemData['text'], startsWith('# Issues')); - expect(systemData['text'], contains('**When**')); + expect(systemData.keys, ['text']); + expect(systemData['text'], startsWith('Issues')); + expect(systemData['text'], isNot(contains('**When**'))); }); testWidgets( @@ -610,34 +609,14 @@ void main() { expect(result, contains('**Bold**')); }); - testWidgets( - 'plain paste and later plain copies never revive cached formatting', - (tester) async { - await copyAll(tester); - var result = ''; - await mount( - tester, - 'destination', - 'Target\n', - (value) => result = value, - ); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyV, shift: true); - expect(result, isNot(contains('# Issues'))); - expect(result, isNot(contains('**When**'))); - final sameText = systemData['text'] as String; - await Clipboard.setData(ClipboardData(text: sameText)); - await mount( - tester, - 'destination2', - 'Target\n', - (value) => result = value, - ); - await key(tester, LogicalKeyboardKey.keyA); - await key(tester, LogicalKeyboardKey.keyV); - expect(result, isNot(contains('**When**'))); - }, - ); + testWidgets('Ctrl+Shift+V is not an Editor paste command', (tester) async { + await copyAll(tester); + var result = 'Target\n'; + await mount(tester, 'destination', result, (value) => result = value); + await key(tester, LogicalKeyboardKey.keyA); + await key(tester, LogicalKeyboardKey.keyV, shift: true); + expect(result, 'Target\n'); + }); testWidgets('failed clipboard write leaves cut selection intact', ( tester, From b88aa47c8bba520f34a4ced9137cf5b5a865ff53 Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Mon, 7 Sep 2026 21:01:15 -0700 Subject: [PATCH 21/37] Refactor TOC view of left sidebar. Add `iconColor` support for native menu items and compact hierarchy indentation improvements --- lib/src/app/busymark_design.dart | 74 ++++-- lib/src/platform/native_menu_service.dart | 4 + .../presentation/workspace_screen.dart | 210 +++++++++++------- linux/runner/my_application.cc | 48 +++- 4 files changed, 236 insertions(+), 100 deletions(-) diff --git a/lib/src/app/busymark_design.dart b/lib/src/app/busymark_design.dart index 6dbff7cd..e66fbd5e 100644 --- a/lib/src/app/busymark_design.dart +++ b/lib/src/app/busymark_design.dart @@ -303,7 +303,7 @@ abstract final class BusyMarkInsets { BusyMarkSpacing.smPlus, ); static const tocHeader = EdgeInsetsDirectional.fromSTEB( - BusyMarkSpacing.sm, + 0, 0, 0, BusyMarkSpacing.sm, @@ -1401,6 +1401,7 @@ List<NativeMenuEntry>? _busyMarkNativeMenuEntries<T>( NativeMenuEntry.command( label: item.label, iconName: BusyMarkGlyphs.nativeMenuIconName(item.icon), + iconColorArgb: item.iconColor?.toARGB32(), shortcut: item.shortcut, enabled: item.enabled, checkable: item.trailingCheck, @@ -1484,6 +1485,7 @@ List<PopupMenuEntry<T>> _busyMarkFallbackItems<T>( value: item.menuValue, label: item.label, icon: item.icon, + iconColor: item.iconColor, shortcut: item.shortcut, enabled: item.enabled, checked: item.checked, @@ -1528,6 +1530,7 @@ class BusyMarkPopupMenuItem<T> extends PopupMenuItem<T> { required T value, required String label, IconData? icon, + Color? iconColor, String? shortcut, super.enabled = true, bool checked = false, @@ -1537,6 +1540,7 @@ class BusyMarkPopupMenuItem<T> extends PopupMenuItem<T> { }) : label = label, menuValue = value, icon = icon, + iconColor = iconColor, shortcut = shortcut, checked = checked, trailingCheck = trailingCheck, @@ -1548,6 +1552,7 @@ class BusyMarkPopupMenuItem<T> extends PopupMenuItem<T> { child: _BusyMarkPopupMenuItemContent( label: label, icon: icon, + iconColor: iconColor, shortcut: shortcut, checked: checked, trailingCheck: trailingCheck, @@ -1559,6 +1564,7 @@ class BusyMarkPopupMenuItem<T> extends PopupMenuItem<T> { final String label; final T menuValue; final IconData? icon; + final Color? iconColor; final String? shortcut; final bool checked; final bool trailingCheck; @@ -1569,6 +1575,7 @@ class _BusyMarkPopupMenuItemContent extends StatelessWidget { const _BusyMarkPopupMenuItemContent({ required this.label, required this.icon, + required this.iconColor, required this.shortcut, required this.checked, required this.trailingCheck, @@ -1577,6 +1584,7 @@ class _BusyMarkPopupMenuItemContent extends StatelessWidget { final String label; final IconData? icon; + final Color? iconColor; final String? shortcut; final bool checked; final bool trailingCheck; @@ -1605,7 +1613,7 @@ class _BusyMarkPopupMenuItemContent extends StatelessWidget { child: Row( children: [ if (icon != null) ...[ - Icon(icon), + Icon(icon, color: iconColor), const SizedBox(width: BusyMarkSpacing.sm), ], Expanded(child: labelText), @@ -1820,11 +1828,13 @@ class BusyMarkPopupSelectorOption<T> { required this.value, required this.label, this.icon, + this.iconColor, }); final T value; final String label; final IconData? icon; + final Color? iconColor; } /// The shared desktop selector used by Settings-style control rows. @@ -1840,6 +1850,9 @@ class BusyMarkPopupSelector<T> extends StatelessWidget { this.popupMinWidth = BusyMarkSizes.languagePopupMinWidth, this.popupMaxWidth = BusyMarkSizes.languagePopupMaxWidth, this.buttonMaxWidth = BusyMarkSizes.languageButtonMaxWidth, + this.leading, + this.fullWidth = false, + this.contentPadding, }); final T? value; @@ -1851,18 +1864,21 @@ class BusyMarkPopupSelector<T> extends StatelessWidget { final double popupMinWidth; final double popupMaxWidth; final double buttonMaxWidth; + final Widget? leading; + final bool fullWidth; + final EdgeInsetsGeometry? contentPadding; @override Widget build(BuildContext context) { final selectorEnabled = enabled && options.isNotEmpty; - final fallbackMenuWidth = buttonMaxWidth.clamp( - popupMinWidth, - popupMaxWidth, - ); + final fallbackMenuWidth = (fullWidth ? popupMaxWidth : buttonMaxWidth) + .clamp(popupMinWidth, popupMaxWidth); return Align( alignment: AlignmentDirectional.centerEnd, child: ConstrainedBox( - constraints: BoxConstraints(maxWidth: buttonMaxWidth), + constraints: BoxConstraints( + maxWidth: fullWidth ? double.infinity : buttonMaxWidth, + ), child: BusyMarkMenuButton<T>( tooltip: tooltip, enabled: selectorEnabled, @@ -1874,6 +1890,7 @@ class BusyMarkPopupSelector<T> extends StatelessWidget { value: option.value, label: option.label, icon: option.icon, + iconColor: option.iconColor, checked: option.value == value, trailingCheck: true, ), @@ -1890,28 +1907,47 @@ class BusyMarkPopupSelector<T> extends StatelessWidget { style: Theme.of(context).outlinedButtonTheme.style ?.copyWith( side: const WidgetStatePropertyAll(BorderSide.none), + padding: contentPadding == null + ? null + : WidgetStatePropertyAll(contentPadding), ), child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisSize: fullWidth + ? MainAxisSize.max + : MainAxisSize.min, children: [ - Flexible( - child: ConstrainedBox( - constraints: BoxConstraints( - maxWidth: math.max( - 0, - buttonMaxWidth - - BusyMarkSizes.iconButton - - BusyMarkSpacing.smPlus, - ), - ), + if (leading != null) ...[ + leading!, + const SizedBox(width: BusyMarkSpacing.sm), + ], + if (fullWidth) + Expanded( child: Text( label, maxLines: 1, overflow: TextOverflow.ellipsis, softWrap: false, ), + ) + else + Flexible( + child: ConstrainedBox( + constraints: BoxConstraints( + maxWidth: math.max( + 0, + buttonMaxWidth - + BusyMarkSizes.iconButton - + BusyMarkSpacing.smPlus, + ), + ), + child: Text( + label, + maxLines: 1, + overflow: TextOverflow.ellipsis, + softWrap: false, + ), + ), ), - ), const SizedBox(width: BusyMarkSpacing.sm), const Icon( BusyMarkGlyphs.downArrow, diff --git a/lib/src/platform/native_menu_service.dart b/lib/src/platform/native_menu_service.dart index 93ba3427..8a2351e8 100644 --- a/lib/src/platform/native_menu_service.dart +++ b/lib/src/platform/native_menu_service.dart @@ -23,6 +23,7 @@ final class NativeMenuEntry { const NativeMenuEntry.command({ required this.label, this.iconName, + this.iconColorArgb, this.shortcut, this.enabled = true, this.checkable = false, @@ -32,6 +33,7 @@ final class NativeMenuEntry { const NativeMenuEntry.separator() : label = '', iconName = null, + iconColorArgb = null, shortcut = null, enabled = false, checkable = false, @@ -40,6 +42,7 @@ final class NativeMenuEntry { final String label; final String? iconName; + final int? iconColorArgb; final String? shortcut; final bool enabled; final bool checkable; @@ -50,6 +53,7 @@ final class NativeMenuEntry { return <String, Object>{ 'label': label, if (iconName != null && iconName!.isNotEmpty) 'icon': iconName!, + if (iconColorArgb != null) 'iconColor': iconColorArgb!, if (shortcut != null && shortcut!.isNotEmpty) 'shortcut': shortcut!, 'enabled': enabled, 'checkable': checkable, diff --git a/lib/src/workspace/presentation/workspace_screen.dart b/lib/src/workspace/presentation/workspace_screen.dart index 8841d3cb..62eada75 100644 --- a/lib/src/workspace/presentation/workspace_screen.dart +++ b/lib/src/workspace/presentation/workspace_screen.dart @@ -4358,6 +4358,7 @@ class _SidebarTreeRow extends StatefulWidget { this.selected = false, this.enabled = true, this.muted = false, + this.compactHierarchyIndent = false, this.vcsColor, this.onToggle, this.onTap, @@ -4373,6 +4374,7 @@ class _SidebarTreeRow extends StatefulWidget { final bool selected; final bool enabled; final bool muted; + final bool compactHierarchyIndent; final BusyMarkVcsFileColor? vcsColor; final VoidCallback? onToggle; final VoidCallback? onTap; @@ -4428,6 +4430,15 @@ class _SidebarTreeRowState extends State<_SidebarTreeRow> { widget.enabled && widget.onMenuRequested != null && (widget.selected || _hovered || _focused); + final depthBase = widget.compactHierarchyIndent + ? 0.0 + : BusyMarkSizes.sidebarTreeDepthBase; + final expanderWidth = widget.compactHierarchyIndent + ? BusyMarkSizes.sidebarTreeArrow + : BusyMarkSizes.sidebarTreeControl; + final expanderGap = widget.compactHierarchyIndent + ? 0.0 + : BusyMarkSpacing.xs; return MouseRegion( onEnter: (_) => setState(() => _hovered = true), onExit: (_) => setState(() => _hovered = false), @@ -4461,11 +4472,11 @@ class _SidebarTreeRowState extends State<_SidebarTreeRow> { children: [ SizedBox( width: - BusyMarkSizes.sidebarTreeDepthBase + + depthBase + widget.depth * BusyMarkSizes.sidebarTreeDepthIndent, ), SizedBox.square( - dimension: BusyMarkSizes.sidebarTreeControl, + dimension: expanderWidth, child: widget.hasChildren ? GestureDetector( behavior: HitTestBehavior.opaque, @@ -4490,7 +4501,7 @@ class _SidebarTreeRowState extends State<_SidebarTreeRow> { ) : const SizedBox.shrink(), ), - const SizedBox(width: BusyMarkSpacing.xs), + SizedBox(width: expanderGap), SizedBox.square( dimension: BusyMarkSizes.sidebarTreeControl, child: Center( @@ -4513,21 +4524,26 @@ class _SidebarTreeRowState extends State<_SidebarTreeRow> { ), ), if (widget.onMenuRequested != null) - SizedBox.square( - dimension: BusyMarkSizes.compactIconButton, - child: menuVisible - ? Builder( - builder: (buttonContext) => - BusyMarkCompactIconButton( - tooltip: context.l10n.actions, - icon: BusyMarkGlyphs.menuVertical, - onPressed: () => widget.onMenuRequested!( - buttonContext, - _sidebarTreeMenuAnchor(buttonContext), + SizedBox( + width: BusyMarkSizes.iconButton, + child: Center( + child: menuVisible + ? Builder( + builder: (buttonContext) => + BusyMarkCompactIconButton( + tooltip: context.l10n.actions, + icon: BusyMarkGlyphs.menuVertical, + onPressed: () => + widget.onMenuRequested!( + buttonContext, + _sidebarTreeMenuAnchor( + buttonContext, + ), + ), ), - ), - ) - : const SizedBox.shrink(), + ) + : const SizedBox.shrink(), + ), ) else const SizedBox(width: BusyMarkSpacing.xs), @@ -5273,6 +5289,7 @@ class _TocTabState extends ConsumerState<_TocTab> { hasChildren: hasChildren, expanded: expanded, muted: node.hidden, + compactHierarchyIndent: true, onToggle: hasChildren ? toggle : null, onTap: topicPath != null ? () async { @@ -6390,40 +6407,45 @@ class _TocHeader extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (modules.length > 1) ...[ - _SidebarHeaderRow( - child: Row( - children: [ - Expanded( - child: Text( - modules - .where((module) => module.id == activeModuleId) - .map((module) => module.label) - .firstOrNull ?? - modules.first.label, - maxLines: 1, - overflow: TextOverflow.ellipsis, - textDirection: TextDirection.ltr, - style: busyMarkSectionHeaderStyle(context), + Padding( + padding: const EdgeInsetsDirectional.only( + start: BusyMarkSpacing.sm, + ), + child: _SidebarHeaderRow( + child: Row( + children: [ + Expanded( + child: Text( + modules + .where((module) => module.id == activeModuleId) + .map((module) => module.label) + .firstOrNull ?? + modules.first.label, + maxLines: 1, + overflow: TextOverflow.ellipsis, + textDirection: TextDirection.ltr, + style: busyMarkSectionHeaderStyle(context), + ), ), - ), - BusyMarkHeaderPopupMenuButton<String>( - key: const ValueKey('writerside-module-selector'), - tooltip: context.l10n.workspaceKindWritersideModule, - icon: BusyMarkGlyphs.menuVertical, - transparent: true, - borderRadius: BusyMarkRadius.nativeHeaderButton, - highlightWhenOpen: false, - itemBuilder: (context) => [ - for (final module in modules) - BusyMarkPopupMenuItem<String>( - value: module.id, - label: module.label, - icon: BusyMarkGlyphs.folder, - ), - ], - onSelected: onSelectModule, - ), - ], + BusyMarkHeaderPopupMenuButton<String>( + key: const ValueKey('writerside-module-selector'), + tooltip: context.l10n.workspaceKindWritersideModule, + icon: BusyMarkGlyphs.menuVertical, + transparent: true, + borderRadius: BusyMarkRadius.nativeHeaderButton, + highlightWhenOpen: false, + itemBuilder: (context) => [ + for (final module in modules) + BusyMarkPopupMenuItem<String>( + value: module.id, + label: module.label, + icon: BusyMarkGlyphs.folder, + ), + ], + onSelected: onSelectModule, + ), + ], + ), ), ), const SizedBox(height: BusyMarkSpacing.sm), @@ -6433,11 +6455,11 @@ class _TocHeader extends StatelessWidget { child: Row( children: [ Expanded( - child: Text( - context.l10n.instances, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: busyMarkSectionHeaderStyle(context), + child: _WritersideInstanceSelector( + instances: instances, + selectedInstance: selectedInstance, + instanceColors: instanceColors, + onSelected: onSelectInstance, ), ), BusyMarkHeaderPopupMenuButton<_TocHeaderAction>( @@ -6494,30 +6516,6 @@ class _TocHeader extends StatelessWidget { ], ), ), - for (final instance in instances) - _SidebarTreeRow( - key: ValueKey('writerside-instance-${instance.id}'), - title: busyMarkLtrIsolateFor(context, instance.name), - depth: 0, - icon: BusyMarkGlyphs.tree, - leading: Icon( - BusyMarkGlyphs.tree, - size: BusyMarkSizes.iconSm, - color: writersideInstanceIconColorValue( - context, - instanceColors[instance.sourceTreePath] ?? - WritersideInstanceIconColor.blue, - ), - ), - hasChildren: false, - expanded: false, - selected: p.equals( - instance.sourceTreePath, - selectedInstance.sourceTreePath, - ), - enabled: true, - onTap: () => onSelectInstance(instance.sourceTreePath), - ), const Divider(height: BusyMarkSpacing.md), ], ), @@ -6525,6 +6523,60 @@ class _TocHeader extends StatelessWidget { } } +class _WritersideInstanceSelector extends StatelessWidget { + const _WritersideInstanceSelector({ + required this.instances, + required this.selectedInstance, + required this.instanceColors, + required this.onSelected, + }); + + final List<WritersideInstance> instances; + final WritersideInstance selectedInstance; + final Map<String, WritersideInstanceIconColor> instanceColors; + final ValueChanged<String> onSelected; + + @override + Widget build(BuildContext context) { + final selectedPath = selectedInstance.sourceTreePath; + final selectedLabel = busyMarkLtrIsolateFor(context, selectedInstance.name); + final selectedColor = writersideInstanceIconColorValue( + context, + instanceColors[selectedPath] ?? WritersideInstanceIconColor.blue, + ); + return BusyMarkPopupSelector<String>( + key: const ValueKey('writerside-instance-selector'), + value: selectedPath, + label: selectedLabel, + tooltip: context.l10n.instances, + options: [ + for (final instance in instances) + BusyMarkPopupSelectorOption<String>( + value: instance.sourceTreePath, + label: busyMarkLtrIsolateFor(context, instance.name), + icon: BusyMarkGlyphs.tree, + iconColor: writersideInstanceIconColorValue( + context, + instanceColors[instance.sourceTreePath] ?? + WritersideInstanceIconColor.blue, + ), + ), + ], + onSelected: onSelected, + leading: Icon( + BusyMarkGlyphs.tree, + size: BusyMarkSizes.iconSm, + color: selectedColor, + ), + fullWidth: true, + contentPadding: const EdgeInsetsDirectional.only( + start: BusyMarkSpacing.headerInset, + end: BusyMarkSpacing.sm, + ), + ); + } +} + WritersideInstanceIconColor _effectiveInstanceIconColor( WritersideInstanceIconColor configured, int index, diff --git a/linux/runner/my_application.cc b/linux/runner/my_application.cc index 54eee74f..f20cac9c 100644 --- a/linux/runner/my_application.cc +++ b/linux/runner/my_application.cc @@ -2462,6 +2462,41 @@ static gboolean parse_native_menu_anchor(FlValue* args, return TRUE; } +static GIcon* create_native_menu_icon(const gchar* icon_name, FlValue* entry) { + if (icon_name == nullptr || icon_name[0] == '\0') { + return nullptr; + } + + FlValue* packed_color = fl_value_lookup_string(entry, "iconColor"); + if (packed_color != nullptr && + fl_value_get_type(packed_color) == FL_VALUE_TYPE_INT) { + const guint32 argb = static_cast<guint32>(fl_value_get_int(packed_color)); + const GdkRGBA foreground = { + static_cast<gdouble>((argb >> 16) & 0xff) / 255.0, + static_cast<gdouble>((argb >> 8) & 0xff) / 255.0, + static_cast<gdouble>(argb & 0xff) / 255.0, + static_cast<gdouble>((argb >> 24) & 0xff) / 255.0, + }; + GtkIconInfo* icon_info = gtk_icon_theme_lookup_icon( + gtk_icon_theme_get_default(), icon_name, 16, + static_cast<GtkIconLookupFlags>(GTK_ICON_LOOKUP_FORCE_SIZE | + GTK_ICON_LOOKUP_FORCE_SYMBOLIC)); + if (icon_info != nullptr) { + gboolean was_symbolic = FALSE; + g_autoptr(GError) error = nullptr; + GdkPixbuf* pixbuf = gtk_icon_info_load_symbolic( + icon_info, &foreground, nullptr, nullptr, nullptr, &was_symbolic, + &error); + g_object_unref(icon_info); + if (pixbuf != nullptr) { + return G_ICON(pixbuf); + } + } + } + + return g_themed_icon_new(icon_name); +} + static void show_native_menu(NativeMenuHandlerData* data, FlMethodCall* method_call, FlValue* args) { @@ -2528,6 +2563,9 @@ static void show_native_menu(NativeMenuHandlerData* data, gboolean in_checkable_run = FALSE; for (size_t index = 0; index < fl_value_get_length(entries); index++) { FlValue* entry = fl_value_get_list_value(entries, index); + FlValue* icon_color = entry == nullptr + ? nullptr + : fl_value_lookup_string(entry, "iconColor"); gboolean separator = FALSE; gboolean enabled = TRUE; gboolean checkable = FALSE; @@ -2545,6 +2583,11 @@ static void show_native_menu(NativeMenuHandlerData* data, (fl_value_lookup_string(entry, "icon") != nullptr && fl_value_get_type(fl_value_lookup_string(entry, "icon")) != FL_VALUE_TYPE_STRING) || + (icon_color != nullptr && + (fl_value_get_type(icon_color) != FL_VALUE_TYPE_INT || + fl_value_get_int(icon_color) < 0 || + fl_value_get_int(icon_color) > + static_cast<gint64>(G_MAXUINT32))) || (selected && !checkable)) { respond_native_menu_argument_error( method_call, @@ -2690,7 +2733,8 @@ static void show_native_menu(NativeMenuHandlerData* data, g_menu_item_set_action_and_target_value( item, detailed_group_action, g_variant_new_string(target)); if (run_icon != nullptr && run_icon[0] != '\0') { - g_autoptr(GIcon) icon = g_themed_icon_new(run_icon); + g_autoptr(GIcon) icon = + create_native_menu_icon(run_icon, run_entry); g_menu_item_set_icon(item, icon); } if (run_shortcut != nullptr && run_shortcut[0] != '\0') { @@ -2718,7 +2762,7 @@ static void show_native_menu(NativeMenuHandlerData* data, g_strdup_printf("%s.%s", kNativeMenuActionNamespace, action_name); g_autoptr(GMenuItem) item = g_menu_item_new(label, detailed_action); if (icon_name != nullptr && icon_name[0] != '\0') { - g_autoptr(GIcon) icon = g_themed_icon_new(icon_name); + g_autoptr(GIcon) icon = create_native_menu_icon(icon_name, entry); g_menu_item_set_icon(item, icon); } if (shortcut != nullptr && shortcut[0] != '\0') { From e38e8d7209ce2dbcfdb915c73832ace0213bc8ec Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Mon, 7 Sep 2026 21:01:33 -0700 Subject: [PATCH 22/37] Add tests for TOC view in left sidebar. --- test/src/app_smoke_test.dart | 132 ++++++++++++++++++++-- test/src/busymark_design_test.dart | 57 +++++++++- test/src/native_headerbar_audit_test.dart | 5 + test/src/native_menu_service_test.dart | 2 + test/src/source_audit_test.dart | 21 ++++ 5 files changed, 204 insertions(+), 13 deletions(-) diff --git a/test/src/app_smoke_test.dart b/test/src/app_smoke_test.dart index b33ac67c..a2200510 100644 --- a/test/src/app_smoke_test.dart +++ b/test/src/app_smoke_test.dart @@ -1889,12 +1889,90 @@ void main() { await tester.tap(find.text(l10n.toc)); await tester.pump(const Duration(milliseconds: 300)); - final guideInstance = find.byKey( - const ValueKey('writerside-instance-guide'), + final instanceSelector = find.byKey( + const ValueKey('writerside-instance-selector'), ); - final apiInstance = find.byKey(const ValueKey('writerside-instance-api')); - expect(guideInstance, findsOneWidget); - expect(apiInstance, findsOneWidget); + expect(instanceSelector, findsOneWidget); + final instanceSelectorButton = find.descendant( + of: instanceSelector, + matching: find.byType(FilledButton), + ); + expect(instanceSelectorButton, findsOneWidget); + expect( + tester + .widget<FilledButton>(instanceSelectorButton) + .style + ?.backgroundColor + ?.resolve({}), + BusyMarkLinuxPalette.transparent, + ); + final instanceSelectorRect = tester.getRect(instanceSelectorButton); + final tocHeaderRowRect = tester.getRect( + find.byKey(const ValueKey('workspace-sidebar-first-content')), + ); + final firstTocRowRect = tester.getRect( + find.byKey(const ValueKey('workspace-sidebar-toc-row-0')), + ); + final primaryIconRect = tester.getRect( + find.descendant( + of: find.byKey(const ValueKey('workspace-sidebar-primary-label')), + matching: find.byType(Icon), + ), + ); + final instanceIconRect = tester.getRect( + find.descendant( + of: instanceSelector, + matching: find.byIcon(BusyMarkGlyphs.tree), + ), + ); + final firstTocIconRect = tester.getRect( + find.descendant( + of: find.byKey(const ValueKey('workspace-sidebar-toc-row-0')), + matching: find.byIcon(BusyMarkGlyphs.document), + ), + ); + expect(instanceIconRect.left, primaryIconRect.left); + expect(firstTocIconRect.left, greaterThan(primaryIconRect.left)); + expect( + firstTocIconRect.left - primaryIconRect.left, + lessThanOrEqualTo(BusyMarkSpacing.smPlus), + ); + expect(tocHeaderRowRect.left, firstTocRowRect.left); + expect(tocHeaderRowRect.right, firstTocRowRect.right); + expect(instanceSelectorRect.left, tocHeaderRowRect.left); + expect(instanceSelectorRect.right, lessThan(tocHeaderRowRect.right)); + final primaryMenuRect = tester.getRect( + find.byTooltip(l10n.sidebarViewMenu), + ); + final tocMenuRect = tester.getRect( + find.descendant( + of: find.byKey(const ValueKey('workspace-sidebar-toc-menu')), + matching: find.byType(IconButton), + ), + ); + final mouse = await tester.createGesture(kind: PointerDeviceKind.mouse); + addTearDown(mouse.removePointer); + await mouse.addPointer(location: Offset.zero); + await mouse.moveTo( + tester.getCenter( + find.byKey(const ValueKey('workspace-sidebar-toc-row-0')), + ), + ); + await tester.pump(); + final tocRowMenuRect = tester.getRect( + find.descendant( + of: find.byKey(const ValueKey('workspace-sidebar-toc-row-0')), + matching: find.byType(IconButton), + ), + ); + expect(tocMenuRect.center.dx, primaryMenuRect.center.dx); + expect(tocRowMenuRect.center.dx, primaryMenuRect.center.dx); + expect(find.text(l10n.instances), findsNothing); + expect( + find.byKey(const ValueKey('writerside-instance-guide')), + findsNothing, + ); + expect(find.byKey(const ValueKey('writerside-instance-api')), findsNothing); expect( find.byKey(const ValueKey('writerside-module-selector')), findsOneWidget, @@ -1903,26 +1981,56 @@ void main() { await tester.tap(find.text('shared-docs')); await tester.pump(const Duration(milliseconds: 200)); expect(controller.selectedWritersideModuleId, 'shared-docs'); - await tester.tap(apiInstance); - await tester.pump(const Duration(milliseconds: 200)); - expect(controller.selectedWritersideInstanceId, 'api'); - await tester.tap(guideInstance); - await tester.pump(const Duration(milliseconds: 200)); final guideIcon = tester.widget<Icon>( + find.descendant( + of: instanceSelector, + matching: find.byIcon(BusyMarkGlyphs.tree), + ), + ); + await openPopup(instanceSelector); + final apiInstance = find.byWidgetPredicate( + (widget) => + widget is BusyMarkPopupMenuItem<String> && + widget.label.contains('API Reference'), + ); + final guideInstance = find.byWidgetPredicate( + (widget) => + widget is BusyMarkPopupMenuItem<String> && + widget.label.contains('Guide'), + ); + expect(apiInstance, findsOneWidget); + expect(guideInstance, findsOneWidget); + final guideOptionIcon = tester.widget<Icon>( find.descendant( of: guideInstance, matching: find.byIcon(BusyMarkGlyphs.tree), ), ); - final apiIcon = tester.widget<Icon>( + final apiOptionIcon = tester.widget<Icon>( find.descendant( of: apiInstance, matching: find.byIcon(BusyMarkGlyphs.tree), ), ); + expect(guideOptionIcon.color, guideIcon.color); + expect(apiOptionIcon.color, isNotNull); + expect(apiOptionIcon.color, isNot(guideOptionIcon.color)); + await tester.tap(apiInstance); + await tester.pump(const Duration(milliseconds: 200)); + expect(controller.selectedWritersideInstanceId, 'api'); + final apiIcon = tester.widget<Icon>( + find.descendant( + of: instanceSelector, + matching: find.byIcon(BusyMarkGlyphs.tree), + ), + ); expect(guideIcon.color, isNotNull); expect(apiIcon.color, isNotNull); expect(guideIcon.color, isNot(apiIcon.color)); + await openPopup(instanceSelector); + expect(guideInstance, findsOneWidget); + await tester.tap(guideInstance); + await tester.pump(const Duration(milliseconds: 200)); expect(find.text('Nested entry'), findsOneWidget); expect(find.byTooltip(l10n.tocActions), findsOneWidget); @@ -2019,6 +2127,7 @@ void main() { expect(controller.createdTopicRequest!.referenceTopic, isNull); expect(controller.createdTopicTreePath, p.join(root.path, 'guide.tree')); + await openPopup(instanceSelector); await tester.tap(apiInstance); await tester.pump(const Duration(milliseconds: 300)); expect(find.text('api.md'), findsOneWidget); @@ -2036,6 +2145,7 @@ void main() { await tester.pump(const Duration(milliseconds: 300)); expect(controller.createdTopicTreePath, p.join(root.path, 'api.tree')); + await openPopup(instanceSelector); await tester.tap(guideInstance); await tester.pump(const Duration(milliseconds: 300)); diff --git a/test/src/busymark_design_test.dart b/test/src/busymark_design_test.dart index 25c89ce3..192850d0 100644 --- a/test/src/busymark_design_test.dart +++ b/test/src/busymark_design_test.dart @@ -168,10 +168,10 @@ void main() { expect(header.bottom + BusyMarkInsets.sidebarList.top, BusyMarkSpacing.sm); expect(tocLtr.top, 0); - expect(tocLtr.left, BusyMarkSpacing.sm); + expect(tocLtr.left, 0); expect(tocLtr.right, 0); expect(tocRtl.left, 0); - expect(tocRtl.right, BusyMarkSpacing.sm); + expect(tocRtl.right, 0); }); testWidgets('header controls delegate geometry and elevation to Yaru', ( @@ -617,6 +617,59 @@ void main() { }, ); + testWidgets('colored popup icons stay on the native menu path', ( + tester, + ) async { + const channel = MethodChannel('busymark/test/colored-popup-menu'); + MethodCall? showCall; + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, (call) async { + if (call.method == 'show') { + showCall = call; + return 0; + } + return null; + }); + addTearDown(() { + TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger + .setMockMethodCallHandler(channel, null); + }); + String? selection; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: BusyMarkHeaderPopupMenuButton<String>( + tooltip: 'Colored menu', + icon: BusyMarkGlyphs.menuVertical, + nativeMenuService: const NativeMenuService(channel: channel), + itemBuilder: (_) => [ + BusyMarkPopupMenuItem<String>( + value: 'guide', + label: 'Guide', + icon: BusyMarkGlyphs.tree, + iconColor: Colors.orange, + ), + ], + onSelected: (value) => selection = value, + ), + ), + ), + ); + + await tester.tap(find.byTooltip('Colored menu')); + await tester.pumpAndSettle(); + + expect(selection, 'guide'); + expect(showCall?.method, 'show'); + final arguments = showCall?.arguments as Map<Object?, Object?>; + expect( + (arguments['entries'] as List<Object?>).single, + containsPair('iconColor', Colors.orange.toARGB32()), + ); + expect(find.text('Guide'), findsNothing); + }); + testWidgets('header popup preserves asynchronous menu loading', ( tester, ) async { diff --git a/test/src/native_headerbar_audit_test.dart b/test/src/native_headerbar_audit_test.dart index 08047d63..1af22882 100644 --- a/test/src/native_headerbar_audit_test.dart +++ b/test/src/native_headerbar_audit_test.dart @@ -1611,7 +1611,9 @@ void main() { expect(nativeMenu, isNot(contains('wl_display_'))); expect(service, contains('final String? shortcut')); expect(service, contains('final String? iconName')); + expect(service, contains('final int? iconColorArgb')); expect(service, contains("'icon': iconName!")); + expect(service, contains("'iconColor': iconColorArgb!")); expect(service, contains("'shortcut': shortcut!")); expect(service, contains('this.checkable = false')); expect(service, contains('separator = false')); @@ -1621,6 +1623,9 @@ void main() { design, contains('iconName: BusyMarkGlyphs.nativeMenuIconName(item.icon)'), ); + expect(design, contains('iconColorArgb: item.iconColor?.toARGB32()')); + expect(nativeMenu, contains('create_native_menu_icon(')); + expect(nativeMenu, contains('gtk_icon_info_load_symbolic(')); expect(design, contains('shortcut: item.shortcut')); expect(design, contains('checkable: item.trailingCheck')); expect(design, contains('class BusyMarkMenuButton<T>')); diff --git a/test/src/native_menu_service_test.dart b/test/src/native_menu_service_test.dart index 92b518a3..932c9cb7 100644 --- a/test/src/native_menu_service_test.dart +++ b/test/src/native_menu_service_test.dart @@ -28,6 +28,7 @@ void main() { NativeMenuEntry.command( label: 'Open', iconName: 'document-open-symbolic', + iconColorArgb: 0xff3584e4, shortcut: 'Ctrl+O', checkable: true, selected: true, @@ -49,6 +50,7 @@ void main() { { 'label': 'Open', 'icon': 'document-open-symbolic', + 'iconColor': 0xff3584e4, 'shortcut': 'Ctrl+O', 'enabled': true, 'checkable': true, diff --git a/test/src/source_audit_test.dart b/test/src/source_audit_test.dart index b77457d7..dc4dcc14 100644 --- a/test/src/source_audit_test.dart +++ b/test/src/source_audit_test.dart @@ -1422,6 +1422,26 @@ void main() { tocHeader, contains('BusyMarkHeaderPopupMenuButton<_TocHeaderAction>'), ); + expect(tocHeader, contains('class _WritersideInstanceSelector')); + expect(tocHeader, contains('BusyMarkPopupSelector<String>')); + expect(tocHeader, contains('fullWidth: true')); + expect(tocHeader, contains('contentPadding: const EdgeInsetsDirectional')); + expect(tocHeader, contains('iconColor: writersideInstanceIconColorValue')); + expect(tocHeader, contains("ValueKey('writerside-instance-selector')")); + expect( + tocHeader, + isNot( + contains('child: Text(\n context.l10n.instances'), + ), + ); + expect( + tocHeader, + isNot( + contains( + 'for (final instance in instances)\n _SidebarTreeRow', + ), + ), + ); expect(tocHeader, contains("ValueKey('workspace-sidebar-toc-menu')")); expect(tocHeader, contains('tooltip: context.l10n.tocActions')); expect(tocHeader, contains('icon: BusyMarkGlyphs.menuVertical')); @@ -1432,6 +1452,7 @@ void main() { expect(tocHeader, isNot(contains('onCreateChildTopic'))); expect(workspace, contains('_TocTreeAction.newChildTopic')); expect(workspace, contains('label: context.l10n.newChildTopic')); + expect(workspace, contains('compactHierarchyIndent: true')); expect(workspace, contains('_SidebarTab.git,')); expect(workspace, isNot(contains('class _FileTreeRow'))); expect(workspace, isNot(contains('class _SidebarTile'))); From 14e9b6d6c0a76a53727bb5a56591011dba001c6c Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Mon, 7 Sep 2026 21:29:44 -0700 Subject: [PATCH 23/37] Add support for excluding PDF outline in Markdown export --- assets/export/markdown.typ | 2 +- docs/writerside-pdf-export.md | 9 +- lib/src/export/markdown_export_mapper.dart | 1 + .../export/writerside_pdf_export_service.dart | 124 ++++++++-- lib/src/export/writerside_pdf_export_ui.dart | 5 +- .../writerside_document_renderer.dart | 30 ++- .../writerside_document_resolver.dart | 21 +- test/src/writerside_pdf_export_test.dart | 229 +++++++++++++++--- 8 files changed, 364 insertions(+), 57 deletions(-) diff --git a/assets/export/markdown.typ b/assets/export/markdown.typ index f3077dc9..226eaeda 100644 --- a/assets/export/markdown.typ +++ b/assets/export/markdown.typ @@ -254,7 +254,7 @@ if kind == "heading" { let element = heading( level: value-or(block-data, "level", 1), - outlined: true, + outlined: value-or(block-data, "outlined", true), render-inlines(inlines), ) let anchor = value-or(block-data, "id", "") diff --git a/docs/writerside-pdf-export.md b/docs/writerside-pdf-export.md index c35ad0ea..0382cddf 100644 --- a/docs/writerside-pdf-export.md +++ b/docs/writerside-pdf-export.md @@ -28,8 +28,9 @@ Generated TOC and heading numbering use the exported heading structure without changing topic source. Custom typography also controls heading and equation sizing; custom dimensions and margins determine the available content width. -The instance's resolved TOC determines topic order. Hidden and work-in-progress -TOC entries are omitted unless a work-in-progress topic is the configured start +The instance's resolved TOC determines topic order. Hidden topics remain in the +PDF but do not appear in its generated table of contents. Work-in-progress TOC +entries are omitted unless a work-in-progress topic is the configured start page. Reused TOC sections already resolved by BusyMark participate in the same ordering. Project variables are substituted in recognized variable tokens. @@ -72,4 +73,6 @@ native export. BusyMark is not the JetBrains Writerside publication builder. The native export targets a reliable offline PDF of the syntax BusyMark understands; teams that need byte-for-byte parity with JetBrains website artifacts can still run -JetBrains' separate CI tooling outside BusyMark. +JetBrains' separate CI tooling outside BusyMark. BusyMark does not import +`cfg/PDF.xml`; configure the cover-free page layout, generated table of contents, +running text, and page numbers in BusyMark's export dialog. diff --git a/lib/src/export/markdown_export_mapper.dart b/lib/src/export/markdown_export_mapper.dart index 6243a8c9..1a9ba3e9 100644 --- a/lib/src/export/markdown_export_mapper.dart +++ b/lib/src/export/markdown_export_mapper.dart @@ -247,6 +247,7 @@ class MarkdownExportMapper { attributes: { 'level': level, if (_safeAnchor(block.attributes['id']) case final id?) 'id': id, + if (block.attributes['pdf-outline'] == 'false') 'outlined': false, }, ); } diff --git a/lib/src/export/writerside_pdf_export_service.dart b/lib/src/export/writerside_pdf_export_service.dart index 9008978a..c8692d9a 100644 --- a/lib/src/export/writerside_pdf_export_service.dart +++ b/lib/src/export/writerside_pdf_export_service.dart @@ -89,6 +89,18 @@ class WritersidePdfExportService { detail: 'Unknown or non-exportable instance: ${request.instanceId}', ); } + final moduleDiagnostics = _moduleDiagnosticsForExport(module); + final moduleErrors = moduleDiagnostics.where( + (diagnostic) => diagnostic.severity == DiagnosticSeverity.error, + ); + if (moduleErrors.isNotEmpty) { + throw WritersidePdfExportException( + WritersidePdfFailureCode.invalidRequest, + detail: + 'Writerside module validation failed: ' + '${moduleErrors.map((diagnostic) => diagnostic.code).toSet().join(', ')}', + ); + } final composition = await _composeInstanceDocument( module, instance, @@ -133,6 +145,12 @@ class WritersidePdfExportService { destinationPath: result.destinationPath, pageCount: result.pageCount, warnings: [ + ...moduleDiagnostics.map( + (diagnostic) => MarkdownPdfWarning( + MarkdownPdfWarningCode.writersideResolution, + diagnostic.code, + ), + ), ...composition.diagnostics.map( (diagnostic) => MarkdownPdfWarning( MarkdownPdfWarningCode.writersideResolution, @@ -193,35 +211,67 @@ class WritersidePdfExportService { Map<String, WritersideModule> modulesByOrigin, WritersidePdfCancellationToken token, ) async { - final selected = <({WritersideTopic topic, String? title})>[]; - final seen = <String>{}; + final selected = <({WritersideTopic topic, bool hidden})>[]; + final selectedIndices = <String, int>{}; - void addReference(String? reference, String? title) { + void addReference(String? reference, {required bool hidden}) { if (reference == null) { return; } final topic = module.topicByReference(reference); - if (topic != null && seen.add(topic.filePath)) { - selected.add((topic: topic, title: title)); + if (topic == null) return; + final existingIndex = selectedIndices[topic.filePath]; + if (existingIndex == null) { + selectedIndices[topic.filePath] = selected.length; + selected.add((topic: topic, hidden: hidden)); + } else if (selected[existingIndex].hidden && !hidden) { + selected[existingIndex] = (topic: topic, hidden: false); } } void addNode(TocNode node) { - if (!node.hidden && !node.workInProgress) { - addReference(node.topicReference, node.tocTitle); + if (!node.workInProgress) { + addReference(node.topicReference, hidden: node.hidden); } for (final child in node.children) { addNode(child); } } - addReference(instance.startPage, null); for (final root in instance.navigationTocRoots) { addNode(root); } + final startTopic = instance.startPage == null + ? null + : module.topicByReference(instance.startPage!); + if (startTopic != null) { + final startNodes = instance.navigationTocRoots + .expand((root) => root.flatten()) + .where( + (node) => + node.topicReference != null && + module.topicByReference(node.topicReference!)?.filePath == + startTopic.filePath, + ) + .toList(growable: false); + final startHidden = + startNodes.isNotEmpty && startNodes.every((node) => node.hidden); + final existingIndex = selectedIndices[startTopic.filePath]; + final start = existingIndex == null + ? (topic: startTopic, hidden: startHidden) + : selected.removeAt(existingIndex); + selected.insert(0, start); + selectedIndices + ..clear() + ..addEntries( + selected.indexed.map( + (entry) => MapEntry(entry.$2.topic.filePath, entry.$1), + ), + ); + } if (selected.isEmpty) { for (final reference in instance.topicFileSet) { - addReference(reference, null); + addReference(reference, hidden: false); } } if (selected.length > maximumTopics) { @@ -286,14 +336,16 @@ class WritersidePdfExportService { ), ); } - final rendered = documentRenderer.toBusyDocument( + var rendered = documentRenderer.toBusyDocument( resolved.document, - title: - selection.title ?? - resolved.title ?? - _topicTitle(parsedTopic, instance.id), + title: resolved.title ?? _topicTitle(parsedTopic, instance.id), includeTitleHeading: true, ); + if (selection.hidden) { + rendered = rendered.copyWith( + blocks: rendered.blocks.map(_excludeHeadingsFromPdfOutline).toList(), + ); + } final assets = await _resolveBusyAssets( module, parsedTopic, @@ -321,6 +373,50 @@ class WritersidePdfExportService { topic.title; } + BusyBlock _excludeHeadingsFromPdfOutline(BusyBlock block) { + return block.copyWith( + attributes: { + ...block.attributes, + if (block.kind == BusyBlockKind.heading) 'pdf-outline': 'false', + }, + children: block.children + .map(_excludeHeadingsFromPdfOutline) + .toList(growable: false), + ); + } + + List<Diagnostic> _moduleDiagnosticsForExport(WritersideModule module) { + return [ + for (final diagnostic in module.diagnostics) + if (!_isDeferredCrossModuleDiagnostic(module, diagnostic)) diagnostic, + ]; + } + + bool _isDeferredCrossModuleDiagnostic( + WritersideModule module, + Diagnostic diagnostic, + ) { + if (!{ + 'writerside.include.unresolved-source', + 'writerside.include.unresolved-element', + }.contains(diagnostic.code)) { + return false; + } + final span = diagnostic.sourceSpan; + if (span == null) return false; + final topic = module.topics + .where((candidate) => p.equals(candidate.filePath, diagnostic.filePath)) + .firstOrNull; + if (topic == null) return false; + return topic.document.elements.any( + (element) => + element.name == 'include' && + element.attributes['origin']?.trim().isNotEmpty == true && + element.span.startOffset <= span.startOffset && + element.span.endOffset >= span.endOffset, + ); + } + Future<BusyDocument> _resolveBusyAssets( WritersideModule module, WritersideTopic topic, diff --git a/lib/src/export/writerside_pdf_export_ui.dart b/lib/src/export/writerside_pdf_export_ui.dart index 1a79166b..cc118280 100644 --- a/lib/src/export/writerside_pdf_export_ui.dart +++ b/lib/src/export/writerside_pdf_export_ui.dart @@ -140,9 +140,12 @@ Future<void> exportWritersideModuleToPdf( } final result = outcome.result!; final fileName = p.basename(result.destinationPath); + final message = result.warnings.isEmpty + ? context.l10n.pdfExported(fileName) + : context.l10n.pdfExportedWithWarnings(fileName, result.warnings.length); BusyMarkToastOverlay.show( context, - message: context.l10n.pdfExported(fileName), + message: message, actionLabel: context.l10n.open, onAction: () => unawaited( launchUrl( diff --git a/lib/src/writerside/writerside_document_renderer.dart b/lib/src/writerside/writerside_document_renderer.dart index a191442b..4e600266 100644 --- a/lib/src/writerside/writerside_document_renderer.dart +++ b/lib/src/writerside/writerside_document_renderer.dart @@ -19,8 +19,13 @@ class WritersideDocumentRenderer { bool includeTitleHeading = false, int titleHeadingLevel = 1, }) { + final hasGeneratedTitle = + includeTitleHeading && title?.trim().isNotEmpty == true; + final contentNodes = hasGeneratedTitle + ? _withoutMarkdownTopicTitle(document) + : document.nodes; var blocks = <BusyBlock>[ - if (includeTitleHeading && title?.trim().isNotEmpty == true) + if (hasGeneratedTitle) BusyBlock( id: 'writerside-document-title', kind: BusyBlockKind.heading, @@ -32,7 +37,7 @@ class WritersideDocumentRenderer { }, isGenerated: true, ), - ..._blocks(document.nodes, headingLevel: titleHeadingLevel + 1), + ..._blocks(contentNodes, headingLevel: titleHeadingLevel + 1), ]; final keys = <String>{}; void inlineKeys(Iterable<BusyInline> values) { @@ -154,6 +159,27 @@ class WritersideDocumentRenderer { ); } + List<WritersideDocumentNode> _withoutMarkdownTopicTitle( + WritersideDocument document, + ) { + if (document.format != WritersideDocumentFormat.markdown) { + return document.nodes; + } + final nodes = <WritersideDocumentNode>[]; + var removed = false; + for (final node in document.nodes) { + if (!removed && + node is WritersideMarkdownBlockNode && + node.block.kind == BusyBlockKind.heading && + node.block.attributes['level'] == '1') { + removed = true; + continue; + } + nodes.add(node); + } + return nodes; + } + List<BusyBlock> _blocks( Iterable<WritersideDocumentNode> nodes, { required int headingLevel, diff --git a/lib/src/writerside/writerside_document_resolver.dart b/lib/src/writerside/writerside_document_resolver.dart index e5a6e5a9..1fec08a8 100644 --- a/lib/src/writerside/writerside_document_resolver.dart +++ b/lib/src/writerside/writerside_document_resolver.dart @@ -968,10 +968,8 @@ class _ResolveState { String? titleFor(WritersideDocument document) { final root = document.rootElement; - if (root == null) { - return context.topic.title; - } - final conditional = root.children + final titleScope = root?.children ?? document.nodes; + final conditional = titleScope .whereType<WritersideElementNode>() .where( (element) => element.semanticKind == WritersideSemanticKind.title, @@ -979,7 +977,20 @@ class _ResolveState { .map((element) => element.plainText.trim()) .where((title) => title.isNotEmpty) .firstOrNull; - return conditional ?? root.attributes['title']?.trim(); + if (conditional != null) return conditional; + final rootTitle = root?.attributes['title']?.trim(); + if (rootTitle?.isNotEmpty == true) return rootTitle; + final markdownTitle = document.nodes + .whereType<WritersideMarkdownBlockNode>() + .where( + (node) => + node.block.kind == BusyBlockKind.heading && + node.block.attributes['level'] == '1', + ) + .map((node) => node.block.plainText.trim()) + .where((title) => title.isNotEmpty) + .firstOrNull; + return markdownTitle ?? context.topic.title; } void _referenceDiagnostic({ diff --git a/test/src/writerside_pdf_export_test.dart b/test/src/writerside_pdf_export_test.dart index 6334866b..9864a79e 100644 --- a/test/src/writerside_pdf_export_test.dart +++ b/test/src/writerside_pdf_export_test.dart @@ -15,7 +15,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:path/path.dart' as p; void main() { - const compiler = 'build/linux/x64/release/bundle/libexec/busymark/typst'; + final compiler = _bundledTypstCompiler(); test( 'bundled Typst compiles semantic tables, anchors and glossary footnotes', () async { @@ -55,7 +55,7 @@ void main() { 'assets/export/markdown.typ', ).copy(p.join(fixture.root.path, 'main.typ')); final pdf = p.join(fixture.root.path, 'semantic.pdf'); - final result = await Process.run(p.absolute(compiler), [ + final result = await Process.run(compiler!, [ 'compile', p.join(fixture.root.path, 'main.typ'), pdf, @@ -63,7 +63,7 @@ void main() { expect(result.exitCode, 0, reason: '${result.stderr}'); expect(await File(pdf).length(), greaterThan(1000)); }, - skip: !File(compiler).existsSync(), + skip: compiler == null, ); test( @@ -121,6 +121,46 @@ void main() { }, ); + test('Markdown topic links retain their PDF destinations', () async { + final fixture = await _WritersideFixture.create(); + addTearDown(fixture.dispose); + await File(p.join(fixture.module.path, 'topics', 'intro.md')).writeAsString( + '# Introduction\n\n[Advanced details](advanced.topic#details)\n', + ); + await File( + p.join(fixture.module.path, 'topics', 'advanced.topic'), + ).writeAsString( + '<topic id="advanced" title="Advanced">' + '<p id="details">Detailed instructions.</p>' + '</topic>', + ); + final exporter = _RecordingMarkdownExporter(); + + await WritersidePdfExportService(markdownExporter: exporter).export( + WritersidePdfExportRequest( + moduleRoot: fixture.module.path, + projectRoot: fixture.root.path, + instanceId: 'guide', + destinationPath: p.join(fixture.root.path, 'markdown-link.pdf'), + overwrite: false, + ), + ); + + final document = const MarkdownExportMapper().map( + exporter.request!.document!, + ); + final blocks = _allExportBlocks(document.blocks).toList(); + final link = blocks + .expand((block) => block.inlines) + .singleWhere((inline) => inline.text == 'Advanced details'); + expect(link.kind, MarkdownExportInlineKind.link); + expect(link.destination, startsWith('#ws-')); + expect( + blocks.map((block) => block.attributes['anchor']), + contains(link.destination!.substring(1)), + ); + }); + test( 'native export composes the selected instance without a container runtime', () async { @@ -211,6 +251,61 @@ void main() { }, ); + test( + 'hidden topics remain content and toc-title stays navigation-only', + () async { + final fixture = await _WritersideFixture.create(); + addTearDown(fixture.dispose); + await File(p.join(fixture.module.path, 'guide.tree')).writeAsString(''' +<instance-profile id="guide" name="Guide" start-page="intro.md"> + <toc-element topic="intro.md" toc-title="Short navigation title"/> + <toc-element topic="hidden.md" hidden="true"/> + <toc-element topic="draft.md" wip="true"/> +</instance-profile> +'''); + await File( + p.join(fixture.module.path, 'topics', 'hidden.md'), + ).writeAsString('# Legal information\n\nRequired legal notice.\n'); + await File( + p.join(fixture.module.path, 'topics', 'draft.md'), + ).writeAsString('# Draft\n\nUnreleased instructions.\n'); + final exporter = _RecordingMarkdownExporter(); + + await WritersidePdfExportService(markdownExporter: exporter).export( + WritersidePdfExportRequest( + moduleRoot: fixture.module.path, + projectRoot: fixture.root.path, + instanceId: 'guide', + destinationPath: p.join(fixture.root.path, 'hidden.pdf'), + overwrite: false, + ), + ); + + final blocks = _allBlocks(exporter.request!.document!.blocks).toList(); + final headings = blocks + .where((block) => block.kind == BusyBlockKind.heading) + .map((block) => block.plainText) + .toList(); + final text = blocks.map((block) => block.plainText).join('\n'); + expect( + headings, + containsAllInOrder(['BusyMark Guide', 'Legal information']), + ); + expect(headings, isNot(contains('Short navigation title'))); + expect(text, contains('Required legal notice.')); + expect(text, isNot(contains('Unreleased instructions.'))); + final mapped = const MarkdownExportMapper().map( + exporter.request!.document!, + ); + final legalHeading = mapped.blocks.singleWhere( + (block) => + block.kind == MarkdownExportBlockKind.heading && + block.inlines.any((inline) => inline.text == 'Legal information'), + ); + expect(legalHeading.attributes['outlined'], isFalse); + }, + ); + test( 'referenced diagrams keep resolved source and all tab panels reach PDF', () async { @@ -344,6 +439,81 @@ void main() { expect(exporter.request, isNull); }); + test('module validation errors prevent PDF compilation', () async { + final fixture = await _WritersideFixture.create(); + addTearDown(fixture.dispose); + await File(p.join(fixture.module.path, 'guide.tree')).writeAsString(''' +<instance-profile id="guide" name="Guide" start-page="intro.md"> + <toc-element topic="intro.md"/> + <toc-element topic="missing.topic"/> +</instance-profile> +'''); + final exporter = _RecordingMarkdownExporter(); + + await expectLater( + WritersidePdfExportService(markdownExporter: exporter).export( + WritersidePdfExportRequest( + moduleRoot: fixture.module.path, + projectRoot: fixture.root.path, + instanceId: 'guide', + destinationPath: p.join(fixture.root.path, 'invalid-module.pdf'), + overwrite: false, + ), + ), + throwsA( + isA<WritersidePdfExportException>() + .having( + (error) => error.code, + 'code', + WritersidePdfFailureCode.invalidRequest, + ) + .having( + (error) => error.detail, + 'detail', + contains('writerside.tree.missing-topic'), + ), + ), + ); + expect(exporter.request, isNull); + }); + + test('module validation warnings are returned to the caller', () async { + final fixture = await _WritersideFixture.create(); + addTearDown(fixture.dispose); + await File( + p.join(fixture.module.path, 'topics', 'unused.topic'), + ).writeAsString('<topic id="unused"><p>Untitled topic.</p></topic>'); + final exporter = _RecordingMarkdownExporter(); + + final result = await WritersidePdfExportService(markdownExporter: exporter) + .export( + WritersidePdfExportRequest( + moduleRoot: fixture.module.path, + projectRoot: fixture.root.path, + instanceId: 'guide', + destinationPath: p.join(fixture.root.path, 'module-warning.pdf'), + overwrite: false, + ), + ); + + expect( + result.warnings, + contains( + isA<MarkdownPdfWarning>() + .having( + (warning) => warning.code, + 'code', + MarkdownPdfWarningCode.writersideResolution, + ) + .having( + (warning) => warning.destination, + 'diagnostic', + 'writerside.topic.missing-title', + ), + ), + ); + }); + test( 'nonfatal resolution diagnostics are returned as PDF warnings', () async { @@ -422,7 +592,7 @@ void main() { }); test( - 'native Writerside demo runs through the bundled PDF pipeline', + 'native Writerside demo compiles end to end with bundled Typst', () async { final output = await Directory.systemTemp.createTemp( 'busymark-writerside-native-pdf-', @@ -430,12 +600,11 @@ void main() { addTearDown(() => output.delete(recursive: true)); final module = Directory('demo/writerside-instances').absolute; final destination = p.join(output.path, 'writerside-demo.pdf'); - const service = WritersidePdfExportService( + final service = WritersidePdfExportService( markdownExporter: MarkdownPdfExportService( compilerLocator: TypstCompilerLocator( - environment: {'BUSYMARK_TYPST_PATH': '/bin/true'}, + environment: {'BUSYMARK_TYPST_PATH': compiler!}, ), - commandRunner: _PdfWritingTypstRunner(), ), ); @@ -449,11 +618,23 @@ void main() { ); expect(await File(destination).length(), greaterThan(1024)); - expect(result.pageCount, isNotNull); + expect(result.destinationPath, p.normalize(p.absolute(destination))); }, + skip: compiler == null, ); } +String? _bundledTypstCompiler() { + for (final candidate in [ + 'build/linux/x64/release/bundle/libexec/busymark/typst', + 'build/linux/x64/debug/bundle/libexec/busymark/typst', + ]) { + final absolute = p.absolute(candidate); + if (File(absolute).existsSync()) return absolute; + } + return null; +} + Iterable<BusyBlock> _allBlocks(Iterable<BusyBlock> blocks) sync* { for (final block in blocks) { yield block; @@ -461,6 +642,15 @@ Iterable<BusyBlock> _allBlocks(Iterable<BusyBlock> blocks) sync* { } } +Iterable<MarkdownExportBlock> _allExportBlocks( + Iterable<MarkdownExportBlock> blocks, +) sync* { + for (final block in blocks) { + yield block; + yield* _allExportBlocks(block.children); + } +} + Iterable<BusyInline> _allInlines(Iterable<BusyInline> inlines) sync* { for (final inline in inlines) { yield inline; @@ -575,26 +765,3 @@ class _RecordingMarkdownExporter extends MarkdownPdfExportService { ); } } - -class _PdfWritingTypstRunner implements TypstCommandRunner { - const _PdfWritingTypstRunner(); - - @override - Future<TypstProcessResult> compile({ - required String executable, - required Directory workingDirectory, - required Duration timeout, - required MarkdownPdfCancellationToken cancellationToken, - }) async { - cancellationToken.throwIfCancelled(); - final bytes = <int>[ - ...'%PDF-1.7\n1 0 obj\n<< /Type /Page >>\nendobj\n'.codeUnits, - ...List<int>.filled(1200, 0x20), - ...'\n%%EOF\n'.codeUnits, - ]; - await File( - p.join(workingDirectory.path, 'output.pdf'), - ).writeAsBytes(bytes, flush: true); - return const TypstProcessResult(exitCode: 0, stdout: '', stderr: ''); - } -} From 90e194cfa1f8cbb4060b6e273175ea839a1b87f1 Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Tue, 8 Sep 2026 11:34:26 -0700 Subject: [PATCH 24/37] Make the instance dropdown and adjacent TOC Actions button 34 px high and vertically centered. --- .github/workflows/flutter-linux.yml | 3 + README.md | 8 +- docs/html-export-verification.md | 6 +- lib/l10n/app_ar.arb | 5 +- lib/l10n/app_de.arb | 3 +- lib/l10n/app_es.arb | 3 +- lib/l10n/app_et.arb | 1 + lib/l10n/app_fa.arb | 1 + lib/l10n/app_fr.arb | 3 +- lib/l10n/app_hi.arb | 3 +- lib/l10n/app_id.arb | 1 + lib/l10n/app_it.arb | 3 +- lib/l10n/app_ja.arb | 1 + lib/l10n/app_ko.arb | 3 +- lib/l10n/app_nb.arb | 3 +- lib/l10n/app_nl.arb | 1 + lib/l10n/app_pl.arb | 3 +- lib/l10n/app_pt.arb | 3015 ++++++++++- lib/l10n/app_pt_BR.arb | 5 +- lib/l10n/app_ru.arb | 1 + lib/l10n/app_tr.arb | 1 + lib/l10n/app_uk.arb | 1 + lib/l10n/app_vi.arb | 1 + lib/l10n/app_zh.arb | 4560 +++++++++++++++++ lib/l10n/app_zh_CN.arb | 1 + lib/l10n/generated/app_localizations_ar.dart | 9 +- lib/l10n/generated/app_localizations_de.dart | 6 +- lib/l10n/generated/app_localizations_es.dart | 6 +- lib/l10n/generated/app_localizations_et.dart | 3 +- lib/l10n/generated/app_localizations_fa.dart | 2 +- lib/l10n/generated/app_localizations_fr.dart | 6 +- lib/l10n/generated/app_localizations_hi.dart | 6 +- lib/l10n/generated/app_localizations_id.dart | 2 +- lib/l10n/generated/app_localizations_it.dart | 6 +- lib/l10n/generated/app_localizations_ja.dart | 3 +- lib/l10n/generated/app_localizations_ko.dart | 5 +- lib/l10n/generated/app_localizations_nb.dart | 6 +- lib/l10n/generated/app_localizations_nl.dart | 2 +- lib/l10n/generated/app_localizations_pl.dart | 6 +- lib/l10n/generated/app_localizations_pt.dart | 1885 +++---- lib/l10n/generated/app_localizations_ru.dart | 2 +- lib/l10n/generated/app_localizations_tr.dart | 3 +- lib/l10n/generated/app_localizations_uk.dart | 2 +- lib/l10n/generated/app_localizations_vi.dart | 2 +- lib/l10n/generated/app_localizations_zh.dart | 1997 ++++---- lib/src/app/busymark_design.dart | 13 + .../presentation/workspace_screen.dart | 1 + test/src/app_smoke_test.dart | 55 + test/src/localization_audit_test.dart | 374 +- 49 files changed, 9933 insertions(+), 2105 deletions(-) diff --git a/.github/workflows/flutter-linux.yml b/.github/workflows/flutter-linux.yml index 7c4388e5..0c0e72eb 100644 --- a/.github/workflows/flutter-linux.yml +++ b/.github/workflows/flutter-linux.yml @@ -87,6 +87,9 @@ jobs: - name: Generate localizations run: flutter gen-l10n + - name: Audit localization catalogs + run: flutter test test/src/localization_audit_test.dart + - name: Verify generated files are committed run: git diff --exit-code diff --git a/README.md b/README.md index a047dca3..5d0b4b82 100644 --- a/README.md +++ b/README.md @@ -269,14 +269,18 @@ BusyMark has ARB localization files for: English in `lib/l10n/app_en.arb` is the source of truth for app strings. -Target ARB files are audited for catalog parity, placeholders, plurals, and -terminology. +Every base and regional ARB catalog must contain the complete current English +message-key set. Language-only catalogs such as `app_pt.arb` and `app_zh.arb` +are required alongside their regional catalogs; they are not partial fallback +stubs. Catalogs are audited for structure, parity, placeholders, plurals, and +reviewed terminology. When changing user-facing text, update `app_en.arb`, keep every target ARB in sync, then run: ```bash flutter gen-l10n +flutter test test/src/localization_audit_test.dart flutter analyze flutter test ``` diff --git a/docs/html-export-verification.md b/docs/html-export-verification.md index 57e031fa..2bfcf0c6 100644 --- a/docs/html-export-verification.md +++ b/docs/html-export-verification.md @@ -53,8 +53,10 @@ refresh could invalidate a foreground Writerside operation. A controlled regress test reproduced that failure. Monitor refreshes now wait for active loading to finish, and stale/disposed refreshes stop before changing controller state. -Base `pt` and `zh` localization templates remain partial as before. The shipped -`pt_BR` and `zh_CN` locales have complete messages and pass the localization audit. +Historical note: at the time of this HTML-export verification, the base `pt` +and `zh` catalogs were still partial while `pt_BR` and `zh_CN` were complete. +That limitation has since been superseded: localization policy now requires +both base and regional catalogs to contain the complete English message-key set. ## Browser and output verification diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index e8c62a35..12c419af 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -95,6 +95,7 @@ }, "copy": "نسخ", "copyPlainText": "نسخ كنص عادي", + "clipboardCopyFailed": "تعذّر نسخ المحتوى المحدد إلى الحافظة.", "@copy": { "description": "Copy command label." }, @@ -2304,7 +2305,7 @@ "gitBinaryFile": "ملف ثنائي. لا يعرض BusyMark رقع الملفات الثنائية.", "gitUnsavedChangesBanner": "لا تُضمّن تغييرات المحرر غير المحفوظة حتى يتم حفظها.", "gitConfirmDiscardTitle": "تجاهل تغييرات Git؟", - "gitConfirmDiscardTracked": "{count, plural, =1{ستتم استعادة جميع تغييرات المرحلة وغير المرحلة في الملف المتعقب المحدد إلى HEAD.} other{ستتم استعادة جميع تغييرات المرحلة وغير المرحلة في الملفات المتعقبة المحددة إلى HEAD.}}", + "gitConfirmDiscardTracked": "{count, plural, =1{ستتم استعادة جميع التغييرات المُرحَّلة وغير المُرحَّلة في الملف المتعقب المحدد إلى HEAD.} other{ستتم استعادة جميع التغييرات المُرحَّلة وغير المُرحَّلة في الملفات المتعقبة المحددة إلى HEAD.}}", "gitConfirmDiscardUntracked": "{count, plural, zero{لا توجد ملفات غير متعقبة محددة لحذفها.} one{سيُحذف الملف غير المتعقب المحدد.} two{سيُحذف الملفان غير المتعقبين المحددان.} few{ستُحذف الملفات غير المتعقبة المحددة.} many{ستُحذف الملفات غير المتعقبة المحددة.} other{ستُحذف الملفات غير المتعقبة المحددة.}}", "gitConfirmDiscardMixed": "{count, plural, zero{لا توجد ملفات محددة لاستعادتها أو حذفها.} one{ستتم استعادة الملف المحدد أو حذفه حسب حالته في Git.} two{ستتم استعادة الملفين المحددين أو حذفهما حسب حالتهما في Git.} few{ستتم استعادة الملفات المحددة أو حذفها حسب حالتها في Git.} many{ستتم استعادة الملفات المحددة أو حذفها حسب حالتها في Git.} other{ستتم استعادة الملفات المحددة أو حذفها حسب حالتها في Git.}}", "gitConfirmSwitchBranchTitle": "التبديل إلى ⁨{branch}⁩؟", @@ -3012,7 +3013,7 @@ "aiColdStartObserved": "تم اكتشاف بدء تشغيل بارد للنموذج المحلي.", "aiNoCompatibleModels": "لا يتوفر نموذج متوافق لإنشاء النص.", "aiEnableProvider": "فعّل مزوّد ذكاء اصطناعي أولًا.", - "aiDraftCommitMessage": "صياغة مسودة رسالة الإيداع", + "aiDraftCommitMessage": "صياغة مسودة رسالة الالتزام", "aiDrafting": "جارٍ إعداد المسودة…", "aiDraftWithAi": "إعداد مسودة بالذكاء الاصطناعي", "generateOrUpdateMarkdownToc": "إنشاء/تحديث جدول المحتويات", diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index aeb2f0da..d43c95c5 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -95,6 +95,7 @@ }, "copy": "Kopieren", "copyPlainText": "Als Nur-Text kopieren", + "clipboardCopyFailed": "Die Auswahl konnte nicht in die Zwischenablage kopiert werden.", "@copy": { "description": "Copy command label." }, @@ -2304,7 +2305,7 @@ "gitBinaryFile": "Binärdatei. BusyMark zeigt keine Binär-Patches an.", "gitUnsavedChangesBanner": "Ungespeicherte Editoränderungen werden erst nach dem Speichern berücksichtigt.", "gitConfirmDiscardTitle": "Git-Änderungen verwerfen?", - "gitConfirmDiscardTracked": "{count, plural, =1{Alle gestageten und nicht gestageten Änderungen der ausgewählten versionierten Datei werden auf den Stand in Git zurückgesetzt.} other{Alle gestageten und nicht gestageten Änderungen der ausgewählten versionierten Dateien werden auf den Stand in Git zurückgesetzt.}}", + "gitConfirmDiscardTracked": "{count, plural, =1{Alle vorgemerkten und nicht vorgemerkten Änderungen der ausgewählten versionierten Datei werden auf HEAD zurückgesetzt.} other{Alle vorgemerkten und nicht vorgemerkten Änderungen der ausgewählten versionierten Dateien werden auf HEAD zurückgesetzt.}}", "gitConfirmDiscardUntracked": "{count, plural, =1{Die ausgewählte nicht versionierte Datei wird gelöscht.} other{Die ausgewählten nicht versionierten Dateien werden gelöscht.}}", "gitConfirmDiscardMixed": "{count, plural, =1{Die ausgewählte Datei wird abhängig von ihrem Git-Status zurückgesetzt oder gelöscht.} other{Die ausgewählten Dateien werden abhängig von ihrem Git-Status zurückgesetzt oder gelöscht.}}", "gitConfirmSwitchBranchTitle": "Zu {branch} wechseln?", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index d5679b4a..338a2169 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -95,6 +95,7 @@ }, "copy": "Copiar", "copyPlainText": "Copiar como texto sin formato", + "clipboardCopyFailed": "No se pudo copiar la selección al portapapeles.", "@copy": { "description": "Copy command label." }, @@ -2304,7 +2305,7 @@ "gitBinaryFile": "Archivo binario. BusyMark no muestra parches binarios.", "gitUnsavedChangesBanner": "Los cambios sin guardar del editor no se incluyen hasta que se guarden.", "gitConfirmDiscardTitle": "¿Descartar los cambios de Git?", - "gitConfirmDiscardTracked": "{count, plural, =1{Se restaurarán en HEAD todos los cambios staged y no staged del archivo rastreado seleccionado.} other{Se restaurarán en HEAD todos los cambios staged y no staged de los archivos rastreados seleccionados.}}", + "gitConfirmDiscardTracked": "{count, plural, =1{Se restaurarán en HEAD todos los cambios preparados y sin preparar del archivo rastreado seleccionado.} other{Se restaurarán en HEAD todos los cambios preparados y sin preparar de los archivos rastreados seleccionados.}}", "gitConfirmDiscardUntracked": "{count, plural, =1{El archivo seleccionado sin seguimiento se eliminará.} other{Los archivos seleccionados sin seguimiento se eliminarán.}}", "gitConfirmDiscardMixed": "{count, plural, =1{El archivo seleccionado se restaurará o eliminará según su estado de Git.} other{Los archivos seleccionados se restaurarán o eliminarán según su estado de Git.}}", "gitConfirmSwitchBranchTitle": "¿Cambiar a {branch}?", diff --git a/lib/l10n/app_et.arb b/lib/l10n/app_et.arb index a58f844e..ce330ee8 100644 --- a/lib/l10n/app_et.arb +++ b/lib/l10n/app_et.arb @@ -179,6 +179,7 @@ }, "copy": "Kopeeri", "copyPlainText": "Kopeeri lihttekstina", + "clipboardCopyFailed": "Valikut ei saanud lõikelauale kopeerida.", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index 7d9da90f..40db2f8f 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -95,6 +95,7 @@ }, "copy": "کپی", "copyPlainText": "کپی به‌صورت متن ساده", + "clipboardCopyFailed": "امکان کپی کردن محتوای انتخاب‌شده در کلیپ‌بورد وجود نداشت.", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index a1747150..23797d5e 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -95,6 +95,7 @@ }, "copy": "Copier", "copyPlainText": "Copier en texte brut", + "clipboardCopyFailed": "Impossible de copier la sélection dans le presse-papiers.", "@copy": { "description": "Copy command label." }, @@ -2304,7 +2305,7 @@ "gitBinaryFile": "Fichier binaire. BusyMark n’affiche pas les patchs binaires.", "gitUnsavedChangesBanner": "Les modifications non enregistrées de l’éditeur ne sont incluses qu’après leur enregistrement.", "gitConfirmDiscardTitle": "Abandonner les modifications Git ?", - "gitConfirmDiscardTracked": "{count, plural, =1{Toutes les modifications staged et unstaged du fichier suivi sélectionné seront restaurées vers HEAD.} other{Toutes les modifications staged et unstaged des fichiers suivis sélectionnés seront restaurées vers HEAD.}}", + "gitConfirmDiscardTracked": "{count, plural, =1{Toutes les modifications indexées et non indexées du fichier suivi sélectionné seront restaurées vers HEAD.} other{Toutes les modifications indexées et non indexées des fichiers suivis sélectionnés seront restaurées vers HEAD.}}", "gitConfirmDiscardUntracked": "{count, plural, =1{Le fichier non suivi sélectionné sera supprimé.} other{Les fichiers non suivis sélectionnés seront supprimés.}}", "gitConfirmDiscardMixed": "{count, plural, =1{Le fichier sélectionné sera restauré ou supprimé selon son état Git.} other{Les fichiers sélectionnés seront restaurés ou supprimés selon leur état Git.}}", "gitConfirmSwitchBranchTitle": "Passer à {branch} ?", diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index b801bbb5..702c97ba 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -95,6 +95,7 @@ }, "copy": "कॉपी करें", "copyPlainText": "सादे पाठ के रूप में कॉपी करें", + "clipboardCopyFailed": "चयनित सामग्री को क्लिपबोर्ड पर कॉपी नहीं किया जा सका।", "@copy": { "description": "Copy command label." }, @@ -2304,7 +2305,7 @@ "gitBinaryFile": "बाइनरी फ़ाइल। BusyMark बाइनरी पैच रेंडर नहीं करता है।", "gitUnsavedChangesBanner": "संपादक के न सहेजे गए बदलाव सहेजे जाने तक शामिल नहीं किए जाते।", "gitConfirmDiscardTitle": "Git बदलाव त्यागें?", - "gitConfirmDiscardTracked": "{count, plural, =1{चयनित ट्रैक की गई फ़ाइल के सभी चरणबद्ध और अचयनित परिवर्तन HEAD पर वापस लाए जाएँगे।} other{चयनित ट्रैक की गई फ़ाइलों के सभी चरणबद्ध और अचयनित परिवर्तन HEAD पर वापस लाए जाएँगे।}}", + "gitConfirmDiscardTracked": "{count, plural, =1{चयनित ट्रैक की गई फ़ाइल के सभी स्टेज किए गए और स्टेज नहीं किए गए बदलाव HEAD पर वापस लाए जाएँगे।} other{चयनित ट्रैक की गई फ़ाइलों के सभी स्टेज किए गए और स्टेज नहीं किए गए बदलाव HEAD पर वापस लाए जाएँगे।}}", "gitConfirmDiscardUntracked": "{count, plural, =1{चयनित अनट्रैक की गई फ़ाइल हटा दी जाएगी।} other{चयनित अनट्रैक की गई फ़ाइलें हटा दी जाएँगी।}}", "gitConfirmDiscardMixed": "{count, plural, =1{चयनित फ़ाइल को उसकी Git स्थिति के आधार पर पुनर्स्थापित किया या हटाया जाएगा।} other{चयनित फ़ाइलों को उनकी Git स्थिति के आधार पर पुनर्स्थापित किया या हटाया जाएगा।}}", "gitConfirmSwitchBranchTitle": "{branch} पर स्विच करें?", diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index 6b949b98..37b88e65 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -179,6 +179,7 @@ }, "copy": "Salin", "copyPlainText": "Salin sebagai teks biasa", + "clipboardCopyFailed": "Konten yang dipilih tidak dapat disalin ke papan klip.", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 983fb496..0e4f5e2f 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -95,6 +95,7 @@ }, "copy": "Copia", "copyPlainText": "Copia come testo semplice", + "clipboardCopyFailed": "Impossibile copiare la selezione negli appunti.", "@copy": { "description": "Copy command label." }, @@ -2304,7 +2305,7 @@ "gitBinaryFile": "File binario. BusyMark non visualizza le patch binarie.", "gitUnsavedChangesBanner": "Le modifiche non salvate dell’editor non vengono incluse finché non vengono salvate.", "gitConfirmDiscardTitle": "Scartare le modifiche Git?", - "gitConfirmDiscardTracked": "{count, plural, =1{Tutte le modifiche staged e non staged nel file tracciato selezionato saranno ripristinate in HEAD.} other{Tutte le modifiche staged e non staged nei file tracciati selezionati saranno ripristinate in HEAD.}}", + "gitConfirmDiscardTracked": "{count, plural, =1{Tutte le modifiche in stage e non in stage nel file tracciato selezionato saranno ripristinate in HEAD.} other{Tutte le modifiche in stage e non in stage nei file tracciati selezionati saranno ripristinate in HEAD.}}", "gitConfirmDiscardUntracked": "{count, plural, =1{Il file non tracciato selezionato verrà eliminato.} other{I file non tracciati selezionati verranno eliminati.}}", "gitConfirmDiscardMixed": "{count, plural, =1{Il file selezionato verrà ripristinato o eliminato in base al suo stato Git.} other{I file selezionati verranno ripristinati o eliminati in base al loro stato Git.}}", "gitConfirmSwitchBranchTitle": "Passare a {branch}?", diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 6f53ce50..8dd5bfe1 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -179,6 +179,7 @@ }, "copy": "コピー", "copyPlainText": "プレーンテキストとしてコピー", + "clipboardCopyFailed": "選択内容をクリップボードにコピーできませんでした。", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index c9bf22d3..d3fa7fbd 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -179,6 +179,7 @@ }, "copy": "복사", "copyPlainText": "일반 텍스트로 복사", + "clipboardCopyFailed": "선택한 내용을 클립보드에 복사할 수 없습니다.", "@copy": { "description": "Copy command label." }, @@ -4553,7 +4554,7 @@ "@aiEnableProvider": { "description": "AI settings error when no provider is enabled." }, - "aiDraftCommitMessage": "초안 커밋 메시지", + "aiDraftCommitMessage": "커밋 메시지 초안 작성", "@aiDraftCommitMessage": { "description": "AI action that drafts a Git commit message." }, diff --git a/lib/l10n/app_nb.arb b/lib/l10n/app_nb.arb index f9d90f5d..c7feaecf 100644 --- a/lib/l10n/app_nb.arb +++ b/lib/l10n/app_nb.arb @@ -95,6 +95,7 @@ }, "copy": "Kopier", "copyPlainText": "Kopier som ren tekst", + "clipboardCopyFailed": "Utvalget kunne ikke kopieres til utklippstavlen.", "@copy": { "description": "Copy command label." }, @@ -2304,7 +2305,7 @@ "gitBinaryFile": "Binærfil. BusyMark viser ikke binære patcher.", "gitUnsavedChangesBanner": "Ulagrede endringer i redigereren tas ikke med før de er lagret.", "gitConfirmDiscardTitle": "Forkaste Git-endringer?", - "gitConfirmDiscardTracked": "{count, plural, =1{Alle staged- og ikke-staged-endringer i den valgte sporede filen vil bli gjenopprettet til HEAD.} other{Alle staged- og ikke-staged-endringer i de valgte sporede filene vil bli gjenopprettet til HEAD.}}", + "gitConfirmDiscardTracked": "{count, plural, =1{Alle indekserte og ikke-indekserte endringer i den valgte sporede filen vil bli gjenopprettet til HEAD.} other{Alle indekserte og ikke-indekserte endringer i de valgte sporede filene vil bli gjenopprettet til HEAD.}}", "gitConfirmDiscardUntracked": "{count, plural, =1{Den valgte usporede filen slettes.} other{De valgte usporede filene slettes.}}", "gitConfirmDiscardMixed": "{count, plural, =1{Den valgte filen gjenopprettes eller slettes ut fra Git-statusen.} other{De valgte filene gjenopprettes eller slettes ut fra Git-statusen.}}", "gitConfirmSwitchBranchTitle": "Bytt til {branch}?", diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 4d8cdd88..98e0b735 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -179,6 +179,7 @@ }, "copy": "Kopiëren", "copyPlainText": "Kopiëren als platte tekst", + "clipboardCopyFailed": "De selectie kon niet naar het klembord worden gekopieerd.", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 5171f52f..2af1e31c 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -95,6 +95,7 @@ }, "copy": "Kopiuj", "copyPlainText": "Kopiuj jako zwykły tekst", + "clipboardCopyFailed": "Nie udało się skopiować zaznaczenia do schowka.", "@copy": { "description": "Copy command label." }, @@ -2330,7 +2331,7 @@ "gitBinaryFile": "Plik binarny. BusyMark nie wyświetla binarnych poprawek.", "gitUnsavedChangesBanner": "Niezapisane zmiany w edytorze nie zostaną uwzględnione, dopóki ich nie zapiszesz.", "gitConfirmDiscardTitle": "Odrzucić zmiany Git?", - "gitConfirmDiscardTracked": "{count, plural, =1{Wszystkie oznaczone i nieoznaczone zmiany w wybranym śledzonym pliku zostaną przywrócone do HEAD.} other{Wszystkie oznaczone i nieoznaczone zmiany w wybranych śledzonych plikach zostaną przywrócone do HEAD.}}", + "gitConfirmDiscardTracked": "{count, plural, =1{Wszystkie zmiany w indeksie i poza indeksem w wybranym śledzonym pliku zostaną przywrócone do HEAD.} other{Wszystkie zmiany w indeksie i poza indeksem w wybranych śledzonych plikach zostaną przywrócone do HEAD.}}", "gitConfirmDiscardUntracked": "{count, plural, one{Wybrany nieśledzony plik zostanie usunięty.} few{Wybrane nieśledzone pliki zostaną usunięte.} many{Wybrane nieśledzone pliki zostaną usunięte.} other{Wybrane nieśledzone pliki zostaną usunięte.}}", "gitConfirmDiscardMixed": "{count, plural, one{Wybrany plik zostanie przywrócony lub usunięty zależnie od jego stanu Git.} few{Wybrane pliki zostaną przywrócone lub usunięte zależnie od ich stanu Git.} many{Wybrane pliki zostaną przywrócone lub usunięte zależnie od ich stanu Git.} other{Wybrane pliki zostaną przywrócone lub usunięte zależnie od ich stanu Git.}}", "gitConfirmSwitchBranchTitle": "Przełączyć na {branch}?", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index c28e12b6..adbb0a5c 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -1,32 +1,2665 @@ { "@@locale": "pt", + "reportIssue": "Comunicar um problema", + "feedbackCategory": "Categoria", + "feedbackChooseCategory": "Escolha uma categoria", + "feedbackCategoryProblem": "Problema ou erro", + "feedbackCategoryFeature": "Pedido de funcionalidade", + "feedbackCategoryPrivacySecurity": "Preocupação com privacidade ou segurança", + "feedbackCategoryUsability": "Preocupação de usabilidade", + "feedbackCategoryOther": "Outro", + "feedbackSubject": "Assunto", + "feedbackMessage": "Mensagem detalhada", + "feedbackReplyEmail": "E-mail para resposta (opcional)", + "feedbackIncludeTechnicalDetails": "Incluir detalhes técnicos", + "feedbackTechnicalDetailsDisclosure": "Quando esta opção está ativada, são adicionados apenas a versão do sistema operativo Linux e o idioma da aplicação BusyMark. Não são anexados registos, ficheiros, dados de conta nem outros diagnósticos.", + "feedbackSubmit": "Enviar", + "feedbackSubmitting": "A enviar…", + "feedbackCategoryRequired": "Escolha uma categoria.", + "feedbackSubjectLength": "O assunto deve ter entre 3 e 120 carateres.", + "feedbackMessageLength": "A mensagem deve ter entre 10 e 5000 carateres.", + "feedbackReplyEmailInvalid": "Introduza um endereço de e-mail válido ou deixe este campo vazio.", + "feedbackConnectionFailure": "O BusyMark não conseguiu estabelecer ligação. Verifique a ligação à Internet e tente novamente.", + "feedbackTimeoutFailure": "O pedido excedeu o tempo limite. Tente novamente.", + "feedbackRateLimitedFailure": "Foram enviados demasiados relatórios a partir desta ligação. Aguarde e tente novamente.", + "feedbackRejectedFailure": "O servidor rejeitou o relatório. Verifique os campos do formulário e tente novamente.", + "feedbackServerFailure": "O servidor não conseguiu aceitar o relatório. Tente novamente mais tarde.", + "feedbackSuccess": "Comentários enviados. ID de referência: {id}", + "appTitle": "BusyMark", + "@appTitle": { + "description": "Application name." + }, + "appSubtitle": "Editor para ficheiros Markdown e projetos de documentação compatíveis com o Writerside.", + "@appSubtitle": { + "description": "Short application description." + }, + "aboutBusyMark": "Sobre BusyMark", + "@aboutBusyMark": { + "description": "Menu item and tooltip for the About dialog." + }, + "aboutTagline": "Editor de Markdown e Writerside", + "@aboutTagline": { + "description": "Short tagline shown under the app name in the About dialog." + }, + "aboutLicenseLabel": "Licença", + "@aboutLicenseLabel": { + "description": "Label for the license row in the About dialog." + }, + "aboutLicenseName": "Apache License 2.0", + "@aboutLicenseName": { + "description": "Formal license name shown in the About dialog. Keep the legal license name exact." + }, + "aboutWebsite": "Site", + "@aboutWebsite": { + "description": "Label for the website row in the About dialog." + }, + "aboutSourceCode": "Código-fonte", + "@aboutSourceCode": { + "description": "Label for the source-code repository row in the About dialog." + }, + "advanced": "Avançado", + "@advanced": { + "description": "Settings section title for advanced actions." + }, + "appearance": "Aparência", + "@appearance": { + "description": "Settings section title for appearance options." + }, + "apply": "Aplicar", + "@apply": { + "description": "Button label that applies a dialog change." + }, + "back": "Voltar", + "@back": { + "description": "Tooltip for navigating back." + }, + "bottomLeft": "Canto inferior esquerdo", + "@bottomLeft": { + "description": "Editing button position option." + }, + "bottomRight": "Canto inferior direito", + "@bottomRight": { + "description": "Editing button position option." + }, + "cancel": "Cancelar", + "@cancel": { + "description": "Cancel button label." + }, + "choose": "Escolher", + "@choose": { + "description": "Button label for choosing a file or path." + }, + "chooseLocation": "Escolher local", + "@chooseLocation": { + "description": "File picker confirmation label for choosing a directory." + }, + "copy": "Copiar", + "copyPlainText": "Copiar como texto simples", + "clipboardCopyFailed": "Não foi possível copiar a seleção para a área de transferência.", + "@copy": { + "description": "Copy command label." + }, + "copyName": "Copiar nome", + "@copyName": { + "description": "Menu action that copies the selected file, folder, or workspace name." + }, + "copyFileName": "Copiar nome do ficheiro", + "@copyFileName": { + "description": "Menu action that copies the active document file name." + }, + "copyPath": "Copiar caminho", + "@copyPath": { + "description": "Menu action that copies the selected file, folder, or workspace path." + }, + "create": "Criar", + "@create": { + "description": "Create action label." + }, + "creating": "A criar…", + "@creating": { + "description": "Progress label while a project or topic is being created." + }, + "cut": "Recortar", + "@cut": { + "description": "Cut command label." + }, + "promoteSection": "Promover secção", + "demoteSection": "Rebaixar secção", + "moveSectionUp": "Mover secção para cima", + "moveSectionDown": "Mover secção para baixo", + "confirmDeleteSectionTitle": "Eliminar secção?", + "confirmDeleteSectionMessage": "Eliminar “{name}” e todo o conteúdo da secção? Esta ação não pode ser anulada.", + "darkTheme": "Escuro", + "@darkTheme": { + "description": "Dark theme option." + }, + "discard": "Descartar", + "@discard": { + "description": "Discard unsaved changes button label." + }, + "editor": "Editor", + "@editor": { + "description": "Editor view label." + }, + "file": "Ficheiro", + "@file": { + "description": "Generic file kind label." + }, + "fileHistory": "Histórico do ficheiro", + "@fileHistory": { + "description": "Menu action and sidebar title for showing Git history for a single file." + }, + "folder": "Pasta", + "@folder": { + "description": "Folder kind label." + }, + "insert": "Inserir", + "@insert": { + "description": "Insert button label." + }, + "keyboardShortcuts": "Atalhos de teclado", + "@keyboardShortcuts": { + "description": "Keyboard shortcuts dialog title and menu item." + }, + "lightTheme": "Claro", + "@lightTheme": { + "description": "Light theme option." + }, + "mainMenu": "Menu principal", + "@mainMenu": { + "description": "Native header bar main menu tooltip." + }, + "fullScreen": "Ecrã inteiro", + "@fullScreen": { + "description": "Command that toggles full-screen window mode." + }, + "markdown": "Markdown", + "@markdown": { + "description": "Markdown format label." + }, + "open": "Abrir", + "@open": { + "description": "Open action label." + }, + "openInFiles": "Abrir em Ficheiros", + "@openInFiles": { + "description": "Menu action that opens the selected file or folder location in the system file manager." + }, + "pathActions": "Ações do caminho", + "@pathActions": { + "description": "Tooltip for the workspace path action menu button." + }, + "outline": "Estrutura", + "@outline": { + "description": "Outline sidebar tab label." + }, + "overwrite": "Sobrescrever", + "@overwrite": { + "description": "Button label for overwriting a changed file." + }, + "paste": "Colar", + "@paste": { + "description": "Paste command label." + }, + "reading": "Leitura", + "@reading": { + "description": "Reading view label." + }, + "removeFromRecent": "Remover dos recentes", + "recent": "Recentes", + "@recent": { + "description": "Recent workspaces section title." + }, + "redo": "Refazer", + "@redo": { + "description": "Redo command label." + }, + "save": "Guardar", + "@save": { + "description": "Save action label." + }, + "search": "Pesquisar", + "@search": { + "description": "Search action label and field hint." + }, + "selectAll": "Selecionar tudo", + "@selectAll": { + "description": "Select all command label." + }, + "settings": "Definições", + "@settings": { + "description": "Settings action label." + }, + "source": "Código-fonte", + "@source": { + "description": "Source view label." + }, + "split": "Vista dividida", + "@split": { + "description": "Split view label." + }, + "systemTheme": "Sistema", + "@systemTheme": { + "description": "System theme option." + }, + "theme": "Tema", + "@theme": { + "description": "Theme setting label." + }, + "appLanguage": "Idioma", + "@appLanguage": { + "description": "Application language setting label." + }, + "systemLanguage": "Sistema", + "@systemLanguage": { + "description": "Language selector option that follows the operating system locale." + }, + "languageEnglish": "English", + "@languageEnglish": { + "description": "Language selector option for English." + }, + "languageGerman": "Deutsch", + "@languageGerman": { + "description": "Language selector option for German." + }, + "languageDutch": "Nederlands", + "@languageDutch": { + "description": "Language selector option for Dutch." + }, + "languageTurkish": "Türkçe", + "@languageTurkish": { + "description": "Language selector option for Turkish." + }, + "languageItalian": "Italiano", + "@languageItalian": { + "description": "Language selector option for Italian." + }, + "languageNorwegian": "Norsk bokmål", + "@languageNorwegian": { + "description": "Language selector option for Norwegian." + }, + "languageFrench": "Français", + "@languageFrench": { + "description": "Language selector option for French." + }, + "languageRussian": "Русский", + "@languageRussian": { + "description": "Language selector option for Russian." + }, + "languageUkrainian": "Українська", + "@languageUkrainian": { + "description": "Language selector option for Ukrainian." + }, + "languagePolish": "Polski", + "@languagePolish": { + "description": "Language selector option for Polish." + }, + "languageSpanish": "Español", + "@languageSpanish": { + "description": "Language selector option for Spanish." + }, + "languagePortuguese": "Português", + "@languagePortuguese": { + "description": "Language selector option for Portuguese." + }, + "languageArabic": "العربية", + "@languageArabic": { + "description": "Language selector option for Arabic." + }, + "languagePersian": "فارسی", + "@languagePersian": { + "description": "Language selector option for Persian." + }, + "languageHindi": "हिन्दी", + "@languageHindi": { + "description": "Language selector option for Hindi." + }, + "languageIndonesian": "Bahasa Indonesia", + "@languageIndonesian": { + "description": "Language selector option for Indonesian." + }, + "languageEstonian": "Eesti", + "@languageEstonian": { + "description": "Language selector option for Estonian." + }, + "languageVietnamese": "Tiếng Việt", + "@languageVietnamese": { + "description": "Language selector option for Vietnamese." + }, + "languageJapanese": "日本語", + "@languageJapanese": { + "description": "Language selector option for Japanese." + }, + "languageKorean": "한국어", + "@languageKorean": { + "description": "Language selector option for Korean." + }, + "languageSimplifiedChinese": "简体中文", + "@languageSimplifiedChinese": { + "description": "Language selector option for Simplified Chinese." + }, + "toggleSidebar": "Painel lateral", + "@toggleSidebar": { + "description": "Native header bar sidebar toggle tooltip." + }, + "topLeft": "Canto superior esquerdo", + "@topLeft": { + "description": "Editing button position option." + }, + "topRight": "Canto superior direito", + "@topRight": { + "description": "Editing button position option." + }, + "undo": "Desfazer", + "@undo": { + "description": "Undo command label." + }, + "validate": "Validar", + "@validate": { + "description": "Validate action label." + }, + "validation": "Validação", + "@validation": { + "description": "Settings section title for validation options." + }, + "viewMode": "Modo de visualização", + "@viewMode": { + "description": "Native header bar view mode control label." + }, + "welcome": "Bem-vindo", + "@welcome": { + "description": "Welcome screen label and tooltip." + }, + "writerside": "Writerside", + "@writerside": { + "description": "Writerside workspace kind label." + }, + "xml": "XML", + "@xml": { + "description": "XML format label." + }, + "fileTypeMarkdown": "Markdown", + "@fileTypeMarkdown": { + "description": "Native file picker type label for Markdown files." + }, + "fileTypeImages": "Imagens", + "@fileTypeImages": { + "description": "Native file picker type label for images." + }, + "openMarkdownFile": "Abrir ficheiro Markdown", + "@openMarkdownFile": { + "description": "Action label for opening a Markdown file." + }, + "markdownFileExtensions": ".md ou .markdown", + "@markdownFileExtensions": { + "description": "Subtitle describing supported Markdown file extensions." + }, + "openFolderOrWritersideProject": "Abrir pasta ou projeto Writerside", + "@openFolderOrWritersideProject": { + "description": "Action label for opening a folder or Writerside project." + }, + "markdownFolderOrWritersideProject": "Pasta Markdown ou projeto compatível com Writerside", + "@markdownFolderOrWritersideProject": { + "description": "Subtitle describing supported folder workspace types." + }, + "noOpenFile": "Nenhum ficheiro aberto", + "@noOpenFile": { + "description": "Header title when a folder or Writerside workspace has no open editor tab." + }, + "shortcutDeleteTreeItemDescription": "Eliminar o item selecionado em Ficheiros ou remover o tópico selecionado do sumário", + "@shortcutDeleteTreeItemDescription": { + "description": "Keyboard shortcut description for deleting the selected Files item or removing the selected topic from the table of contents." + }, + "shortcutGroupGeneral": "Geral", + "@shortcutGroupGeneral": { + "description": "Keyboard shortcut group for general application commands." + }, + "shortcutNewDocument": "Criar", + "@shortcutNewDocument": { + "description": "Keyboard shortcut label for creating a document." + }, + "shortcutNewDocumentDescription": "Criar ficheiro Markdown ou projeto Writerside", + "@shortcutNewDocumentDescription": { + "description": "Keyboard shortcut description for creating a document." + }, + "shortcutOpenDescription": "Abrir um ficheiro Markdown, uma pasta ou um projeto Writerside", + "@shortcutOpenDescription": { + "description": "Keyboard shortcut description for opening content." + }, + "shortcutSaveDescription": "Guardar o documento atual", + "@shortcutSaveDescription": { + "description": "Keyboard shortcut description for saving content." + }, + "shortcutSearchDescription": "Pesquisar no espaço de trabalho atual", + "@shortcutSearchDescription": { + "description": "Keyboard shortcut description for search." + }, + "shortcutKeyboardShortcutsDescription": "Mostrar esta referência de atalhos de teclado", + "@shortcutKeyboardShortcutsDescription": { + "description": "Keyboard shortcut description for opening shortcuts." + }, "shortcutSyntaxReferenceDescription": "Abrir a referência de sintaxe", + "@shortcutSyntaxReferenceDescription": { + "description": "Keyboard shortcut description for opening the Syntax Reference." + }, + "shortcutSettingsDescription": "Abrir as definições do BusyMark", + "@shortcutSettingsDescription": { + "description": "Keyboard shortcut description for opening settings." + }, + "shortcutNextTab": "Próxima guia", + "@shortcutNextTab": { + "description": "Keyboard shortcut label for moving to the next tab." + }, + "shortcutNextTabDescription": "Ir para a próxima guia aberta", + "@shortcutNextTabDescription": { + "description": "Keyboard shortcut description for moving to the next tab." + }, + "shortcutPreviousTab": "Guia anterior", + "@shortcutPreviousTab": { + "description": "Keyboard shortcut label for moving to the previous tab." + }, + "shortcutPreviousTabDescription": "Ir para a guia aberta anterior", + "@shortcutPreviousTabDescription": { + "description": "Keyboard shortcut description for moving to the previous tab." + }, + "shortcutCloseTab": "Fechar guia", + "@shortcutCloseTab": { + "description": "Keyboard shortcut label for closing the active tab." + }, + "shortcutCloseTabDescription": "Fechar a guia ativa", + "@shortcutCloseTabDescription": { + "description": "Keyboard shortcut description for closing the active tab." + }, + "shortcutCloseAllTabs": "Fechar todas as guias", + "@shortcutCloseAllTabs": { + "description": "Keyboard shortcut label for closing all tabs." + }, + "shortcutCloseAllTabsDescription": "Fechar todas as guias abertas", + "@shortcutCloseAllTabsDescription": { + "description": "Keyboard shortcut description for closing all tabs." + }, + "shortcutGroupTextEditing": "Edição de texto", + "@shortcutGroupTextEditing": { + "description": "Keyboard shortcut group for text editing commands." + }, + "shortcutSelectAllDescription": "No modo Código-fonte, selecionar todo o texto; no modo Editor, pressionar duas vezes para selecionar todos os blocos", + "@shortcutSelectAllDescription": { + "description": "Keyboard shortcut description for selecting source text or visual-editor blocks." + }, + "shortcutCutDescription": "Recortar o texto selecionado", + "@shortcutCutDescription": { + "description": "Keyboard shortcut description for cut." + }, + "shortcutCopyDescription": "Copiar o texto selecionado", + "@shortcutCopyDescription": { + "description": "Keyboard shortcut description for copy." + }, + "shortcutPasteDescription": "Colar da área de transferência", + "@shortcutPasteDescription": { + "description": "Keyboard shortcut description for paste." + }, + "shortcutPastePlainTextDescription": "Colar o texto da área de transferência sem formatação", + "@shortcutPastePlainTextDescription": { + "description": "Keyboard shortcut description for plain text paste." + }, + "shortcutUndoDescription": "Desfazer a última edição", + "@shortcutUndoDescription": { + "description": "Keyboard shortcut description for undo." + }, + "shortcutRedoDescription": "Refazer a última edição desfeita", + "@shortcutRedoDescription": { + "description": "Keyboard shortcut description for redo." + }, + "shortcutInsertIndentation": "Inserir recuo", + "@shortcutInsertIndentation": { + "description": "Keyboard shortcut label for inserting indentation." + }, + "shortcutInsertIndentationDescription": "Inserir recuo na posição do cursor", + "@shortcutInsertIndentationDescription": { + "description": "Keyboard shortcut description for inserting indentation." + }, + "shortcutOutdentSource": "Diminuir recuo do código-fonte", + "@shortcutOutdentSource": { + "description": "Keyboard shortcut label for outdenting in Source mode." + }, + "shortcutOutdentSourceDescription": "Remover um nível de recuo no modo Código-fonte", + "@shortcutOutdentSourceDescription": { + "description": "Keyboard shortcut description for outdenting in Source mode." + }, + "shortcutEscape": "Fechar a pesquisa ou limpar a seleção de blocos", + "@shortcutEscape": { + "description": "Keyboard shortcut label for closing search or clearing a block selection." + }, + "shortcutEscapeDescription": "Fechar a pesquisa do espaço de trabalho ou limpar uma seleção de blocos no modo Editor", + "@shortcutEscapeDescription": { + "description": "Keyboard shortcut description for closing search or clearing a block selection." + }, + "shortcutGroupFormatting": "Formatação", + "@shortcutGroupFormatting": { + "description": "Keyboard shortcut group for inline formatting." + }, + "shortcutBoldDescription": "Alternar negrito no texto selecionado", + "@shortcutBoldDescription": { + "description": "Keyboard shortcut description for bold." + }, + "shortcutItalicDescription": "Alternar itálico no texto selecionado", + "@shortcutItalicDescription": { + "description": "Keyboard shortcut description for italic." + }, + "shortcutUnderlineDescription": "Alternar sublinhado no texto selecionado", + "@shortcutUnderlineDescription": { + "description": "Keyboard shortcut description for underline." + }, + "shortcutLinkDescription": "Inserir ou editar uma ligação", + "@shortcutLinkDescription": { + "description": "Keyboard shortcut description for link insertion." + }, + "shortcutInlineCodeDescription": "Alternar código embutido no texto selecionado", + "@shortcutInlineCodeDescription": { + "description": "Keyboard shortcut description for inline code." + }, + "shortcutStrikethroughDescription": "Alternar tachado no texto selecionado", + "@shortcutStrikethroughDescription": { + "description": "Keyboard shortcut description for strikethrough." + }, + "shortcutGroupBlocks": "Blocos", + "@shortcutGroupBlocks": { + "description": "Keyboard shortcut group for block styles." + }, + "shortcutParagraphDescription": "Definir o bloco atual como parágrafo", + "@shortcutParagraphDescription": { + "description": "Keyboard shortcut description for paragraph style." + }, + "shortcutHeading1Description": "Definir o bloco atual como Título 1", + "@shortcutHeading1Description": { + "description": "Keyboard shortcut description for heading 1." + }, + "shortcutHeading2Description": "Definir o bloco atual como Título 2", + "@shortcutHeading2Description": { + "description": "Keyboard shortcut description for heading 2." + }, + "shortcutHeading3Description": "Definir o bloco atual como Título 3", + "@shortcutHeading3Description": { + "description": "Keyboard shortcut description for heading 3." + }, + "shortcutHeading4Description": "Definir o bloco atual como Título 4", + "@shortcutHeading4Description": { + "description": "Keyboard shortcut description for heading 4." + }, + "shortcutHeading5Description": "Definir o bloco atual como Título 5", + "@shortcutHeading5Description": { + "description": "Keyboard shortcut description for heading 5." + }, + "shortcutHeading6Description": "Definir o bloco atual como Título 6", + "@shortcutHeading6Description": { + "description": "Keyboard shortcut description for heading 6." + }, + "shortcutGroupLists": "Listas", + "@shortcutGroupLists": { + "description": "Keyboard shortcut group for list commands." + }, + "numberedList": "Lista numerada", + "@numberedList": { + "description": "Keyboard shortcut label for numbered list formatting." + }, + "shortcutNumberedListDescription": "Alternar formatação de lista numerada", + "@shortcutNumberedListDescription": { + "description": "Keyboard shortcut description for numbered list." + }, + "bulletedList": "Lista com marcadores", + "@bulletedList": { + "description": "Keyboard shortcut label for bulleted list formatting." + }, + "shortcutBulletedListDescription": "Alternar formatação de lista com marcadores", + "@shortcutBulletedListDescription": { + "description": "Keyboard shortcut description for bulleted list." + }, + "checklist": "Lista de verificação", + "@checklist": { + "description": "Keyboard shortcut label for checklist formatting." + }, + "shortcutChecklistDescription": "Alternar formatação de lista de verificação", + "@shortcutChecklistDescription": { + "description": "Keyboard shortcut description for checklist." + }, + "shortcutGroupSidebar": "Barra lateral", + "@shortcutGroupSidebar": { + "description": "Keyboard shortcut group for sidebar view switching." + }, + "sidebarViewMenu": "Visualização da barra lateral", + "@sidebarViewMenu": { + "description": "Tooltip for the sidebar view selector button." + }, + "createMarkdownFile": "Criar ficheiro Markdown", + "@createMarkdownFile": { + "description": "Welcome screen action for creating a Markdown file." + }, + "createMarkdownFileDescription": "Iniciar um documento Markdown local não guardado", + "@createMarkdownFileDescription": { + "description": "Welcome screen subtitle for creating a Markdown file." + }, + "createWritersideProject": "Criar projeto Writerside", + "@createWritersideProject": { + "description": "Welcome screen action for creating a Writerside project." + }, + "createWritersideProjectDescription": "Iniciar um projeto local compatível com Writerside", + "@createWritersideProjectDescription": { + "description": "Welcome screen subtitle for creating a Writerside project." + }, + "defaultProjectName": "Documentação", + "@defaultProjectName": { + "description": "Default project name shown in the create project dialog." + }, + "defaultInstanceName": "Guia do utilizador", + "@defaultInstanceName": { + "description": "Default Writerside instance name shown in the create project dialog." + }, + "defaultStartTopicTitle": "Primeiros passos", + "@defaultStartTopicTitle": { + "description": "Default start topic title shown in the create project dialog." + }, + "projectName": "Nome do projeto", + "@projectName": { + "description": "Create project dialog field label." + }, + "directoryName": "Nome do diretório", + "@directoryName": { + "description": "Create project dialog field label." + }, + "instanceName": "Nome da instância", + "@instanceName": { + "description": "Create project dialog field label." + }, + "instanceId": "ID da instância", + "@instanceId": { + "description": "Create project dialog field label." + }, + "startTopicTitle": "Título do tópico inicial", + "@startTopicTitle": { + "description": "Create project dialog field label." + }, + "location": "Local", + "@location": { + "description": "Create dialog location section label." + }, + "projectNameRequired": "O nome do projeto é obrigatório.", + "@projectNameRequired": { + "description": "Validation message for missing project name." + }, + "directoryNameRequired": "O nome do diretório é obrigatório.", + "@directoryNameRequired": { + "description": "Validation message for missing directory name." + }, + "useSingleSafeDirectoryName": "Use um único nome de diretório seguro.", + "@useSingleSafeDirectoryName": { + "description": "Validation message for unsafe directory names." + }, + "useLowercaseIdentifier": "Use um identificador em minúsculas com letras, números, sublinhados ou hifens.", + "@useLowercaseIdentifier": { + "description": "Validation message for invalid Writerside instance IDs." + }, + "startTopicTitleRequired": "O título do tópico inicial é obrigatório.", + "@startTopicTitleRequired": { + "description": "Validation message for missing start topic title." + }, + "createWritersideProjectFailed": "Não foi possível criar o projeto Writerside.", + "@createWritersideProjectFailed": { + "description": "Fallback error shown when Writerside project creation fails." + }, + "settingsTitle": "Definições do BusyMark", + "@settingsTitle": { + "description": "Settings screen title." + }, + "autoSave": "Gravação automática", + "@autoSave": { + "description": "Editor setting label for saving files automatically." + }, + "autoSaveDescription": "Guarda automaticamente as alterações do ficheiro após um curto período de inatividade.", + "@autoSaveDescription": { + "description": "Editor setting description for saving files automatically." + }, + "wordWrap": "Quebra de linha", + "@wordWrap": { + "description": "Word wrap setting label." + }, + "editorFontSize": "Tamanho da fonte do editor", + "@editorFontSize": { + "description": "Editor font size setting label." + }, + "validateOnEdit": "Validar ao editar", + "@validateOnEdit": { + "description": "Validation setting label." + }, + "clearRecentWorkspaces": "Limpar espaços de trabalho recentes", + "@clearRecentWorkspaces": { + "description": "Settings action label for clearing recent workspaces." + }, + "editingButtonsPosition": "Posição dos botões de edição", + "@editingButtonsPosition": { + "description": "Settings label for WYSIWYG editing button position." + }, + "editingButtonsPositionDescription": "Escolha onde os botões flutuantes de edição WYSIWYG aparecem.", + "@editingButtonsPositionDescription": { + "description": "Description for WYSIWYG editing button position setting." + }, + "editingButtonsDirection": "Orientação dos botões de edição", + "@editingButtonsDirection": { + "description": "Settings label for WYSIWYG editing button direction." + }, + "editingButtonsDirectionDescription": "Escolha se os botões flutuantes de edição WYSIWYG ficam dispostos horizontalmente ou verticalmente.", + "@editingButtonsDirectionDescription": { + "description": "Description for WYSIWYG editing button direction setting." + }, + "horizontal": "Horizontal", + "@horizontal": { + "description": "Editing button direction option." + }, + "vertical": "Vertical", + "@vertical": { + "description": "Editing button direction option." + }, + "privacy": "Privacidade", + "@privacy": { + "description": "Settings section title for privacy options." + }, + "allowRemoteImages": "Carregar imagens remotas", + "@allowRemoteImages": { + "description": "Settings switch title for loading remote images." + }, + "allowRemoteImagesDescription": "Permitir que a pré-visualização do Markdown e o editor carreguem imagens de URLs HTTP e HTTPS.", + "@allowRemoteImagesDescription": { + "description": "Settings switch description for loading remote images." + }, + "clearRemoteImagePermissions": "Limpar permissões de imagens remotas", + "@clearRemoteImagePermissions": { + "description": "Settings action label for clearing per-workspace remote image permissions." + }, + "clearRemoteImagePermissionsDescription": "Esquecer os espaços de trabalho autorizados a carregar imagens remotas.", + "@clearRemoteImagePermissionsDescription": { + "description": "Settings action description for clearing per-workspace remote image permissions." + }, + "clearGitWorkspaceTrust": "Limpar espaços de trabalho confiáveis para o Git", + "@clearGitWorkspaceTrust": { + "description": "Settings action label for clearing trusted Git workspaces." + }, + "clearGitWorkspaceTrustDescription": "Perguntar antes de ativar recursos do Git em espaços de trabalho considerados confiáveis anteriormente.", + "@clearGitWorkspaceTrustDescription": { + "description": "Settings action description for clearing trusted Git workspaces." + }, + "settingsWindowSectionTitle": "Janela", + "@settingsWindowSectionTitle": { + "description": "Settings section title for native window behavior." + }, + "settingsReopenWorkspaceOnStartupTitle": "Reabrir o espaço de trabalho anterior ao iniciar", + "@settingsReopenWorkspaceOnStartupTitle": { + "description": "Settings switch title for reopening the previous workspace on a normal startup." + }, + "settingsReopenWorkspaceOnStartupDescription": "Abra o espaço de trabalho e as abas da sessão anterior quando o BusyMark iniciar.", + "@settingsReopenWorkspaceOnStartupDescription": { + "description": "Settings switch description for reopening the previous workspace on a normal startup." + }, + "settingsConfirmCloseWithUnsavedChangesTitle": "Confirmar antes de fechar com alterações não guardadas", + "@settingsConfirmCloseWithUnsavedChangesTitle": { + "description": "Settings switch title for close confirmation when documents have unsaved changes." + }, + "settingsConfirmCloseWithUnsavedChangesDescription": "Perguntar antes de fechar o BusyMark quando documentos tiverem alterações não guardadas.", + "@settingsConfirmCloseWithUnsavedChangesDescription": { + "description": "Settings switch description for close confirmation when documents have unsaved changes." + }, + "closeUnsavedChangesTitle": "Alterações não guardadas", + "@closeUnsavedChangesTitle": { + "description": "Window close confirmation dialog title when documents have unsaved changes." + }, + "closeUnsavedChangesSingleMessage": "Este documento tem alterações não guardadas. Guardar as alterações antes de fechar o BusyMark?", + "@closeUnsavedChangesSingleMessage": { + "description": "Window close confirmation message when one document has unsaved changes." + }, + "closeUnsavedChangesMultipleMessage": "{count, plural, =0{Guardar as alterações antes de fechar o BusyMark?} =1{1 documento tem alterações não guardadas. Guardar as alterações antes de fechar o BusyMark?} other{{count} documentos têm alterações não guardadas. Guardar as alterações antes de fechar o BusyMark?}}", + "@closeUnsavedChangesMultipleMessage": { + "description": "Window close confirmation message when multiple documents have unsaved changes.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "closeUnsavedChangesCancel": "Cancelar", + "@closeUnsavedChangesCancel": { + "description": "Cancel button label in the window close unsaved-changes dialog." + }, + "closeUnsavedChangesDiscard": "Descartar", + "@closeUnsavedChangesDiscard": { + "description": "Discard button label in the window close unsaved-changes dialog." + }, + "closeUnsavedChangesSave": "Guardar", + "@closeUnsavedChangesSave": { + "description": "Save button label in the window close unsaved-changes dialog." + }, + "currentFile": "ficheiro atual", + "@currentFile": { + "description": "Fallback file name in unsaved changes dialog." + }, + "unsavedChanges": "Alterações não guardadas", + "@unsavedChanges": { + "description": "Unsaved changes dialog title." + }, + "unsavedChangesMessage": "Existem alterações não guardadas em {fileName}. Pretende guardá-las antes de continuar?", + "@unsavedChangesMessage": { + "description": "Unsaved changes confirmation message.", + "placeholders": { + "fileName": { + "type": "String" + } + } + }, + "fileChangedOnDisk": "Ficheiro alterado no disco", + "@fileChangedOnDisk": { + "description": "File changed confirmation dialog title." + }, + "fileChangedOnDiskMessage": "Este ficheiro foi alterado no disco desde que foi aberto. Sobrescrever?", + "@fileChangedOnDiskMessage": { + "description": "File changed confirmation dialog message." + }, + "untitledMarkdownFileName": "Sem título.md", + "@untitledMarkdownFileName": { + "description": "Display name for a new unsaved Markdown document." + }, + "unorderedList": "Lista não ordenada", + "@unorderedList": { + "description": "WYSIWYG toolbar tooltip for unordered list." + }, + "orderedList": "Lista ordenada", + "@orderedList": { + "description": "WYSIWYG toolbar tooltip for ordered list." + }, + "taskList": "Lista de tarefas", + "@taskList": { + "description": "WYSIWYG toolbar tooltip for task list." + }, + "toggleTaskChecked": "Marcar/desmarcar tarefa", + "@toggleTaskChecked": { + "description": "WYSIWYG toolbar tooltip for toggling task state." + }, + "indentListItem": "Recuar item da lista", + "@indentListItem": { + "description": "WYSIWYG toolbar tooltip for indenting a list item." + }, + "outdentListItem": "Remover recuo do item da lista", + "@outdentListItem": { + "description": "WYSIWYG toolbar tooltip for outdenting a list item." + }, + "blockquote": "Citação em bloco", + "@blockquote": { + "description": "Blockquote command label." + }, + "codeBlock": "Bloco de código", + "@codeBlock": { + "description": "Code block command or preview label." + }, + "codeBlockLanguage": "Linguagem do bloco de código", + "@codeBlockLanguage": { + "description": "Dialog title and toolbar tooltip for code block language." + }, + "image": "Imagem", + "video": "Vídeo", + "openVideo": "Reproduzir vídeo", + "pauseVideo": "Pausar vídeo", + "videoUnavailable": "Vídeo indisponível", + "videoPreview": "Pré-visualização do vídeo", + "diagnosticWritersideVideoMissingSource": "O vídeo não tem o atributo src.", + "diagnosticWritersideVideoUnsupportedSource": "Fonte de vídeo não suportada: {source}", + "diagnosticWritersideVideoMissingFile": "O ficheiro de vídeo não existe: {source}", + "diagnosticWritersideVideoMissingPreview": "A imagem de pré-visualização do vídeo não existe: {preview}", + "@image": { + "description": "Image command and document kind label." + }, + "inlineImage": "Imagem embutida", + "@inlineImage": { + "description": "Inline image command label." + }, + "table": "Tabela", + "@table": { + "description": "Table command label." + }, + "htmlBlock": "Bloco HTML", + "@htmlBlock": { + "description": "HTML block command label." + }, + "shortcutHtmlBlockDescription": "Inserir ou editar um bloco HTML", + "@shortcutHtmlBlockDescription": { + "description": "Keyboard shortcut description for inserting or editing an HTML block." + }, + "renderedHtml": "HTML renderizado", + "@renderedHtml": { + "description": "Badge label for HTML rendered in the WYSIWYG editor." + }, + "editHtml": "Editar HTML", + "@editHtml": { + "description": "Dialog title and tooltip for editing raw HTML source." + }, + "htmlSource": "Código-fonte HTML", + "@htmlSource": { + "description": "Text field label for raw HTML source." + }, + "htmlContentDefault": "Conteúdo HTML", + "@htmlContentDefault": { + "description": "Default editable text inserted into a new HTML block." + }, + "thematicBreak": "Separador temático", + "@thematicBreak": { + "description": "Thematic break command label." + }, + "bold": "Negrito", + "@bold": { + "description": "Bold command label." + }, + "italic": "Itálico", + "@italic": { + "description": "Italic command label." + }, + "underline": "Sublinhado", + "@underline": { + "description": "Underline command label." + }, + "strikethrough": "Tachado", + "@strikethrough": { + "description": "Strikethrough command label." + }, + "inlineCode": "Código embutido", + "@inlineCode": { + "description": "Inline code command label." + }, + "link": "Ligação", + "@link": { + "description": "Link command and preview label." + }, + "hardLineBreak": "Quebra de linha forçada", + "@hardLineBreak": { + "description": "Hard line break command label." + }, + "textStyle": "Estilo de texto", + "@textStyle": { + "description": "Text style menu tooltip." + }, + "paragraph": "Parágrafo", + "@paragraph": { + "description": "Paragraph style label." + }, + "heading1": "Título 1", + "@heading1": { + "description": "Heading 1 style label." + }, + "heading2": "Título 2", + "@heading2": { + "description": "Heading 2 style label." + }, + "heading3": "Título 3", + "@heading3": { + "description": "Heading 3 style label." + }, + "heading4": "Título 4", + "@heading4": { + "description": "Heading 4 style label." + }, + "heading5": "Título 5", + "@heading5": { + "description": "Heading 5 style label." + }, + "heading6": "Título 6", + "@heading6": { + "description": "Heading 6 style label." + }, + "headingLevelAbbreviation": "H{level}", + "@headingLevelAbbreviation": { + "description": "Compact outline badge for a heading level.", + "placeholders": { + "level": { + "type": "int" + } + } + }, + "deleteTable": "Eliminar tabela", + "@deleteTable": { + "description": "Tooltip for deleting a table." + }, + "tableColumnNumber": "Coluna {columnNumber}", + "@tableColumnNumber": { + "description": "Tooltip for a table column control.", + "placeholders": { + "columnNumber": { + "type": "int" + } + } + }, + "insertColumnLeft": "Inserir coluna à esquerda", + "@insertColumnLeft": { + "description": "Menu item for inserting a table column to the left." + }, + "insertColumnRight": "Inserir coluna à direita", + "@insertColumnRight": { + "description": "Menu item for inserting a table column to the right." + }, + "deleteColumn": "Eliminar coluna", + "@deleteColumn": { + "description": "Menu item for deleting a table column." + }, + "tableRowNumber": "Linha {rowNumber}", + "@tableRowNumber": { + "description": "Tooltip for a table row control.", + "placeholders": { + "rowNumber": { + "type": "int" + } + } + }, + "insertRowAbove": "Inserir linha acima", + "@insertRowAbove": { + "description": "Menu item for inserting a table row above." + }, + "insertRowBelow": "Inserir linha abaixo", + "@insertRowBelow": { + "description": "Menu item for inserting a table row below." + }, + "deleteRow": "Eliminar linha", + "@deleteRow": { + "description": "Menu item for deleting a table row." + }, + "tableHeaderHint": "Cabeçalho", + "@tableHeaderHint": { + "description": "Hint for an empty table header cell." + }, + "tableCellHint": "Célula", + "@tableCellHint": { + "description": "Hint for an empty table body cell." + }, + "language": "Linguagem", + "@language": { + "description": "Code block language field label." + }, + "hideEditingButtons": "Ocultar botões de edição", + "@hideEditingButtons": { + "description": "Tooltip for hiding floating editing buttons." + }, + "showEditingButtons": "Mostrar botões de edição", + "@showEditingButtons": { + "description": "Tooltip for showing floating editing buttons." + }, + "altText": "Texto alternativo", + "@altText": { + "description": "Image alt text field label." + }, + "editorPlaceholderText": "texto", + "@editorPlaceholderText": { + "description": "Default selected text inserted by a source-editor formatting command." + }, + "editorPlaceholderCode": "código", + "@editorPlaceholderCode": { + "description": "Default selected code inserted by a source-editor code command." + }, + "editorPlaceholderAltText": "texto alternativo", + "@editorPlaceholderAltText": { + "description": "Default selected image description inserted by a source-editor image command." + }, + "describeTheImage": "Descreva a imagem", + "@describeTheImage": { + "description": "Image alt text hint." + }, + "columns": "Colunas", + "@columns": { + "description": "Table dialog columns field label." + }, + "rows": "Linhas", + "@rows": { + "description": "Table dialog rows field label." + }, + "tableHeaderNumber": "Cabeçalho {columnNumber}", + "@tableHeaderNumber": { + "description": "Default header text for a newly inserted table column.", + "placeholders": { + "columnNumber": { + "type": "int" + } + } + }, + "tableCellDefault": "Célula", + "@tableCellDefault": { + "description": "Default cell text for newly inserted table cells." + }, + "noImageSource": "Nenhuma origem de imagem", + "@noImageSource": { + "description": "Placeholder shown when an image has no source." + }, + "remoteImageBlocked": "Imagem remota bloqueada", + "@remoteImageBlocked": { + "description": "Placeholder label shown when a remote image is blocked." + }, + "remoteImageBlockedTooltip": "Escolha se o BusyMark pode carregar imagens remotas.", + "@remoteImageBlockedTooltip": { + "description": "Tooltip for a blocked remote image placeholder." + }, + "remoteImagesBlockedTitle": "As imagens remotas estão bloqueadas", + "@remoteImagesBlockedTitle": { + "description": "Dialog title for remote image loading permission." + }, + "remoteImagesBlockedMessage": "Este documento faz referência a imagens da Internet. Carregá-las pode revelar informações de rede ao servidor que as hospeda.", + "@remoteImagesBlockedMessage": { + "description": "Dialog message explaining the privacy risk of remote images." + }, + "loadRemoteImagesForWorkspace": "Carregar neste espaço de trabalho", + "@loadRemoteImagesForWorkspace": { + "description": "Dialog button that allows remote images for the current workspace." + }, + "alwaysLoadRemoteImages": "Sempre carregar imagens remotas", + "@alwaysLoadRemoteImages": { + "description": "Dialog button that enables remote images globally." + }, + "hideSidebar": "Ocultar painel lateral", + "@hideSidebar": { + "description": "Tooltip for hiding the workspace sidebar." + }, + "showSidebar": "Mostrar painel lateral", + "@showSidebar": { + "description": "Tooltip for showing the workspace sidebar." + }, + "showPreview": "Mostrar pré-visualização", + "@showPreview": { + "description": "Tooltip for showing the preview pane." + }, + "hidePreview": "Ocultar pré-visualização", + "@hidePreview": { + "description": "Tooltip for hiding the preview pane." + }, + "workspaceKindUnsavedMarkdown": "Ficheiro Markdown não guardado", + "@workspaceKindUnsavedMarkdown": { + "description": "Workspace kind label for an unsaved Markdown file." + }, + "workspaceKindSingleMarkdown": "Ficheiro Markdown único", + "@workspaceKindSingleMarkdown": { + "description": "Workspace kind label for a single Markdown file." + }, + "workspaceKindMarkdownFolder": "Pasta Markdown", + "@workspaceKindMarkdownFolder": { + "description": "Workspace kind label for a Markdown folder." + }, + "workspaceKindWritersideModule": "Módulo Writerside", + "@workspaceKindWritersideModule": { + "description": "Workspace kind label for a Writerside module." + }, + "problems": "Problemas", + "@problems": { + "description": "Diagnostics dialog title." + }, + "diagnosticCount": "{count, plural, =0{Nenhum diagnóstico} =1{1 diagnóstico} other{{count} diagnósticos}}", + "@diagnosticCount": { + "description": "Count of diagnostics in the workspace.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "files": "Ficheiros", + "@files": { + "description": "Files sidebar tab label." + }, + "toc": "TOC", + "@toc": { + "description": "Writerside table of contents sidebar tab label." + }, + "tocActions": "Ações do sumário", + "@tocActions": { + "description": "Tooltip for the Writerside TOC action menu button." + }, + "markdownUnsaved": "Markdown - não guardado", + "@markdownUnsaved": { + "description": "Workspace detail label for an unsaved Markdown file." + }, + "workspaceDetail": "{kind} - {count, plural, =1{1 ficheiro} other{{count} ficheiros}}", + "@workspaceDetail": { + "description": "Workspace detail with kind and file count.", + "placeholders": { + "kind": { + "type": "String" + }, + "count": { + "type": "int" + } + } + }, + "noFiles": "Nenhum ficheiro", + "@noFiles": { + "description": "Empty state shown when there are no files." + }, + "noWritersideToc": "Nenhum TOC do Writerside", + "@noWritersideToc": { + "description": "Empty state shown when there is no Writerside TOC." + }, + "tocSection": "Secção do TOC", + "@tocSection": { + "description": "Fallback label for a Writerside TOC section." + }, + "newTopic": "Novo tópico", + "@newTopic": { + "description": "Create new Writerside topic action label." + }, + "newChildTopic": "Novo subtópico", + "@newChildTopic": { + "description": "Create new child Writerside topic action label." + }, + "newSiblingTopic": "Novo tópico no mesmo nível", + "@newSiblingTopic": { + "description": "Create new sibling Writerside topic action label." + }, + "renameTopicFile": "Renomear ficheiro do tópico", + "@renameTopicFile": { + "description": "Context-menu action that renames a Writerside topic file." + }, + "topicPlacement": "Posição no TOC", + "@topicPlacement": { + "description": "Create topic dialog label for selecting TOC placement." + }, + "tocRoot": "Na raiz do TOC", + "@tocRoot": { + "description": "TOC placement option for the root level." + }, + "afterSelectedTopic": "Após o tópico selecionado", + "@afterSelectedTopic": { + "description": "TOC placement option after the selected topic." + }, + "insideSelectedTopic": "Dentro do tópico selecionado", + "@insideSelectedTopic": { + "description": "TOC placement option inside the selected topic." + }, + "pasteAfterTopic": "Colar depois", + "@pasteAfterTopic": { + "description": "Action that moves a cut TOC entry after the selected topic." + }, + "pasteAsChildTopic": "Colar como subtópico", + "@pasteAsChildTopic": { + "description": "Action that moves a cut TOC entry inside the selected topic." + }, + "removeFromToc": "Remover do TOC", + "@removeFromToc": { + "description": "Action that removes an entry from a Writerside table of contents without deleting its topic file." + }, + "confirmRemoveFromTocTitle": "Remover do TOC?", + "@confirmRemoveFromTocTitle": { + "description": "Confirmation title before removing a Writerside TOC entry." + }, + "confirmRemoveFromTocMessage": "Remover {name} deste TOC? O ficheiro do tópico será mantido.", + "@confirmRemoveFromTocMessage": { + "description": "Confirmation message before removing a Writerside TOC entry without deleting its topic file.", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "confirmDeleteTopicTitle": "Eliminar o ficheiro do tópico?", + "@confirmDeleteTopicTitle": { + "description": "Confirmation title before deleting a Writerside topic file." + }, + "confirmDeleteTopicMessage": "Eliminar {name} e removê-lo de todos os TOCs? Esta ação não pode ser anulada.", + "@confirmDeleteTopicMessage": { + "description": "Confirmation message before deleting a Writerside topic file and removing its TOC entries.", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "defaultNewTopicTitle": "Novo tópico", + "@defaultNewTopicTitle": { + "description": "Default topic title in the create topic dialog." + }, + "topicTitle": "Título do tópico", + "@topicTitle": { + "description": "Create topic dialog field label." + }, + "fileName": "Nome do ficheiro", + "@fileName": { + "description": "Create topic dialog field label." + }, + "topicTitleRequired": "O título do tópico é obrigatório.", + "@topicTitleRequired": { + "description": "Validation message for missing topic title." + }, + "fileNameRequired": "O nome do ficheiro é obrigatório.", + "@fileNameRequired": { + "description": "Validation message for missing file name." + }, + "useSingleSafeFileName": "Use um único nome de ficheiro seguro.", + "@useSingleSafeFileName": { + "description": "Validation message for unsafe file names." + }, + "useExpectedExtension": "Use a extensão {extension} para o formato selecionado.", + "@useExpectedExtension": { + "description": "Validation message for an unexpected file extension.", + "placeholders": { + "extension": { + "type": "String" + } + } + }, + "useIdentifierCharacters": "Use letras, números, sublinhados ou hifens antes da extensão.", + "@useIdentifierCharacters": { + "description": "Validation message for invalid topic IDs." + }, + "topicIdAlreadyExists": "O ID do tópico já existe.", + "@topicIdAlreadyExists": { + "description": "Validation message for duplicate topic IDs." + }, + "createWritersideTopicFailed": "Não foi possível criar o tópico do Writerside.", + "@createWritersideTopicFailed": { + "description": "Fallback error shown when topic creation fails." + }, + "noOutline": "Sem estrutura", + "@noOutline": { + "description": "Empty state shown when a document has no outline." + }, + "expandKind": "Expandir {kind}", + "@expandKind": { + "description": "Tooltip for expanding a foldable source section.", + "placeholders": { + "kind": { + "type": "String" + } + } + }, + "collapseKind": "Recolher {kind}", + "@collapseKind": { + "description": "Tooltip for collapsing a foldable source section.", + "placeholders": { + "kind": { + "type": "String" + } + } + }, + "foldKindSection": "secção", + "@foldKindSection": { + "description": "Fold kind label for a section." + }, + "foldKindList": "lista", + "@foldKindList": { + "description": "Fold kind label for a list." + }, + "foldKindQuote": "citação", + "@foldKindQuote": { + "description": "Fold kind label for a blockquote." + }, + "foldKindTag": "tag", + "@foldKindTag": { + "description": "Fold kind label for an XML tag." + }, + "sourceSearchPreviousMatch": "Correspondência anterior", + "@sourceSearchPreviousMatch": { + "description": "Tooltip for moving to the previous source search match." + }, + "sourceSearchNextMatch": "Próxima correspondência", + "@sourceSearchNextMatch": { + "description": "Tooltip for moving to the next source search match." + }, + "sourceSearchCaseSensitive": "Diferenciar maiúsculas de minúsculas", + "@sourceSearchCaseSensitive": { + "description": "Tooltip for toggling case-sensitive source search." + }, + "sourceSearchWholeWord": "Palavra inteira", + "@sourceSearchWholeWord": { + "description": "Tooltip for toggling whole-word source search." + }, + "sourceSearchRegex": "Expressão regular", + "@sourceSearchRegex": { + "description": "Tooltip for toggling regular-expression source search." + }, + "sourceSearchInvalidRegex": "Expressão regular inválida", + "@sourceSearchInvalidRegex": { + "description": "Source search status shown when the regular expression is invalid." + }, + "sourceLargeFileFeaturesPaused": "Ficheiro grande: o realce e o recolhimento estão pausados", + "@sourceLargeFileFeaturesPaused": { + "description": "Status banner shown when source highlighting and folding are disabled for a large file." + }, + "nothingToRead": "Nenhum conteúdo para ler", + "admonition": "Bloco de destaque", + "quote": "Citação", + "@nothingToRead": { + "description": "Empty state shown when there is no content to read." + }, + "note": "Observação", + "@note": { + "description": "Preview label for a note admonition." + }, + "tip": "Dica", + "@tip": { + "description": "Preview label for a tip admonition." + }, + "warning": "Aviso", + "@warning": { + "description": "Preview label for a warning admonition." + }, + "tabs": "Guias", + "@tabs": { + "description": "Preview label for a tabs block." + }, + "tab": "Guia", + "@tab": { + "description": "Preview label for a tab block." + }, + "procedure": "Procedimento", + "@procedure": { + "description": "Preview label for a procedure block." + }, + "step": "Etapa", + "@step": { + "description": "Preview label for a procedure step." + }, + "topic": "Tópico", + "@topic": { + "description": "Preview label for a topic element." + }, + "chapter": "Capítulo", + "@chapter": { + "description": "Preview label for a chapter element." + }, + "couldNotOpenTarget": "Não foi possível abrir {target}", + "@couldNotOpenTarget": { + "description": "Toast shown when a link target cannot be opened.", + "placeholders": { + "target": { + "type": "String" + } + } + }, + "linkTargetNotFound": "Destino da ligação não encontrado: {targetPath}", + "@linkTargetNotFound": { + "description": "Toast shown when a link target path is missing.", + "placeholders": { + "targetPath": { + "type": "String" + } + } + }, + "cannotOpenFileTypeInEditor": "Não é possível abrir este tipo de ficheiro no editor", + "@cannotOpenFileTypeInEditor": { + "description": "Toast shown when a file type cannot be opened in the editor." + }, + "anchorNotFound": "Âncora não encontrada: {anchor}", + "@anchorNotFound": { + "description": "Toast shown when a link anchor is missing.", + "placeholders": { + "anchor": { + "type": "String" + } + } + }, + "noProblemsFound": "Nenhum problema encontrado", + "@noProblemsFound": { + "description": "Diagnostics empty state." + }, + "noResults": "Nenhum resultado", + "@noResults": { + "description": "Search empty state." + }, + "searchResultLine": "{relativePath} - linha {lineNumber}", + "@searchResultLine": { + "description": "Search result subtitle with file path and line number.", + "placeholders": { + "relativePath": { + "type": "String" + }, + "lineNumber": { + "type": "int" + } + } + }, + "untitledResult": "Resultado sem título", + "@untitledResult": { + "description": "Fallback search result title." + }, + "documentKindMarkdownFile": "Ficheiro Markdown", + "@documentKindMarkdownFile": { + "description": "Search result document kind label." + }, + "documentKindWritersideMarkdownTopic": "Tópico Markdown do Writerside", + "@documentKindWritersideMarkdownTopic": { + "description": "Search result document kind label." + }, + "documentKindWritersideXmlTopic": "Tópico XML do Writerside", + "@documentKindWritersideXmlTopic": { + "description": "Search result document kind label." + }, + "documentKindWritersideTree": "Árvore do Writerside", + "@documentKindWritersideTree": { + "description": "Search result document kind label." + }, + "documentKindConfigurationFile": "Ficheiro de configuração", + "@documentKindConfigurationFile": { + "description": "Search result document kind label." + }, + "documentKindVariablesFile": "Ficheiro de variáveis", + "@documentKindVariablesFile": { + "description": "Search result document kind label." + }, + "documentKindCategoriesFile": "Ficheiro de categorias", + "@documentKindCategoriesFile": { + "description": "Search result document kind label." + }, + "documentKindResourceFile": "Ficheiro de recursos", + "@documentKindResourceFile": { + "description": "Search result document kind label." + }, + "workspaceErrorOpenFailed": "Falha ao abrir: {error}", + "@workspaceErrorOpenFailed": { + "description": "Workspace error message shown when opening a path fails.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "workspaceErrorCreateWritersideProjectFailed": "Não foi possível criar o projeto Writerside: {error}", + "@workspaceErrorCreateWritersideProjectFailed": { + "description": "Workspace error message shown when Writerside project creation fails.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "workspaceErrorCreateWritersideTopicFailed": "Não foi possível criar o tópico do Writerside: {error}", + "@workspaceErrorCreateWritersideTopicFailed": { + "description": "Workspace error message shown when Writerside topic creation fails.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "workspaceErrorCouldNotOpenFile": "Não foi possível abrir o ficheiro: {error}", + "@workspaceErrorCouldNotOpenFile": { + "description": "Workspace error message shown when opening a file fails.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "workspaceErrorChooseWhereToSaveMarkdown": "Escolha onde guardar este ficheiro Markdown.", + "@workspaceErrorChooseWhereToSaveMarkdown": { + "description": "Workspace error message shown when an untitled file needs a save location." + }, + "workspaceErrorSaveBlockedFileChangedOnDisk": "Gravação bloqueada: o ficheiro foi alterado no disco.", + "@workspaceErrorSaveBlockedFileChangedOnDisk": { + "description": "Workspace error message shown when a save is blocked by external changes." + }, + "workspaceErrorSaveFailed": "Falha ao guardar: {error}", + "@workspaceErrorSaveFailed": { + "description": "Workspace error message shown when saving fails.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "workspaceErrorValidationFailed": "Falha na validação: {error}", + "@workspaceErrorValidationFailed": { + "description": "Workspace error message shown when validation fails.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "errorPathDoesNotExist": "O caminho não existe: {path}", + "@errorPathDoesNotExist": { + "description": "Detail for a missing path error.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorTargetDirectoryNotEmpty": "O diretório de destino já existe e não está vazio: {path}", + "@errorTargetDirectoryNotEmpty": { + "description": "Detail for a non-empty target directory error.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorTargetPathNotDirectory": "O caminho de destino já existe e não é um diretório: {path}", + "@errorTargetPathNotDirectory": { + "description": "Detail for a target path that is not a directory.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorGeneratedFileAlreadyExists": "O ficheiro gerado já existe: {path}", + "@errorGeneratedFileAlreadyExists": { + "description": "Detail for a generated file conflict.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorParentDirectoryRequired": "O diretório pai é obrigatório.", + "@errorParentDirectoryRequired": { + "description": "Detail for missing parent directory input." + }, + "errorParentDirectoryMissing": "O diretório pai não existe: {path}", + "@errorParentDirectoryMissing": { + "description": "Detail for a missing parent directory.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorProjectNameRequired": "O nome do projeto é obrigatório.", + "@errorProjectNameRequired": { + "description": "Detail for a missing project name." + }, + "errorDirectoryNameRequired": "O nome do diretório é obrigatório.", + "@errorDirectoryNameRequired": { + "description": "Detail for a missing directory name." + }, + "errorDirectoryNameUnsafe": "O nome do diretório deve ser um único segmento de caminho seguro.", + "@errorDirectoryNameUnsafe": { + "description": "Detail for an unsafe directory name." + }, + "errorInstanceIdInvalid": "O ID da instância deve começar com uma letra minúscula e conter apenas letras minúsculas, números, sublinhados e hifens.", + "@errorInstanceIdInvalid": { + "description": "Detail for an invalid Writerside instance ID." + }, + "errorTopicFileInvalid": "O nome do ficheiro do tópico deve ser um nome de ficheiro Markdown sem separadores de caminho.", + "@errorTopicFileInvalid": { + "description": "Detail for an invalid topic file name." + }, + "errorTopicTitleRequired": "O título do tópico é obrigatório.", + "@errorTopicTitleRequired": { + "description": "Detail for a missing topic title." + }, + "errorWritersideModuleRootMissing": "A raiz do módulo Writerside não existe: {path}", + "@errorWritersideModuleRootMissing": { + "description": "Detail for a missing Writerside module root.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorWritersideModuleNotOpen": "Um módulo Writerside deve estar aberto para criar um tópico.", + "@errorWritersideModuleNotOpen": { + "description": "Detail shown when creating a topic without an open Writerside module." + }, + "errorWritersideInstanceTreeMissing": "O módulo Writerside não tem uma árvore de instância.", + "@errorWritersideInstanceTreeMissing": { + "description": "Detail shown when creating a topic without a Writerside instance tree." + }, + "errorWritersideTreeFileMissing": "O ficheiro de árvore do Writerside não existe: {path}", + "@errorWritersideTreeFileMissing": { + "description": "Detail for a missing Writerside tree file.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorTopicIdAlreadyExists": "O ID do tópico \"{topicId}\" já existe neste módulo de ajuda.", + "@errorTopicIdAlreadyExists": { + "description": "Detail for a duplicate topic ID.", + "placeholders": { + "topicId": { + "type": "String" + } + } + }, + "errorTopicFileAlreadyExists": "O ficheiro do tópico já existe: {path}", + "@errorTopicFileAlreadyExists": { + "description": "Detail for an existing topic file.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorReferenceTopicMissing": "O tópico de referência não está presente na árvore selecionada: {topic}", + "@errorReferenceTopicMissing": { + "description": "Detail for a missing reference topic in a tree.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "errorWritersideTocNodeMissing": "A entrada selecionada do TOC não existe mais.", + "@errorWritersideTocNodeMissing": { + "description": "Detail shown when a selected Writerside TOC entry no longer exists." + }, + "errorWritersideTocInvalidMove": "Uma entrada do TOC não pode ser movida para dentro de si mesma nem de um de seus descendentes.", + "@errorWritersideTocInvalidMove": { + "description": "Detail shown when a Writerside TOC move would create a cycle." + }, + "errorWritersideStartTopicDelete": "O tópico inicial {topic} não pode ser eliminado. Escolha primeiro outra página inicial.", + "@errorWritersideStartTopicDelete": { + "description": "Detail shown when attempting to delete the start topic of a Writerside instance.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "errorTopicsRootUnsafe": "A raiz dos tópicos deve ser um diretório relativo seguro.", + "@errorTopicsRootUnsafe": { + "description": "Detail for an unsafe topics root directory." + }, + "errorTopicFileNameUnsafe": "O nome do ficheiro do tópico deve ser um único segmento de caminho seguro.", + "@errorTopicFileNameUnsafe": { + "description": "Detail for an unsafe topic file name." + }, + "errorTopicFileExtensionMismatch": "A extensão do ficheiro do tópico deve corresponder ao formato selecionado ({extension}).", + "@errorTopicFileExtensionMismatch": { + "description": "Detail for a topic file extension mismatch.", + "placeholders": { + "extension": { + "type": "String" + } + } + }, + "errorTopicFileNameInvalid": "O nome do ficheiro do tópico deve conter apenas letras, números, sublinhados e hifens.", + "@errorTopicFileNameInvalid": { + "description": "Detail for a topic file name with invalid characters." + }, + "errorUnknown": "Erro desconhecido: {code}", + "@errorUnknown": { + "description": "Fallback detail for an unknown coded application error.", + "placeholders": { + "code": { + "type": "String" + } + } + }, + "diagnosticWorkspaceFileStatFailed": "Não foi possível ler os metadados do ficheiro: {error}", + "@diagnosticWorkspaceFileStatFailed": { + "description": "Diagnostic shown when file metadata cannot be read.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "diagnosticWorkspaceScanSkipped": "Foi detetado um espaço de trabalho grande. Alguns ficheiros foram ignorados para manter a aplicação responsiva.", + "@diagnosticWorkspaceScanSkipped": { + "description": "Diagnostic shown when workspace scanning skips files." + }, + "diagnosticWorkspaceScanInspectFailed": "Não foi possível inspecionar a entrada do espaço de trabalho: {error}", + "@diagnosticWorkspaceScanInspectFailed": { + "description": "Diagnostic shown when a workspace entry cannot be inspected.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "diagnosticWorkspaceFileTooLarge": "O ficheiro excede o limite beta de análise automática.", + "@diagnosticWorkspaceFileTooLarge": { + "description": "Diagnostic shown when a file is too large to parse automatically." + }, + "diagnosticWorkspaceFileReadFailed": "Não foi possível ler o ficheiro Markdown: {error}", + "@diagnosticWorkspaceFileReadFailed": { + "description": "Diagnostic shown when a Markdown file cannot be read.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "diagnosticMarkdownAttributeMalformed": "O bloco de atributos de título do Writerside está malformado.", + "@diagnosticMarkdownAttributeMalformed": { + "description": "Markdown parser diagnostic for malformed Writerside heading attributes." + }, + "diagnosticMarkdownHeadingDuplicateId": "ID de título duplicado \"{id}\".", + "@diagnosticMarkdownHeadingDuplicateId": { + "description": "Markdown parser diagnostic for duplicate heading IDs.", + "placeholders": { + "id": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicH1ConvertedToChapter": "Títulos H1 adicionais no nível superior são tratados como capítulos.", + "@diagnosticWritersideTopicH1ConvertedToChapter": { + "description": "Markdown parser diagnostic for additional H1 headings in Writerside mode." + }, + "diagnosticWritersideMarkdownTopicMissingTitle": "O tópico Markdown do Writerside não tem H1 nem título no front matter.", + "@diagnosticWritersideMarkdownTopicMissingTitle": { + "description": "Diagnostic for a Writerside Markdown topic without a title." + }, + "diagnosticWritersideXmlTopicMissingTitle": "O tópico XML não tem título.", + "@diagnosticWritersideXmlTopicMissingTitle": { + "description": "Diagnostic for a Writerside XML topic without a title." + }, + "diagnosticWritersideTopicFileMissingTitle": "O tópico \"{fileName}\" não tem título.", + "@diagnosticWritersideTopicFileMissingTitle": { + "description": "Diagnostic for a Writerside topic file without a title.", + "placeholders": { + "fileName": { + "type": "String" + } + } + }, + "diagnosticMarkdownFrontMatterMalformed": "O front matter não foi fechado.", + "@diagnosticMarkdownFrontMatterMalformed": { + "description": "Markdown parser diagnostic for unclosed front matter." + }, + "diagnosticMarkdownRawHtmlUnsafe": "Elemento HTML inseguro.", + "@diagnosticMarkdownRawHtmlUnsafe": { + "description": "Markdown parser diagnostic for unsafe raw HTML." + }, + "diagnosticMarkdownLinkUnresolvedTarget": "O destino da ligação não existe: {targetPath}", + "@diagnosticMarkdownLinkUnresolvedTarget": { + "description": "Markdown parser diagnostic for a missing link target.", + "placeholders": { + "targetPath": { + "type": "String" + } + } + }, + "diagnosticMarkdownLinkUnresolvedAnchor": "A âncora \"{anchor}\" não existe.", + "@diagnosticMarkdownLinkUnresolvedAnchor": { + "description": "Markdown parser diagnostic for a missing local anchor.", + "placeholders": { + "anchor": { + "type": "String" + } + } + }, + "diagnosticMarkdownImageMissingAlt": "A imagem \"{destination}\" não tem texto alternativo.", + "@diagnosticMarkdownImageMissingAlt": { + "description": "Markdown parser diagnostic for a missing image alt text.", + "placeholders": { + "destination": { + "type": "String" + } + } + }, + "diagnosticMarkdownImageMissingFile": "A imagem não existe: {destination}", + "@diagnosticMarkdownImageMissingFile": { + "description": "Markdown parser diagnostic for a missing image file.", + "placeholders": { + "destination": { + "type": "String" + } + } + }, + "diagnosticInvalidXml": "XML inválido: {message}", + "@diagnosticInvalidXml": { + "description": "XML parser diagnostic for invalid XML.", + "placeholders": { + "message": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigInvalidRoot": "A raiz do ficheiro writerside.cfg deve ser <ihp>.", + "@diagnosticWritersideConfigInvalidRoot": { + "description": "Writerside parser diagnostic for an invalid writerside.cfg root element." + }, + "diagnosticWritersideConfigMissingSnippetsSrc": "A declaração de snippets está sem o atributo src.", + "@diagnosticWritersideConfigMissingSnippetsSrc": { + "description": "Writerside parser diagnostic for a snippets declaration without src." + }, + "diagnosticWritersideConfigMissingInstanceGroupsSrc": "A declaração de instance-groups está sem o atributo src.", + "@diagnosticWritersideConfigMissingInstanceGroupsSrc": { + "description": "Writerside parser diagnostic for an instance-groups declaration without src." + }, + "diagnosticWritersideConfigInvalidKeymapsMode": "Modo de keymaps não suportado: {mode}", + "@diagnosticWritersideConfigInvalidKeymapsMode": { + "description": "Writerside parser diagnostic for an unsupported keymaps mode.", + "placeholders": { + "mode": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigMissingInstanceSrc": "A declaração de instância está sem o atributo src.", + "@diagnosticWritersideConfigMissingInstanceSrc": { + "description": "Writerside parser diagnostic for an instance declaration without src." + }, + "diagnosticWritersideConfigMissingInstance": "O ficheiro writerside.cfg não regista uma instância.", + "@diagnosticWritersideConfigMissingInstance": { + "description": "Writerside parser diagnostic for a config with no instance." + }, + "diagnosticWritersideTreeInvalidRoot": "A raiz do ficheiro .tree deve ser <instance-profile>.", + "@diagnosticWritersideTreeInvalidRoot": { + "description": "Writerside parser diagnostic for an invalid tree root element." + }, + "diagnosticWritersideTreeMissingId": "O perfil da instância está sem o atributo id.", + "@diagnosticWritersideTreeMissingId": { + "description": "Writerside parser diagnostic for an instance profile without id." + }, + "diagnosticWritersideTreeIdMismatch": "O nome-base do ficheiro .tree não corresponde ao ID da instância \"{id}\".", + "@diagnosticWritersideTreeIdMismatch": { + "description": "Writerside parser diagnostic for a tree filename and ID mismatch.", + "placeholders": { + "id": { + "type": "String" + } + } + }, + "diagnosticWritersideTreeMissingStartPage": "A instância que não é de biblioteca não tem start-page.", + "@diagnosticWritersideTreeMissingStartPage": { + "description": "Writerside parser diagnostic for a tree missing start-page." + }, + "diagnosticWritersideStartPageMissing": "A página inicial \"{startPage}\" não existe.", + "@diagnosticWritersideStartPageMissing": { + "description": "Writerside diagnostic for a missing start page.", + "placeholders": { + "startPage": { + "type": "String" + } + } + }, + "diagnosticWritersideTreeDuplicateTopic": "O tópico \"{topic}\" aparece mais de uma vez no TOC desta instância.", + "@diagnosticWritersideTreeDuplicateTopic": { + "description": "Writerside parser diagnostic for a duplicate topic in a TOC.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "diagnosticWritersideVariableMalformedDeclaration": "A declaração de variável deve ter nome e valor.", + "@diagnosticWritersideVariableMalformedDeclaration": { + "description": "Writerside parser diagnostic for a malformed variable declaration." + }, + "diagnosticWritersideVariableDuplicateName": "A variável \"{name}\" é declarada mais de uma vez.", + "@diagnosticWritersideVariableDuplicateName": { + "description": "Writerside parser diagnostic for a duplicate variable name.", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "diagnosticWritersideCategoryMissingId": "A categoria está sem o atributo id.", + "@diagnosticWritersideCategoryMissingId": { + "description": "Writerside parser diagnostic for a category without id." + }, + "diagnosticWritersideCategoryDuplicateId": "A categoria \"{id}\" é declarada mais de uma vez.", + "@diagnosticWritersideCategoryDuplicateId": { + "description": "Writerside parser diagnostic for a duplicate category ID.", + "placeholders": { + "id": { + "type": "String" + } + } + }, + "diagnosticWritersideCategoryDuplicateOrder": "A ordem da categoria \"{order}\" foi declarada mais de uma vez.", + "@diagnosticWritersideCategoryDuplicateOrder": { + "description": "Writerside parser diagnostic for a duplicate category order.", + "placeholders": { + "order": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicInvalidRoot": "A raiz do ficheiro .topic deve ser <topic>.", + "@diagnosticWritersideTopicInvalidRoot": { + "description": "Writerside parser diagnostic for an invalid XML topic root." + }, + "diagnosticWritersideTopicMissingRootId": "A raiz do tópico XML está sem o atributo id.", + "@diagnosticWritersideTopicMissingRootId": { + "description": "Writerside parser diagnostic for an XML topic missing root id." + }, + "diagnosticWritersideTopicRootIdMismatch": "O ID raiz do tópico XML \"{id}\" deve corresponder ao nome do ficheiro \"{expectedId}\".", + "@diagnosticWritersideTopicRootIdMismatch": { + "description": "Writerside parser diagnostic for an XML topic root ID mismatch.", + "placeholders": { + "id": { + "type": "String" + }, + "expectedId": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicDuplicateElementId": "O ID do elemento \"{elementId}\" aparece mais de uma vez.", + "@diagnosticWritersideTopicDuplicateElementId": { + "description": "Writerside parser diagnostic for a duplicate XML element ID.", + "placeholders": { + "elementId": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicAnchorMissingHref": "<a> está sem o atributo href.", + "@diagnosticWritersideTopicAnchorMissingHref": { + "description": "Writerside parser diagnostic for an anchor without href." + }, + "diagnosticWritersideConfigMissing": "O modo Writerside requer o ficheiro writerside.cfg.", + "@diagnosticWritersideConfigMissing": { + "description": "Writerside module diagnostic for a missing writerside.cfg." + }, + "diagnosticWritersideConfigMissingBuildConfigDirectory": "O diretório configurado para a compilação está ausente: {relativePath}", + "@diagnosticWritersideConfigMissingBuildConfigDirectory": { + "description": "Writerside module diagnostic for a missing build config directory.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigMissingApiSpecificationsDirectory": "O diretório de especificações de API configurado está ausente: {relativePath}", + "@diagnosticWritersideConfigMissingApiSpecificationsDirectory": { + "description": "Writerside module diagnostic for a missing API specifications directory.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigMissingSnippetsDirectory": "O diretório de snippets configurado está ausente: {relativePath}", + "@diagnosticWritersideConfigMissingSnippetsDirectory": { + "description": "Writerside module diagnostic for a missing snippets directory.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigMissingVarsFile": "O ficheiro de variáveis configurado está ausente: {relativePath}", + "@diagnosticWritersideConfigMissingVarsFile": { + "description": "Writerside module diagnostic for a missing variables file.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigMissingCategoriesFile": "O ficheiro de categorias configurado está ausente: {relativePath}", + "@diagnosticWritersideConfigMissingCategoriesFile": { + "description": "Writerside module diagnostic for a missing categories file.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigMissingInstanceGroupsFile": "O ficheiro de grupos de instâncias configurado está ausente: {relativePath}", + "@diagnosticWritersideConfigMissingInstanceGroupsFile": { + "description": "Writerside module diagnostic for a missing instance groups file.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigMissingInstanceTree": "A árvore de instância registada \"{source}\" não existe.", + "@diagnosticWritersideConfigMissingInstanceTree": { + "description": "Writerside module diagnostic for a missing registered instance tree.", + "placeholders": { + "source": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicReadFailed": "Não foi possível ler o ficheiro do tópico: {error}", + "@diagnosticWritersideTopicReadFailed": { + "description": "Writerside module diagnostic for a topic file read failure.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "diagnosticWritersideDefaultTopicsDirectoryMissing": "O diretório de tópicos predefinido está ausente: {relativePath}", + "@diagnosticWritersideDefaultTopicsDirectoryMissing": { + "description": "Writerside module diagnostic for a missing default topics directory.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicsDirectoryMissing": "O diretório de tópicos configurado está ausente: {relativePath}", + "@diagnosticWritersideTopicsDirectoryMissing": { + "description": "Writerside module diagnostic for a missing topics directory.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideImagesDirectoryMissing": "O diretório de imagens configurado está ausente: {relativePath}", + "@diagnosticWritersideImagesDirectoryMissing": { + "description": "Writerside module diagnostic for a missing images directory.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicDuplicateId": "O ID do elemento \"{id}\" aparece mais de uma vez.", + "@diagnosticWritersideTopicDuplicateId": { + "description": "Writerside module diagnostic for a duplicate topic element ID.", + "placeholders": { + "id": { + "type": "String" + } + } + }, + "diagnosticWritersideTreeMissingTopic": "O TOC faz referência ao tópico ausente \"{topic}\".", + "@diagnosticWritersideTreeMissingTopic": { + "description": "Writerside module diagnostic for a TOC reference to a missing topic.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "diagnosticWritersideTreeInvalidHref": "O href externo \"{href}\" é inválido.", + "@diagnosticWritersideTreeInvalidHref": { + "description": "Writerside module diagnostic for an invalid external href.", + "placeholders": { + "href": { + "type": "String" + } + } + }, + "diagnosticWritersideVariableUnresolved": "A variável \"%{name}%\" não foi declarada.", + "@diagnosticWritersideVariableUnresolved": { + "description": "Writerside module diagnostic for an undeclared variable.", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicLinkUnresolved": "Não foi possível resolver a ligação para o tópico \"{destination}\".", + "@diagnosticWritersideTopicLinkUnresolved": { + "description": "Writerside module diagnostic for an unresolved topic link.", + "placeholders": { + "destination": { + "type": "String" + } + } + }, + "diagnosticWritersideAnchorUnresolved": "A âncora \"{anchor}\" não existe em \"{targetName}\".", + "@diagnosticWritersideAnchorUnresolved": { + "description": "Writerside module diagnostic for an unresolved topic anchor.", + "placeholders": { + "anchor": { + "type": "String" + }, + "targetName": { + "type": "String" + } + } + }, + "diagnosticWritersideIncludeMissingFrom": "<include> está sem o atributo from.", + "@diagnosticWritersideIncludeMissingFrom": { + "description": "Writerside module diagnostic for an include without a from attribute." + }, + "diagnosticWritersideIncludeSourceMissing": "A origem da inclusão \"{from}\" não existe.", + "@diagnosticWritersideIncludeSourceMissing": { + "description": "Writerside module diagnostic for a missing include source.", + "placeholders": { + "from": { + "type": "String" + } + } + }, + "diagnosticWritersideIncludeElementMissing": "O elemento incluído \"{elementId}\" não existe em \"{from}\".", + "@diagnosticWritersideIncludeElementMissing": { + "description": "Writerside module diagnostic for a missing include element.", + "placeholders": { + "elementId": { + "type": "String" + }, + "from": { + "type": "String" + } + } + }, + "diagnosticWritersideCategoryUnresolved": "A categoria seealso \"{ref}\" não foi declarada.", + "@diagnosticWritersideCategoryUnresolved": { + "description": "Writerside module diagnostic for an unresolved seealso category.", + "placeholders": { + "ref": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicAmbiguousReference": "A referência de tópico \"{reference}\" é ambígua.", + "@diagnosticWritersideTopicAmbiguousReference": { + "description": "Writerside module diagnostic for an ambiguous topic reference.", + "placeholders": { + "reference": { + "type": "String" + } + } + }, + "diagnosticUnknown": "Diagnóstico desconhecido: {code}", + "@diagnosticUnknown": { + "description": "Fallback text for an unknown diagnostic code.", + "placeholders": { + "code": { + "type": "String" + } + } + }, + "close": "Fechar", + "git": "Git", + "gitDiff": "Diff do Git", + "gitShowDiff": "Mostrar diff", + "gitDiffHunkRange": "anterior {oldRange} → novo {newRange}", + "gitDiffNoLines": "sem linhas", + "gitUnavailableTitle": "Git não está disponível", + "gitUnavailableMessage": "{reason, select, other{Instale o Git ou configure o BusyMark para usar um executável do Git disponível. {reason}}}", + "gitTrustRequiredTitle": "Confiar neste espaço de trabalho para o Git?", + "gitTrustRequiredMessage": "Os repositórios Git podem executar programas por meio de hooks, filtros e outras definições. Confie neste espaço de trabalho antes que o BusyMark leia os dados do repositório ou ative ações do Git.", + "gitTrustWorkspace": "Confiar no espaço de trabalho", + "gitNotRepositoryTitle": "Não é um repositório Git", + "gitNotRepositoryMessage": "Este espaço de trabalho não está em um repositório Git.", + "gitInitializeRepository": "Inicializar repositório", + "gitDetachedHead": "HEAD desanexado", + "gitDetachedHeadAt": "Desanexado em {commit}", + "gitNoUpstream": "Sem upstream", + "gitAheadCount": "{count, plural, =1{1 commit não enviado} other{{count} commits não enviados}}", + "gitBehindCount": "{count, plural, =1{1 commit para obter} other{{count} commits para obter}}", + "gitClean": "Limpo", + "gitConflicts": "Conflitos", + "gitChanges": "Alterações", + "gitHistory": "Histórico", + "gitBranches": "Ramificações", + "gitActions": "Ações do Git", + "@gitActions": { + "description": "Tooltip for the Git action menu button." + }, + "gitPull": "Pull", + "gitPush": "Push", + "gitCommit": "Commit", + "gitSelectForCommit": "Adicionar ficheiro ao índice", + "gitRemoveFromCommit": "Remover ficheiro do índice", + "gitDiscard": "Descartar", + "gitOpenFile": "Abrir ficheiro", + "gitMarkResolved": "Marcar como resolvido", + "gitUntracked": "Ficheiros não monitorizados", + "gitCommitMessage": "Mensagem de commit", + "gitCommitSelectedFiles": "Ficheiros selecionados", + "gitCommitNoSelectedFiles": "Adicione pelo menos um ficheiro ao índice antes de criar o commit.", + "gitCommitMessageRequired": "Introduza uma mensagem de commit.", + "gitCreateBranch": "Criar ramificação", + "gitNewBranch": "Nova ramificação", + "gitBranchName": "Nome da ramificação", + "gitSwitchBranch": "Trocar", + "gitNoChanges": "Nenhuma alteração", + "gitNoHistory": "Nenhum histórico", + "gitNoBranches": "Nenhuma ramificação", + "gitNoDiff": "Nenhuma diferença para apresentar", + "gitBinaryFile": "Ficheiro binário. O BusyMark não apresenta patches binários.", + "gitUnsavedChangesBanner": "As alterações não guardadas do editor não são incluídas até serem guardadas.", + "gitConfirmDiscardTitle": "Descartar alterações do Git?", + "gitConfirmDiscardTracked": "{count, plural, =1{Todas as alterações indexadas e não indexadas no ficheiro monitorizado selecionado serão repostas para HEAD.} other{Todas as alterações indexadas e não indexadas nos ficheiros monitorizados selecionados serão repostas para HEAD.}}", + "gitConfirmDiscardUntracked": "{count, plural, =1{O ficheiro não monitorizado selecionado será eliminado.} other{Os ficheiros não monitorizados selecionados serão eliminados.}}", + "gitConfirmDiscardMixed": "{count, plural, =1{O ficheiro selecionado será reposto ou eliminado consoante o respetivo estado no Git.} other{Os ficheiros selecionados serão repostos ou eliminados consoante o respetivo estado no Git.}}", + "gitConfirmSwitchBranchTitle": "Trocar para {branch}?", + "gitConfirmSwitchBranchMessage": "O BusyMark voltará a carregar o espaço de trabalho a partir do disco depois de o Git mudar de ramificação.", + "gitConfirmPushSetUpstreamTitle": "Definir ramificação upstream?", + "gitConfirmPushSetUpstreamMessage": "Esta ramificação não tem upstream. O BusyMark pode enviar {branch} e definir o respetivo upstream quando existir exatamente um remoto configurado.", + "gitProjectHistory": "Histórico do projeto", + "gitFileHistory": "Histórico do ficheiro", + "gitAdditionsDeletions": "+{additions} -{deletions}", + "fileActions": "Ações do ficheiro", + "actions": "Ações", + "gitStatusAdded": "Adicionado", + "gitStatusDeleted": "Eliminado", + "gitStatusRenamed": "Renomeado", + "gitStatusCopied": "Copiado", + "gitStatusUntracked": "Não monitorizado", + "gitStatusConflicted": "Em conflito", + "gitStatusIgnored": "Ignorado", + "gitStatusTypeChanged": "Tipo alterado", + "gitStatusModified": "Modificado", + "gitStatusUnknown": "Desconhecido", + "gitErrorUnavailable": "Git não está disponível.", + "gitErrorNotRepository": "Este espaço de trabalho não é um repositório Git.", + "gitErrorUnsafePath": "O BusyMark bloqueou um caminho Git inseguro.", + "gitErrorInvalidBranchName": "Introduza um nome de ramificação válido.", + "gitErrorNoRemote": "Nenhum remoto Git está configurado.", + "gitErrorNoUpstream": "Nenhuma ramificação upstream está configurada.", + "gitErrorMultipleRemotes": "Há vários remotos configurados. Escolha um upstream fora desta versão do BusyMark.", + "gitErrorDirtyWorkspace": "Guarde ou descarte as alterações do editor do BusyMark antes de trocar de ramificação.", + "gitErrorDiverged": "A ramificação divergiu. Resolva o merge ou o rebase fora desta versão do BusyMark.", + "gitErrorAuthorIdentity": "O Git precisa do nome e do e-mail do autor antes de criar um commit.", + "gitAuthorIdentityTitle": "Identidade do autor do Git", + "gitAuthorIdentityMessage": "Indique a identidade que o Git deve registar nos commits. O BusyMark irá guardá-la e tentar este commit novamente.", + "gitAuthorName": "Nome", + "gitAuthorEmail": "E-mail", + "gitAuthorIdentityGlobal": "Usar em todos os repositórios", + "gitAuthorIdentityGlobalDescription": "Quando instalado como Snap, isto se aplica aos repositórios abertos no BusyMark.", + "gitSaveIdentityAndCommit": "Guardar e criar commit", + "gitErrorAuthentication": "A autenticação do Git falhou.", + "gitErrorNetwork": "A operação de rede do Git falhou.", + "gitErrorConflict": "O Git relatou conflitos não resolvidos.", + "gitErrorCommandFailed": "O comando Git falhou.", "syntaxReference": "Referência de sintaxe", + "@syntaxReference": { + "description": "Syntax Reference dialog title and menu item." + }, "syntaxReferenceMarkdownBlocks": "Blocos Markdown", + "@syntaxReferenceMarkdownBlocks": { + "description": "Reference section title for Markdown block syntax." + }, "syntaxReferenceMarkdownBlocksDescription": "Estruturas de bloco compatíveis no código Markdown e na pré-visualização.", + "@syntaxReferenceMarkdownBlocksDescription": { + "description": "Reference section description for Markdown block syntax." + }, "syntaxReferenceInlineFormatting": "Markdown em linha", + "@syntaxReferenceInlineFormatting": { + "description": "Reference section title for Markdown inline syntax." + }, "syntaxReferenceInlineFormattingDescription": "Formatação dentro de parágrafos, itens de lista e células de tabela.", + "@syntaxReferenceInlineFormattingDescription": { + "description": "Reference section description for Markdown inline syntax." + }, "syntaxReferenceRawHtmlBlocks": "Blocos de HTML bruto", + "@syntaxReferenceRawHtmlBlocks": { + "description": "Reference section title for supported raw HTML block tags." + }, "syntaxReferenceRawHtmlBlocksDescription": "Tags HTML de bloco seguras renderizadas pelos widgets de pré-visualização do BusyMark.", + "@syntaxReferenceRawHtmlBlocksDescription": { + "description": "Reference section description for supported raw HTML block tags." + }, "syntaxReferenceRawHtmlInline": "Tags de HTML bruto em linha", + "@syntaxReferenceRawHtmlInline": { + "description": "Reference section title for supported raw HTML inline tags." + }, "syntaxReferenceRawHtmlInlineDescription": "Tags HTML em linha seguras renderizadas sem mostrar as tags literais.", + "@syntaxReferenceRawHtmlInlineDescription": { + "description": "Reference section description for supported raw HTML inline tags." + }, "syntaxReferenceHeadings": "Títulos", + "@syntaxReferenceHeadings": { + "description": "Reference row label for Markdown headings." + }, "syntaxReferenceParagraphs": "Parágrafos", + "@syntaxReferenceParagraphs": { + "description": "Reference row label for Markdown paragraphs." + }, "syntaxReferenceLists": "Listas", + "@syntaxReferenceLists": { + "description": "Reference row label for list syntax." + }, "syntaxReferenceHtmlContainers": "Contêineres", + "@syntaxReferenceHtmlContainers": { + "description": "Reference row label for HTML container tags." + }, "syntaxReferenceHtmlTextBlocks": "Blocos de texto", + "@syntaxReferenceHtmlTextBlocks": { + "description": "Reference row label for HTML text block tags." + }, "syntaxReferenceHtmlFigures": "Figuras e imagens", + "@syntaxReferenceHtmlFigures": { + "description": "Reference row label for HTML figure and image tags." + }, "syntaxReferenceHtmlPreformatted": "Código pré-formatado", + "@syntaxReferenceHtmlPreformatted": { + "description": "Reference row label for HTML preformatted/code tags." + }, "syntaxReferenceHtmlDisclosure": "Blocos expansíveis", + "@syntaxReferenceHtmlDisclosure": { + "description": "Reference row label for HTML details/summary tags." + }, "syntaxReferenceHtmlDescriptionLists": "Listas de descrição", + "@syntaxReferenceHtmlDescriptionLists": { + "description": "Reference row label for HTML description list tags." + }, "syntaxReferenceHtmlFormattingTags": "Tags de formatação", + "@syntaxReferenceHtmlFormattingTags": { + "description": "Reference row label for HTML inline formatting tags." + }, "syntaxReferenceHtmlInlineCodeTags": "Tags de código em linha", + "@syntaxReferenceHtmlInlineCodeTags": { + "description": "Reference row label for HTML inline code-related tags." + }, "syntaxReferenceHtmlNeutralInlineTags": "Tags de texto semântico", + "@syntaxReferenceHtmlNeutralInlineTags": { + "description": "Reference row label for HTML inline semantic tags that render as text." + }, "syntaxReferenceSanitizedPreviewDescription": "O HTML permitido é convertido em blocos de pré-visualização do BusyMark e não é renderizado em um navegador.", - "syntaxReferenceSourcePreservedDescription": "HTML bruto não editado é salvo exatamente como texto fonte.", - "syntaxReferenceMarkdownInsideHtmlDescription": "Marcadores Markdown dentro de HTML bruto são exibidos como texto literal.", + "@syntaxReferenceSanitizedPreviewDescription": { + "description": "Reference row description for sanitized preview behavior." + }, + "syntaxReferenceSourcePreservedDescription": "HTML bruto não editado é guardado exatamente como texto fonte.", + "@syntaxReferenceSourcePreservedDescription": { + "description": "Reference row description for raw source preservation." + }, + "syntaxReferenceMarkdownInsideHtmlDescription": "Marcadores Markdown dentro de HTML bruto são apresentados como texto literal.", + "@syntaxReferenceMarkdownInsideHtmlDescription": { + "description": "Reference row description for Markdown inside raw HTML." + }, "syntaxReferenceBlockedContentDescription": "Scripts, estilos, frames, formulários, SVG, MathML, eventos e atributos inseguros são bloqueados.", - "syntaxReferenceSafeUrlsDescription": "Links permitem http, https, mailto, tel, URLs relativas e fragmentos; esquemas inseguros são bloqueados.", + "@syntaxReferenceBlockedContentDescription": { + "description": "Reference row description for blocked HTML content." + }, + "syntaxReferenceSafeUrlsDescription": "Ligações permitem http, https, mailto, tel, URLs relativas e fragmentos; esquemas inseguros são bloqueados.", + "@syntaxReferenceSafeUrlsDescription": { + "description": "Reference row description for safe URL policy." + }, + "addToGit": "Adicionar ao Git", + "delete": "Eliminar", + "newFile": "Novo ficheiro", + "rename": "Renomear", + "confirmDeleteFileTitle": "Eliminar ficheiro?", + "confirmDeleteFolderTitle": "Eliminar pasta?", + "confirmDeleteFileMessage": "Eliminar {name}? Esta ação não pode ser anulada.", + "confirmDeleteFolderMessage": "Eliminar {name} e todos os ficheiros dentro dela? Esta ação não pode ser anulada.", + "workspaceErrorFileOperationFailed": "Falha na operação de ficheiro: {error}", + "errorDirectoryMissing": "O diretório não existe: {path}", + "errorPathAlreadyExists": "O caminho já existe: {path}", + "errorFileNameRequired": "O nome do ficheiro é obrigatório.", + "errorFileNameUnsafe": "O nome do ficheiro deve ser um único segmento de caminho seguro.", + "errorFileOperationInvalidTarget": "Não é possível mover uma pasta para dentro dela mesma.", + "errorFileOperationOutsideRoot": "A operação de ficheiro deve permanecer dentro do espaço de trabalho.", + "errorFileOperationRoot": "A raiz do espaço de trabalho não pode ser alterada pela árvore de ficheiros.", + "safeDeleteTopicFile": "Eliminar o ficheiro do tópico com segurança…", + "@safeDeleteTopicFile": { + "description": "Action that safely deletes a Writerside topic file after finding usages." + }, + "removeTocElement": "Remover elemento do TOC", + "@removeTocElement": { + "description": "Action that removes a topic element from the selected table of contents." + }, + "removeTocElements": "Remover elementos do TOC", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, + "reviewUsages": "Rever usos", + "@reviewUsages": { + "description": "Action that opens the topic usage review." + }, + "deleteTopicFile": "Eliminar ficheiro do tópico", + "@deleteTopicFile": { + "description": "Action that deletes a Writerside topic file." + }, + "removeAction": "Remover", + "@removeAction": { + "description": "Generic remove action label." + }, + "topicRemovalSummary": "Remova “{topic}” da instância selecionada. O ficheiro do tópico será mantido.", + "@topicRemovalSummary": { + "description": "Summary of removing a topic from one TOC while keeping its file.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "safeDeleteTopicSummary": "Elimine “{topic}” e atualize com segurança as referências a ele em todo este projeto Writerside.", + "@safeDeleteTopicSummary": { + "description": "Summary of safely deleting a topic file.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "childTopicsPromoted": "{count, plural, =1{O tópico filho subirá um nível.} other{Os {count} tópicos filhos subirão um nível.}}", + "@childTopicsPromoted": { + "description": "Explains that direct child topics will be promoted when their parent TOC element is removed.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "topicIsStartPageRemovalWarning": "Este tópico é usado como página inicial de uma instância. Reveja os usos dele e atribua outra página inicial antes de continuar.", + "@topicIsStartPageRemovalWarning": { + "description": "Warning shown when the topic is used as an instance start page." + }, + "topicUsagesCount": "Usos ({count})", + "@topicUsagesCount": { + "description": "Number of discovered topic usages.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "noBreakingTopicUsages": "Não foram encontradas referências que deixariam de funcionar.", + "@noBreakingTopicUsages": { + "description": "Message shown when removal will not leave breaking topic usages." + }, + "topicUsagesFound": "O BusyMark encontrou as seguintes referências a este tópico.", + "@topicUsagesFound": { + "description": "Heading for topic usages found by safe delete." + }, + "topicUsageTocElements": "Elementos do TOC", + "@topicUsageTocElements": { + "description": "Usage group label for TOC elements." + }, + "topicUsageStartPages": "Páginas iniciais", + "@topicUsageStartPages": { + "description": "Usage group label for instance start pages." + }, + "topicUsageTopicLinks": "Ligações para tópicos", + "@topicUsageTopicLinks": { + "description": "Usage group label for links to the topic." + }, + "topicUsageIncludes": "Inclusões", + "@topicUsageIncludes": { + "description": "Usage group label for topic includes." + }, + "usageCount": "{count, plural, =1{1 uso} other{{count} usos}}", + "@usageCount": { + "description": "Compact topic usage count.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "refactoringOptions": "Opções de refatoração", + "@refactoringOptions": { + "description": "Heading for safe-delete refactoring options." + }, + "updateUsagesAutomatically": "Atualizar usos automaticamente", + "@updateUsagesAutomatically": { + "description": "Option to update supported topic usages automatically." + }, + "updateUsagesAutomaticallyDescription": "Remova referências dos TOCs e inclusões e preserve o texto dos ligações.", + "@updateUsagesAutomaticallyDescription": { + "description": "Description of automatic topic usage updates." + }, + "manualUsageUpdatesRequired": "Alguns usos exigem alterações manuais antes desta refatoração.", + "@manualUsageUpdatesRequired": { + "description": "Message shown when usages require manual updates." + }, + "setRedirectTo": "Redirecionar para", + "@setRedirectTo": { + "description": "Option to redirect the removed topic URL to another topic." + }, + "noRedirectDescription": "Não redirecionar a página publicada antiga.", + "@noRedirectDescription": { + "description": "Description for choosing no redirect target." + }, + "redirectTarget": "Destino do redirecionamento", + "@redirectTarget": { + "description": "Field label for selecting a redirect target." + }, + "remainingUsagesBlockRemoval": "Reveja e atualize os usos restantes antes de continuar ou ative as atualizações automáticas quando estiverem disponíveis.", + "@remainingUsagesBlockRemoval": { + "description": "Message explaining that unresolved usages block removal." + }, + "usagesOfTopic": "Usos de {topic}", + "@usagesOfTopic": { + "description": "Title for the usage review of a topic.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "noUsagesFound": "Nenhum uso encontrado.", + "@noUsagesFound": { + "description": "Empty state shown when no topic usages were found." + }, + "outsideSelectedInstance": "Fora da instância selecionada", + "@outsideSelectedInstance": { + "description": "Label for a usage outside the selected Writerside instance." + }, + "doRefactor": "Refatorar", + "@doRefactor": { + "description": "Action that applies the selected safe-delete refactoring." + }, + "orphanTopicTitle": "O ficheiro do tópico não é mais usado", + "@orphanTopicTitle": { + "description": "Title shown when a removed topic file has become orphaned." + }, + "keepTopicFile": "Manter o ficheiro do tópico", + "@keepTopicFile": { + "description": "Action that keeps an orphaned topic file." + }, + "orphanTopicMessage": "“{topic}” não é mais usado em nenhum lugar deste projeto Writerside. Elimine o ficheiro ou mantenha-o para uso em outra instância.", + "@orphanTopicMessage": { + "description": "Prompt to safely delete a topic after its final TOC element is removed.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "errorWritersideSafeDeleteRequired": "Use a eliminação segura para ficheiros de tópicos do Writerside.", + "@errorWritersideSafeDeleteRequired": { + "description": "Detail shown when a Writerside topic file must be deleted through Safe Delete." + }, + "errorWritersideTopicUsageScanFailed": "Não foi possível concluir a verificação dos usos do tópico. Nenhum ficheiro foi alterado.", + "@errorWritersideTopicUsageScanFailed": { + "description": "Error shown when safe-delete usage analysis cannot complete reliably." + }, + "errorWritersideTopicUsagesRemain": "Alguns usos do tópico ainda precisam de atenção. Reveja-os antes de continuar.", + "@errorWritersideTopicUsagesRemain": { + "description": "Error shown when unresolved topic usages block removal." + }, + "errorWritersideRedirectInvalid": "O destino de redirecionamento selecionado não é mais válido. Selecione-o novamente.", + "@errorWritersideRedirectInvalid": { + "description": "Error shown when a safe-delete redirect target is stale or conflicts." + }, + "errorWritersideRollbackFailed": "Não foi possível reverter completamente a remoção do tópico. Reveja estes caminhos antes de continuar: {paths}", + "@errorWritersideRollbackFailed": { + "description": "Error shown when safe-delete recovery leaves files requiring manual review.", + "placeholders": { + "paths": { + "type": "String" + } + } + }, "syntaxReferenceCategoryHtml": "HTML", "syntaxReferenceMermaid": "Mermaid", "syntaxReferencePlantUml": "PlantUML", @@ -40,8 +2673,8 @@ "syntaxReferenceScope": "Escopo", "syntaxReferenceLimitation": "Limitação do BusyMark", "syntaxReferenceOfficialDocumentation": "Documentação oficial", - "syntaxReferenceScopeWritersideMarkdown": "Somente Markdown do Writerside", - "syntaxReferenceScopeWritersideMarkdownAndXml": "Somente Markdown e XML do Writerside", + "syntaxReferenceScopeWritersideMarkdown": "Apenas Markdown do Writerside", + "syntaxReferenceScopeWritersideMarkdownAndXml": "Apenas Markdown e XML do Writerside", "syntaxReferenceMarkdownDescription": "As formas essenciais de Markdown que o BusyMark pode criar e visualizar.", "syntaxReferenceParagraphExample": "Um parágrafo de texto.", "syntaxReferenceTableLimitation": "As tabelas usam a sintaxe de barras verticais do GitHub Flavored Markdown.", @@ -50,7 +2683,7 @@ "syntaxReferenceDiagramsDescription": "Blocos cercados Mermaid, PlantUML, D2 e OpenAPI funcionam no código Markdown. Os identificadores não diferenciam maiúsculas de minúsculas, e o BusyMark preserva a grafia original.", "syntaxReferenceOpenApiLimitation": "Use conteúdo YAML ou JSON em um bloco cercado. O BusyMark não trata um documento YAML ou JSON completo qualquer como referência OpenAPI.", "syntaxReferenceSemanticDiagramBlocks": "Blocos de código semânticos para diagramas", - "syntaxReferenceSemanticDiagramLimitation": "As formas semânticas code-block e src aceitam Mermaid, PlantUML e D2, não OpenAPI, e somente em projetos Writerside.", + "syntaxReferenceSemanticDiagramLimitation": "As formas semânticas code-block e src aceitam Mermaid, PlantUML e D2, não OpenAPI, e apenas em projetos Writerside.", "syntaxReferenceReferencedDiagramSource": "Origem de diagrama referenciada", "syntaxReferenceReferencedDiagramLimitation": "Os caminhos devem ser relativos e permanecer dentro do projeto Writerside aberto; a forma de bloco cercado com src é exclusiva do Markdown do Writerside.", "syntaxReferenceMathematicsDescription": "O BusyMark aceita expressões TeX, não documentos TeX ou LaTeX completos.", @@ -64,7 +2697,7 @@ "syntaxReferenceWritersideMathElement": "Elemento math do Writerside", "syntaxReferenceWritersideMathElementLimitation": "O elemento math é sintaxe semântica do Writerside, não MathML HTML bruto permitido.", "syntaxReferenceSemanticTexBlock": "Bloco de código TeX semântico", - "syntaxReferenceWritersideDescription": "Estas extensões específicas são interpretadas somente em projetos Writerside abertos.", + "syntaxReferenceWritersideDescription": "Estas extensões específicas são interpretadas apenas em projetos Writerside abertos.", "syntaxReferenceAdmonitionBlockquote": "Citação de aviso", "syntaxReferenceAdmonitionLimitation": "Uma citação simples é uma dica no Markdown do Writerside; no Markdown comum, continua sendo uma citação normal.", "syntaxReferenceSemanticAdmonitions": "Avisos semânticos", @@ -76,6 +2709,374 @@ "syntaxReferenceSemanticCodeBlocks": "Blocos de código semânticos para matemática e diagramas", "syntaxReferenceVideo": "Vídeo do Writerside", "syntaxReferenceVideoLimitation": "Vídeo local usa uma imagem preview-src local; fontes hospedadas devem ser URLs HTTPS compatíveis do YouTube ou Vimeo.", + "exportAsPdf": "Exportar como PDF", + "@exportAsPdf": { + "description": "Menu action and dialog title for exporting the active Markdown document as PDF." + }, + "pdfExportDescription": "Escolha o esquema da página para criar um PDF bem acabado e independente.", + "@pdfExportDescription": { + "description": "Introductory text in the PDF export options dialog." + }, + "pdfRemoteImagesNote": "As imagens remotas não são transferidas durante a exportação. As imagens locais são incluídas quando disponíveis.", + "@pdfRemoteImagesNote": { + "description": "Privacy note explaining image handling during PDF export." + }, + "pdfPageSize": "Tamanho da página", + "@pdfPageSize": { + "description": "PDF export page-size setting." + }, + "pdfPageSizeA4": "A4", + "@pdfPageSizeA4": { + "description": "A4 PDF page-size option." + }, + "pdfPageSizeLetter": "Carta", + "@pdfPageSizeLetter": { + "description": "US Letter PDF page-size option." + }, + "pdfOrientation": "Orientação", + "@pdfOrientation": { + "description": "PDF export page-orientation setting." + }, + "pdfPortrait": "Vertical", + "@pdfPortrait": { + "description": "Portrait PDF page-orientation option." + }, + "pdfLandscape": "Horizontal", + "@pdfLandscape": { + "description": "Landscape PDF page-orientation option." + }, + "pdfMargins": "Margens", + "@pdfMargins": { + "description": "PDF export page-margin setting." + }, + "pdfMarginNarrow": "Estreitas", + "@pdfMarginNarrow": { + "description": "Narrow PDF page-margin option." + }, + "pdfMarginNormal": "Normais", + "@pdfMarginNormal": { + "description": "Normal PDF page-margin option." + }, + "pdfMarginWide": "Largas", + "@pdfMarginWide": { + "description": "Wide PDF page-margin option." + }, + "pdfIncludePageNumbers": "Incluir números de página", + "@pdfIncludePageNumbers": { + "description": "Toggle for page numbers in an exported PDF." + }, + "export": "Exportar", + "@export": { + "description": "Button label that starts an export." + }, + "exportingPdf": "A exportar PDF…", + "@exportingPdf": { + "description": "Progress dialog title while a PDF is being exported." + }, + "fileTypePdf": "Documento PDF", + "@fileTypePdf": { + "description": "File picker label for PDF documents." + }, + "pdfExported": "{fileName} foi exportado.", + "@pdfExported": { + "description": "PDF export success message.", + "placeholders": { + "fileName": { + "type": "String" + } + } + }, + "pdfExportedWithWarnings": "{fileName} foi exportado com {count, plural, =1{1 aviso} other{{count} avisos}}.", + "@pdfExportedWithWarnings": { + "description": "PDF export success message when some images were omitted.", + "placeholders": { + "fileName": { + "type": "String" + }, + "count": { + "type": "int" + } + } + }, + "pdfExportUnavailable": "O componente de exportação para PDF está ausente. Reinstale o BusyMark e tente novamente.", + "@pdfExportUnavailable": { + "description": "Error shown when the bundled PDF compiler is unavailable." + }, + "pdfExportTimedOut": "A exportação para PDF demorou demasiado e foi interrompida.", + "@pdfExportTimedOut": { + "description": "Error shown when PDF compilation times out." + }, + "pdfExportFailed": "O BusyMark não conseguiu exportar este documento como PDF.", + "@pdfExportFailed": { + "description": "Generic PDF export failure message." + }, + "visualizationRendering": "A renderizar…", + "visualizationStale": "A apresentar a última renderização válida", + "visualizationShowSource": "Mostrar código-fonte", + "visualizationShowRender": "Mostrar renderização", + "visualizationFitWidth": "Ajustar à largura", + "visualizationSaveImage": "Guardar imagem", + "visualizationCopyImage": "Copiar imagem", + "visualizationImageCopied": "Imagem copiada", + "visualizationOpenApiReference": "Abrir referência da API", + "visualizationValid": "Válido", + "visualizationInvalid": "Inválido", + "visualizationServers": "Servidores", + "visualizationPaths": "Caminhos", + "visualizationOperations": "Operações", + "visualizationTags": "Etiquetas", + "visualizationNoOperations": "Nenhuma operação correspondente", + "visualizationSearchOperations": "Pesquisar operações", + "visualizationRenderFailed": "Não foi possível renderizar esta visualização.", + "visualizationRetry": "Tentar novamente", + "visualizationSaved": "{fileName} guardado", + "shortcutExportPdfDescription": "Exportar o documento ativo ou o módulo do Writerside como PDF.", + "@shortcutExportPdfDescription": { + "description": "Keyboard-shortcut description for PDF export." + }, + "gitStaged": "Indexadas", + "gitUnstaged": "Não indexadas", + "gitFetch": "Buscar", + "gitStagedFileCount": "{count, plural, =1{1 ficheiro no índice} other{{count} ficheiros no índice}}", + "gitOutsideWorkspace": "Fora do espaço de trabalho", + "gitFileHistoryRequiresOpenFile": "O histórico do ficheiro requer um ficheiro Markdown aberto.", + "gitLoadMore": "Carregar mais", + "gitChangesInCommit": "Alterações neste commit", + "gitCompareWithCurrent": "Comparar com a versão atual", + "gitRestoreVersion": "Restaurar esta versão", + "gitConfirmRestoreTitle": "Restaurar esta versão do ficheiro?", + "gitConfirmRestoreMessage": "O BusyMark substituirá o ficheiro atual da árvore de trabalho pela versão selecionada do commit. O ficheiro reposto permanecerá fora do índice.", + "gitBinaryFileInfo": "Ficheiro binário ({size} bytes). O BusyMark não apresenta patches binários.", + "gitErrorRestoreStagedFile": "Retire o ficheiro do índice antes de repor uma versão anterior.", + "gitCommitActions": "Ações do commit", + "gitResetCurrentBranchToHere": "Redefinir a ramificação atual aqui…", + "gitResetCurrentBranchTitle": "Redefinir {branch} para {commit}?", + "gitResetCurrentBranchMessage": "Isto move a ramificação {branch} para o commit {commit}. Escolha como o Git deve atualizar o índice e a árvore de trabalho.", + "gitReset": "Redefinir", + "gitResetModeSoft": "Soft", + "gitResetModeSoftDescription": "Mover apenas a ramificação. Manter o índice e a árvore de trabalho inalterados; as diferenças em relação ao commit selecionado permanecem no índice.", + "gitResetModeMixed": "Mixed", + "gitResetModeMixedDescription": "Mover a ramificação e redefinir o índice. Manter a árvore de trabalho inalterada, deixando as diferenças fora do índice.", + "gitResetModeHard": "Hard", + "gitResetModeHardDescription": "Mover a ramificação e redefinir o índice e a árvore de trabalho. As alterações monitorizadas são descartadas; os ficheiros não monitorizados que bloqueiam a operação podem ser eliminados.", + "gitResetModeKeep": "Keep", + "gitResetModeKeepDescription": "Mover a ramificação e redefinir os ficheiros monitorizados, preservando as alterações locais. O Git aborta se essas alterações entrarem em conflito com a redefinição.", + "gitErrorResetDirtyWorkspace": "Guarde ou descarte as alterações no editor do BusyMark antes de redefinir a ramificação atual.", + "gitErrorResetDetachedHead": "Alterne para uma ramificação antes de redefini-la.", + "instances": "Instâncias", + "newInstance": "Nova instância", + "newTocLibrary": "Nova biblioteca de sumário", + "editInstance": "Editar instância", + "openTocFile": "Abrir ficheiro do índice", + "createInstance": "Criar instância", + "createTocLibrary": "Criar biblioteca de sumário", + "instanceContent": "Conteúdo", + "instanceContentSource": "Criar a partir de", + "emptyInstance": "Instância vazia", + "markdownFiles": "Ficheiros Markdown locais", + "chooseMarkdownFolder": "Escolher pasta de Markdown", + "errorWritersideInstanceImportSourceRequired": "Escolha uma pasta que contenha ficheiros Markdown.", + "instanceAppearance": "Aparência", + "instanceColor": "Cor do ícone", + "instanceVersion": "Versão", + "instanceVersionInherited": "Quando este campo está vazio, é usada a versão do projeto {version}.", + "instanceWebPath": "Caminho web", + "instanceStatus": "Estado", + "instanceStatusRelease": "Lançamento", + "instanceStatusEap": "Acesso antecipado", + "instanceStatusDeprecated": "Obsoleta", + "allowSearchEngineIndexing": "Permitir indexação por mecanismos de busca", + "allowSearchEngineIndexingDescription": "Permita que mecanismos de busca externos indexem esta saída.", + "offlineArtifact": "Artefato offline", + "offlineArtifactDescription": "Inclua os recursos para que a documentação gerada funcione de forma autônoma.", + "instanceOutputSettings": "Definições de saída", + "markdownImportSource": "Origem Markdown", + "markdownImportFiles": "Ficheiros Markdown", + "selectNone": "Não selecionar nenhum", + "markdownFilesFound": "{count, plural, =1{Foi encontrado 1 ficheiro Markdown} other{Foram encontrados {count} ficheiros Markdown}}", + "noMarkdownFilesFound": "Não foram encontrados ficheiros Markdown neste diretório.", + "copyReferencedMedia": "Copiar multimédia referenciada", + "copyReferencedMediaDescription": "Copie imagens e vídeos locais referenciados pelos ficheiros selecionados, preservando os caminhos relativos.", + "instanceIdRenameWarningTitle": "Mudar o nome do ID da instância?", + "instanceIdRenameWarning": "O BusyMark mudará o nome do ficheiro .tree e atualizará as referências do projeto Writerside de “{oldId}” para “{newId}”. Os scripts de publicação não são alterados e devem ser atualizados separadamente.", + "renameAndUpdateReferences": "Mudar o nome e atualizar referências", + "tocLibraryDescription": "Uma biblioteca de sumário armazena secções reutilizáveis e não produz uma saída própria.", + "defaultTocLibraryName": "Sumário partilhado", + "instanceColorAutomatic": "Automático", + "instanceColorBlue": "Azul", + "instanceColorGreen": "Verde", + "instanceColorOrange": "Laranja", + "instanceColorPurple": "Roxo", + "instanceColorRed": "Vermelho", + "instanceColorTeal": "Verde-azulado", + "instanceColorYellow": "Amarelo", + "errorWritersideInstanceNameRequired": "Introduza um nome para a instância.", + "errorWritersideInstanceIdExists": "Já existe uma instância com o ID “{id}”.", + "errorWritersideInstanceTreeExists": "A árvore da instância já existe: {path}", + "errorWritersideInstanceImportSourceMissing": "O diretório de origem Markdown não existe: {path}", + "errorWritersideInstanceImportSelectionRequired": "Selecione pelo menos um ficheiro Markdown para importar.", + "errorWritersideInstanceImportFileInvalid": "Este não é um ficheiro Markdown legível dentro da origem selecionada: {path}", + "errorWritersideInstanceImportTargetExists": "A importação substituiria um ficheiro existente do projeto: {path}", + "errorWritersideInstanceFilesChanged": "Os ficheiros da instância foram alterados no disco. Reveja-os e tente novamente.", + "errorWritersideInstanceRollbackFailed": "O BusyMark não conseguiu reverter completamente a alteração da instância. Reveja estes ficheiros antes de continuar: {paths}", + "errorWritersideInstanceLibraryImport": "Uma biblioteca de sumário não pode importar tópicos Markdown.", + "errorWritersideInstanceWebPathInvalid": "O caminho web deve ter uma única linha.", + "errorWritersideInstanceConfigurationInvalid": "A configuração da instância do Writerside é inválida. Corrija os diagnósticos e tente novamente.", + "errorWritersideInstanceTemporaryFile": "O BusyMark não conseguiu preparar com segurança as alterações da instância.", + "diagnosticWritersideTreeInvalidStatus": "Estado de instância desconhecido “{status}”. Use release, eap ou deprecated.", + "diagnosticWritersideDuplicateInstanceId": "O ID de instância “{id}” é usado por mais de um ficheiro de árvore.", + "diagnosticWritersideBuildProfilesInvalidRoot": "buildprofiles.xml deve ter um elemento raiz <buildprofiles>.", + "diagnosticWritersideBuildProfilesInvalidBoolean": "O valor {name} “{value}” deve ser true ou false.", + "diagnosticWritersideBuildProfileMissingInstance": "Um elemento <build-profile> deve especificar um ID de instância.", + "diagnosticWritersideTreeInvalidInclude": "Um <include> da árvore deve especificar from e element-id.", + "diagnosticWritersideTreeMissingSnippetId": "Um <snippet> da árvore deve especificar um id.", + "diagnosticWritersideTreeInvalidCrossInstanceReference": "Uma referência de sumário entre instâncias deve especificar ref e in.", + "diagnosticWritersideTreeConflictingTargets": "Um elemento do sumário não pode apontar para mais do que um tópico, referência, ligação ou redirecionamento.", + "diagnosticWritersideTreeDuplicateElementId": "O ID de elemento da árvore “{id}” foi declarado mais de uma vez.", + "diagnosticWritersideInstanceGroupsInvalidRoot": "O ficheiro de grupos de instâncias deve ter um elemento raiz <instance-groups>.", + "diagnosticWritersideInstanceGroupInvalid": "Um grupo de instâncias deve especificar um id e uma lista de instâncias não vazios.", + "diagnosticWritersideInstanceGroupDuplicateId": "O ID do grupo de instâncias “{id}” foi declarado mais de uma vez.", + "diagnosticWritersideExternalTreeInclude": "A inclusão de sumário “{source}#{id}” pertence ao módulo externo “{origin}” e não pode ser expandida neste espaço de trabalho.", + "diagnosticWritersideTreeIncludeElementMissing": "O elemento de árvore “{id}” não existe na árvore registada “{source}”.", + "diagnosticWritersideTreeCircularInclude": "A inclusão de árvore “{source}#{id}” cria um ciclo.", + "diagnosticWritersideUnknownInstanceGroup": "A condição de instância referencia o grupo desconhecido “@{group}”.", + "diagnosticWritersideReferenceInstanceMissing": "A referência entre instâncias aponta para a instância desconhecida “{instance}”.", + "diagnosticWritersideReferenceTopicMissing": "O tópico “{topic}” não está na instância referenciada “{instance}”.", + "download": "Transferir", + "exportWritersideAsPdf": "Exportar Writerside como PDF", + "writersidePdfContent": "Conteúdo da exportação", + "writersidePdfPage": "Página", + "exportingWritersidePdf": "A exportar PDF do Writerside…", + "ai": "IA", + "aiLocalOllama": "Ollama local", + "aiDisabled": "Desativado", + "aiProvider": "Fornecedor de IA", + "aiDefaultProvider": "Fornecedor predefinido", + "aiConfigureProvider": "Configurar fornecedor", + "aiChooseProvider": "Escolher fornecedor de IA", + "aiOllamaEndpoint": "Endpoint do Ollama", + "aiOllamaModel": "Modelo do Ollama", + "aiTestConnection": "Testar ligação", + "aiTestingConnection": "A testar…", + "aiConnectionReady": "Conectado. {count, plural, =1{Foi encontrado 1 modelo instalado} other{Foram encontrados {count} modelos instalados}}.", + "aiNoModels": "Nenhum modelo selecionado.", + "aiConnectionFailed": "O BusyMark não conseguiu verificar a geração de texto por IA.", + "aiConfigureFirst": "Ative um fornecedor de IA e verifique um modelo em Definições → IA.", + "aiEditWithAi": "Editar com IA", + "aiRefineWithAi": "Melhorar com IA", + "aiInstruction": "Instrução", + "aiChangeTarget": "O que pode ser alterado", + "aiSharedContext": "Contexto partilhado com a IA", + "aiTargetSelection": "Conteúdo selecionado", + "aiTargetInsertAfterBlock": "Inserir após o bloco atual", + "aiTargetCurrentBlock": "Bloco atual", + "aiTargetCurrentSection": "Secção atual", + "aiTargetCompleteDocument": "Documento completo", + "aiContextNone": "Sem contexto do documento", + "aiContextSelection": "Conteúdo selecionado", + "aiContextCurrentBlock": "Bloco atual", + "aiContextCurrentSection": "Secção atual", + "aiContextCompleteDocument": "Documento completo", + "aiGenerating": "A gerar proposta…", + "aiProposal": "Proposta de IA", + "aiGenerateProposal": "Gerar proposta", + "aiContextDisclosure": "O fornecedor selecionado receberá {count} carateres do contexto apresentado.", + "aiOriginal": "Texto original", + "aiSuggested": "Sugestão", + "aiApplyProposal": "Aplicar proposta", + "aiTokenUsage": "{input} tokens de entrada · {output} tokens de saída", + "aiStaleProposal": "O documento foi alterado enquanto esta proposta era gerada. Execute a ação novamente.", + "gitAiStagedChangesChanged": "As alterações no índice mudaram enquanto esta mensagem de commit era gerada. Execute a ação novamente.", + "aiViewContext": "Ver contexto enviado", + "aiReviewExactContent": "Rever conteúdo exato", + "aiContentToChange": "Conteúdo a alterar", + "aiContentSentToAi": "Conteúdo enviado à IA", + "aiApiKey": "Chave de API", + "aiApiKeyStoredHint": "Uma chave está armazenada no cofre de credenciais do sistema", + "aiApiKeyEnterHint": "Introduza uma chave de API do fornecedor", + "aiReplaceApiKey": "Substituir chave de API", + "aiSaveApiKey": "Guardar chave de API com segurança", + "aiRemoveApiKey": "Remover chave de API guardada", + "aiCredentialSaved": "A chave de API foi guardada no cofre de credenciais do sistema.", + "aiCredentialRemoved": "A chave de API guardada foi removida.", + "aiModelRouting": "Seleção de modelo", + "aiAutomaticRouting": "Automática conforme a tarefa", + "aiFixedModelRouting": "Usar o modelo selecionado", + "aiPreferredModel": "Modelo preferido", + "aiModel": "Modelo", + "aiUsageThisMonth": "{requests} pedidos · {input} tokens de entrada · {output} tokens de saída", + "aiCloudConsentTitle": "Enviar conteúdo para {provider}?", + "aiCloudConsentEnable": "Ativar {provider}", + "aiCloudConsentMessage": "Apenas o conteúdo apresentado em cada caixa de diálogo de revisão de IA é enviado. Os pedidos não mantêm estado, as propostas exigem revisão e a chave de API é guardada no cofre de credenciais do sistema Linux.", + "aiCloudConsentRequired": "Primeiro, confirme o partilha de dados com {provider} em Definições → IA.", + "aiGenerationVerified": "Geração verificada com {model}. Há {count} modelos compatíveis disponíveis.", + "aiColdStartObserved": "Foi detetado um arranque a frio do modelo local.", + "aiNoCompatibleModels": "Não há nenhum modelo compatível de geração de texto disponível.", + "aiEnableProvider": "Primeiro, ative um fornecedor de IA.", + "aiDraftCommitMessage": "Criar rascunho da mensagem de commit", + "aiDrafting": "A criar rascunho…", + "aiDraftWithAi": "Criar rascunho com IA", + "generateOrUpdateMarkdownToc": "Gerar/atualizar sumário", + "markdownTocTitle": "Sumário", + "markdownTocUpdated": "Sumário atualizado com {count} entradas.", + "markdownTocNoHeadings": "Adicione pelo menos um título de secção antes de gerar um sumário.", + "markdownTocMalformedMarkers": "Os marcadores de sumário do BusyMark estão ausentes, duplicados ou fora de ordem.", + "diagnosticMarkdownHeadingSkippedLevel": "O título de nível {level} vem após o nível {previousLevel}; reveja o aninhamento das secções.", + "diagnosticMarkdownLinkEmptyText": "O texto da ligação está vazio; forneça um nome acessível que descreva a respetiva finalidade.", + "diagnosticMarkdownLinkReviewText": "Verifique se o texto da ligação “{text}” descreve a respetiva finalidade no contexto.", + "diagnosticMarkdownTableEmptyHeader": "Os cabeçalhos da tabela devem identificar suas colunas; preencha cada cabeçalho vazio.", + "commandPalette": "Paleta de comandos", + "commandPaletteHint": "Introduza um comando", + "commandPaletteEmpty": "Nenhum comando correspondente", + "tableAlignmentUnspecified": "Alinhamento: não especificado", + "tableAlignmentLeft": "Alinhamento: esquerda", + "tableAlignmentCenter": "Alinhamento: centro", + "tableAlignmentRight": "Alinhamento: direita", + "sourceSearchReplacement": "Substituir por", + "sourceSearchReplaceCurrent": "Substituir correspondência atual", + "sourceSearchReplaceAndFindNext": "Substituir e localizar próximo", + "sourceSearchReplaceAll": "Substituir tudo", + "workspaceReplace": "Substituir no espaço de trabalho", + "reviewReplacements": "Rever substituições", + "applyReplacements": "Aplicar substituições", + "skippedFiles": "Ficheiros ignorados", + "workspaceReplaceDirtyBuffer": "Conteúdo não guardado do editor", + "workspaceReplaceDiskContent": "Conteúdo guardado no disco", + "selectFileMatches": "Selecionar todas as {count} correspondências", + "workspaceReplaceApplied": "Foram substituídas {matches} correspondências em {files} ficheiros; {skipped} ignoradas.", + "documentFormatWithFinalNewline": "{encoding} · {lineEnding} · Quebra de linha final", + "documentFormatWithoutFinalNewline": "{encoding} · {lineEnding} · Sem quebra de linha final", + "normalizeLineEndings": "Normalizar finais de linha", + "workspaceReplaceMixedLineEndings": "{fileName} usa finais de linha mistos. Escolha o formato antes de substituir.", + "mixedLineEndingsSavePrompt": "Este documento contém finais de linha mistos. Escolha um formato.", + "workspaceReplaceIssueOversized": "Foi ignorado um ficheiro demasiado grande.", + "workspaceReplaceIssueUnreadable": "Um ficheiro que não pôde ser lido foi ignorado.", + "workspaceReplaceIssueInvalidUtf8": "Um ficheiro que não é UTF-8 válido foi ignorado.", + "workspaceReplaceIssueTruncated": "A pré-visualização de substituições foi truncada.", + "workspaceReplaceIssueFileChanged": "Um ficheiro alterado após a pré-visualização foi ignorado.", + "workspaceReplaceIssueBufferChanged": "Um buffer do editor alterado após a pré-visualização foi ignorado.", + "workspaceReplaceIssueNormalizationRequired": "Escolha a normalização LF ou CRLF antes de substituir.", + "externalChangesTitle": "Alterações externas — {fileName}", + "externalFileDeleted": "Este ficheiro foi eliminado do disco.", + "externalFileChanged": "Este ficheiro foi alterado no disco enquanto existem alterações não guardadas no editor.", + "compare": "Comparar", + "reloadFromDisk": "Recarregar do disco", + "keepMine": "Manter minha versão", + "saveAs": "Guardar como", + "unsavedChangesMultipleMessage": "{count, plural, =1{Existe 1 documento com alterações não guardadas. Pretende guardá-lo antes de continuar?} other{Existem {count} documentos com alterações não guardadas. Pretende guardá-los antes de continuar?}}", + "workspaceReplaceIssuePartialConflict": "A reversão foi interrompida porque o ficheiro foi alterado simultaneamente. Algumas substituições podem permanecer; o conteúdo deslocado foi preservado no caminho abaixo.", + "workspaceReplaceIssueApplyFailed": "Nenhuma substituição foi aplicada porque o conjunto revisto não pôde ser guardado com segurança.", + "workspaceRecoveryRestored": "{count, plural, =1{Foi recuperado 1 documento não guardado. Reveja-o antes de o guardar ou descartar.} other{Foram recuperados {count} documentos não guardados. Reveja cada um antes de o guardar ou descartar.}}", + "workspaceRecoveryDamaged": "{count, plural, =1{Não foi possível restaurar 1 registo de recuperação danificado. O ficheiro de recuperação original foi preservado para inspeção.} other{Não foi possível restaurar {count} registos de recuperação danificados. Os registos de recuperação válidos continuam disponíveis.}}", + "recoveredDocumentReview": "O conteúdo não guardado de {fileName} foi recuperado. Reveja-o e, em seguida, guarde-o, guarde-o como ou descarte-o.", + "commandUnavailableInContext": "Este comando não está disponível no contexto atual.", + "mathRenderFailed": "Não foi possível renderizar a expressão matemática.", + "inlineMath": "Matemática em linha", + "displayMath": "Matemática em bloco", + "aiExplicitEditingDescription": "A edição com IA é iniciada apenas de forma explícita. O BusyMark envia apenas o contexto apresentado ao fornecedor selecionado e nunca aplica uma proposta sem revisão.", + "@aiExplicitEditingDescription": { + "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." + }, "exportAsHtml": "Exportar como HTML…", "fileTypeHtml": "Documento HTML", "exportingHtml": "A exportar HTML…", diff --git a/lib/l10n/app_pt_BR.arb b/lib/l10n/app_pt_BR.arb index 5bbe3c10..108e41db 100644 --- a/lib/l10n/app_pt_BR.arb +++ b/lib/l10n/app_pt_BR.arb @@ -95,6 +95,7 @@ }, "copy": "Copiar", "copyPlainText": "Copiar como texto simples", + "clipboardCopyFailed": "Não foi possível copiar a seleção para a área de transferência.", "@copy": { "description": "Copy command label." }, @@ -2304,7 +2305,7 @@ "gitBinaryFile": "Arquivo binário. O BusyMark não exibe patches binários.", "gitUnsavedChangesBanner": "As alterações não salvas do editor não são incluídas até serem salvas.", "gitConfirmDiscardTitle": "Descartar alterações do Git?", - "gitConfirmDiscardTracked": "{count, plural, =1{Todas as mudanças staged e unstaged no arquivo selecionado rastreado serão restauradas para HEAD.} other{Todas as mudanças staged e unstaged nos arquivos rastreados selecionados serão restauradas para HEAD.}}", + "gitConfirmDiscardTracked": "{count, plural, =1{Todas as alterações preparadas e não preparadas no arquivo rastreado selecionado serão restauradas para HEAD.} other{Todas as alterações preparadas e não preparadas nos arquivos rastreados selecionados serão restauradas para HEAD.}}", "gitConfirmDiscardUntracked": "{count, plural, =1{O arquivo não rastreado selecionado será excluído.} other{Os arquivos não rastreados selecionados serão excluídos.}}", "gitConfirmDiscardMixed": "{count, plural, =1{O arquivo selecionado será restaurado ou excluído de acordo com o status do Git.} other{Os arquivos selecionados serão restaurados ou excluídos de acordo com o status do Git.}}", "gitConfirmSwitchBranchTitle": "Trocar para {branch}?", @@ -3065,7 +3066,7 @@ "unsavedChangesMultipleMessage": "{count, plural, =1{Há 1 documento com alterações não salvas. Deseja salvá-lo antes de continuar?} other{{count} documentos com alterações não salvas. Deseja salvá-los antes de continuar?}}", "workspaceReplaceIssuePartialConflict": "A reversão foi interrompida porque o arquivo foi alterado simultaneamente. Algumas substituições podem permanecer; o conteúdo deslocado foi preservado no caminho abaixo.", "workspaceReplaceIssueApplyFailed": "Nenhuma substituição foi aplicada porque o conjunto revisado não pôde ser salvo com segurança.", - "workspaceRecoveryRestored": "{count, plural, =1{1 documento sem salvamento recuperado. Revise antes de salvar ou descartar.} other{{count} documentos sem salvamento recuperados. Revise cada um antes de salvar ou descartar.}}", + "workspaceRecoveryRestored": "{count, plural, =1{1 documento não salvo foi recuperado. Revise-o antes de salvar ou descartar.} other{{count} documentos não salvos foram recuperados. Revise cada um antes de salvar ou descartar.}}", "workspaceRecoveryDamaged": "{count, plural, =1{1 registro de recuperação danificado não pôde ser restaurado. O arquivo de recuperação original foi preservado para inspeção.} other{{count} registros de recuperação danificados não puderam ser restaurados. Os registros de recuperação válidos permanecem disponíveis.}}", "recoveredDocumentReview": "O conteúdo não salvo de {fileName} foi recuperado. Revise-o e depois salve, salve como ou descarte-o.", "commandUnavailableInContext": "Este comando não está disponível no contexto atual.", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 9a1a1b22..be2a0027 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -95,6 +95,7 @@ }, "copy": "Копировать", "copyPlainText": "Копировать как обычный текст", + "clipboardCopyFailed": "Не удалось скопировать выделенный фрагмент в буфер обмена.", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 394ec723..e52f096a 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -179,6 +179,7 @@ }, "copy": "Kopyala", "copyPlainText": "Düz metin olarak kopyala", + "clipboardCopyFailed": "Seçili içerik panoya kopyalanamadı.", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index a559ec3d..b562bbb6 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -95,6 +95,7 @@ }, "copy": "Копіювати", "copyPlainText": "Копіювати як звичайний текст", + "clipboardCopyFailed": "Не вдалося скопіювати виділений фрагмент до буфера обміну.", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index c9977647..5e827cd4 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -179,6 +179,7 @@ }, "copy": "Sao chép", "copyPlainText": "Sao chép dưới dạng văn bản thuần", + "clipboardCopyFailed": "Không thể sao chép nội dung đã chọn vào bảng nhớ tạm.", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index b1fd8e44..98c567c8 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1,32 +1,3589 @@ { "@@locale": "zh", + "appTitle": "BusyMark", + "@appTitle": { + "description": "Application name." + }, + "appSubtitle": "Markdown 文件和兼容 Writerside 的文档项目编辑器。", + "@appSubtitle": { + "description": "Short application description." + }, + "aboutBusyMark": "关于 BusyMark", + "@aboutBusyMark": { + "description": "Menu item and tooltip for the About dialog." + }, + "aboutTagline": "Markdown 和 Writerside 编辑器", + "@aboutTagline": { + "description": "Short tagline shown under the app name in the About dialog." + }, + "aboutLicenseLabel": "许可证", + "@aboutLicenseLabel": { + "description": "Label for the license row in the About dialog." + }, + "aboutLicenseName": "Apache License 2.0", + "@aboutLicenseName": { + "description": "Formal license name shown in the About dialog. Keep the legal license name exact." + }, + "aboutWebsite": "网站", + "@aboutWebsite": { + "description": "Label for the website row in the About dialog." + }, + "aboutSourceCode": "源代码", + "@aboutSourceCode": { + "description": "Label for the source-code repository row in the About dialog." + }, + "reportIssue": "报告问题", + "@reportIssue": { + "description": "Menu action and dialog title for reporting an issue." + }, + "feedbackCategory": "类别", + "@feedbackCategory": { + "description": "Feedback category field label." + }, + "feedbackChooseCategory": "选择类别", + "@feedbackChooseCategory": { + "description": "Placeholder for the feedback category selector." + }, + "feedbackCategoryProblem": "问题或错误", + "@feedbackCategoryProblem": { + "description": "Feedback category for a problem or bug." + }, + "feedbackCategoryFeature": "功能请求", + "@feedbackCategoryFeature": { + "description": "Feedback category for a feature request." + }, + "feedbackCategoryPrivacySecurity": "隐私或安全问题", + "@feedbackCategoryPrivacySecurity": { + "description": "Feedback category for a privacy or security concern." + }, + "feedbackCategoryUsability": "可用性问题", + "@feedbackCategoryUsability": { + "description": "Feedback category for a usability concern." + }, + "feedbackCategoryOther": "其他", + "@feedbackCategoryOther": { + "description": "Feedback category for other concerns." + }, + "feedbackSubject": "主题", + "@feedbackSubject": { + "description": "Feedback subject field label." + }, + "feedbackMessage": "详细留言", + "@feedbackMessage": { + "description": "Detailed feedback message field label." + }, + "feedbackReplyEmail": "回复邮箱(可选)", + "@feedbackReplyEmail": { + "description": "Optional reply email field label." + }, + "feedbackIncludeTechnicalDetails": "包含技术详细信息", + "@feedbackIncludeTechnicalDetails": { + "description": "Checkbox label for optional technical details." + }, + "feedbackTechnicalDetailsDisclosure": "启用后,此选项仅会添加您的 Linux 操作系统版本和 BusyMark 应用语言。不会附加日志、文件、账户数据或其他诊断信息。", + "@feedbackTechnicalDetailsDisclosure": { + "description": "Disclosure explaining exactly which optional technical details are submitted." + }, + "feedbackSubmit": "提交", + "@feedbackSubmit": { + "description": "Button that submits feedback." + }, + "feedbackSubmitting": "正在提交…", + "@feedbackSubmitting": { + "description": "Button label while feedback is being submitted." + }, + "feedbackCategoryRequired": "请选择类别。", + "@feedbackCategoryRequired": { + "description": "Validation error for a missing feedback category." + }, + "feedbackSubjectLength": "主题必须包含 3 到 120 个字符。", + "@feedbackSubjectLength": { + "description": "Validation error for feedback subject length." + }, + "feedbackMessageLength": "信息必须包含 10 到 5,000 个字符。", + "@feedbackMessageLength": { + "description": "Validation error for feedback message length." + }, + "feedbackReplyEmailInvalid": "请输入有效的邮箱地址,或将此字段留空。", + "@feedbackReplyEmailInvalid": { + "description": "Validation error for an invalid optional reply email." + }, + "feedbackConnectionFailure": "BusyMark 无法连接。请检查网络连接后重试。", + "@feedbackConnectionFailure": { + "description": "Feedback submission error for a connection failure." + }, + "feedbackTimeoutFailure": "请求超时。请重试。", + "@feedbackTimeoutFailure": { + "description": "Feedback submission error for a timeout." + }, + "feedbackRateLimitedFailure": "此连接发送的报告过多。请稍候再试。", + "@feedbackRateLimitedFailure": { + "description": "Feedback submission error when the server rate limit is reached." + }, + "feedbackRejectedFailure": "服务器拒绝了此报告。请检查表单字段后重试。", + "@feedbackRejectedFailure": { + "description": "Feedback submission error when the server rejects invalid request data." + }, + "feedbackServerFailure": "服务器无法接收此报告。请稍后重试。", + "@feedbackServerFailure": { + "description": "Generic feedback submission server error." + }, + "feedbackSuccess": "反馈已发送。参考 ID:{id}", + "@feedbackSuccess": { + "description": "Success message containing the server reference ID.", + "placeholders": { + "id": { + "type": "String" + } + } + }, + "advanced": "高级", + "@advanced": { + "description": "Settings section title for advanced actions." + }, + "addToGit": "添加到 Git", + "@addToGit": { + "description": "Menu action that stages the selected file or folder in Git." + }, + "appearance": "外观", + "@appearance": { + "description": "Settings section title for appearance options." + }, + "apply": "应用", + "@apply": { + "description": "Button label that applies a dialog change." + }, + "back": "返回", + "@back": { + "description": "Tooltip for navigating back." + }, + "bottomLeft": "左下", + "@bottomLeft": { + "description": "Editing button position option." + }, + "bottomRight": "右下", + "@bottomRight": { + "description": "Editing button position option." + }, + "cancel": "取消", + "@cancel": { + "description": "Cancel button label." + }, + "choose": "选择", + "@choose": { + "description": "Button label for choosing a file or path." + }, + "chooseLocation": "选择位置", + "@chooseLocation": { + "description": "File picker confirmation label for choosing a directory." + }, + "copy": "复制", + "copyPlainText": "复制为纯文本", + "clipboardCopyFailed": "无法将所选内容复制到剪贴板。", + "@copy": { + "description": "Copy command label." + }, + "copyName": "复制名称", + "@copyName": { + "description": "Menu action that copies the selected file, folder, or workspace name." + }, + "copyFileName": "复制文件名", + "@copyFileName": { + "description": "Menu action that copies the active document file name." + }, + "copyPath": "复制路径", + "@copyPath": { + "description": "Menu action that copies the selected file, folder, or workspace path." + }, + "create": "创建", + "@create": { + "description": "Create action label." + }, + "creating": "正在创建…", + "@creating": { + "description": "Progress label while a project or topic is being created." + }, + "cut": "剪切", + "@cut": { + "description": "Cut command label." + }, + "promoteSection": "提升节级别", + "@promoteSection": { + "description": "Outline action that raises a heading section, including descendant headings, by one rank." + }, + "demoteSection": "降低节级别", + "@demoteSection": { + "description": "Outline action that lowers a heading section, including descendant headings, by one rank." + }, + "moveSectionUp": "上移节", + "@moveSectionUp": { + "description": "Outline action that swaps a heading section with its previous sibling section." + }, + "moveSectionDown": "下移节", + "@moveSectionDown": { + "description": "Outline action that swaps a heading section with its next sibling section." + }, + "confirmDeleteSectionTitle": "删除此节?", + "@confirmDeleteSectionTitle": { + "description": "Confirmation title before deleting a Markdown heading section." + }, + "confirmDeleteSectionMessage": "删除“{name}”及其节中的全部内容?此操作无法撤销。", + "@confirmDeleteSectionMessage": { + "description": "Confirmation message before deleting a Markdown heading section.", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "darkTheme": "深色", + "@darkTheme": { + "description": "Dark theme option." + }, + "delete": "删除", + "@delete": { + "description": "Delete command label." + }, + "discard": "放弃", + "@discard": { + "description": "Destructive button that throws away unsaved editor changes. Translate it distinctly from Cancel." + }, + "editor": "编辑器", + "@editor": { + "description": "Editor view label." + }, + "file": "文件", + "@file": { + "description": "Generic file kind label." + }, + "fileHistory": "文件历史记录", + "@fileHistory": { + "description": "Menu action and sidebar title for showing Git history for a single file." + }, + "folder": "文件夹", + "@folder": { + "description": "Folder kind label." + }, + "insert": "插入", + "@insert": { + "description": "Insert button label." + }, + "keyboardShortcuts": "键盘快捷键", + "commandPalette": "命令面板", + "@commandPalette": { + "description": "Title and command label for the searchable command palette." + }, + "commandPaletteHint": "输入命令", + "@commandPaletteHint": { + "description": "Search hint in the command palette." + }, + "commandPaletteEmpty": "没有匹配的命令", + "@commandPaletteEmpty": { + "description": "Empty state in the command palette." + }, + "commandUnavailableInContext": "当前编辑器上下文中无法使用此命令", + "@commandUnavailableInContext": { + "description": "Reason shown for a disabled contextual command." + }, + "@keyboardShortcuts": { + "description": "Keyboard shortcuts dialog title and menu item." + }, + "lightTheme": "浅色", + "@lightTheme": { + "description": "Light theme option." + }, + "mainMenu": "主菜单", + "@mainMenu": { + "description": "Native header bar main menu tooltip." + }, + "fullScreen": "全屏", + "@fullScreen": { + "description": "Command that toggles full-screen window mode." + }, + "markdown": "Markdown", + "@markdown": { + "description": "Markdown format label." + }, + "open": "打开", + "@open": { + "description": "Open action label." + }, + "openInFiles": "在文件中打开", + "@openInFiles": { + "description": "Menu action that opens the selected file or folder location in the system file manager." + }, + "pathActions": "路径操作", + "@pathActions": { + "description": "Tooltip for the workspace path action menu button." + }, + "outline": "大纲", + "@outline": { + "description": "Outline sidebar tab label." + }, + "overwrite": "覆盖", + "@overwrite": { + "description": "Button label for overwriting a changed file." + }, + "paste": "粘贴", + "@paste": { + "description": "Paste command label." + }, + "reading": "阅读", + "@reading": { + "description": "Reading view label." + }, + "removeFromRecent": "从最近使用记录中移除", + "@removeFromRecent": { + "description": "Action that removes a workspace from the Recent list without deleting its files." + }, + "recent": "最近使用", + "@recent": { + "description": "Recent workspaces section title." + }, + "redo": "重做", + "@redo": { + "description": "Redo command label." + }, + "save": "保存", + "@save": { + "description": "Save action label." + }, + "search": "搜索", + "@search": { + "description": "Search action label and field hint." + }, + "selectAll": "全选", + "@selectAll": { + "description": "Select all command label." + }, + "settings": "设置", + "@settings": { + "description": "Settings action label." + }, + "source": "源代码", + "@source": { + "description": "Source view label." + }, + "split": "拆分", + "@split": { + "description": "Split view label." + }, + "systemTheme": "系统", + "@systemTheme": { + "description": "System theme option." + }, + "theme": "主题", + "@theme": { + "description": "Theme setting label." + }, + "appLanguage": "语言", + "@appLanguage": { + "description": "Application language setting label." + }, + "systemLanguage": "系统", + "@systemLanguage": { + "description": "Language selector option that follows the operating system locale." + }, + "languageEnglish": "English", + "@languageEnglish": { + "description": "Language selector option for English." + }, + "languageGerman": "Deutsch", + "@languageGerman": { + "description": "Language selector option for German." + }, + "languageDutch": "Nederlands", + "@languageDutch": { + "description": "Language selector option for Dutch." + }, + "languageTurkish": "Türkçe", + "@languageTurkish": { + "description": "Language selector option for Turkish." + }, + "languageItalian": "Italiano", + "@languageItalian": { + "description": "Language selector option for Italian." + }, + "languageNorwegian": "Norsk bokmål", + "@languageNorwegian": { + "description": "Language selector option for Norwegian." + }, + "languageFrench": "Français", + "@languageFrench": { + "description": "Language selector option for French." + }, + "languageRussian": "Русский", + "@languageRussian": { + "description": "Language selector option for Russian." + }, + "languageUkrainian": "Українська", + "@languageUkrainian": { + "description": "Language selector option for Ukrainian." + }, + "languagePolish": "Polski", + "@languagePolish": { + "description": "Language selector option for Polish." + }, + "languageSpanish": "Español", + "@languageSpanish": { + "description": "Language selector option for Spanish." + }, + "languagePortuguese": "Português", + "@languagePortuguese": { + "description": "Language selector option for Portuguese." + }, + "languageArabic": "العربية", + "@languageArabic": { + "description": "Language selector option for Arabic." + }, + "languagePersian": "فارسی", + "@languagePersian": { + "description": "Language selector option for Persian." + }, + "languageHindi": "हिन्दी", + "@languageHindi": { + "description": "Language selector option for Hindi." + }, + "languageIndonesian": "Bahasa Indonesia", + "@languageIndonesian": { + "description": "Language selector option for Indonesian." + }, + "languageEstonian": "Eesti", + "@languageEstonian": { + "description": "Language selector option for Estonian." + }, + "languageVietnamese": "Tiếng Việt", + "@languageVietnamese": { + "description": "Language selector option for Vietnamese." + }, + "languageJapanese": "日本語", + "@languageJapanese": { + "description": "Language selector option for Japanese." + }, + "languageKorean": "한국어", + "@languageKorean": { + "description": "Language selector option for Korean." + }, + "languageSimplifiedChinese": "简体中文", + "@languageSimplifiedChinese": { + "description": "Language selector option for Simplified Chinese." + }, + "toggleSidebar": "侧边栏面板", + "@toggleSidebar": { + "description": "Keyboard shortcuts label for the sidebar panel toggle." + }, + "topLeft": "左上", + "@topLeft": { + "description": "Editing button position option." + }, + "topRight": "右上", + "@topRight": { + "description": "Editing button position option." + }, + "undo": "撤销", + "@undo": { + "description": "Undo command label." + }, + "validate": "验证", + "@validate": { + "description": "Validate action label." + }, + "validation": "验证", + "@validation": { + "description": "Settings section title for validation options." + }, + "viewMode": "视图模式", + "@viewMode": { + "description": "Native header bar view mode control label." + }, + "welcome": "欢迎", + "@welcome": { + "description": "Welcome screen label and tooltip." + }, + "writerside": "Writerside", + "@writerside": { + "description": "Writerside workspace kind label." + }, + "xml": "XML", + "@xml": { + "description": "XML format label." + }, + "fileTypeMarkdown": "Markdown", + "@fileTypeMarkdown": { + "description": "Native file picker type label for Markdown files." + }, + "fileTypeImages": "图像", + "@fileTypeImages": { + "description": "Native file picker type label for images." + }, + "openMarkdownFile": "打开 Markdown 文件", + "@openMarkdownFile": { + "description": "Action label for opening a Markdown file." + }, + "markdownFileExtensions": ".md 或 .markdown", + "@markdownFileExtensions": { + "description": "Subtitle describing supported Markdown file extensions." + }, + "openFolderOrWritersideProject": "打开文件夹或 Writerside 项目", + "@openFolderOrWritersideProject": { + "description": "Action label for opening a folder or Writerside project." + }, + "markdownFolderOrWritersideProject": "Markdown 文件夹或兼容 Writerside 的项目", + "@markdownFolderOrWritersideProject": { + "description": "Subtitle describing supported folder workspace types." + }, + "noOpenFile": "没有打开的文件", + "@noOpenFile": { + "description": "Header title when a folder or Writerside workspace has no open editor tab." + }, + "shortcutDeleteTreeItemDescription": "删除选中的文件项,或从目录中移除选中的主题", + "@shortcutDeleteTreeItemDescription": { + "description": "Keyboard shortcut description for deleting the selected Files item or removing the selected topic from the table of contents." + }, + "shortcutGroupGeneral": "常规", + "@shortcutGroupGeneral": { + "description": "Keyboard shortcut group for general application commands." + }, + "shortcutNewDocument": "创建", + "@shortcutNewDocument": { + "description": "Keyboard shortcut label for opening the content creation chooser." + }, + "shortcutNewDocumentDescription": "创建 Markdown 文件或 Writerside 项目", + "@shortcutNewDocumentDescription": { + "description": "Keyboard shortcut description for creating Markdown files or Writerside projects." + }, + "shortcutOpenDescription": "打开 Markdown 文件、文件夹或 Writerside 项目", + "@shortcutOpenDescription": { + "description": "Keyboard shortcut description for opening content." + }, + "shortcutSaveDescription": "保存当前文档", + "@shortcutSaveDescription": { + "description": "Keyboard shortcut description for saving content." + }, + "shortcutSearchDescription": "搜索当前工作区", + "@shortcutSearchDescription": { + "description": "Keyboard shortcut description for search." + }, + "shortcutKeyboardShortcutsDescription": "显示此键盘快捷键参考", + "@shortcutKeyboardShortcutsDescription": { + "description": "Keyboard shortcut description for opening shortcuts." + }, "shortcutSyntaxReferenceDescription": "打开语法参考", + "@shortcutSyntaxReferenceDescription": { + "description": "Keyboard shortcut description for opening the Syntax Reference." + }, + "shortcutSettingsDescription": "打开 BusyMark 设置", + "@shortcutSettingsDescription": { + "description": "Keyboard shortcut description for opening settings." + }, + "shortcutNextTab": "下一个标签页", + "@shortcutNextTab": { + "description": "Keyboard shortcut label for moving to the next tab." + }, + "shortcutNextTabDescription": "移至下一个打开的标签页", + "@shortcutNextTabDescription": { + "description": "Keyboard shortcut description for moving to the next tab." + }, + "shortcutPreviousTab": "上一个标签页", + "@shortcutPreviousTab": { + "description": "Keyboard shortcut label for moving to the previous tab." + }, + "shortcutPreviousTabDescription": "移至上一个打开的标签页", + "@shortcutPreviousTabDescription": { + "description": "Keyboard shortcut description for moving to the previous tab." + }, + "shortcutCloseTab": "关闭标签页", + "@shortcutCloseTab": { + "description": "Keyboard shortcut label for closing the active tab." + }, + "shortcutCloseTabDescription": "关闭当前标签页", + "@shortcutCloseTabDescription": { + "description": "Keyboard shortcut description for closing the active tab." + }, + "shortcutCloseAllTabs": "关闭所有标签页", + "@shortcutCloseAllTabs": { + "description": "Keyboard shortcut label for closing all tabs." + }, + "shortcutCloseAllTabsDescription": "关闭所有打开的标签页", + "@shortcutCloseAllTabsDescription": { + "description": "Keyboard shortcut description for closing all tabs." + }, + "shortcutGroupTextEditing": "文本编辑", + "@shortcutGroupTextEditing": { + "description": "Keyboard shortcut group for text editing commands." + }, + "shortcutSelectAllDescription": "在源代码模式下选择全部文本;在编辑器模式下按两次以选择所有块", + "@shortcutSelectAllDescription": { + "description": "Keyboard shortcut description for selecting source text or visual-editor blocks." + }, + "shortcutCutDescription": "剪切选中的文本", + "@shortcutCutDescription": { + "description": "Keyboard shortcut description for cut." + }, + "shortcutCopyDescription": "复制选中的文本", + "@shortcutCopyDescription": { + "description": "Keyboard shortcut description for copy." + }, + "shortcutPasteDescription": "从剪贴板粘贴", + "@shortcutPasteDescription": { + "description": "Keyboard shortcut description for paste." + }, + "shortcutPastePlainTextDescription": "粘贴剪贴板中的无格式文本", + "@shortcutPastePlainTextDescription": { + "description": "Keyboard shortcut description for plain text paste." + }, + "shortcutUndoDescription": "撤销上次编辑", + "@shortcutUndoDescription": { + "description": "Keyboard shortcut description for undo." + }, + "shortcutRedoDescription": "重做上次撤销的编辑", + "@shortcutRedoDescription": { + "description": "Keyboard shortcut description for redo." + }, + "shortcutInsertIndentation": "插入缩进", + "@shortcutInsertIndentation": { + "description": "Keyboard shortcut label for inserting indentation." + }, + "shortcutInsertIndentationDescription": "在光标处插入缩进", + "@shortcutInsertIndentationDescription": { + "description": "Keyboard shortcut description for inserting indentation." + }, + "shortcutOutdentSource": "减少源代码缩进", + "@shortcutOutdentSource": { + "description": "Keyboard shortcut label for outdenting in Source mode." + }, + "shortcutOutdentSourceDescription": "在源代码模式下减少一级缩进", + "@shortcutOutdentSourceDescription": { + "description": "Keyboard shortcut description for outdenting in Source mode." + }, + "shortcutEscape": "关闭搜索或清除块选择", + "@shortcutEscape": { + "description": "Keyboard shortcut label for closing search or clearing a block selection." + }, + "shortcutEscapeDescription": "关闭工作区搜索,或在编辑器模式下清除块选择", + "@shortcutEscapeDescription": { + "description": "Keyboard shortcut description for closing search or clearing a block selection." + }, + "shortcutGroupFormatting": "格式", + "@shortcutGroupFormatting": { + "description": "Keyboard shortcut group for inline formatting." + }, + "shortcutBoldDescription": "切换选中文本的粗体", + "@shortcutBoldDescription": { + "description": "Keyboard shortcut description for bold." + }, + "shortcutItalicDescription": "切换选中文本的斜体", + "@shortcutItalicDescription": { + "description": "Keyboard shortcut description for italic." + }, + "shortcutUnderlineDescription": "切换选中文本的下划线", + "@shortcutUnderlineDescription": { + "description": "Keyboard shortcut description for underline." + }, + "shortcutLinkDescription": "插入或编辑链接", + "@shortcutLinkDescription": { + "description": "Keyboard shortcut description for link insertion." + }, + "shortcutInlineCodeDescription": "切换选中文本的行内代码格式", + "@shortcutInlineCodeDescription": { + "description": "Keyboard shortcut description for inline code." + }, + "shortcutStrikethroughDescription": "切换选中文本的删除线", + "@shortcutStrikethroughDescription": { + "description": "Keyboard shortcut description for strikethrough." + }, + "shortcutGroupBlocks": "块", + "@shortcutGroupBlocks": { + "description": "Keyboard shortcut group for block styles." + }, + "shortcutParagraphDescription": "将当前块设为段落", + "@shortcutParagraphDescription": { + "description": "Keyboard shortcut description for paragraph style." + }, + "shortcutHeading1Description": "将当前块设为标题 1", + "@shortcutHeading1Description": { + "description": "Keyboard shortcut description for heading 1." + }, + "shortcutHeading2Description": "将当前块设为标题 2", + "@shortcutHeading2Description": { + "description": "Keyboard shortcut description for heading 2." + }, + "shortcutHeading3Description": "将当前块设为标题 3", + "@shortcutHeading3Description": { + "description": "Keyboard shortcut description for heading 3." + }, + "shortcutHeading4Description": "将当前块设为标题 4", + "@shortcutHeading4Description": { + "description": "Keyboard shortcut description for heading 4." + }, + "shortcutHeading5Description": "将当前块设为标题 5", + "@shortcutHeading5Description": { + "description": "Keyboard shortcut description for heading 5." + }, + "shortcutHeading6Description": "将当前块设为标题 6", + "@shortcutHeading6Description": { + "description": "Keyboard shortcut description for heading 6." + }, + "shortcutGroupLists": "列表", + "@shortcutGroupLists": { + "description": "Keyboard shortcut group for list commands." + }, + "numberedList": "编号列表", + "@numberedList": { + "description": "Keyboard shortcut label for numbered list formatting." + }, + "shortcutNumberedListDescription": "切换编号列表格式", + "@shortcutNumberedListDescription": { + "description": "Keyboard shortcut description for numbered list." + }, + "bulletedList": "项目符号列表", + "@bulletedList": { + "description": "Keyboard shortcut label for bulleted list formatting." + }, + "shortcutBulletedListDescription": "切换项目符号列表格式", + "@shortcutBulletedListDescription": { + "description": "Keyboard shortcut description for bulleted list." + }, + "checklist": "检查清单", + "@checklist": { + "description": "Keyboard shortcut label for checklist formatting." + }, + "shortcutChecklistDescription": "切换检查清单格式", + "@shortcutChecklistDescription": { + "description": "Keyboard shortcut description for checklist." + }, + "shortcutGroupSidebar": "侧边栏", + "@shortcutGroupSidebar": { + "description": "Keyboard shortcut group for sidebar view switching." + }, + "sidebarViewMenu": "侧边栏视图", + "@sidebarViewMenu": { + "description": "Tooltip for the sidebar view selector button." + }, + "createMarkdownFile": "创建 Markdown 文件", + "@createMarkdownFile": { + "description": "Welcome screen action for creating a Markdown file." + }, + "createMarkdownFileDescription": "开始创建未保存的本地 Markdown 文档", + "@createMarkdownFileDescription": { + "description": "Welcome screen subtitle for creating a Markdown file." + }, + "createWritersideProject": "创建 Writerside 项目", + "@createWritersideProject": { + "description": "Welcome screen action for creating a Writerside project." + }, + "createWritersideProjectDescription": "开始创建本地兼容 Writerside 的项目", + "@createWritersideProjectDescription": { + "description": "Welcome screen subtitle for creating a Writerside project." + }, + "defaultProjectName": "文档", + "@defaultProjectName": { + "description": "Default project name shown in the create project dialog." + }, + "defaultInstanceName": "用户指南", + "@defaultInstanceName": { + "description": "Default Writerside instance name shown in the create project dialog." + }, + "defaultStartTopicTitle": "开始使用", + "@defaultStartTopicTitle": { + "description": "Default start topic title shown in the create project dialog." + }, + "projectName": "项目名称", + "@projectName": { + "description": "Create project dialog field label." + }, + "directoryName": "目录名称", + "@directoryName": { + "description": "Create project dialog field label." + }, + "instanceName": "实例名称", + "@instanceName": { + "description": "Create project dialog field label." + }, + "instanceId": "实例 ID", + "@instanceId": { + "description": "Create project dialog field label." + }, + "startTopicTitle": "起始主题标题", + "@startTopicTitle": { + "description": "Create project dialog field label." + }, + "location": "位置", + "@location": { + "description": "Create dialog location section label." + }, + "projectNameRequired": "项目名称为必填项。", + "@projectNameRequired": { + "description": "Validation message for missing project name." + }, + "directoryNameRequired": "目录名称为必填项。", + "@directoryNameRequired": { + "description": "Validation message for missing directory name." + }, + "useSingleSafeDirectoryName": "使用单一且安全的目录名称。", + "@useSingleSafeDirectoryName": { + "description": "Validation message for unsafe directory names." + }, + "useLowercaseIdentifier": "使用仅包含小写字母、数字、下划线或连字符的小写标识符。", + "@useLowercaseIdentifier": { + "description": "Validation message for invalid Writerside instance IDs." + }, + "startTopicTitleRequired": "起始主题标题为必填项。", + "@startTopicTitleRequired": { + "description": "Validation message for missing start topic title." + }, + "createWritersideProjectFailed": "无法创建 Writerside 项目。", + "@createWritersideProjectFailed": { + "description": "Fallback error shown when Writerside project creation fails." + }, + "settingsTitle": "BusyMark 设置", + "@settingsTitle": { + "description": "Settings screen title." + }, + "autoSave": "自动保存", + "@autoSave": { + "description": "Editor setting label for saving files automatically." + }, + "autoSaveDescription": "在短暂空闲后自动保存文件更改。", + "@autoSaveDescription": { + "description": "Editor setting description for saving files automatically." + }, + "wordWrap": "自动换行", + "@wordWrap": { + "description": "Word wrap setting label." + }, + "editorFontSize": "编辑器字体大小", + "@editorFontSize": { + "description": "Editor font size setting label." + }, + "validateOnEdit": "编辑时验证", + "@validateOnEdit": { + "description": "Validation setting label." + }, + "clearRecentWorkspaces": "清除最近使用的工作区", + "@clearRecentWorkspaces": { + "description": "Settings action label for clearing recent workspaces." + }, + "editingButtonsPosition": "编辑按钮位置", + "@editingButtonsPosition": { + "description": "Settings label for WYSIWYG editing button position." + }, + "editingButtonsPositionDescription": "选择浮动 WYSIWYG 编辑按钮的显示位置。", + "@editingButtonsPositionDescription": { + "description": "Description for WYSIWYG editing button position setting." + }, + "editingButtonsDirection": "编辑按钮方向", + "@editingButtonsDirection": { + "description": "Settings label for WYSIWYG editing button direction." + }, + "editingButtonsDirectionDescription": "选择水平或垂直排列浮动 WYSIWYG 编辑按钮。", + "@editingButtonsDirectionDescription": { + "description": "Description for WYSIWYG editing button direction setting." + }, + "horizontal": "水平", + "@horizontal": { + "description": "Editing button direction option." + }, + "vertical": "垂直", + "@vertical": { + "description": "Editing button direction option." + }, + "privacy": "隐私", + "@privacy": { + "description": "Settings section title for privacy options." + }, + "allowRemoteImages": "加载远程图像", + "@allowRemoteImages": { + "description": "Settings switch title for loading remote images." + }, + "allowRemoteImagesDescription": "允许 Markdown 预览和编辑器从 http 和 https URL 加载图像。", + "@allowRemoteImagesDescription": { + "description": "Settings switch description for loading remote images." + }, + "clearRemoteImagePermissions": "清除远程图像权限", + "@clearRemoteImagePermissions": { + "description": "Settings action label for clearing per-workspace remote image permissions." + }, + "clearRemoteImagePermissionsDescription": "忘记已获准加载远程图像的工作区。", + "@clearRemoteImagePermissionsDescription": { + "description": "Settings action description for clearing per-workspace remote image permissions." + }, + "clearGitWorkspaceTrust": "清除受信任的 Git 工作区", + "@clearGitWorkspaceTrust": { + "description": "Settings action label for clearing trusted Git workspaces." + }, + "clearGitWorkspaceTrustDescription": "为之前受信任的工作区启用 Git 功能前先进行询问。", + "@clearGitWorkspaceTrustDescription": { + "description": "Settings action description for clearing trusted Git workspaces." + }, + "settingsWindowSectionTitle": "窗口", + "@settingsWindowSectionTitle": { + "description": "Settings section title for native window behavior." + }, + "settingsReopenWorkspaceOnStartupTitle": "启动时重新打开上次的工作区", + "@settingsReopenWorkspaceOnStartupTitle": { + "description": "Settings switch title for reopening the previous workspace on a normal startup." + }, + "settingsReopenWorkspaceOnStartupDescription": "BusyMark 启动时打开上次会话中的工作区和标签页。", + "@settingsReopenWorkspaceOnStartupDescription": { + "description": "Settings switch description for reopening the previous workspace on a normal startup." + }, + "settingsConfirmCloseWithUnsavedChangesTitle": "有未保存更改时关闭前进行确认", + "@settingsConfirmCloseWithUnsavedChangesTitle": { + "description": "Settings switch title for close confirmation when documents have unsaved changes." + }, + "settingsConfirmCloseWithUnsavedChangesDescription": "文档有未保存更改时,关闭 BusyMark 前先进行询问。", + "@settingsConfirmCloseWithUnsavedChangesDescription": { + "description": "Settings switch description for close confirmation when documents have unsaved changes." + }, + "closeUnsavedChangesTitle": "未保存的更改", + "@closeUnsavedChangesTitle": { + "description": "Window close confirmation dialog title when documents have unsaved changes." + }, + "closeUnsavedChangesSingleMessage": "此文档有未保存的更改。关闭 BusyMark 前保存更改?", + "@closeUnsavedChangesSingleMessage": { + "description": "Window close confirmation message when one document has unsaved changes." + }, + "closeUnsavedChangesMultipleMessage": "{count, plural, =0{关闭 BusyMark 前保存更改?} =1{有 1 个文档包含未保存的更改。关闭 BusyMark 前保存更改?} other{有 {count} 个文档包含未保存的更改。关闭 BusyMark 前保存更改?}}", + "@closeUnsavedChangesMultipleMessage": { + "description": "Window close confirmation message when multiple documents have unsaved changes.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "closeUnsavedChangesCancel": "取消", + "@closeUnsavedChangesCancel": { + "description": "Cancel button label in the window close unsaved-changes dialog." + }, + "closeUnsavedChangesDiscard": "放弃", + "@closeUnsavedChangesDiscard": { + "description": "Destructive button that closes BusyMark without saving editor changes. Translate it distinctly from Cancel." + }, + "closeUnsavedChangesSave": "保存", + "@closeUnsavedChangesSave": { + "description": "Save button label in the window close unsaved-changes dialog." + }, + "currentFile": "当前文件", + "@currentFile": { + "description": "Fallback file name in unsaved changes dialog." + }, + "unsavedChanges": "未保存的更改", + "@unsavedChanges": { + "description": "Unsaved changes dialog title." + }, + "unsavedChangesMessage": "{fileName} 中有未保存的更改。继续前保存这些更改?", + "@unsavedChangesMessage": { + "description": "Unsaved changes confirmation message.", + "placeholders": { + "fileName": { + "type": "String" + } + } + }, + "unsavedChangesMultipleMessage": "{count, plural, =1{有 1 个文档包含未保存的更改。继续前保存它?} other{有 {count} 个文档包含未保存的更改。继续前保存它们?}}", + "@unsavedChangesMultipleMessage": { + "description": "Confirmation message before replacing workspace state when several documents are dirty.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "fileChangedOnDisk": "文件已在磁盘上更改", + "@fileChangedOnDisk": { + "description": "File changed confirmation dialog title." + }, + "fileChangedOnDiskMessage": "自打开此文件后,它已在磁盘上发生更改。覆盖它?", + "@fileChangedOnDiskMessage": { + "description": "File changed confirmation dialog message." + }, + "untitledMarkdownFileName": "未命名.md", + "@untitledMarkdownFileName": { + "description": "Display name for a new unsaved Markdown document." + }, + "unorderedList": "无序列表", + "@unorderedList": { + "description": "WYSIWYG toolbar tooltip for unordered list." + }, + "orderedList": "有序列表", + "@orderedList": { + "description": "WYSIWYG toolbar tooltip for ordered list." + }, + "taskList": "任务列表", + "@taskList": { + "description": "WYSIWYG toolbar tooltip for task list." + }, + "toggleTaskChecked": "切换任务选中状态", + "@toggleTaskChecked": { + "description": "WYSIWYG toolbar tooltip for toggling task state." + }, + "indentListItem": "增加列表项缩进", + "@indentListItem": { + "description": "WYSIWYG toolbar tooltip for indenting a list item." + }, + "outdentListItem": "减少列表项缩进", + "@outdentListItem": { + "description": "WYSIWYG toolbar tooltip for outdenting a list item." + }, + "blockquote": "引用块", + "@blockquote": { + "description": "Blockquote command label." + }, + "codeBlock": "代码块", + "@codeBlock": { + "description": "Code block command or preview label." + }, + "codeBlockLanguage": "代码块语言", + "@codeBlockLanguage": { + "description": "Dialog title and toolbar tooltip for code block language." + }, + "image": "图像", + "video": "视频", + "openVideo": "播放视频", + "pauseVideo": "暂停视频", + "videoUnavailable": "视频不可用", + "videoPreview": "视频预览", + "diagnosticWritersideVideoMissingSource": "视频缺少 src 属性。", + "diagnosticWritersideVideoUnsupportedSource": "不支持的视频源:{source}", + "@diagnosticWritersideVideoUnsupportedSource": { + "placeholders": { + "source": { + "type": "String" + } + } + }, + "diagnosticWritersideVideoMissingFile": "视频文件不存在:{source}", + "@diagnosticWritersideVideoMissingFile": { + "placeholders": { + "source": { + "type": "String" + } + } + }, + "diagnosticWritersideVideoMissingPreview": "视频预览图像不存在:{preview}", + "@diagnosticWritersideVideoMissingPreview": { + "placeholders": { + "preview": { + "type": "String" + } + } + }, + "@image": { + "description": "Image command and document kind label." + }, + "inlineImage": "行内图像", + "@inlineImage": { + "description": "Inline image command label." + }, + "table": "表格", + "@table": { + "description": "Table command label." + }, + "htmlBlock": "HTML 块", + "@htmlBlock": { + "description": "HTML block command label." + }, + "htmlContentDefault": "HTML 内容", + "@htmlContentDefault": { + "description": "Default editable text inserted into a new HTML block." + }, + "shortcutHtmlBlockDescription": "插入或编辑 HTML 块", + "@shortcutHtmlBlockDescription": { + "description": "Keyboard shortcut description for inserting or editing an HTML block." + }, + "renderedHtml": "已渲染的 HTML", + "@renderedHtml": { + "description": "Badge label for HTML rendered in the WYSIWYG editor." + }, + "editHtml": "编辑 HTML", + "@editHtml": { + "description": "Dialog title and tooltip for editing raw HTML source." + }, + "htmlSource": "HTML 源代码", + "@htmlSource": { + "description": "Text field label for raw HTML source." + }, + "thematicBreak": "分隔线", + "@thematicBreak": { + "description": "Thematic break command label." + }, + "bold": "粗体", + "@bold": { + "description": "Bold command label." + }, + "italic": "斜体", + "@italic": { + "description": "Italic command label." + }, + "underline": "下划线", + "@underline": { + "description": "Underline command label." + }, + "strikethrough": "删除线", + "@strikethrough": { + "description": "Strikethrough command label." + }, + "inlineCode": "行内代码", + "@inlineCode": { + "description": "Inline code command label." + }, + "link": "链接", + "@link": { + "description": "Link command and preview label." + }, + "hardLineBreak": "硬换行", + "@hardLineBreak": { + "description": "Hard line break command label." + }, + "textStyle": "文本样式", + "@textStyle": { + "description": "Text style menu tooltip." + }, + "paragraph": "段落", + "@paragraph": { + "description": "Paragraph style label." + }, + "heading1": "标题 1", + "@heading1": { + "description": "Heading 1 style label." + }, + "heading2": "标题 2", + "@heading2": { + "description": "Heading 2 style label." + }, + "heading3": "标题 3", + "@heading3": { + "description": "Heading 3 style label." + }, + "heading4": "标题 4", + "@heading4": { + "description": "Heading 4 style label." + }, + "heading5": "标题 5", + "@heading5": { + "description": "Heading 5 style label." + }, + "heading6": "标题 6", + "@heading6": { + "description": "Heading 6 style label." + }, + "headingLevelAbbreviation": "H{level}", + "@headingLevelAbbreviation": { + "description": "Compact outline badge for a heading level.", + "placeholders": { + "level": { + "type": "int" + } + } + }, + "deleteTable": "删除表格", + "@deleteTable": { + "description": "Tooltip for deleting a table." + }, + "tableColumnNumber": "列 {columnNumber}", + "@tableColumnNumber": { + "description": "Tooltip for a table column control.", + "placeholders": { + "columnNumber": { + "type": "int" + } + } + }, + "insertColumnLeft": "在左侧插入列", + "@insertColumnLeft": { + "description": "Menu item for inserting a table column to the left." + }, + "insertColumnRight": "在右侧插入列", + "@insertColumnRight": { + "description": "Menu item for inserting a table column to the right." + }, + "deleteColumn": "删除列", + "@deleteColumn": { + "description": "Menu item for deleting a table column." + }, + "tableAlignmentUnspecified": "对齐方式:未指定", + "@tableAlignmentUnspecified": { + "description": "Menu item for using unspecified Markdown table-column alignment." + }, + "tableAlignmentLeft": "对齐方式:左对齐", + "@tableAlignmentLeft": { + "description": "Menu item for left-aligning a Markdown table column." + }, + "tableAlignmentCenter": "对齐方式:居中", + "@tableAlignmentCenter": { + "description": "Menu item for centering a Markdown table column." + }, + "tableAlignmentRight": "对齐方式:右对齐", + "@tableAlignmentRight": { + "description": "Menu item for right-aligning a Markdown table column." + }, + "tableRowNumber": "行 {rowNumber}", + "@tableRowNumber": { + "description": "Tooltip for a table row control.", + "placeholders": { + "rowNumber": { + "type": "int" + } + } + }, + "insertRowAbove": "在上方插入行", + "@insertRowAbove": { + "description": "Menu item for inserting a table row above." + }, + "insertRowBelow": "在下方插入行", + "@insertRowBelow": { + "description": "Menu item for inserting a table row below." + }, + "deleteRow": "删除行", + "@deleteRow": { + "description": "Menu item for deleting a table row." + }, + "tableHeaderHint": "标题", + "@tableHeaderHint": { + "description": "Hint for an empty table header cell." + }, + "tableCellHint": "单元格", + "@tableCellHint": { + "description": "Hint for an empty table body cell." + }, + "language": "语言", + "@language": { + "description": "Code block language field label." + }, + "hideEditingButtons": "隐藏编辑按钮", + "@hideEditingButtons": { + "description": "Tooltip for hiding floating editing buttons." + }, + "showEditingButtons": "显示编辑按钮", + "@showEditingButtons": { + "description": "Tooltip for showing floating editing buttons." + }, + "altText": "替代文本", + "@altText": { + "description": "Image alt text field label." + }, + "editorPlaceholderText": "文本", + "@editorPlaceholderText": { + "description": "Default selected text inserted by a source-editor formatting command." + }, + "editorPlaceholderCode": "代码", + "@editorPlaceholderCode": { + "description": "Default selected code inserted by a source-editor code command." + }, + "editorPlaceholderAltText": "替代文本", + "@editorPlaceholderAltText": { + "description": "Default selected image description inserted by a source-editor image command." + }, + "describeTheImage": "描述图像", + "@describeTheImage": { + "description": "Image alt text hint." + }, + "columns": "列", + "@columns": { + "description": "Table dialog columns field label." + }, + "rows": "行", + "@rows": { + "description": "Table dialog rows field label." + }, + "tableHeaderNumber": "标题 {columnNumber}", + "@tableHeaderNumber": { + "description": "Default header text for a newly inserted table column.", + "placeholders": { + "columnNumber": { + "type": "int" + } + } + }, + "tableCellDefault": "单元格", + "@tableCellDefault": { + "description": "Default cell text for newly inserted table cells." + }, + "noImageSource": "没有图像源", + "@noImageSource": { + "description": "Placeholder shown when an image has no source." + }, + "remoteImageBlocked": "远程图像已阻止", + "@remoteImageBlocked": { + "description": "Placeholder label shown when a remote image is blocked." + }, + "remoteImageBlockedTooltip": "选择是否允许 BusyMark 加载远程图像。", + "@remoteImageBlockedTooltip": { + "description": "Tooltip for a blocked remote image placeholder." + }, + "remoteImagesBlockedTitle": "远程图像已阻止", + "@remoteImagesBlockedTitle": { + "description": "Dialog title for remote image loading permission." + }, + "remoteImagesBlockedMessage": "本文档引用了来自互联网的图像。加载这些图像可能会向图像托管方泄露网络信息。", + "@remoteImagesBlockedMessage": { + "description": "Dialog message explaining the privacy risk of remote images." + }, + "loadRemoteImagesForWorkspace": "为此工作区加载", + "@loadRemoteImagesForWorkspace": { + "description": "Dialog button that allows remote images for the current workspace." + }, + "alwaysLoadRemoteImages": "始终加载远程图像", + "@alwaysLoadRemoteImages": { + "description": "Dialog button that enables remote images globally." + }, + "hideSidebar": "隐藏侧边栏面板", + "@hideSidebar": { + "description": "Tooltip for hiding the workspace sidebar panel." + }, + "showSidebar": "显示侧边栏面板", + "@showSidebar": { + "description": "Tooltip for showing the workspace sidebar panel." + }, + "showPreview": "显示预览", + "@showPreview": { + "description": "Tooltip for showing the preview pane." + }, + "hidePreview": "隐藏预览", + "@hidePreview": { + "description": "Tooltip for hiding the preview pane." + }, + "workspaceKindUnsavedMarkdown": "未保存的 Markdown 文件", + "@workspaceKindUnsavedMarkdown": { + "description": "Workspace kind label for an unsaved Markdown file." + }, + "workspaceKindSingleMarkdown": "单个 Markdown 文件", + "@workspaceKindSingleMarkdown": { + "description": "Workspace kind label for a single Markdown file." + }, + "workspaceKindMarkdownFolder": "Markdown 文件夹", + "@workspaceKindMarkdownFolder": { + "description": "Workspace kind label for a Markdown folder." + }, + "workspaceKindWritersideModule": "Writerside 模块", + "@workspaceKindWritersideModule": { + "description": "Workspace kind label for a Writerside module." + }, + "problems": "问题", + "@problems": { + "description": "Diagnostics dialog title." + }, + "diagnosticCount": "{count, plural, =0{没有诊断信息} =1{1 条诊断信息} other{{count} 条诊断信息}}", + "@diagnosticCount": { + "description": "Count of diagnostics in the workspace.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "files": "文件", + "@files": { + "description": "Files sidebar tab label." + }, + "toc": "目录", + "@toc": { + "description": "Writerside table of contents sidebar tab label." + }, + "tocActions": "目录操作", + "@tocActions": { + "description": "Tooltip for the Writerside TOC action menu button." + }, + "markdownUnsaved": "Markdown - 未保存", + "@markdownUnsaved": { + "description": "Workspace detail label for an unsaved Markdown file." + }, + "workspaceDetail": "{kind} - {count, plural, =1{1 个文件} other{{count} 个文件}}", + "@workspaceDetail": { + "description": "Workspace detail with kind and file count.", + "placeholders": { + "kind": { + "type": "String" + }, + "count": { + "type": "int" + } + } + }, + "noFiles": "没有文件", + "@noFiles": { + "description": "Empty state shown when there are no files." + }, + "newFile": "新建文件", + "@newFile": { + "description": "Menu action and dialog title for creating a new file." + }, + "noWritersideToc": "没有 Writerside 目录", + "@noWritersideToc": { + "description": "Empty state shown when there is no Writerside TOC." + }, + "tocSection": "目录节", + "@tocSection": { + "description": "Fallback label for a Writerside TOC section." + }, + "newTopic": "新建主题", + "@newTopic": { + "description": "Create new Writerside topic action label." + }, + "newChildTopic": "新建子主题", + "@newChildTopic": { + "description": "Create new child Writerside topic action label." + }, + "newSiblingTopic": "新建同级主题", + "@newSiblingTopic": { + "description": "Create new sibling Writerside topic action label." + }, + "renameTopicFile": "重命名主题文件", + "@renameTopicFile": { + "description": "Context-menu action that renames a Writerside topic file." + }, + "topicPlacement": "目录位置", + "@topicPlacement": { + "description": "Create topic dialog label for selecting TOC placement." + }, + "tocRoot": "位于目录根级别", + "@tocRoot": { + "description": "TOC placement option for the root level." + }, + "afterSelectedTopic": "位于选中主题之后", + "@afterSelectedTopic": { + "description": "TOC placement option after the selected topic." + }, + "insideSelectedTopic": "位于选中主题内", + "@insideSelectedTopic": { + "description": "TOC placement option inside the selected topic." + }, + "pasteAfterTopic": "粘贴到主题之后", + "@pasteAfterTopic": { + "description": "Action that moves a cut TOC entry after the selected topic." + }, + "pasteAsChildTopic": "粘贴为子主题", + "@pasteAsChildTopic": { + "description": "Action that moves a cut TOC entry inside the selected topic." + }, + "removeFromToc": "从目录中移除", + "@removeFromToc": { + "description": "Action that removes an entry from a Writerside table of contents without deleting its topic file." + }, + "confirmRemoveFromTocTitle": "从目录中移除?", + "@confirmRemoveFromTocTitle": { + "description": "Confirmation title before removing a Writerside TOC entry." + }, + "confirmRemoveFromTocMessage": "从此目录中移除 {name}?主题文件将被保留。", + "@confirmRemoveFromTocMessage": { + "description": "Confirmation message before removing a Writerside TOC entry without deleting its topic file.", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "confirmDeleteTopicTitle": "删除主题文件?", + "@confirmDeleteTopicTitle": { + "description": "Confirmation title before deleting a Writerside topic file." + }, + "confirmDeleteTopicMessage": "删除 {name} 并从每个目录中移除它?此操作无法撤销。", + "@confirmDeleteTopicMessage": { + "description": "Confirmation message before deleting a Writerside topic file and removing its TOC entries.", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "safeDeleteTopicFile": "安全删除主题文件…", + "@safeDeleteTopicFile": { + "description": "Writerside action that safely deletes a topic after checking usages." + }, + "removeTocElement": "移除目录元素", + "@removeTocElement": { + "description": "Writerside action and dialog title for removing a topic from one table of contents." + }, + "removeTocElements": "移除目录元素", + "@removeTocElements": { + "description": "Action that removes multiple selected elements from one Writerside table of contents." + }, + "reviewUsages": "查看使用情况", + "@reviewUsages": { + "description": "Action that opens the Writerside topic usages review." + }, + "deleteTopicFile": "删除主题文件", + "@deleteTopicFile": { + "description": "Action that deletes a Writerside topic source file." + }, + "removeAction": "移除", + "@removeAction": { + "description": "Short action label for removing an item without deleting its source file." + }, + "topicRemovalSummary": "从选中的实例中移除“{topic}”。主题文件将被保留。", + "@topicRemovalSummary": { + "description": "Summary in the dialog for removing a topic from one Writerside instance.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "safeDeleteTopicSummary": "删除“{topic}”,并在整个 Writerside 项目中安全更新其引用。", + "@safeDeleteTopicSummary": { + "description": "Summary in the Writerside safe-delete dialog.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "childTopicsPromoted": "{count, plural, =1{1 个子主题将上移一级。} other{{count} 个子主题将上移一级。}}", + "@childTopicsPromoted": { + "description": "Disclosure that children of a removed TOC element are promoted.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "topicIsStartPageRemovalWarning": "此主题被用作实例的起始页。请查看其使用情况,并在继续前指定其他起始页。", + "@topicIsStartPageRemovalWarning": { + "description": "Warning that blocks deletion of a Writerside start-page topic." + }, + "topicUsagesCount": "使用情况({count})", + "@topicUsagesCount": { + "description": "Heading with the number of Writerside topic usages.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "noBreakingTopicUsages": "未找到会导致引用失效的引用。", + "@noBreakingTopicUsages": { + "description": "Safe-delete message when no breaking references were found." + }, + "topicUsagesFound": "BusyMark 找到了以下对该主题的引用。", + "@topicUsagesFound": { + "description": "Description above Writerside topic usage groups." + }, + "topicUsageTocElements": "目录元素", + "@topicUsageTocElements": { + "description": "Usage group label for Writerside TOC elements." + }, + "topicUsageStartPages": "起始页", + "@topicUsageStartPages": { + "description": "Usage group label for Writerside instance start pages." + }, + "topicUsageTopicLinks": "主题链接", + "@topicUsageTopicLinks": { + "description": "Usage group label for links to a Writerside topic." + }, + "topicUsageIncludes": "包含项", + "@topicUsageIncludes": { + "description": "Usage group label for Writerside include elements." + }, + "usageCount": "{count, plural, =1{1 次使用} other{{count} 次使用}}", + "@usageCount": { + "description": "Number of references that use a Writerside topic.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "refactoringOptions": "重构选项", + "@refactoringOptions": { + "description": "Heading for Writerside topic removal options." + }, + "updateUsagesAutomatically": "自动更新使用情况", + "@updateUsagesAutomatically": { + "description": "Option to rewrite Writerside topic usages during removal." + }, + "updateUsagesAutomaticallyDescription": "移除目录引用和包含项,同时保留链接文本。", + "@updateUsagesAutomaticallyDescription": { + "description": "Description of automatic Writerside usage updates." + }, + "manualUsageUpdatesRequired": "执行此重构前,某些使用情况需要手动更改。", + "@manualUsageUpdatesRequired": { + "description": "Message when some Writerside usages cannot be updated automatically." + }, + "setRedirectTo": "设置重定向到", + "@setRedirectTo": { + "description": "Option to redirect an old Writerside page to another topic." + }, + "noRedirectDescription": "不重定向旧的已发布页面。", + "@noRedirectDescription": { + "description": "Description when no Writerside page redirect is selected." + }, + "redirectTarget": "重定向目标", + "@redirectTarget": { + "description": "Field label for a Writerside redirect destination." + }, + "remainingUsagesBlockRemoval": "请在继续前查看并更新剩余的使用情况,或在可用时启用自动更新。", + "@remainingUsagesBlockRemoval": { + "description": "Instruction shown when unresolved usages block topic removal." + }, + "usagesOfTopic": "{topic} 的使用情况", + "@usagesOfTopic": { + "description": "Writerside usages sidebar title.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "noUsagesFound": "未找到使用情况", + "@noUsagesFound": { + "description": "Empty state in the Writerside usages review." + }, + "outsideSelectedInstance": "在选中的实例之外", + "@outsideSelectedInstance": { + "description": "Marker for a usage outside the selected Writerside instance." + }, + "doRefactor": "执行重构", + "@doRefactor": { + "description": "Action to return from usage review and continue the topic refactoring." + }, + "orphanTopicTitle": "主题文件已不再使用", + "@orphanTopicTitle": { + "description": "Dialog title after a topic is removed from its last table of contents." + }, + "keepTopicFile": "保留主题文件", + "@keepTopicFile": { + "description": "Action that keeps an orphaned Writerside topic file." + }, + "orphanTopicMessage": "“{topic}”在此 Writerside 项目中已不再使用。删除该文件,或保留它以供其他实例使用。", + "@orphanTopicMessage": { + "description": "Prompt to delete or keep an orphaned Writerside topic file.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "defaultNewTopicTitle": "新主题", + "@defaultNewTopicTitle": { + "description": "Default topic title in the create topic dialog." + }, + "topicTitle": "主题标题", + "@topicTitle": { + "description": "Create topic dialog field label." + }, + "fileName": "文件名", + "@fileName": { + "description": "Create topic dialog field label." + }, + "topicTitleRequired": "主题标题为必填项。", + "@topicTitleRequired": { + "description": "Validation message for missing topic title." + }, + "fileNameRequired": "文件名为必填项。", + "@fileNameRequired": { + "description": "Validation message for missing file name." + }, + "rename": "重命名", + "@rename": { + "description": "Rename command label." + }, + "confirmDeleteFileTitle": "删除文件?", + "@confirmDeleteFileTitle": { + "description": "Confirmation dialog title before deleting a file." + }, + "confirmDeleteFolderTitle": "删除文件夹?", + "@confirmDeleteFolderTitle": { + "description": "Confirmation dialog title before deleting a folder." + }, + "confirmDeleteFileMessage": "删除 {name}?此操作无法撤销。", + "@confirmDeleteFileMessage": { + "description": "Confirmation dialog message before deleting a file.", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "confirmDeleteFolderMessage": "删除 {name} 及其中的所有文件?此操作无法撤销。", + "@confirmDeleteFolderMessage": { + "description": "Confirmation dialog message before deleting a folder.", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "useSingleSafeFileName": "使用单一且安全的文件名。", + "@useSingleSafeFileName": { + "description": "Validation message for unsafe file names." + }, + "useExpectedExtension": "为选中的格式使用 {extension} 扩展名。", + "@useExpectedExtension": { + "description": "Validation message for an unexpected file extension.", + "placeholders": { + "extension": { + "type": "String" + } + } + }, + "useIdentifierCharacters": "在扩展名之前仅使用字母、数字、下划线或连字符。", + "@useIdentifierCharacters": { + "description": "Validation message for invalid topic IDs." + }, + "topicIdAlreadyExists": "主题 ID 已存在。", + "@topicIdAlreadyExists": { + "description": "Validation message for duplicate topic IDs." + }, + "createWritersideTopicFailed": "无法创建 Writerside 主题。", + "@createWritersideTopicFailed": { + "description": "Fallback error shown when topic creation fails." + }, + "noOutline": "没有大纲", + "@noOutline": { + "description": "Empty state shown when a document has no outline." + }, + "expandKind": "展开 {kind}", + "@expandKind": { + "description": "Tooltip for expanding a foldable source section.", + "placeholders": { + "kind": { + "type": "String" + } + } + }, + "collapseKind": "折叠 {kind}", + "@collapseKind": { + "description": "Tooltip for collapsing a foldable source section.", + "placeholders": { + "kind": { + "type": "String" + } + } + }, + "foldKindSection": "节", + "@foldKindSection": { + "description": "Fold kind label for a section." + }, + "foldKindList": "列表", + "@foldKindList": { + "description": "Fold kind label for a list." + }, + "foldKindQuote": "引用", + "@foldKindQuote": { + "description": "Fold kind label for a blockquote." + }, + "foldKindTag": "标签", + "@foldKindTag": { + "description": "Fold kind label for an XML tag." + }, + "sourceSearchPreviousMatch": "上一个匹配项", + "@sourceSearchPreviousMatch": { + "description": "Tooltip for moving to the previous source search match." + }, + "sourceSearchNextMatch": "下一个匹配项", + "@sourceSearchNextMatch": { + "description": "Tooltip for moving to the next source search match." + }, + "sourceSearchCaseSensitive": "区分大小写", + "@sourceSearchCaseSensitive": { + "description": "Tooltip for toggling case-sensitive source search." + }, + "sourceSearchWholeWord": "全字匹配", + "@sourceSearchWholeWord": { + "description": "Tooltip for toggling whole-word source search." + }, + "sourceSearchRegex": "正则表达式", + "@sourceSearchRegex": { + "description": "Tooltip for toggling regular-expression source search." + }, + "sourceSearchReplacement": "替换为", + "@sourceSearchReplacement": { + "description": "Placeholder for the active-document replacement field." + }, + "sourceSearchReplaceCurrent": "替换当前匹配项", + "@sourceSearchReplaceCurrent": { + "description": "Tooltip for replacing the current search match." + }, + "sourceSearchReplaceAndFindNext": "替换并查找下一个", + "@sourceSearchReplaceAndFindNext": { + "description": "Tooltip for replacing the current match and moving to the next." + }, + "sourceSearchReplaceAll": "全部替换", + "@sourceSearchReplaceAll": { + "description": "Tooltip for replacing every active-document search match." + }, + "workspaceReplace": "在工作区中替换", + "@workspaceReplace": { + "description": "Action that previews replacements across the workspace." + }, + "reviewReplacements": "查看替换内容", + "@reviewReplacements": { + "description": "Action and dialog title for reviewing workspace replacements." + }, + "applyReplacements": "应用替换", + "@applyReplacements": { + "description": "Action that applies selected workspace replacements." + }, + "skippedFiles": "跳过的文件", + "@skippedFiles": { + "description": "Heading for files excluded from a workspace replacement." + }, + "workspaceReplaceDirtyBuffer": "未保存的编辑器内容", + "@workspaceReplaceDirtyBuffer": { + "description": "Source label for a workspace replacement preview using a dirty document buffer." + }, + "workspaceReplaceDiskContent": "磁盘上的已保存内容", + "@workspaceReplaceDiskContent": { + "description": "Source label for a workspace replacement preview using disk content." + }, + "selectFileMatches": "选择全部 {count} 个匹配项", + "@selectFileMatches": { + "description": "Checkbox label for selecting every replacement match in a file.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "workspaceReplaceApplied": "已在 {files} 个文件中替换 {matches} 个匹配项;跳过 {skipped} 个。", + "@workspaceReplaceApplied": { + "description": "Summary shown after applying workspace replacements.", + "placeholders": { + "matches": { + "type": "int" + }, + "files": { + "type": "int" + }, + "skipped": { + "type": "int" + } + } + }, + "documentFormatWithFinalNewline": "{encoding} · {lineEnding} · 末尾有换行符", + "@documentFormatWithFinalNewline": { + "description": "Document format tooltip when the file ends with a newline.", + "placeholders": { + "encoding": { + "type": "String" + }, + "lineEnding": { + "type": "String" + } + } + }, + "documentFormatWithoutFinalNewline": "{encoding} · {lineEnding} · 末尾无换行符", + "@documentFormatWithoutFinalNewline": { + "description": "Document format tooltip when the file does not end with a newline.", + "placeholders": { + "encoding": { + "type": "String" + }, + "lineEnding": { + "type": "String" + } + } + }, + "normalizeLineEndings": "规范化行尾", + "@normalizeLineEndings": { + "description": "Dialog title for selecting a line-ending style." + }, + "mixedLineEndingsSavePrompt": "此文档包含混合的行尾格式。请选择一种格式。", + "@mixedLineEndingsSavePrompt": { + "description": "Prompt shown before saving a document with mixed line endings." + }, + "workspaceReplaceMixedLineEndings": "{fileName} 使用混合的行尾格式。请在替换前选择要使用的格式。", + "@workspaceReplaceMixedLineEndings": { + "description": "Prompt shown before replacing content in a mixed-line-ending file.", + "placeholders": { + "fileName": { + "type": "String" + } + } + }, + "workspaceReplaceIssueOversized": "已跳过过大的文件。", + "@workspaceReplaceIssueOversized": { + "description": "Workspace replacement issue for a file above the size limit." + }, + "workspaceReplaceIssueUnreadable": "已跳过无法读取的文件。", + "@workspaceReplaceIssueUnreadable": { + "description": "Workspace replacement issue for an unreadable file." + }, + "workspaceReplaceIssueInvalidUtf8": "已跳过不是有效 UTF-8 的文件。", + "@workspaceReplaceIssueInvalidUtf8": { + "description": "Workspace replacement issue for invalid UTF-8 content." + }, + "workspaceReplaceIssueTruncated": "替换预览已被截断。", + "@workspaceReplaceIssueTruncated": { + "description": "Workspace replacement issue when the match limit is reached." + }, + "workspaceReplaceIssueFileChanged": "已跳过预览后发生变化的文件。", + "@workspaceReplaceIssueFileChanged": { + "description": "Workspace replacement issue for stale disk content." + }, + "workspaceReplaceIssueBufferChanged": "已跳过预览后发生变化的编辑器缓冲区。", + "@workspaceReplaceIssueBufferChanged": { + "description": "Workspace replacement issue for stale in-memory content." + }, + "workspaceReplaceIssueNormalizationRequired": "请在替换前选择 LF 或 CRLF 规范化。", + "@workspaceReplaceIssueNormalizationRequired": { + "description": "Workspace replacement issue for mixed line endings without a selected format." + }, + "workspaceReplaceIssuePartialConflict": "由于文件同时发生了变化,回滚已停止。部分替换可能仍然存在;被移出的内容已保留在下方路径中。", + "@workspaceReplaceIssuePartialConflict": { + "description": "Workspace replacement issue when a concurrent edit prevents safe transactional rollback." + }, + "workspaceReplaceIssueApplyFailed": "无法提交经过审查的替换;没有文件发生更改。", + "@workspaceReplaceIssueApplyFailed": { + "description": "Workspace replacement issue when the transactional file commit fails." + }, + "externalChangesTitle": "外部更改 — {fileName}", + "@externalChangesTitle": { + "description": "Title of the external-file comparison dialog.", + "placeholders": { + "fileName": { + "type": "String" + } + } + }, + "externalFileDeleted": "此文件已从磁盘删除。", + "@externalFileDeleted": { + "description": "Persistent banner shown when an open file is deleted externally." + }, + "externalFileChanged": "在您有未保存编辑时,此文件已在磁盘上发生变化。", + "@externalFileChanged": { + "description": "Persistent banner shown when a dirty file changes externally." + }, + "recoveredDocumentReview": "已恢复 {fileName} 的未保存内容。请检查后保存、另存为或放弃。", + "@recoveredDocumentReview": { + "description": "Persistent recovery review banner.", + "placeholders": { + "fileName": { + "type": "String" + } + } + }, + "compare": "比较", + "@compare": { + "description": "Action that compares the editor buffer with the disk version." + }, + "reloadFromDisk": "从磁盘重新加载", + "@reloadFromDisk": { + "description": "Action that replaces the editor buffer with the disk version." + }, + "keepMine": "保留我的版本", + "@keepMine": { + "description": "Action that keeps the editor buffer after an external change." + }, + "saveAs": "另存为", + "@saveAs": { + "description": "Action that saves the current document to another path." + }, + "sourceSearchInvalidRegex": "无效的正则表达式", + "@sourceSearchInvalidRegex": { + "description": "Source search status shown when the regular expression is invalid." + }, + "sourceLargeFileFeaturesPaused": "大文件:已暂停语法突出显示和折叠", + "@sourceLargeFileFeaturesPaused": { + "description": "Status banner shown when source highlighting and folding are disabled for a large file." + }, + "nothingToRead": "没有可读取的内容", + "@nothingToRead": { + "description": "Empty state shown when there is no content to read." + }, + "admonition": "提示块", + "@admonition": { + "description": "Tooltip for the Writerside admonition editing menu." + }, + "quote": "引用", + "@quote": { + "description": "Label for a neutral Writerside quote block." + }, + "note": "备注", + "@note": { + "description": "Preview label for a note admonition." + }, + "tip": "提示", + "@tip": { + "description": "Preview label for a tip admonition." + }, + "warning": "警告", + "@warning": { + "description": "Preview label for a warning admonition." + }, + "tabs": "标签页", + "@tabs": { + "description": "Preview label for a tabs block." + }, + "tab": "标签页", + "@tab": { + "description": "Preview label for a tab block." + }, + "procedure": "操作步骤", + "@procedure": { + "description": "Preview label for a procedure block." + }, + "step": "步骤", + "@step": { + "description": "Preview label for a procedure step." + }, + "topic": "主题", + "@topic": { + "description": "Preview label for a topic element." + }, + "chapter": "章节", + "@chapter": { + "description": "Preview label for a chapter element." + }, + "couldNotOpenTarget": "无法打开 {target}", + "@couldNotOpenTarget": { + "description": "Toast shown when a link target cannot be opened.", + "placeholders": { + "target": { + "type": "String" + } + } + }, + "linkTargetNotFound": "找不到链接目标:{targetPath}", + "@linkTargetNotFound": { + "description": "Toast shown when a link target path is missing.", + "placeholders": { + "targetPath": { + "type": "String" + } + } + }, + "cannotOpenFileTypeInEditor": "无法在编辑器中打开此文件类型", + "@cannotOpenFileTypeInEditor": { + "description": "Toast shown when a file type cannot be opened in the editor." + }, + "anchorNotFound": "找不到锚点:{anchor}", + "@anchorNotFound": { + "description": "Toast shown when a link anchor is missing.", + "placeholders": { + "anchor": { + "type": "String" + } + } + }, + "noProblemsFound": "未发现问题", + "@noProblemsFound": { + "description": "Diagnostics empty state." + }, + "noResults": "无结果", + "@noResults": { + "description": "Search empty state." + }, + "searchResultLine": "{relativePath} - 第 {lineNumber} 行", + "@searchResultLine": { + "description": "Search result subtitle with file path and line number.", + "placeholders": { + "relativePath": { + "type": "String" + }, + "lineNumber": { + "type": "int" + } + } + }, + "untitledResult": "未命名结果", + "@untitledResult": { + "description": "Fallback search result title." + }, + "documentKindMarkdownFile": "Markdown 文件", + "@documentKindMarkdownFile": { + "description": "Search result document kind label." + }, + "documentKindWritersideMarkdownTopic": "Writerside Markdown 主题", + "@documentKindWritersideMarkdownTopic": { + "description": "Search result document kind label." + }, + "documentKindWritersideXmlTopic": "Writerside XML 主题", + "@documentKindWritersideXmlTopic": { + "description": "Search result document kind label." + }, + "documentKindWritersideTree": "Writerside 树", + "@documentKindWritersideTree": { + "description": "Search result document kind label." + }, + "documentKindConfigurationFile": "配置文件", + "@documentKindConfigurationFile": { + "description": "Search result document kind label." + }, + "documentKindVariablesFile": "变量文件", + "@documentKindVariablesFile": { + "description": "Search result document kind label." + }, + "documentKindCategoriesFile": "类别文件", + "@documentKindCategoriesFile": { + "description": "Search result document kind label." + }, + "documentKindResourceFile": "资源文件", + "@documentKindResourceFile": { + "description": "Search result document kind label." + }, + "workspaceErrorOpenFailed": "打开失败:{error}", + "@workspaceErrorOpenFailed": { + "description": "Workspace error message shown when opening a path fails.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "workspaceErrorCreateWritersideProjectFailed": "无法创建 Writerside 项目:{error}", + "@workspaceErrorCreateWritersideProjectFailed": { + "description": "Workspace error message shown when Writerside project creation fails.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "workspaceErrorCreateWritersideTopicFailed": "无法创建 Writerside 主题:{error}", + "@workspaceErrorCreateWritersideTopicFailed": { + "description": "Workspace error message shown when Writerside topic creation fails.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "workspaceErrorCouldNotOpenFile": "无法打开文件:{error}", + "@workspaceErrorCouldNotOpenFile": { + "description": "Workspace error message shown when opening a file fails.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "workspaceErrorChooseWhereToSaveMarkdown": "选择保存此 Markdown 文件的位置。", + "@workspaceErrorChooseWhereToSaveMarkdown": { + "description": "Workspace error message shown when an untitled file needs a save location." + }, + "workspaceErrorSaveBlockedFileChangedOnDisk": "保存已阻止:文件已在磁盘上发生变化。", + "@workspaceErrorSaveBlockedFileChangedOnDisk": { + "description": "Workspace error message shown when a save is blocked by external changes." + }, + "workspaceErrorSaveFailed": "保存失败:{error}", + "@workspaceErrorSaveFailed": { + "description": "Workspace error message shown when saving fails.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "workspaceErrorFileOperationFailed": "文件操作失败:{error}", + "@workspaceErrorFileOperationFailed": { + "description": "Workspace error message shown when creating, renaming, moving, or deleting a file fails.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "workspaceErrorValidationFailed": "验证失败:{error}", + "@workspaceErrorValidationFailed": { + "description": "Workspace error message shown when validation fails.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "workspaceRecoveryRestored": "{count, plural, =1{已恢复 1 个未保存的文档。请在保存或放弃前进行检查。} other{已恢复 {count} 个未保存的文档。请在保存或放弃前逐一检查。}}", + "@workspaceRecoveryRestored": { + "description": "Notice shown after crash recovery restores documents.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "workspaceRecoveryDamaged": "{count, plural, =1{无法恢复一条损坏的恢复记录。原始恢复文件已保留以供检查。} other{无法恢复 {count} 条损坏的恢复记录。有效的恢复记录仍可用。}}", + "@workspaceRecoveryDamaged": { + "description": "Notice shown when recovery data is partly or wholly malformed.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "errorPathDoesNotExist": "路径不存在:{path}", + "@errorPathDoesNotExist": { + "description": "Detail for a missing path error.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorTargetDirectoryNotEmpty": "目标目录已存在且不为空:{path}", + "@errorTargetDirectoryNotEmpty": { + "description": "Detail for a non-empty target directory error.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorTargetPathNotDirectory": "目标路径已存在但不是目录:{path}", + "@errorTargetPathNotDirectory": { + "description": "Detail for a target path that is not a directory.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorGeneratedFileAlreadyExists": "生成的文件已存在:{path}", + "@errorGeneratedFileAlreadyExists": { + "description": "Detail for a generated file conflict.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorParentDirectoryRequired": "必须指定父目录。", + "@errorParentDirectoryRequired": { + "description": "Detail for missing parent directory input." + }, + "errorParentDirectoryMissing": "父目录不存在:{path}", + "@errorParentDirectoryMissing": { + "description": "Detail for a missing parent directory.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorDirectoryMissing": "目录不存在:{path}", + "@errorDirectoryMissing": { + "description": "Detail for a missing directory.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorPathAlreadyExists": "路径已存在:{path}", + "@errorPathAlreadyExists": { + "description": "Detail for a file operation target that already exists.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorFileNameRequired": "文件名为必填项。", + "@errorFileNameRequired": { + "description": "Detail for a missing file name in a file operation." + }, + "errorFileNameUnsafe": "文件名必须是单一且安全的路径段。", + "@errorFileNameUnsafe": { + "description": "Detail for an unsafe file name in a file operation." + }, + "errorFileOperationInvalidTarget": "无法将文件夹移动到其自身中。", + "@errorFileOperationInvalidTarget": { + "description": "Detail for an invalid file operation target." + }, + "errorFileOperationOutsideRoot": "文件操作必须在工作区内进行。", + "@errorFileOperationOutsideRoot": { + "description": "Detail for a file operation outside the workspace root." + }, + "errorFileOperationRoot": "无法从文件树更改工作区根目录。", + "@errorFileOperationRoot": { + "description": "Detail for a file operation attempted on the workspace root." + }, + "errorProjectNameRequired": "项目名称为必填项。", + "@errorProjectNameRequired": { + "description": "Detail for a missing project name." + }, + "errorDirectoryNameRequired": "目录名称为必填项。", + "@errorDirectoryNameRequired": { + "description": "Detail for a missing directory name." + }, + "errorDirectoryNameUnsafe": "目录名称必须是单一且安全的路径段。", + "@errorDirectoryNameUnsafe": { + "description": "Detail for an unsafe directory name." + }, + "errorInstanceIdInvalid": "实例 ID 必须以小写字母开头,且只能包含小写字母、数字、下划线和连字符。", + "@errorInstanceIdInvalid": { + "description": "Detail for an invalid Writerside instance ID." + }, + "errorTopicFileInvalid": "主题文件名必须是没有路径分隔符的 Markdown 文件名。", + "@errorTopicFileInvalid": { + "description": "Detail for an invalid topic file name." + }, + "errorTopicTitleRequired": "主题标题为必填项。", + "@errorTopicTitleRequired": { + "description": "Detail for a missing topic title." + }, + "errorWritersideModuleRootMissing": "Writerside 模块根目录不存在:{path}", + "@errorWritersideModuleRootMissing": { + "description": "Detail for a missing Writerside module root.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorWritersideModuleNotOpen": "必须打开 Writerside 模块才能创建主题。", + "@errorWritersideModuleNotOpen": { + "description": "Detail shown when creating a topic without an open Writerside module." + }, + "errorWritersideInstanceTreeMissing": "Writerside 模块没有实例树。", + "@errorWritersideInstanceTreeMissing": { + "description": "Detail shown when creating a topic without a Writerside instance tree." + }, + "errorWritersideTreeFileMissing": "Writerside 树文件不存在:{path}", + "@errorWritersideTreeFileMissing": { + "description": "Detail for a missing Writerside tree file.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorTopicIdAlreadyExists": "主题 ID \"{topicId}\" 已存在于此帮助模块中。", + "@errorTopicIdAlreadyExists": { + "description": "Detail for a duplicate topic ID.", + "placeholders": { + "topicId": { + "type": "String" + } + } + }, + "errorTopicFileAlreadyExists": "主题文件已存在:{path}", + "@errorTopicFileAlreadyExists": { + "description": "Detail for an existing topic file.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorReferenceTopicMissing": "选中的树中不存在引用主题:{topic}", + "@errorReferenceTopicMissing": { + "description": "Detail for a missing reference topic in a tree.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "errorWritersideTocNodeMissing": "选中的目录项已不存在。", + "@errorWritersideTocNodeMissing": { + "description": "Detail shown when a selected Writerside TOC entry no longer exists." + }, + "errorWritersideTocInvalidMove": "目录项无法移动到自身或其子项中。", + "@errorWritersideTocInvalidMove": { + "description": "Detail shown when a Writerside TOC move would create a cycle." + }, + "errorWritersideStartTopicDelete": "无法删除起始主题 {topic}。请先选择其他起始页。", + "@errorWritersideStartTopicDelete": { + "description": "Detail shown when attempting to delete the start topic of a Writerside instance.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "errorWritersideSafeDeleteRequired": "请对 Writerside 主题文件使用安全删除。", + "@errorWritersideSafeDeleteRequired": { + "description": "Error shown when generic file deletion is attempted for a Writerside topic." + }, + "errorWritersideTopicUsageScanFailed": "无法完成主题使用情况扫描。没有文件发生更改。", + "@errorWritersideTopicUsageScanFailed": { + "description": "Error shown when safe-delete usage analysis cannot complete reliably." + }, + "errorWritersideTopicUsagesRemain": "某些主题使用情况仍需处理。请先查看后再继续。", + "@errorWritersideTopicUsagesRemain": { + "description": "Error shown when unresolved topic usages block removal." + }, + "errorWritersideRedirectInvalid": "选中的重定向目标已无效。请重新选择。", + "@errorWritersideRedirectInvalid": { + "description": "Error shown when a safe-delete redirect target is stale or conflicts." + }, + "errorWritersideRollbackFailed": "无法完全回滚主题移除。请在继续前查看这些路径:{paths}", + "@errorWritersideRollbackFailed": { + "description": "Error shown when safe-delete recovery leaves files requiring manual review.", + "placeholders": { + "paths": { + "type": "String" + } + } + }, + "errorTopicsRootUnsafe": "主题根目录必须是安全的相对目录。", + "@errorTopicsRootUnsafe": { + "description": "Detail for an unsafe topics root directory." + }, + "errorTopicFileNameUnsafe": "主题文件名必须是单一且安全的路径段。", + "@errorTopicFileNameUnsafe": { + "description": "Detail for an unsafe topic file name." + }, + "errorTopicFileExtensionMismatch": "主题文件扩展名必须与选中的格式匹配({extension})。", + "@errorTopicFileExtensionMismatch": { + "description": "Detail for a topic file extension mismatch.", + "placeholders": { + "extension": { + "type": "String" + } + } + }, + "errorTopicFileNameInvalid": "主题文件名只能包含字母、数字、下划线和连字符。", + "@errorTopicFileNameInvalid": { + "description": "Detail for a topic file name with invalid characters." + }, + "errorUnknown": "未知错误:{code}", + "@errorUnknown": { + "description": "Fallback detail for an unknown coded application error.", + "placeholders": { + "code": { + "type": "String" + } + } + }, + "diagnosticWorkspaceFileStatFailed": "无法读取文件元数据:{error}", + "@diagnosticWorkspaceFileStatFailed": { + "description": "Diagnostic shown when file metadata cannot be read.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "diagnosticWorkspaceScanSkipped": "检测到大型工作区。为保持应用响应速度,已跳过部分文件。", + "@diagnosticWorkspaceScanSkipped": { + "description": "Diagnostic shown when workspace scanning skips files." + }, + "diagnosticWorkspaceScanInspectFailed": "无法检查工作区项:{error}", + "@diagnosticWorkspaceScanInspectFailed": { + "description": "Diagnostic shown when a workspace entry cannot be inspected.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "diagnosticWorkspaceFileTooLarge": "文件超过 beta 自动解析限制。", + "@diagnosticWorkspaceFileTooLarge": { + "description": "Diagnostic shown when a file is too large to parse automatically." + }, + "diagnosticWorkspaceFileReadFailed": "无法读取 Markdown 文件:{error}", + "@diagnosticWorkspaceFileReadFailed": { + "description": "Diagnostic shown when a Markdown file cannot be read.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "diagnosticMarkdownAttributeMalformed": "Writerside 标题属性块格式错误。", + "@diagnosticMarkdownAttributeMalformed": { + "description": "Markdown parser diagnostic for malformed Writerside heading attributes." + }, + "diagnosticMarkdownHeadingDuplicateId": "标题 ID“{id}”重复。", + "@diagnosticMarkdownHeadingDuplicateId": { + "description": "Markdown parser diagnostic for duplicate heading IDs.", + "placeholders": { + "id": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicH1ConvertedToChapter": "额外的顶级 H1 标题将被视为章节。", + "@diagnosticWritersideTopicH1ConvertedToChapter": { + "description": "Markdown parser diagnostic for additional H1 headings in Writerside mode." + }, + "diagnosticWritersideMarkdownTopicMissingTitle": "Writerside Markdown 主题没有 H1 或 front matter 标题。", + "@diagnosticWritersideMarkdownTopicMissingTitle": { + "description": "Diagnostic for a Writerside Markdown topic without a title." + }, + "diagnosticWritersideXmlTopicMissingTitle": "XML 主题缺少标题。", + "@diagnosticWritersideXmlTopicMissingTitle": { + "description": "Diagnostic for a Writerside XML topic without a title." + }, + "diagnosticWritersideTopicFileMissingTitle": "主题“{fileName}”缺少标题。", + "@diagnosticWritersideTopicFileMissingTitle": { + "description": "Diagnostic for a Writerside topic file without a title.", + "placeholders": { + "fileName": { + "type": "String" + } + } + }, + "diagnosticMarkdownFrontMatterMalformed": "front matter 未闭合。", + "@diagnosticMarkdownFrontMatterMalformed": { + "description": "Markdown parser diagnostic for unclosed front matter." + }, + "diagnosticMarkdownRawHtmlUnsafe": "不安全的 HTML 元素。", + "@diagnosticMarkdownRawHtmlUnsafe": { + "description": "Markdown parser diagnostic for unsafe raw HTML." + }, + "diagnosticMarkdownLinkUnresolvedTarget": "链接目标不存在:{targetPath}", + "@diagnosticMarkdownLinkUnresolvedTarget": { + "description": "Markdown parser diagnostic for a missing link target.", + "placeholders": { + "targetPath": { + "type": "String" + } + } + }, + "diagnosticMarkdownLinkUnresolvedAnchor": "锚点“{anchor}”不存在。", + "@diagnosticMarkdownLinkUnresolvedAnchor": { + "description": "Markdown parser diagnostic for a missing local anchor.", + "placeholders": { + "anchor": { + "type": "String" + } + } + }, + "diagnosticMarkdownImageMissingAlt": "图像“{destination}”缺少替代文本。", + "@diagnosticMarkdownImageMissingAlt": { + "description": "Markdown parser diagnostic for a missing image alt text.", + "placeholders": { + "destination": { + "type": "String" + } + } + }, + "diagnosticMarkdownImageMissingFile": "图像不存在:{destination}", + "@diagnosticMarkdownImageMissingFile": { + "description": "Markdown parser diagnostic for a missing image file.", + "placeholders": { + "destination": { + "type": "String" + } + } + }, + "diagnosticInvalidXml": "无效的 XML:{message}", + "@diagnosticInvalidXml": { + "description": "XML parser diagnostic for invalid XML.", + "placeholders": { + "message": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigInvalidRoot": "writerside.cfg 根元素必须是 <ihp>。", + "@diagnosticWritersideConfigInvalidRoot": { + "description": "Writerside parser diagnostic for an invalid writerside.cfg root element." + }, + "diagnosticWritersideConfigMissingSnippetsSrc": "snippets 声明缺少 src。", + "@diagnosticWritersideConfigMissingSnippetsSrc": { + "description": "Writerside parser diagnostic for a snippets declaration without src." + }, + "diagnosticWritersideConfigMissingInstanceGroupsSrc": "instance-groups 声明缺少 src。", + "@diagnosticWritersideConfigMissingInstanceGroupsSrc": { + "description": "Writerside parser diagnostic for an instance-groups declaration without src." + }, + "diagnosticWritersideConfigInvalidKeymapsMode": "不支持的 keymaps 模式:{mode}", + "@diagnosticWritersideConfigInvalidKeymapsMode": { + "description": "Writerside parser diagnostic for an unsupported keymaps mode.", + "placeholders": { + "mode": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigMissingInstanceSrc": "instance 声明缺少 src。", + "@diagnosticWritersideConfigMissingInstanceSrc": { + "description": "Writerside parser diagnostic for an instance declaration without src." + }, + "diagnosticWritersideConfigMissingInstance": "writerside.cfg 未注册实例。", + "@diagnosticWritersideConfigMissingInstance": { + "description": "Writerside parser diagnostic for a config with no instance." + }, + "diagnosticWritersideTreeInvalidRoot": ".tree 根元素必须是 <instance-profile>。", + "@diagnosticWritersideTreeInvalidRoot": { + "description": "Writerside parser diagnostic for an invalid tree root element." + }, + "diagnosticWritersideTreeMissingId": "实例配置文件缺少 id。", + "@diagnosticWritersideTreeMissingId": { + "description": "Writerside parser diagnostic for an instance profile without id." + }, + "diagnosticWritersideTreeIdMismatch": "树文件名(不含扩展名)与实例 ID“{id}”不匹配。", + "@diagnosticWritersideTreeIdMismatch": { + "description": "Writerside parser diagnostic for a tree filename and ID mismatch.", + "placeholders": { + "id": { + "type": "String" + } + } + }, + "diagnosticWritersideTreeMissingStartPage": "非库实例缺少 start-page。", + "@diagnosticWritersideTreeMissingStartPage": { + "description": "Writerside parser diagnostic for a tree missing start-page." + }, + "diagnosticWritersideStartPageMissing": "起始页“{startPage}”不存在。", + "@diagnosticWritersideStartPageMissing": { + "description": "Writerside diagnostic for a missing start page.", + "placeholders": { + "startPage": { + "type": "String" + } + } + }, + "diagnosticWritersideTreeDuplicateTopic": "主题“{topic}”在此实例目录中出现多次。", + "@diagnosticWritersideTreeDuplicateTopic": { + "description": "Writerside parser diagnostic for a duplicate topic in a TOC.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "diagnosticWritersideVariableMalformedDeclaration": "变量声明必须包含名称和值。", + "@diagnosticWritersideVariableMalformedDeclaration": { + "description": "Writerside parser diagnostic for a malformed variable declaration." + }, + "diagnosticWritersideVariableDuplicateName": "变量“{name}”被声明了多次。", + "@diagnosticWritersideVariableDuplicateName": { + "description": "Writerside parser diagnostic for a duplicate variable name.", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "diagnosticWritersideCategoryMissingId": "类别缺少 id。", + "@diagnosticWritersideCategoryMissingId": { + "description": "Writerside parser diagnostic for a category without id." + }, + "diagnosticWritersideCategoryDuplicateId": "类别“{id}”被声明了多次。", + "@diagnosticWritersideCategoryDuplicateId": { + "description": "Writerside parser diagnostic for a duplicate category ID.", + "placeholders": { + "id": { + "type": "String" + } + } + }, + "diagnosticWritersideCategoryDuplicateOrder": "类别顺序“{order}”被声明了多次。", + "@diagnosticWritersideCategoryDuplicateOrder": { + "description": "Writerside parser diagnostic for a duplicate category order.", + "placeholders": { + "order": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicInvalidRoot": ".topic 根元素必须是 <topic>。", + "@diagnosticWritersideTopicInvalidRoot": { + "description": "Writerside parser diagnostic for an invalid XML topic root." + }, + "diagnosticWritersideTopicMissingRootId": "XML 主题缺少根 id。", + "@diagnosticWritersideTopicMissingRootId": { + "description": "Writerside parser diagnostic for an XML topic missing root id." + }, + "diagnosticWritersideTopicRootIdMismatch": "XML 主题根 ID“{id}”必须与文件名“{expectedId}”匹配。", + "@diagnosticWritersideTopicRootIdMismatch": { + "description": "Writerside parser diagnostic for an XML topic root ID mismatch.", + "placeholders": { + "id": { + "type": "String" + }, + "expectedId": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicDuplicateElementId": "元素 ID“{elementId}”出现多次。", + "@diagnosticWritersideTopicDuplicateElementId": { + "description": "Writerside parser diagnostic for a duplicate XML element ID.", + "placeholders": { + "elementId": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicAnchorMissingHref": "<a> 缺少 href。", + "@diagnosticWritersideTopicAnchorMissingHref": { + "description": "Writerside parser diagnostic for an anchor without href." + }, + "diagnosticWritersideConfigMissing": "Writerside 模式需要 writerside.cfg。", + "@diagnosticWritersideConfigMissing": { + "description": "Writerside module diagnostic for a missing writerside.cfg." + }, + "diagnosticWritersideConfigMissingBuildConfigDirectory": "配置的构建配置目录不存在:{relativePath}", + "@diagnosticWritersideConfigMissingBuildConfigDirectory": { + "description": "Writerside module diagnostic for a missing build config directory.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigMissingApiSpecificationsDirectory": "配置的 API 规范目录不存在:{relativePath}", + "@diagnosticWritersideConfigMissingApiSpecificationsDirectory": { + "description": "Writerside module diagnostic for a missing API specifications directory.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigMissingSnippetsDirectory": "配置的 snippets 目录不存在:{relativePath}", + "@diagnosticWritersideConfigMissingSnippetsDirectory": { + "description": "Writerside module diagnostic for a missing snippets directory.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigMissingVarsFile": "配置的变量文件不存在:{relativePath}", + "@diagnosticWritersideConfigMissingVarsFile": { + "description": "Writerside module diagnostic for a missing variables file.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigMissingCategoriesFile": "配置的类别文件不存在:{relativePath}", + "@diagnosticWritersideConfigMissingCategoriesFile": { + "description": "Writerside module diagnostic for a missing categories file.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigMissingInstanceGroupsFile": "配置的实例组文件不存在:{relativePath}", + "@diagnosticWritersideConfigMissingInstanceGroupsFile": { + "description": "Writerside module diagnostic for a missing instance groups file.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideConfigMissingInstanceTree": "已注册的实例树“{source}”不存在。", + "@diagnosticWritersideConfigMissingInstanceTree": { + "description": "Writerside module diagnostic for a missing registered instance tree.", + "placeholders": { + "source": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicReadFailed": "无法读取主题文件:{error}", + "@diagnosticWritersideTopicReadFailed": { + "description": "Writerside module diagnostic for a topic file read failure.", + "placeholders": { + "error": { + "type": "String" + } + } + }, + "diagnosticWritersideDefaultTopicsDirectoryMissing": "默认主题目录不存在:{relativePath}", + "@diagnosticWritersideDefaultTopicsDirectoryMissing": { + "description": "Writerside module diagnostic for a missing default topics directory.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicsDirectoryMissing": "配置的主题目录不存在:{relativePath}", + "@diagnosticWritersideTopicsDirectoryMissing": { + "description": "Writerside module diagnostic for a missing topics directory.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideImagesDirectoryMissing": "配置的图像目录不存在:{relativePath}", + "@diagnosticWritersideImagesDirectoryMissing": { + "description": "Writerside module diagnostic for a missing images directory.", + "placeholders": { + "relativePath": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicDuplicateId": "元素 ID“{id}”出现多次。", + "@diagnosticWritersideTopicDuplicateId": { + "description": "Writerside module diagnostic for a duplicate topic element ID.", + "placeholders": { + "id": { + "type": "String" + } + } + }, + "diagnosticWritersideTreeMissingTopic": "目录引用了缺失的主题“{topic}”。", + "@diagnosticWritersideTreeMissingTopic": { + "description": "Writerside module diagnostic for a TOC reference to a missing topic.", + "placeholders": { + "topic": { + "type": "String" + } + } + }, + "diagnosticWritersideTreeInvalidHref": "外部 href“{href}”无效。", + "@diagnosticWritersideTreeInvalidHref": { + "description": "Writerside module diagnostic for an invalid external href.", + "placeholders": { + "href": { + "type": "String" + } + } + }, + "diagnosticWritersideVariableUnresolved": "变量“%{name}%”未声明。", + "@diagnosticWritersideVariableUnresolved": { + "description": "Writerside module diagnostic for an undeclared variable.", + "placeholders": { + "name": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicLinkUnresolved": "主题链接“{destination}”无法解析。", + "@diagnosticWritersideTopicLinkUnresolved": { + "description": "Writerside module diagnostic for an unresolved topic link.", + "placeholders": { + "destination": { + "type": "String" + } + } + }, + "diagnosticWritersideAnchorUnresolved": "“{targetName}”中不存在锚点“{anchor}”。", + "@diagnosticWritersideAnchorUnresolved": { + "description": "Writerside module diagnostic for an unresolved topic anchor.", + "placeholders": { + "anchor": { + "type": "String" + }, + "targetName": { + "type": "String" + } + } + }, + "diagnosticWritersideIncludeMissingFrom": "<include> 缺少 from。", + "@diagnosticWritersideIncludeMissingFrom": { + "description": "Writerside module diagnostic for an include without a from attribute." + }, + "diagnosticWritersideIncludeSourceMissing": "包含源“{from}”不存在。", + "@diagnosticWritersideIncludeSourceMissing": { + "description": "Writerside module diagnostic for a missing include source.", + "placeholders": { + "from": { + "type": "String" + } + } + }, + "diagnosticWritersideIncludeElementMissing": "“{from}”中不存在包含元素“{elementId}”。", + "@diagnosticWritersideIncludeElementMissing": { + "description": "Writerside module diagnostic for a missing include element.", + "placeholders": { + "elementId": { + "type": "String" + }, + "from": { + "type": "String" + } + } + }, + "diagnosticWritersideCategoryUnresolved": "seealso 类别“{ref}”未声明。", + "@diagnosticWritersideCategoryUnresolved": { + "description": "Writerside module diagnostic for an unresolved seealso category.", + "placeholders": { + "ref": { + "type": "String" + } + } + }, + "diagnosticWritersideTopicAmbiguousReference": "主题引用“{reference}”不明确。", + "@diagnosticWritersideTopicAmbiguousReference": { + "description": "Writerside module diagnostic for an ambiguous topic reference.", + "placeholders": { + "reference": { + "type": "String" + } + } + }, + "diagnosticUnknown": "未知诊断信息:{code}", + "@diagnosticUnknown": { + "description": "Fallback text for an unknown diagnostic code.", + "placeholders": { + "code": { + "type": "String" + } + } + }, + "close": "关闭", + "@close": { + "description": "Close action label." + }, + "git": "Git", + "@git": { + "description": "Git sidebar tab label." + }, + "gitDiff": "Git 差异", + "@gitDiff": { + "description": "Title for the Git diff viewer." + }, + "gitShowDiff": "显示差异", + "@gitShowDiff": { + "description": "Menu action that opens the diff for a file in Git history." + }, + "gitDiffHunkRange": "旧 {oldRange} → 新 {newRange}", + "@gitDiffHunkRange": { + "description": "Readable old-to-new line range shown for a Git diff hunk.", + "placeholders": { + "oldRange": { + "type": "String" + }, + "newRange": { + "type": "String" + } + } + }, + "gitDiffNoLines": "无行", + "@gitDiffNoLines": { + "description": "Line range text for an empty side of a Git diff hunk." + }, + "gitUnavailableTitle": "Git 不可用", + "@gitUnavailableTitle": { + "description": "Git empty state title when Git cannot be used." + }, + "gitUnavailableMessage": "{reason, select, other{安装 Git,或配置 BusyMark 以使用可用的 Git 可执行文件。{reason}}}", + "@gitUnavailableMessage": { + "description": "Git empty state message when Git cannot be used.", + "placeholders": { + "reason": { + "type": "String" + } + } + }, + "gitTrustRequiredTitle": "信任此工作区以使用 Git?", + "@gitTrustRequiredTitle": { + "description": "Git empty state title shown before repository-controlled commands may run." + }, + "gitTrustRequiredMessage": "Git 存储库可以通过 hook、过滤器和其他配置运行程序。在 BusyMark 读取存储库数据或启用 Git 操作前,请先信任此工作区。", + "@gitTrustRequiredMessage": { + "description": "Security warning shown before Git repository access is enabled for a workspace." + }, + "gitTrustWorkspace": "信任工作区", + "@gitTrustWorkspace": { + "description": "Action label for trusting a workspace before enabling Git." + }, + "gitNotRepositoryTitle": "不是 Git 存储库", + "@gitNotRepositoryTitle": { + "description": "Git empty state title for non-repository workspaces." + }, + "gitNotRepositoryMessage": "此工作区不在 Git 存储库中。", + "@gitNotRepositoryMessage": { + "description": "Git empty state message for non-repository workspaces." + }, + "gitInitializeRepository": "初始化存储库", + "@gitInitializeRepository": { + "description": "Action label for git init." + }, + "gitDetachedHead": "分离的 HEAD", + "@gitDetachedHead": { + "description": "Detached HEAD label." + }, + "gitDetachedHeadAt": "分离于 {commit}", + "@gitDetachedHeadAt": { + "description": "Detached HEAD label with short commit.", + "placeholders": { + "commit": { + "type": "String" + } + } + }, + "gitNoUpstream": "没有上游分支", + "@gitNoUpstream": { + "description": "Repository label when no upstream branch is configured." + }, + "gitAheadCount": "{count, plural, =1{1 个未推送的提交} other{{count} 个未推送的提交}}", + "@gitAheadCount": { + "description": "Count of local commits not pushed to the upstream branch.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "gitBehindCount": "{count, plural, =1{1 个待拉取的提交} other{{count} 个待拉取的提交}}", + "@gitBehindCount": { + "description": "Count of upstream commits not pulled into the local branch.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "gitClean": "干净", + "@gitClean": { + "description": "Git clean state label." + }, + "gitConflicts": "冲突", + "@gitConflicts": { + "description": "Git conflicts group label." + }, + "gitChanges": "更改", + "@gitChanges": { + "description": "Git changes view label." + }, + "gitStaged": "已暂存", + "@gitStaged": { + "description": "Git staged changes group label." + }, + "gitUnstaged": "未暂存", + "@gitUnstaged": { + "description": "Git unstaged changes group label." + }, + "gitHistory": "历史记录", + "@gitHistory": { + "description": "Git history view label." + }, + "gitBranches": "分支", + "@gitBranches": { + "description": "Git branch menu label." + }, + "gitActions": "Git 操作", + "@gitActions": { + "description": "Tooltip for the Git action menu button." + }, + "gitPull": "Pull", + "@gitPull": { + "description": "Git pull action label." + }, + "gitFetch": "Fetch", + "@gitFetch": { + "description": "Git fetch action label." + }, + "gitPush": "Push", + "@gitPush": { + "description": "Git push action label." + }, + "gitCommit": "Commit", + "@gitCommit": { + "description": "Git commit action label." + }, + "gitSelectForCommit": "暂存文件", + "@gitSelectForCommit": { + "description": "Tooltip for staging a Git file." + }, + "gitRemoveFromCommit": "取消暂存文件", + "@gitRemoveFromCommit": { + "description": "Tooltip for unstaging a Git file." + }, + "gitDiscard": "还原", + "@gitDiscard": { + "description": "Action that rolls a tracked file back to HEAD." + }, + "gitOpenFile": "打开文件", + "@gitOpenFile": { + "description": "Action label for opening a file from a Git row or diff." + }, + "gitMarkResolved": "标记为已解决", + "@gitMarkResolved": { + "description": "Tooltip for marking a conflicted Git file as resolved." + }, + "gitUntracked": "未跟踪", + "@gitUntracked": { + "description": "Git untracked files group label." + }, + "gitCommitMessage": "提交消息", + "@gitCommitMessage": { + "description": "Commit message field label." + }, + "gitCommitSelectedFiles": "选中的文件", + "@gitCommitSelectedFiles": { + "description": "Commit panel selected files section label." + }, + "gitCommitNoSelectedFiles": "提交前至少暂存一个文件。", + "@gitCommitNoSelectedFiles": { + "description": "Commit validation error when the repository index is empty." + }, + "gitStagedFileCount": "{count, plural, =1{1 个已暂存文件} other{{count} 个已暂存文件}}", + "@gitStagedFileCount": { + "description": "Number of repository files currently staged for commit.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "gitOutsideWorkspace": "工作区之外", + "@gitOutsideWorkspace": { + "description": "Marker for a staged repository file outside the opened workspace." + }, + "gitCommitMessageRequired": "请输入提交消息。", + "@gitCommitMessageRequired": { + "description": "Commit validation error when the message is empty." + }, + "gitCreateBranch": "创建分支", + "@gitCreateBranch": { + "description": "Git create branch action label." + }, + "gitNewBranch": "新分支", + "@gitNewBranch": { + "description": "Git branch dropdown action for creating a new branch." + }, + "gitBranchName": "分支名称", + "@gitBranchName": { + "description": "Branch name field label." + }, + "gitSwitchBranch": "切换", + "@gitSwitchBranch": { + "description": "Git switch branch action label." + }, + "gitNoChanges": "没有更改", + "@gitNoChanges": { + "description": "Git empty state when there are no changes." + }, + "gitNoHistory": "没有历史记录", + "@gitNoHistory": { + "description": "Git empty state when history is empty." + }, + "gitNoBranches": "没有分支", + "@gitNoBranches": { + "description": "Git empty state when branch list is empty." + }, + "gitNoDiff": "没有可显示的差异", + "@gitNoDiff": { + "description": "Git diff empty state." + }, + "gitBinaryFile": "二进制文件。BusyMark 不渲染二进制补丁。", + "@gitBinaryFile": { + "description": "Git diff binary file message." + }, + "gitBinaryFileInfo": "二进制文件({size} 字节)。BusyMark 不渲染二进制补丁。", + "@gitBinaryFileInfo": { + "description": "Git diff binary file message with file size.", + "placeholders": { + "size": { + "type": "int" + } + } + }, + "gitUnsavedChangesBanner": "保存前不会包含未保存的编辑器更改。", + "@gitUnsavedChangesBanner": { + "description": "Git diff banner for unsaved editor changes." + }, + "gitConfirmDiscardTitle": "放弃 Git 更改?", + "@gitConfirmDiscardTitle": { + "description": "Confirmation title for discarding Git changes." + }, + "gitConfirmDiscardTracked": "{count, plural, =1{选中的已跟踪文件中的所有已暂存和未暂存更改都将还原到 HEAD。} other{选中的已跟踪文件中的所有已暂存和未暂存更改都将还原到 HEAD。}}", + "@gitConfirmDiscardTracked": { + "description": "Confirmation body for discarding tracked changes.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "gitConfirmDiscardUntracked": "{count, plural, =1{选中的未跟踪文件将被删除。} other{选中的未跟踪文件将被删除。}}", + "@gitConfirmDiscardUntracked": { + "description": "Confirmation body for deleting untracked files.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "gitConfirmDiscardMixed": "{count, plural, =1{将根据其 Git 状态还原或删除选中的文件。} other{将根据其 Git 状态还原或删除选中的文件。}}", + "@gitConfirmDiscardMixed": { + "description": "Confirmation body for discarding mixed tracked and untracked files.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "gitConfirmSwitchBranchTitle": "切换到 {branch}?", + "@gitConfirmSwitchBranchTitle": { + "description": "Confirmation title for switching branches.", + "placeholders": { + "branch": { + "type": "String" + } + } + }, + "gitConfirmSwitchBranchMessage": "Git 切换分支后,BusyMark 将从磁盘重新加载工作区。", + "@gitConfirmSwitchBranchMessage": { + "description": "Confirmation body for switching branches." + }, + "gitConfirmPushSetUpstreamTitle": "设置上游分支?", + "@gitConfirmPushSetUpstreamTitle": { + "description": "Confirmation title for pushing with set-upstream." + }, + "gitConfirmPushSetUpstreamMessage": "此分支没有上游分支。当只配置了一个远程仓库时,BusyMark 可以推送 {branch} 并设置其上游分支。", + "@gitConfirmPushSetUpstreamMessage": { + "description": "Confirmation body for pushing with set-upstream.", + "placeholders": { + "branch": { + "type": "String" + } + } + }, + "gitProjectHistory": "项目历史记录", + "@gitProjectHistory": { + "description": "Project history action label." + }, + "gitFileHistory": "文件历史记录", + "@gitFileHistory": { + "description": "Current file history action label." + }, + "gitFileHistoryRequiresOpenFile": "文件历史记录需要打开的 Markdown 文件。", + "@gitFileHistoryRequiresOpenFile": { + "description": "File History empty state when no Markdown file is active." + }, + "gitLoadMore": "加载更多", + "@gitLoadMore": { + "description": "Action to load another page of Git history." + }, + "gitChangesInCommit": "此提交中的更改", + "@gitChangesInCommit": { + "description": "Historical comparison between a commit and its parent." + }, + "gitCompareWithCurrent": "与当前版本比较", + "@gitCompareWithCurrent": { + "description": "Historical comparison between a commit and the working-tree file." + }, + "gitRestoreVersion": "还原此版本", + "@gitRestoreVersion": { + "description": "Action to restore one file from a selected commit." + }, + "gitConfirmRestoreTitle": "还原此文件版本?", + "@gitConfirmRestoreTitle": { + "description": "Confirmation title for restoring a historical file version." + }, + "gitConfirmRestoreMessage": "BusyMark 将使用选中的已提交版本替换当前工作树中的文件。还原后的文件将保持未暂存状态。", + "@gitConfirmRestoreMessage": { + "description": "Confirmation body for restoring a historical file version." + }, + "gitCommitActions": "提交操作", + "@gitCommitActions": { + "description": "Tooltip for actions on a selected Git commit." + }, + "gitResetCurrentBranchToHere": "将当前分支重置到此处…", + "@gitResetCurrentBranchToHere": { + "description": "Project History action that moves the current branch to the selected commit." + }, + "gitResetCurrentBranchTitle": "将 {branch} 重置到 {commit}?", + "@gitResetCurrentBranchTitle": { + "description": "Title for choosing how to reset the current branch to a selected commit.", + "placeholders": { + "branch": { + "type": "String" + }, + "commit": { + "type": "String" + } + } + }, + "gitResetCurrentBranchMessage": "这会将分支 {branch} 移动到提交 {commit}。请选择 Git 更新索引和工作树的方式。", + "@gitResetCurrentBranchMessage": { + "description": "Explanation shown before resetting the current branch.", + "placeholders": { + "branch": { + "type": "String" + }, + "commit": { + "type": "String" + } + } + }, + "gitReset": "重置", + "@gitReset": { + "description": "Action that confirms resetting the current Git branch." + }, + "gitResetModeSoft": "软", + "@gitResetModeSoft": { + "description": "Git soft reset mode label." + }, + "gitResetModeSoftDescription": "仅移动分支。保持索引和工作树不变;与选中提交之间的差异仍会保持暂存状态。", + "@gitResetModeSoftDescription": { + "description": "Git soft reset mode explanation." + }, + "gitResetModeMixed": "混合", + "@gitResetModeMixed": { + "description": "Git mixed reset mode label." + }, + "gitResetModeMixedDescription": "移动分支并重置索引。保持工作树不变,使差异处于未暂存状态。", + "@gitResetModeMixedDescription": { + "description": "Git mixed reset mode explanation." + }, + "gitResetModeHard": "硬", + "@gitResetModeHard": { + "description": "Git hard reset mode label." + }, + "gitResetModeHardDescription": "移动分支并重置索引和工作树。已跟踪的更改将被放弃;造成阻碍的未跟踪文件可能会被删除。", + "@gitResetModeHardDescription": { + "description": "Git hard reset mode explanation." + }, + "gitResetModeKeep": "保留", + "@gitResetModeKeep": { + "description": "Git keep reset mode label." + }, + "gitResetModeKeepDescription": "移动分支并重置已跟踪文件,同时保留本地更改。如果这些更改与重置冲突,Git 将中止操作。", + "@gitResetModeKeepDescription": { + "description": "Git keep reset mode explanation." + }, + "gitAdditionsDeletions": "+{additions} -{deletions}", + "@gitAdditionsDeletions": { + "description": "Diff additions and deletions count.", + "placeholders": { + "additions": { + "type": "int" + }, + "deletions": { + "type": "int" + } + } + }, + "fileActions": "文件操作", + "@fileActions": { + "description": "Tooltip for a file action menu." + }, + "actions": "操作", + "@actions": { + "description": "Tooltip for a general action menu." + }, + "gitStatusAdded": "已添加", + "@gitStatusAdded": { + "description": "Git file status label." + }, + "gitStatusDeleted": "已删除", + "@gitStatusDeleted": { + "description": "Git file status label." + }, + "gitStatusRenamed": "已重命名", + "@gitStatusRenamed": { + "description": "Git file status label." + }, + "gitStatusCopied": "已复制", + "@gitStatusCopied": { + "description": "Git file status label." + }, + "gitStatusUntracked": "未跟踪", + "@gitStatusUntracked": { + "description": "Git file status label." + }, + "gitStatusConflicted": "有冲突", + "@gitStatusConflicted": { + "description": "Git file status label." + }, + "gitStatusIgnored": "已忽略", + "@gitStatusIgnored": { + "description": "Git file status label." + }, + "gitStatusTypeChanged": "类型已更改", + "@gitStatusTypeChanged": { + "description": "Git file status label." + }, + "gitStatusModified": "已修改", + "@gitStatusModified": { + "description": "Git file status label." + }, + "gitStatusUnknown": "未知", + "@gitStatusUnknown": { + "description": "Git file status label." + }, + "gitErrorUnavailable": "Git 不可用。", + "@gitErrorUnavailable": { + "description": "Git error message." + }, + "gitErrorNotRepository": "此工作区不是 Git 存储库。", + "@gitErrorNotRepository": { + "description": "Git error message." + }, + "gitErrorUnsafePath": "BusyMark 阻止了不安全的 Git 路径。", + "@gitErrorUnsafePath": { + "description": "Git error message." + }, + "gitErrorInvalidBranchName": "请输入有效的分支名称。", + "@gitErrorInvalidBranchName": { + "description": "Git error message." + }, + "gitErrorNoRemote": "未配置 Git 远程仓库。", + "@gitErrorNoRemote": { + "description": "Git error message." + }, + "gitErrorNoUpstream": "未配置上游分支。", + "@gitErrorNoUpstream": { + "description": "Git error message." + }, + "gitErrorMultipleRemotes": "配置了多个远程仓库。请在此 BusyMark 版本之外选择上游分支。", + "@gitErrorMultipleRemotes": { + "description": "Git error message." + }, + "gitErrorDirtyWorkspace": "切换分支前,请保存或放弃 BusyMark 编辑器中的更改。", + "@gitErrorDirtyWorkspace": { + "description": "Git error message." + }, + "gitErrorResetDirtyWorkspace": "重置当前分支前,请保存或放弃 BusyMark 编辑器中的更改。", + "@gitErrorResetDirtyWorkspace": { + "description": "Git reset error shown when the editor has unsaved content." + }, + "gitErrorRestoreStagedFile": "还原历史版本前,请取消暂存此文件。", + "@gitErrorRestoreStagedFile": { + "description": "Git error shown when historical restoration is blocked because the current file is staged." + }, + "gitErrorResetDetachedHead": "重置前请先检出一个分支。", + "@gitErrorResetDetachedHead": { + "description": "Git reset error shown while HEAD is detached." + }, + "gitErrorDiverged": "分支已发生分歧。请在此 BusyMark 版本之外解决合并或变基问题。", + "@gitErrorDiverged": { + "description": "Git error message." + }, + "gitErrorAuthorIdentity": "Git 需要作者姓名和邮箱地址才能提交。", + "@gitErrorAuthorIdentity": { + "description": "Git error shown when no commit author identity is configured." + }, + "gitAuthorIdentityTitle": "Git 作者身份", + "@gitAuthorIdentityTitle": { + "description": "Title of the Git author identity recovery dialog." + }, + "gitAuthorIdentityMessage": "请输入 Git 应记录在提交中的身份信息。BusyMark 将保存它并重试此次提交。", + "@gitAuthorIdentityMessage": { + "description": "Explanation in the Git author identity recovery dialog." + }, + "gitAuthorName": "姓名", + "@gitAuthorName": { + "description": "Git commit author name field label." + }, + "gitAuthorEmail": "Email", + "@gitAuthorEmail": { + "description": "Git commit author email field label." + }, + "gitAuthorIdentityGlobal": "用于所有存储库", + "@gitAuthorIdentityGlobal": { + "description": "Switch label for saving Git identity globally." + }, + "gitAuthorIdentityGlobalDescription": "作为 Snap 安装时,此设置适用于在 BusyMark 中打开的存储库。", + "@gitAuthorIdentityGlobalDescription": { + "description": "Description of global Git identity scope in the Snap." + }, + "gitSaveIdentityAndCommit": "保存并提交", + "@gitSaveIdentityAndCommit": { + "description": "Action that saves Git author identity and retries a commit." + }, + "gitErrorAuthentication": "Git 身份验证失败。", + "@gitErrorAuthentication": { + "description": "Git error message." + }, + "gitErrorNetwork": "Git 网络操作失败。", + "@gitErrorNetwork": { + "description": "Git error message." + }, + "gitErrorConflict": "Git 报告存在未解决的冲突。", + "@gitErrorConflict": { + "description": "Git error message." + }, + "gitErrorCommandFailed": "Git 命令失败。", + "@gitErrorCommandFailed": { + "description": "Git error message." + }, "syntaxReference": "语法参考", + "@syntaxReference": { + "description": "Syntax Reference dialog title and menu item." + }, "syntaxReferenceMarkdownBlocks": "Markdown 块", + "@syntaxReferenceMarkdownBlocks": { + "description": "Reference section title for Markdown block syntax." + }, "syntaxReferenceMarkdownBlocksDescription": "Markdown 源代码和预览中支持的块结构。", + "@syntaxReferenceMarkdownBlocksDescription": { + "description": "Reference section description for Markdown block syntax." + }, "syntaxReferenceInlineFormatting": "行内 Markdown", + "@syntaxReferenceInlineFormatting": { + "description": "Reference section title for Markdown inline syntax." + }, "syntaxReferenceInlineFormattingDescription": "可出现在段落、列表项和表格单元格中的格式。", + "@syntaxReferenceInlineFormattingDescription": { + "description": "Reference section description for Markdown inline syntax." + }, "syntaxReferenceRawHtmlBlocks": "原始 HTML 块", + "@syntaxReferenceRawHtmlBlocks": { + "description": "Reference section title for supported raw HTML block tags." + }, "syntaxReferenceRawHtmlBlocksDescription": "通过 BusyMark 预览组件渲染的安全块级 HTML 标签。", + "@syntaxReferenceRawHtmlBlocksDescription": { + "description": "Reference section description for supported raw HTML block tags." + }, "syntaxReferenceRawHtmlInline": "原始 HTML 行内标签", + "@syntaxReferenceRawHtmlInline": { + "description": "Reference section title for supported raw HTML inline tags." + }, "syntaxReferenceRawHtmlInlineDescription": "安全的行内 HTML 标签,渲染时不会显示字面标签。", + "@syntaxReferenceRawHtmlInlineDescription": { + "description": "Reference section description for supported raw HTML inline tags." + }, "syntaxReferenceHeadings": "标题", + "@syntaxReferenceHeadings": { + "description": "Reference row label for Markdown headings." + }, "syntaxReferenceParagraphs": "段落", + "@syntaxReferenceParagraphs": { + "description": "Reference row label for Markdown paragraphs." + }, "syntaxReferenceLists": "列表", + "@syntaxReferenceLists": { + "description": "Reference row label for list syntax." + }, "syntaxReferenceHtmlContainers": "容器", + "@syntaxReferenceHtmlContainers": { + "description": "Reference row label for HTML container tags." + }, "syntaxReferenceHtmlTextBlocks": "文本块", + "@syntaxReferenceHtmlTextBlocks": { + "description": "Reference row label for HTML text block tags." + }, "syntaxReferenceHtmlFigures": "图和图像", + "@syntaxReferenceHtmlFigures": { + "description": "Reference row label for HTML figure and image tags." + }, "syntaxReferenceHtmlPreformatted": "预格式化代码", + "@syntaxReferenceHtmlPreformatted": { + "description": "Reference row label for HTML preformatted/code tags." + }, "syntaxReferenceHtmlDisclosure": "折叠块", + "@syntaxReferenceHtmlDisclosure": { + "description": "Reference row label for HTML details/summary tags." + }, "syntaxReferenceHtmlDescriptionLists": "描述列表", + "@syntaxReferenceHtmlDescriptionLists": { + "description": "Reference row label for HTML description list tags." + }, "syntaxReferenceHtmlFormattingTags": "格式标签", + "@syntaxReferenceHtmlFormattingTags": { + "description": "Reference row label for HTML inline formatting tags." + }, "syntaxReferenceHtmlInlineCodeTags": "行内代码标签", + "@syntaxReferenceHtmlInlineCodeTags": { + "description": "Reference row label for HTML inline code-related tags." + }, "syntaxReferenceHtmlNeutralInlineTags": "语义文本标签", + "@syntaxReferenceHtmlNeutralInlineTags": { + "description": "Reference row label for HTML inline semantic tags that render as text." + }, "syntaxReferenceSanitizedPreviewDescription": "允许的 HTML 会转换为 BusyMark 预览块,而不是在浏览器中渲染。", + "@syntaxReferenceSanitizedPreviewDescription": { + "description": "Reference row description for sanitized preview behavior." + }, "syntaxReferenceSourcePreservedDescription": "未经编辑的原始 HTML 会按源文本原样保存。", + "@syntaxReferenceSourcePreservedDescription": { + "description": "Reference row description for raw source preservation." + }, "syntaxReferenceMarkdownInsideHtmlDescription": "原始 HTML 内的 Markdown 标记会按字面文本渲染。", + "@syntaxReferenceMarkdownInsideHtmlDescription": { + "description": "Reference row description for Markdown inside raw HTML." + }, "syntaxReferenceBlockedContentDescription": "脚本、样式、框架、表单、SVG、MathML、事件和不安全属性都会被阻止。", + "@syntaxReferenceBlockedContentDescription": { + "description": "Reference row description for blocked HTML content." + }, "syntaxReferenceSafeUrlsDescription": "链接允许 http、https、mailto、tel、相对路径和片段 URL;不安全的 scheme 会被阻止。", + "@syntaxReferenceSafeUrlsDescription": { + "description": "Reference row description for safe URL policy." + }, "syntaxReferenceCategoryHtml": "HTML", "syntaxReferenceMermaid": "Mermaid", "syntaxReferencePlantUml": "PlantUML", @@ -76,6 +3633,1009 @@ "syntaxReferenceSemanticCodeBlocks": "数学和图表的语义代码块", "syntaxReferenceVideo": "Writerside 视频", "syntaxReferenceVideoLimitation": "本地视频使用本地 preview-src 图像;托管视频源必须是受支持的 YouTube 或 Vimeo HTTPS URL。", + "exportAsPdf": "导出为 PDF", + "@exportAsPdf": { + "description": "Menu action and dialog title for exporting the active document or Writerside module as PDF." + }, + "pdfExportDescription": "选择页面布局,生成精美且自包含的 PDF。", + "@pdfExportDescription": { + "description": "Introductory text in the PDF export options dialog." + }, + "pdfRemoteImagesNote": "导出过程中不会下载远程图像。有可用的本地图像时将包含它们。", + "@pdfRemoteImagesNote": { + "description": "Privacy note explaining image handling during PDF export." + }, + "pdfPageSize": "页面大小", + "@pdfPageSize": { + "description": "PDF export page-size setting." + }, + "pdfPageSizeA4": "A4", + "@pdfPageSizeA4": { + "description": "A4 PDF page-size option." + }, + "pdfPageSizeLetter": "Letter", + "@pdfPageSizeLetter": { + "description": "US Letter PDF page-size option." + }, + "pdfOrientation": "方向", + "@pdfOrientation": { + "description": "PDF export page-orientation setting." + }, + "pdfPortrait": "纵向", + "@pdfPortrait": { + "description": "Portrait PDF page-orientation option." + }, + "pdfLandscape": "横向", + "@pdfLandscape": { + "description": "Landscape PDF page-orientation option." + }, + "pdfMargins": "页边距", + "@pdfMargins": { + "description": "PDF export page-margin setting." + }, + "pdfMarginNarrow": "窄", + "@pdfMarginNarrow": { + "description": "Narrow PDF page-margin option." + }, + "pdfMarginNormal": "普通", + "@pdfMarginNormal": { + "description": "Normal PDF page-margin option." + }, + "pdfMarginWide": "宽", + "@pdfMarginWide": { + "description": "Wide PDF page-margin option." + }, + "pdfIncludePageNumbers": "包含页码", + "@pdfIncludePageNumbers": { + "description": "Toggle for page numbers in an exported PDF." + }, + "export": "导出", + "@export": { + "description": "Button label that starts an export." + }, + "exportingPdf": "正在导出 PDF…", + "@exportingPdf": { + "description": "Progress dialog title while a PDF is being exported." + }, + "fileTypePdf": "PDF 文档", + "@fileTypePdf": { + "description": "File picker label for PDF documents." + }, + "pdfExported": "已导出 {fileName}。", + "@pdfExported": { + "description": "PDF export success message.", + "placeholders": { + "fileName": { + "type": "String" + } + } + }, + "pdfExportedWithWarnings": "{fileName} 已导出,包含 {count, plural, =1{1 条警告} other{{count} 条警告}}。", + "@pdfExportedWithWarnings": { + "description": "PDF export success message when some content fell back or was omitted.", + "placeholders": { + "fileName": { + "type": "String" + }, + "count": { + "type": "int" + } + } + }, + "pdfExportUnavailable": "缺少 PDF 导出组件。请重新安装 BusyMark 后重试。", + "@pdfExportUnavailable": { + "description": "Error shown when the bundled PDF compiler is unavailable." + }, + "pdfExportTimedOut": "PDF 导出耗时过长,已停止。", + "@pdfExportTimedOut": { + "description": "Error shown when PDF compilation times out." + }, + "pdfExportFailed": "BusyMark 无法将此文档导出为 PDF。", + "@pdfExportFailed": { + "description": "Generic PDF export failure message." + }, + "visualizationRendering": "正在渲染…", + "@visualizationRendering": { + "description": "Status shown while a fenced visualization is rendering." + }, + "visualizationStale": "正在显示上次有效的渲染结果", + "@visualizationStale": { + "description": "Status shown when a visualization displays its last valid result while newer source renders or is invalid." + }, + "visualizationShowSource": "显示源代码", + "@visualizationShowSource": { + "description": "Action that reveals the original source fence for a visualization." + }, + "visualizationShowRender": "显示渲染结果", + "@visualizationShowRender": { + "description": "Action that returns from visualization source to its rendered output." + }, + "visualizationFitWidth": "适应宽度", + "@visualizationFitWidth": { + "description": "Action that resets diagram zoom to fit its card." + }, + "visualizationSaveImage": "保存图像", + "@visualizationSaveImage": { + "description": "Action that saves a rendered diagram as an SVG or PNG file." + }, + "visualizationCopyImage": "复制图像", + "@visualizationCopyImage": { + "description": "Action that copies a rendered diagram to the image clipboard." + }, + "visualizationImageCopied": "图像已复制", + "@visualizationImageCopied": { + "description": "Confirmation after copying a rendered diagram to the clipboard." + }, + "visualizationOpenApiReference": "打开 API 参考", + "@visualizationOpenApiReference": { + "description": "Action that opens the complete interactive OpenAPI reference window." + }, + "visualizationValid": "有效", + "@visualizationValid": { + "description": "OpenAPI validation success state." + }, + "visualizationInvalid": "无效", + "@visualizationInvalid": { + "description": "OpenAPI validation failure state." + }, + "visualizationServers": "服务器", + "@visualizationServers": { + "description": "OpenAPI server count label." + }, + "visualizationPaths": "路径", + "@visualizationPaths": { + "description": "OpenAPI path count label." + }, + "visualizationOperations": "操作", + "@visualizationOperations": { + "description": "OpenAPI operation count label." + }, + "visualizationTags": "标签", + "@visualizationTags": { + "description": "OpenAPI tag summary label." + }, + "visualizationNoOperations": "没有匹配的操作", + "@visualizationNoOperations": { + "description": "Empty state for the filtered OpenAPI operation list." + }, + "visualizationSearchOperations": "搜索操作", + "@visualizationSearchOperations": { + "description": "Hint for the OpenAPI operation search field." + }, + "visualizationRenderFailed": "无法渲染此可视化内容。", + "@visualizationRenderFailed": { + "description": "Fallback message for a failed visualization render." + }, + "visualizationRetry": "重试", + "@visualizationRetry": { + "description": "Action that retries a failed visualization render." + }, + "visualizationSaved": "已保存 {fileName}", + "@visualizationSaved": { + "description": "Confirmation after saving a rendered diagram.", + "placeholders": { + "fileName": { + "type": "String" + } + } + }, + "shortcutExportPdfDescription": "将当前文档或 Writerside 模块导出为 PDF。", + "@shortcutExportPdfDescription": { + "description": "Keyboard-shortcut description for PDF export." + }, + "instances": "实例", + "@instances": { + "description": "Heading for the Writerside instances shown in the TOC sidebar." + }, + "newInstance": "新建实例", + "@newInstance": { + "description": "Action that creates a Writerside instance." + }, + "newTocLibrary": "新建目录库", + "@newTocLibrary": { + "description": "Action that creates a Writerside library instance for reusable TOC sections." + }, + "editInstance": "编辑实例", + "@editInstance": { + "description": "Action and dialog title for editing a Writerside instance." + }, + "openTocFile": "打开目录文件", + "@openTocFile": { + "description": "Action that opens the selected Writerside instance tree file." + }, + "createInstance": "创建实例", + "@createInstance": { + "description": "Dialog title for creating a Writerside instance." + }, + "createTocLibrary": "创建目录库", + "@createTocLibrary": { + "description": "Dialog title for creating a Writerside TOC library instance." + }, + "instanceContent": "内容", + "@instanceContent": { + "description": "Group title for choosing the initial content of a Writerside instance." + }, + "instanceContentSource": "创建来源", + "@instanceContentSource": { + "description": "Field for choosing how a Writerside instance is initialized." + }, + "emptyInstance": "空实例", + "@emptyInstance": { + "description": "Option to create a Writerside instance without imported topics." + }, + "markdownFiles": "本地 Markdown 文件", + "@markdownFiles": { + "description": "Option to initialize a Writerside instance from Markdown files." + }, + "chooseMarkdownFolder": "选择 Markdown 文件夹", + "@chooseMarkdownFolder": { + "description": "Action to choose a folder containing Markdown files." + }, + "errorWritersideInstanceImportSourceRequired": "选择包含 Markdown 文件的文件夹。", + "@errorWritersideInstanceImportSourceRequired": { + "description": "Validation shown when an imported instance has no source folder." + }, + "instanceAppearance": "外观", + "@instanceAppearance": { + "description": "Group title for the local appearance of a Writerside instance." + }, + "instanceColor": "图标颜色", + "@instanceColor": { + "description": "Writerside instance icon-color field." + }, + "instanceVersion": "版本", + "@instanceVersion": { + "description": "Writerside instance version field." + }, + "instanceVersionInherited": "此字段为空时,项目版本为 {version}。", + "@instanceVersionInherited": { + "description": "Explanation of an inherited Writerside project version.", + "placeholders": { + "version": { + "type": "String" + } + } + }, + "instanceWebPath": "Web 路径", + "@instanceWebPath": { + "description": "Writerside instance publication web-path field." + }, + "instanceStatus": "状态", + "@instanceStatus": { + "description": "Writerside instance status field." + }, + "instanceStatusRelease": "发布", + "@instanceStatusRelease": { + "description": "Regular Writerside instance status." + }, + "instanceStatusEap": "抢先体验", + "@instanceStatusEap": { + "description": "Writerside early-access instance status." + }, + "instanceStatusDeprecated": "已弃用", + "@instanceStatusDeprecated": { + "description": "Writerside deprecated instance status." + }, + "allowSearchEngineIndexing": "允许搜索引擎建立索引", + "@allowSearchEngineIndexing": { + "description": "Per-instance Writerside search-engine indexing setting." + }, + "allowSearchEngineIndexingDescription": "允许外部搜索引擎为此输出建立索引。", + "@allowSearchEngineIndexingDescription": { + "description": "Description of the Writerside indexing setting." + }, + "offlineArtifact": "离线构件", + "@offlineArtifact": { + "description": "Per-instance Writerside offline artifact setting." + }, + "offlineArtifactDescription": "捆绑资源,使构建的文档可以自包含。", + "@offlineArtifactDescription": { + "description": "Description of the Writerside offline artifact setting." + }, + "instanceOutputSettings": "输出设置", + "@instanceOutputSettings": { + "description": "Group title for Writerside instance build and publication settings." + }, + "markdownImportSource": "Markdown 源", + "@markdownImportSource": { + "description": "Group title for the source directory of a Writerside Markdown import." + }, + "markdownImportFiles": "Markdown 文件", + "@markdownImportFiles": { + "description": "Group title for files selected for a Writerside Markdown import." + }, + "selectNone": "全部取消选择", + "@selectNone": { + "description": "Action that clears all items in a multiple selection." + }, + "markdownFilesFound": "找到 {count} 个 Markdown 文件", + "@markdownFilesFound": { + "description": "Count of discovered Markdown import files.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "noMarkdownFilesFound": "在此目录中未找到 Markdown 文件。", + "@noMarkdownFilesFound": { + "description": "Empty state for a Writerside Markdown import source." + }, + "copyReferencedMedia": "复制引用的媒体", + "@copyReferencedMedia": { + "description": "Option to copy media used by imported Markdown files." + }, + "copyReferencedMediaDescription": "复制选中文件引用的本地图像和视频,同时保留相对路径。", + "@copyReferencedMediaDescription": { + "description": "Description of the Writerside Markdown media import option." + }, + "instanceIdRenameWarningTitle": "重命名实例 ID?", + "@instanceIdRenameWarningTitle": { + "description": "Confirmation title before refactoring a Writerside instance ID." + }, + "instanceIdRenameWarning": "BusyMark 将重命名 .tree 文件,并将 Writerside 项目引用从“{oldId}”更新为“{newId}”。发布脚本不会更改,必须单独更新。", + "@instanceIdRenameWarning": { + "description": "Warning shown before a Writerside instance ID refactor.", + "placeholders": { + "oldId": { + "type": "String" + }, + "newId": { + "type": "String" + } + } + }, + "renameAndUpdateReferences": "重命名并更新引用", + "@renameAndUpdateReferences": { + "description": "Confirmation action for a Writerside instance ID refactor." + }, + "tocLibraryDescription": "目录库用于存储可复用的节,不会生成自己的输出。", + "@tocLibraryDescription": { + "description": "Explanation shown while creating a Writerside TOC library." + }, + "defaultTocLibraryName": "共享目录", + "@defaultTocLibraryName": { + "description": "Default name for a new Writerside TOC library instance." + }, + "instanceColorAutomatic": "自动", + "@instanceColorAutomatic": { + "description": "Automatic Writerside instance icon color option." + }, + "instanceColorBlue": "蓝色", + "@instanceColorBlue": { + "description": "Blue Writerside instance icon color option." + }, + "instanceColorGreen": "绿色", + "@instanceColorGreen": { + "description": "Green Writerside instance icon color option." + }, + "instanceColorOrange": "橙色", + "@instanceColorOrange": { + "description": "Orange Writerside instance icon color option." + }, + "instanceColorPurple": "紫色", + "@instanceColorPurple": { + "description": "Purple Writerside instance icon color option." + }, + "instanceColorRed": "红色", + "@instanceColorRed": { + "description": "Red Writerside instance icon color option." + }, + "instanceColorTeal": "青绿色", + "@instanceColorTeal": { + "description": "Teal Writerside instance icon color option." + }, + "instanceColorYellow": "黄色", + "@instanceColorYellow": { + "description": "Yellow Writerside instance icon color option." + }, + "errorWritersideInstanceNameRequired": "请输入实例名称。", + "@errorWritersideInstanceNameRequired": { + "description": "Validation error for an empty Writerside instance name." + }, + "errorWritersideInstanceIdExists": "已存在 ID 为“{id}”的实例。", + "@errorWritersideInstanceIdExists": { + "description": "Error for a duplicate Writerside instance ID.", + "placeholders": { + "id": { + "type": "String" + } + } + }, + "errorWritersideInstanceTreeExists": "实例树已存在:{path}", + "@errorWritersideInstanceTreeExists": { + "description": "Error for an existing Writerside instance tree path.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorWritersideInstanceImportSourceMissing": "Markdown 源目录不存在:{path}", + "@errorWritersideInstanceImportSourceMissing": { + "description": "Error for a missing Writerside Markdown import source.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorWritersideInstanceImportSelectionRequired": "请选择至少一个 Markdown 文件进行导入。", + "@errorWritersideInstanceImportSelectionRequired": { + "description": "Validation error when no Markdown import files are selected." + }, + "errorWritersideInstanceImportFileInvalid": "选中的源中有一个不是可读取的 Markdown 文件:{path}", + "@errorWritersideInstanceImportFileInvalid": { + "description": "Error for an invalid Writerside Markdown import file.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorWritersideInstanceImportTargetExists": "导入将覆盖现有项目文件:{path}", + "@errorWritersideInstanceImportTargetExists": { + "description": "Error for a colliding Writerside Markdown import target.", + "placeholders": { + "path": { + "type": "String" + } + } + }, + "errorWritersideInstanceFilesChanged": "实例文件已在磁盘上发生变化。请查看后重试。", + "@errorWritersideInstanceFilesChanged": { + "description": "Concurrent-change error for a Writerside instance mutation." + }, + "errorWritersideInstanceRollbackFailed": "BusyMark 无法完全回滚实例更改。请在继续前查看这些文件:{paths}", + "@errorWritersideInstanceRollbackFailed": { + "description": "Error when a Writerside instance mutation rollback is incomplete.", + "placeholders": { + "paths": { + "type": "String" + } + } + }, + "errorWritersideInstanceLibraryImport": "目录库无法导入 Markdown 主题。", + "@errorWritersideInstanceLibraryImport": { + "description": "Error when Markdown import is requested for a TOC library." + }, + "errorWritersideInstanceWebPathInvalid": "Web 路径必须为单行文本。", + "@errorWritersideInstanceWebPathInvalid": { + "description": "Validation error for an invalid Writerside instance web path." + }, + "errorWritersideInstanceConfigurationInvalid": "Writerside 实例配置无效。请修正其诊断信息后重试。", + "@errorWritersideInstanceConfigurationInvalid": { + "description": "Error when an instance tree, project config, or build profiles file cannot be safely edited." + }, + "errorWritersideInstanceTemporaryFile": "BusyMark 无法安全暂存实例更改。", + "@errorWritersideInstanceTemporaryFile": { + "description": "Error when a temporary file for an instance mutation cannot be created." + }, + "diagnosticWritersideTreeInvalidStatus": "未知的实例状态“{status}”。请使用 release、eap 或 deprecated。", + "@diagnosticWritersideTreeInvalidStatus": { + "description": "Diagnostic for an unsupported Writerside instance status.", + "placeholders": { + "status": { + "type": "String" + } + } + }, + "diagnosticWritersideDuplicateInstanceId": "实例 ID“{id}”被多个树文件使用。", + "@diagnosticWritersideDuplicateInstanceId": { + "description": "Diagnostic for a duplicate Writerside instance ID.", + "placeholders": { + "id": { + "type": "String" + } + } + }, + "diagnosticWritersideBuildProfilesInvalidRoot": "buildprofiles.xml 必须包含 <buildprofiles> 根元素。", + "@diagnosticWritersideBuildProfilesInvalidRoot": { + "description": "Diagnostic for an invalid Writerside build profiles root." + }, + "diagnosticWritersideBuildProfilesInvalidBoolean": "{name} 值“{value}”必须为 true 或 false。", + "@diagnosticWritersideBuildProfilesInvalidBoolean": { + "description": "Diagnostic for an invalid Writerside build profile Boolean.", + "placeholders": { + "name": { + "type": "String" + }, + "value": { + "type": "String" + } + } + }, + "diagnosticWritersideBuildProfileMissingInstance": "<build-profile> 元素必须指定实例 ID。", + "@diagnosticWritersideBuildProfileMissingInstance": { + "description": "Diagnostic for a Writerside build profile without an instance attribute." + }, + "diagnosticWritersideTreeInvalidInclude": "树中的 <include> 必须同时指定 from 和 element-id。", + "@diagnosticWritersideTreeInvalidInclude": { + "description": "Diagnostic for an incomplete Writerside tree include." + }, + "diagnosticWritersideTreeMissingSnippetId": "树中的 <snippet> 必须指定 id。", + "@diagnosticWritersideTreeMissingSnippetId": { + "description": "Diagnostic for a Writerside tree snippet without an ID." + }, + "diagnosticWritersideTreeInvalidCrossInstanceReference": "跨实例目录引用必须同时指定 ref 和 in。", + "@diagnosticWritersideTreeInvalidCrossInstanceReference": { + "description": "Diagnostic for an incomplete Writerside ref/in pair." + }, + "diagnosticWritersideTreeConflictingTargets": "目录元素不能同时指向多个主题、引用、链接或重定向。", + "@diagnosticWritersideTreeConflictingTargets": { + "description": "Diagnostic for conflicting Writerside TOC targets." + }, + "diagnosticWritersideTreeDuplicateElementId": "树元素 ID“{id}”被声明了多次。", + "@diagnosticWritersideTreeDuplicateElementId": { + "description": "Diagnostic for a duplicate Writerside tree element ID.", + "placeholders": { + "id": { + "type": "String" + } + } + }, + "diagnosticWritersideInstanceGroupsInvalidRoot": "实例组文件必须包含 <instance-groups> 根元素。", + "@diagnosticWritersideInstanceGroupsInvalidRoot": { + "description": "Diagnostic for an invalid Writerside instance groups root." + }, + "diagnosticWritersideInstanceGroupInvalid": "实例组必须指定非空 ID 和实例列表。", + "@diagnosticWritersideInstanceGroupInvalid": { + "description": "Diagnostic for an invalid Writerside instance group." + }, + "diagnosticWritersideInstanceGroupDuplicateId": "实例组 ID“{id}”被声明了多次。", + "@diagnosticWritersideInstanceGroupDuplicateId": { + "description": "Diagnostic for a duplicate Writerside instance group ID.", + "placeholders": { + "id": { + "type": "String" + } + } + }, + "diagnosticWritersideExternalTreeInclude": "目录包含项“{source}#{id}”属于外部模块“{origin}”,无法在此工作区中展开。", + "@diagnosticWritersideExternalTreeInclude": { + "description": "Diagnostic for a tree include from another Writerside module.", + "placeholders": { + "source": { + "type": "String" + }, + "id": { + "type": "String" + }, + "origin": { + "type": "String" + } + } + }, + "diagnosticWritersideTreeIncludeElementMissing": "已注册树“{source}”中不存在树元素“{id}”。", + "@diagnosticWritersideTreeIncludeElementMissing": { + "description": "Diagnostic for a missing reusable tree element.", + "placeholders": { + "source": { + "type": "String" + }, + "id": { + "type": "String" + } + } + }, + "diagnosticWritersideTreeCircularInclude": "树包含项“{source}#{id}”创建了循环。", + "@diagnosticWritersideTreeCircularInclude": { + "description": "Diagnostic for a circular Writerside tree include.", + "placeholders": { + "source": { + "type": "String" + }, + "id": { + "type": "String" + } + } + }, + "diagnosticWritersideUnknownInstanceGroup": "实例条件引用了未知组“@{group}”。", + "@diagnosticWritersideUnknownInstanceGroup": { + "description": "Diagnostic for an unknown Writerside instance group.", + "placeholders": { + "group": { + "type": "String" + } + } + }, + "diagnosticWritersideReferenceInstanceMissing": "跨实例引用指向未知实例“{instance}”。", + "@diagnosticWritersideReferenceInstanceMissing": { + "description": "Diagnostic for a missing Writerside reference instance.", + "placeholders": { + "instance": { + "type": "String" + } + } + }, + "diagnosticWritersideReferenceTopicMissing": "主题“{topic}”不在被引用的实例“{instance}”中。", + "@diagnosticWritersideReferenceTopicMissing": { + "description": "Diagnostic for a missing topic in a cross-instance Writerside reference.", + "placeholders": { + "topic": { + "type": "String" + }, + "instance": { + "type": "String" + } + } + }, + "download": "下载", + "@download": { + "description": "Button label that downloads a required component." + }, + "exportWritersideAsPdf": "将 Writerside 导出为 PDF", + "@exportWritersideAsPdf": { + "description": "Menu action and dialog title for exporting a Writerside instance as PDF." + }, + "writersidePdfContent": "导出内容", + "@writersidePdfContent": { + "description": "Group title for selecting Writerside PDF content." + }, + "writersidePdfPage": "页面", + "@writersidePdfPage": { + "description": "Writerside PDF page settings group title." + }, + "exportingWritersidePdf": "正在导出 Writerside PDF…", + "@exportingWritersidePdf": { + "description": "Progress title while building a Writerside PDF." + }, + "ai": "AI", + "@ai": { + "description": "Settings section and editing menu label for artificial-intelligence features." + }, + "aiLocalOllama": "本地 Ollama", + "@aiLocalOllama": { + "description": "AI provider option for a loopback Ollama service." + }, + "aiDisabled": "已禁用", + "@aiDisabled": { + "description": "AI provider option that disables AI features." + }, + "aiProvider": "AI 提供商", + "@aiProvider": { + "description": "Label for an AI provider selection." + }, + "aiDefaultProvider": "默认提供商", + "@aiDefaultProvider": { + "description": "Settings label for the provider selected by default for AI actions." + }, + "aiConfigureProvider": "配置提供商", + "@aiConfigureProvider": { + "description": "Settings label for choosing which AI provider configuration to edit." + }, + "aiChooseProvider": "选择 AI 提供商", + "@aiChooseProvider": { + "description": "Dialog title shown before selecting the AI provider for an action." + }, + "aiOllamaEndpoint": "Ollama 端点", + "@aiOllamaEndpoint": { + "description": "Settings label for the local Ollama origin." + }, + "aiOllamaModel": "Ollama 模型", + "@aiOllamaModel": { + "description": "Settings label for the installed Ollama model." + }, + "aiTestConnection": "测试连接", + "@aiTestConnection": { + "description": "Button that verifies generation with the configured AI provider and model." + }, + "aiTestingConnection": "正在测试…", + "@aiTestingConnection": { + "description": "Status while BusyMark verifies the configured AI provider and model." + }, + "aiConnectionReady": "已连接。找到 {count} 个已安装模型。", + "@aiConnectionReady": { + "description": "Successful Ollama connection status.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "aiNoModels": "未选择模型。", + "@aiNoModels": { + "description": "AI model setting shown before a model has been selected or discovered." + }, + "aiConnectionFailed": "BusyMark 无法验证 AI 文本生成。", + "@aiConnectionFailed": { + "description": "Generic failure shown while testing AI generation." + }, + "aiConfigureFirst": "请先在设置 → AI 中启用 AI 提供商并验证模型。", + "aiEditWithAi": "使用 AI 编辑", + "aiRefineWithAi": "使用 AI 优化", + "@aiRefineWithAi": { + "description": "Selected-text context-menu action that opens AI refinement." + }, + "aiInstruction": "指令", + "aiChangeTarget": "可更改内容", + "aiSharedContext": "与 AI 共享的上下文", + "aiTargetSelection": "选中的内容", + "aiTargetInsertAfterBlock": "插入到当前块之后", + "aiTargetCurrentBlock": "当前块", + "aiTargetCurrentSection": "当前节", + "aiTargetCompleteDocument": "完整文档", + "aiContextNone": "没有文档上下文", + "aiContextSelection": "选中的内容", + "aiContextCurrentBlock": "当前块", + "aiContextCurrentSection": "当前节", + "aiContextCompleteDocument": "完整文档", + "@aiConfigureFirst": { + "description": "Message shown when an AI action is unavailable." + }, + "aiGenerating": "正在生成建议…", + "@aiGenerating": { + "description": "Progress text while an AI proposal streams." + }, + "aiProposal": "AI 建议", + "@aiProposal": { + "description": "Title of the AI proposal review dialog." + }, + "aiGenerateProposal": "生成建议", + "@aiGenerateProposal": { + "description": "Button that starts generation after the user reviews the AI instruction, change target, and shared context." + }, + "aiContextDisclosure": "所选提供商将接收显示上下文中的 {count} 个字符。", + "@aiContextDisclosure": { + "description": "Disclosure of AI context size.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "aiOriginal": "原始内容", + "@aiOriginal": { + "description": "Label for original text in an AI proposal review." + }, + "aiSuggested": "建议内容", + "@aiSuggested": { + "description": "Label for proposed text in an AI proposal review." + }, + "aiApplyProposal": "应用建议", + "@aiApplyProposal": { + "description": "Button that applies a reviewed AI proposal." + }, + "aiTokenUsage": "输入 token:{input} · 输出 token:{output}", + "@aiTokenUsage": { + "description": "Local Ollama token usage for one proposal.", + "placeholders": { + "input": { + "type": "int" + }, + "output": { + "type": "int" + } + } + }, + "aiStaleProposal": "生成此建议期间文档发生了变化。请重新执行操作。", + "gitAiStagedChangesChanged": "生成此提交消息期间,已暂存的更改发生了变化。请重新执行操作。", + "@gitAiStagedChangesChanged": { + "description": "Warning shown when an AI commit-message proposal was generated from an obsolete staged diff." + }, + "@aiStaleProposal": { + "description": "Message for an AI result based on an old editor revision." + }, + "aiViewContext": "查看已发送的上下文", + "@aiViewContext": { + "description": "Action that reveals the exact AI input context." + }, + "aiReviewExactContent": "查看确切内容", + "@aiReviewExactContent": { + "description": "Action that reveals the exact content affected by and shared with an AI edit." + }, + "aiContentToChange": "要更改的内容", + "@aiContentToChange": { + "description": "Label for the exact Markdown that an AI proposal may change." + }, + "aiContentSentToAi": "发送给 AI 的内容", + "@aiContentSentToAi": { + "description": "Label for the exact document context that will be sent to the configured AI provider." + }, + "aiApiKey": "API 密钥", + "@aiApiKey": { + "description": "Label for a cloud AI provider API key." + }, + "aiApiKeyStoredHint": "密钥已存储在系统凭据存储中", + "@aiApiKeyStoredHint": { + "description": "Hint when a cloud API key is already stored." + }, + "aiApiKeyEnterHint": "输入提供商 API 密钥", + "@aiApiKeyEnterHint": { + "description": "Hint for entering a cloud provider API key." + }, + "aiReplaceApiKey": "替换 API 密钥", + "@aiReplaceApiKey": { + "description": "Action that replaces a stored cloud provider key." + }, + "aiSaveApiKey": "安全保存 API 密钥", + "@aiSaveApiKey": { + "description": "Action that saves a cloud provider key to the system credential store." + }, + "aiRemoveApiKey": "移除已保存的 API 密钥", + "@aiRemoveApiKey": { + "description": "Action that removes a cloud provider key from the system credential store." + }, + "aiCredentialSaved": "API 密钥已保存到系统凭据存储中。", + "@aiCredentialSaved": { + "description": "Confirmation after saving an AI provider key." + }, + "aiCredentialRemoved": "已移除保存的 API 密钥。", + "@aiCredentialRemoved": { + "description": "Confirmation after removing an AI provider key." + }, + "aiModelRouting": "模型路由", + "@aiModelRouting": { + "description": "Settings label for AI model routing." + }, + "aiAutomaticRouting": "按任务自动选择", + "@aiAutomaticRouting": { + "description": "AI model routing option that chooses by task class." + }, + "aiFixedModelRouting": "使用选中的模型", + "@aiFixedModelRouting": { + "description": "AI model routing option that always uses the preferred model." + }, + "aiPreferredModel": "首选模型", + "@aiPreferredModel": { + "description": "Settings label for a preferred cloud AI model." + }, + "aiModel": "模型", + "@aiModel": { + "description": "Label for selecting a model for one AI request." + }, + "aiUsageThisMonth": "{requests} 个请求 · {input} 个输入 token · {output} 个输出 token", + "@aiUsageThisMonth": { + "description": "Local monthly AI usage summary.", + "placeholders": { + "requests": { + "type": "int" + }, + "input": { + "type": "int" + }, + "output": { + "type": "int" + } + } + }, + "aiCloudConsentTitle": "将内容发送给 {provider}?", + "@aiCloudConsentTitle": { + "description": "Cloud AI data-sharing confirmation title.", + "placeholders": { + "provider": { + "type": "String" + } + } + }, + "aiCloudConsentEnable": "启用 {provider}", + "@aiCloudConsentEnable": { + "description": "Action that confirms use of a cloud AI provider.", + "placeholders": { + "provider": { + "type": "String" + } + } + }, + "aiCloudConsentMessage": "只会发送每个 AI 审核对话框中显示的内容。请求不保存状态,建议需要审核,API 密钥存储在 Linux 系统凭据存储中。", + "@aiCloudConsentMessage": { + "description": "Cloud AI data-sharing and credential disclosure." + }, + "aiCloudConsentRequired": "请先在设置 → AI 中确认与 {provider} 共享数据。", + "@aiCloudConsentRequired": { + "description": "AI action error when cloud consent is missing.", + "placeholders": { + "provider": { + "type": "String" + } + } + }, + "aiGenerationVerified": "已通过 {model} 验证生成能力。有 {count} 个兼容模型可用。", + "@aiGenerationVerified": { + "description": "Successful AI model generation qualification.", + "placeholders": { + "model": { + "type": "String" + }, + "count": { + "type": "int" + } + } + }, + "aiColdStartObserved": "检测到本地模型冷启动。", + "@aiColdStartObserved": { + "description": "Additional model qualification status when local generation required a cold start." + }, + "aiNoCompatibleModels": "没有可用的兼容文本生成模型。", + "@aiNoCompatibleModels": { + "description": "AI connection status when no compatible generation model is available." + }, + "aiEnableProvider": "请先启用 AI 提供商。", + "@aiEnableProvider": { + "description": "AI settings error when no provider is enabled." + }, + "aiDraftCommitMessage": "起草提交消息", + "@aiDraftCommitMessage": { + "description": "AI action that drafts a Git commit message." + }, + "aiDrafting": "正在起草…", + "@aiDrafting": { + "description": "Progress label while AI drafts a commit message." + }, + "aiDraftWithAi": "使用 AI 起草", + "@aiDraftWithAi": { + "description": "Action that drafts a Git commit message with AI." + }, + "generateOrUpdateMarkdownToc": "生成/更新目录", + "@generateOrUpdateMarkdownToc": { + "description": "Deterministic action that creates or refreshes a Markdown table of contents." + }, + "markdownTocTitle": "目录", + "@markdownTocTitle": { + "description": "Heading inserted above a generated Markdown table of contents." + }, + "markdownTocUpdated": "目录已更新,包含 {count} 个条目。", + "@markdownTocUpdated": { + "description": "Confirmation after generating a Markdown table of contents.", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "markdownTocNoHeadings": "请先添加至少一个节标题,再生成目录。", + "@markdownTocNoHeadings": { + "description": "Message when a Markdown document has no section headings for a generated table of contents." + }, + "markdownTocMalformedMarkers": "BusyMark 目录标记缺失、重复或顺序错误。", + "@markdownTocMalformedMarkers": { + "description": "Message when a generated Markdown table-of-contents region cannot be safely updated." + }, + "diagnosticMarkdownHeadingSkippedLevel": "标题级别 {level} 跟在级别 {previousLevel} 之后;请检查节的嵌套结构。", + "@diagnosticMarkdownHeadingSkippedLevel": { + "description": "Accessibility diagnostic for a skipped Markdown heading level.", + "placeholders": { + "level": { + "type": "int" + }, + "previousLevel": { + "type": "int" + } + } + }, + "diagnosticMarkdownLinkEmptyText": "链接文本为空;请提供能描述其用途的可访问名称。", + "@diagnosticMarkdownLinkEmptyText": { + "description": "Accessibility diagnostic for a Markdown link without text." + }, + "diagnosticMarkdownLinkReviewText": "请检查链接文本“{text}”是否在上下文中描述了其用途。", + "@diagnosticMarkdownLinkReviewText": { + "description": "Accessibility hint for potentially non-descriptive Markdown link text.", + "placeholders": { + "text": { + "type": "String" + } + } + }, + "diagnosticMarkdownTableEmptyHeader": "表头单元格必须标识其列;请补全每个空表头。", + "@diagnosticMarkdownTableEmptyHeader": { + "description": "Accessibility diagnostic for an empty Markdown table header cell." + }, + "mathRenderFailed": "无法渲染数学表达式。", + "@mathRenderFailed": { + "description": "Tooltip and diagnostic text shown when a mathematical expression cannot be rendered." + }, + "inlineMath": "行内数学", + "@inlineMath": { + "description": "Editor action that inserts an inline mathematical expression." + }, + "displayMath": "显示数学", + "@displayMath": { + "description": "Editor action that inserts a display mathematical expression." + }, + "aiExplicitEditingDescription": "AI 编辑需要明确发起。BusyMark 只会将所选提供商对应的显示上下文发送出去,且不会在未经审核的情况下应用建议。", + "@aiExplicitEditingDescription": { + "description": "Privacy disclosure for explicit AI editing with selected-provider context visibility." + }, "exportAsHtml": "导出为 HTML…", "fileTypeHtml": "HTML 文档", "exportingHtml": "正在导出 HTML…", diff --git a/lib/l10n/app_zh_CN.arb b/lib/l10n/app_zh_CN.arb index 269baadc..b5198c57 100644 --- a/lib/l10n/app_zh_CN.arb +++ b/lib/l10n/app_zh_CN.arb @@ -179,6 +179,7 @@ }, "copy": "复制", "copyPlainText": "复制为纯文本", + "clipboardCopyFailed": "无法将所选内容复制到剪贴板。", "@copy": { "description": "Copy command label." }, diff --git a/lib/l10n/generated/app_localizations_ar.dart b/lib/l10n/generated/app_localizations_ar.dart index 83ce3337..fd291a1e 100644 --- a/lib/l10n/generated/app_localizations_ar.dart +++ b/lib/l10n/generated/app_localizations_ar.dart @@ -156,8 +156,7 @@ class AppLocalizationsAr extends AppLocalizations { String get copyPlainText => 'نسخ كنص عادي'; @override - String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + String get clipboardCopyFailed => 'تعذّر نسخ المحتوى المحدد إلى الحافظة.'; @override String get copyName => 'نسخ الاسم'; @@ -2442,9 +2441,9 @@ class AppLocalizationsAr extends AppLocalizations { count, locale: localeName, other: - 'ستتم استعادة جميع تغييرات المرحلة وغير المرحلة في الملفات المتعقبة المحددة إلى HEAD.', + 'ستتم استعادة جميع التغييرات المُرحَّلة وغير المُرحَّلة في الملفات المتعقبة المحددة إلى HEAD.', one: - 'ستتم استعادة جميع تغييرات المرحلة وغير المرحلة في الملف المتعقب المحدد إلى HEAD.', + 'ستتم استعادة جميع التغييرات المُرحَّلة وغير المُرحَّلة في الملف المتعقب المحدد إلى HEAD.', ); return '$_temp0'; } @@ -3658,7 +3657,7 @@ class AppLocalizationsAr extends AppLocalizations { String get aiEnableProvider => 'فعّل مزوّد ذكاء اصطناعي أولًا.'; @override - String get aiDraftCommitMessage => 'صياغة مسودة رسالة الإيداع'; + String get aiDraftCommitMessage => 'صياغة مسودة رسالة الالتزام'; @override String get aiDrafting => 'جارٍ إعداد المسودة…'; diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 9fbaa04d..37f310dc 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -161,7 +161,7 @@ class AppLocalizationsDe extends AppLocalizations { @override String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + 'Die Auswahl konnte nicht in die Zwischenablage kopiert werden.'; @override String get copyName => 'Namen kopieren'; @@ -2436,9 +2436,9 @@ class AppLocalizationsDe extends AppLocalizations { count, locale: localeName, other: - 'Alle gestageten und nicht gestageten Änderungen der ausgewählten versionierten Dateien werden auf den Stand in Git zurückgesetzt.', + 'Alle vorgemerkten und nicht vorgemerkten Änderungen der ausgewählten versionierten Dateien werden auf HEAD zurückgesetzt.', one: - 'Alle gestageten und nicht gestageten Änderungen der ausgewählten versionierten Datei werden auf den Stand in Git zurückgesetzt.', + 'Alle vorgemerkten und nicht vorgemerkten Änderungen der ausgewählten versionierten Datei werden auf HEAD zurückgesetzt.', ); return '$_temp0'; } diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart index e070e427..4529a74b 100644 --- a/lib/l10n/generated/app_localizations_es.dart +++ b/lib/l10n/generated/app_localizations_es.dart @@ -160,7 +160,7 @@ class AppLocalizationsEs extends AppLocalizations { @override String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + 'No se pudo copiar la selección al portapapeles.'; @override String get copyName => 'Copiar nombre'; @@ -2437,9 +2437,9 @@ class AppLocalizationsEs extends AppLocalizations { count, locale: localeName, other: - 'Se restaurarán en HEAD todos los cambios staged y no staged de los archivos rastreados seleccionados.', + 'Se restaurarán en HEAD todos los cambios preparados y sin preparar de los archivos rastreados seleccionados.', one: - 'Se restaurarán en HEAD todos los cambios staged y no staged del archivo rastreado seleccionado.', + 'Se restaurarán en HEAD todos los cambios preparados y sin preparar del archivo rastreado seleccionado.', ); return '$_temp0'; } diff --git a/lib/l10n/generated/app_localizations_et.dart b/lib/l10n/generated/app_localizations_et.dart index acadc20f..e5bb4ad4 100644 --- a/lib/l10n/generated/app_localizations_et.dart +++ b/lib/l10n/generated/app_localizations_et.dart @@ -156,8 +156,7 @@ class AppLocalizationsEt extends AppLocalizations { String get copyPlainText => 'Kopeeri lihttekstina'; @override - String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + String get clipboardCopyFailed => 'Valikut ei saanud lõikelauale kopeerida.'; @override String get copyName => 'Kopeeri nimi'; diff --git a/lib/l10n/generated/app_localizations_fa.dart b/lib/l10n/generated/app_localizations_fa.dart index b1a30ac5..d5f38f1e 100644 --- a/lib/l10n/generated/app_localizations_fa.dart +++ b/lib/l10n/generated/app_localizations_fa.dart @@ -157,7 +157,7 @@ class AppLocalizationsFa extends AppLocalizations { @override String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + 'امکان کپی کردن محتوای انتخاب‌شده در کلیپ‌بورد وجود نداشت.'; @override String get copyName => 'کپی نام'; diff --git a/lib/l10n/generated/app_localizations_fr.dart b/lib/l10n/generated/app_localizations_fr.dart index e4d0eb8b..86f26d31 100644 --- a/lib/l10n/generated/app_localizations_fr.dart +++ b/lib/l10n/generated/app_localizations_fr.dart @@ -160,7 +160,7 @@ class AppLocalizationsFr extends AppLocalizations { @override String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + 'Impossible de copier la sélection dans le presse-papiers.'; @override String get copyName => 'Copier le nom'; @@ -2437,9 +2437,9 @@ class AppLocalizationsFr extends AppLocalizations { count, locale: localeName, other: - 'Toutes les modifications staged et unstaged des fichiers suivis sélectionnés seront restaurées vers HEAD.', + 'Toutes les modifications indexées et non indexées des fichiers suivis sélectionnés seront restaurées vers HEAD.', one: - 'Toutes les modifications staged et unstaged du fichier suivi sélectionné seront restaurées vers HEAD.', + 'Toutes les modifications indexées et non indexées du fichier suivi sélectionné seront restaurées vers HEAD.', ); return '$_temp0'; } diff --git a/lib/l10n/generated/app_localizations_hi.dart b/lib/l10n/generated/app_localizations_hi.dart index 8dd264b2..3673d44e 100644 --- a/lib/l10n/generated/app_localizations_hi.dart +++ b/lib/l10n/generated/app_localizations_hi.dart @@ -159,7 +159,7 @@ class AppLocalizationsHi extends AppLocalizations { @override String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + 'चयनित सामग्री को क्लिपबोर्ड पर कॉपी नहीं किया जा सका।'; @override String get copyName => 'नाम कॉपी करें'; @@ -2404,9 +2404,9 @@ class AppLocalizationsHi extends AppLocalizations { count, locale: localeName, other: - 'चयनित ट्रैक की गई फ़ाइलों के सभी चरणबद्ध और अचयनित परिवर्तन HEAD पर वापस लाए जाएँगे।', + 'चयनित ट्रैक की गई फ़ाइलों के सभी स्टेज किए गए और स्टेज नहीं किए गए बदलाव HEAD पर वापस लाए जाएँगे।', one: - 'चयनित ट्रैक की गई फ़ाइल के सभी चरणबद्ध और अचयनित परिवर्तन HEAD पर वापस लाए जाएँगे।', + 'चयनित ट्रैक की गई फ़ाइल के सभी स्टेज किए गए और स्टेज नहीं किए गए बदलाव HEAD पर वापस लाए जाएँगे।', ); return '$_temp0'; } diff --git a/lib/l10n/generated/app_localizations_id.dart b/lib/l10n/generated/app_localizations_id.dart index 41530a15..b7e7c9ce 100644 --- a/lib/l10n/generated/app_localizations_id.dart +++ b/lib/l10n/generated/app_localizations_id.dart @@ -159,7 +159,7 @@ class AppLocalizationsId extends AppLocalizations { @override String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + 'Konten yang dipilih tidak dapat disalin ke papan klip.'; @override String get copyName => 'Salin nama'; diff --git a/lib/l10n/generated/app_localizations_it.dart b/lib/l10n/generated/app_localizations_it.dart index 85370c8d..e9c4395b 100644 --- a/lib/l10n/generated/app_localizations_it.dart +++ b/lib/l10n/generated/app_localizations_it.dart @@ -159,7 +159,7 @@ class AppLocalizationsIt extends AppLocalizations { @override String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + 'Impossibile copiare la selezione negli appunti.'; @override String get copyName => 'Copia nome'; @@ -2433,9 +2433,9 @@ class AppLocalizationsIt extends AppLocalizations { count, locale: localeName, other: - 'Tutte le modifiche staged e non staged nei file tracciati selezionati saranno ripristinate in HEAD.', + 'Tutte le modifiche in stage e non in stage nei file tracciati selezionati saranno ripristinate in HEAD.', one: - 'Tutte le modifiche staged e non staged nel file tracciato selezionato saranno ripristinate in HEAD.', + 'Tutte le modifiche in stage e non in stage nel file tracciato selezionato saranno ripristinate in HEAD.', ); return '$_temp0'; } diff --git a/lib/l10n/generated/app_localizations_ja.dart b/lib/l10n/generated/app_localizations_ja.dart index fef2fd05..1b814f56 100644 --- a/lib/l10n/generated/app_localizations_ja.dart +++ b/lib/l10n/generated/app_localizations_ja.dart @@ -153,8 +153,7 @@ class AppLocalizationsJa extends AppLocalizations { String get copyPlainText => 'プレーンテキストとしてコピー'; @override - String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + String get clipboardCopyFailed => '選択内容をクリップボードにコピーできませんでした。'; @override String get copyName => '名前をコピー'; diff --git a/lib/l10n/generated/app_localizations_ko.dart b/lib/l10n/generated/app_localizations_ko.dart index dbb8fd10..2a207ac6 100644 --- a/lib/l10n/generated/app_localizations_ko.dart +++ b/lib/l10n/generated/app_localizations_ko.dart @@ -152,8 +152,7 @@ class AppLocalizationsKo extends AppLocalizations { String get copyPlainText => '일반 텍스트로 복사'; @override - String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + String get clipboardCopyFailed => '선택한 내용을 클립보드에 복사할 수 없습니다.'; @override String get copyName => '이름 복사'; @@ -3515,7 +3514,7 @@ class AppLocalizationsKo extends AppLocalizations { String get aiEnableProvider => '먼저 AI 제공자를 활성화하세요.'; @override - String get aiDraftCommitMessage => '초안 커밋 메시지'; + String get aiDraftCommitMessage => '커밋 메시지 초안 작성'; @override String get aiDrafting => '작성 중…'; diff --git a/lib/l10n/generated/app_localizations_nb.dart b/lib/l10n/generated/app_localizations_nb.dart index 9f8197a3..e3e19a05 100644 --- a/lib/l10n/generated/app_localizations_nb.dart +++ b/lib/l10n/generated/app_localizations_nb.dart @@ -160,7 +160,7 @@ class AppLocalizationsNb extends AppLocalizations { @override String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + 'Utvalget kunne ikke kopieres til utklippstavlen.'; @override String get copyName => 'Kopier navn'; @@ -2412,9 +2412,9 @@ class AppLocalizationsNb extends AppLocalizations { count, locale: localeName, other: - 'Alle staged- og ikke-staged-endringer i de valgte sporede filene vil bli gjenopprettet til HEAD.', + 'Alle indekserte og ikke-indekserte endringer i de valgte sporede filene vil bli gjenopprettet til HEAD.', one: - 'Alle staged- og ikke-staged-endringer i den valgte sporede filen vil bli gjenopprettet til HEAD.', + 'Alle indekserte og ikke-indekserte endringer i den valgte sporede filen vil bli gjenopprettet til HEAD.', ); return '$_temp0'; } diff --git a/lib/l10n/generated/app_localizations_nl.dart b/lib/l10n/generated/app_localizations_nl.dart index 6607dad2..544a47a0 100644 --- a/lib/l10n/generated/app_localizations_nl.dart +++ b/lib/l10n/generated/app_localizations_nl.dart @@ -160,7 +160,7 @@ class AppLocalizationsNl extends AppLocalizations { @override String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + 'De selectie kon niet naar het klembord worden gekopieerd.'; @override String get copyName => 'Kopieer naam'; diff --git a/lib/l10n/generated/app_localizations_pl.dart b/lib/l10n/generated/app_localizations_pl.dart index 17ef5fb5..5a7aaa07 100644 --- a/lib/l10n/generated/app_localizations_pl.dart +++ b/lib/l10n/generated/app_localizations_pl.dart @@ -159,7 +159,7 @@ class AppLocalizationsPl extends AppLocalizations { @override String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + 'Nie udało się skopiować zaznaczenia do schowka.'; @override String get copyName => 'Kopiuj nazwę'; @@ -2455,9 +2455,9 @@ class AppLocalizationsPl extends AppLocalizations { count, locale: localeName, other: - 'Wszystkie oznaczone i nieoznaczone zmiany w wybranych śledzonych plikach zostaną przywrócone do HEAD.', + 'Wszystkie zmiany w indeksie i poza indeksem w wybranych śledzonych plikach zostaną przywrócone do HEAD.', one: - 'Wszystkie oznaczone i nieoznaczone zmiany w wybranym śledzonym pliku zostaną przywrócone do HEAD.', + 'Wszystkie zmiany w indeksie i poza indeksem w wybranym śledzonym pliku zostaną przywrócone do HEAD.', ); return '$_temp0'; } diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart index 5700c21d..c2e39da8 100644 --- a/lib/l10n/generated/app_localizations_pt.dart +++ b/lib/l10n/generated/app_localizations_pt.dart @@ -15,300 +15,302 @@ class AppLocalizationsPt extends AppLocalizations { @override String get appSubtitle => - 'Editor for Markdown files and Writerside-compatible documentation projects.'; + 'Editor para ficheiros Markdown e projetos de documentação compatíveis com o Writerside.'; @override - String get aboutBusyMark => 'About BusyMark'; + String get aboutBusyMark => 'Sobre BusyMark'; @override - String get aboutTagline => 'Markdown and Writerside Editor'; + String get aboutTagline => 'Editor de Markdown e Writerside'; @override - String get aboutLicenseLabel => 'License'; + String get aboutLicenseLabel => 'Licença'; @override String get aboutLicenseName => 'Apache License 2.0'; @override - String get aboutWebsite => 'Website'; + String get aboutWebsite => 'Site'; @override - String get aboutSourceCode => 'Source code'; + String get aboutSourceCode => 'Código-fonte'; @override - String get reportIssue => 'Report an issue'; + String get reportIssue => 'Comunicar um problema'; @override - String get feedbackCategory => 'Category'; + String get feedbackCategory => 'Categoria'; @override - String get feedbackChooseCategory => 'Choose a category'; + String get feedbackChooseCategory => 'Escolha uma categoria'; @override - String get feedbackCategoryProblem => 'Problem or bug'; + String get feedbackCategoryProblem => 'Problema ou erro'; @override - String get feedbackCategoryFeature => 'Feature request'; + String get feedbackCategoryFeature => 'Pedido de funcionalidade'; @override - String get feedbackCategoryPrivacySecurity => 'Privacy or security concern'; + String get feedbackCategoryPrivacySecurity => + 'Preocupação com privacidade ou segurança'; @override - String get feedbackCategoryUsability => 'Usability concern'; + String get feedbackCategoryUsability => 'Preocupação de usabilidade'; @override - String get feedbackCategoryOther => 'Other'; + String get feedbackCategoryOther => 'Outro'; @override - String get feedbackSubject => 'Subject'; + String get feedbackSubject => 'Assunto'; @override - String get feedbackMessage => 'Detailed message'; + String get feedbackMessage => 'Mensagem detalhada'; @override - String get feedbackReplyEmail => 'Email address for replies (optional)'; + String get feedbackReplyEmail => 'E-mail para resposta (opcional)'; @override - String get feedbackIncludeTechnicalDetails => 'Include technical details'; + String get feedbackIncludeTechnicalDetails => 'Incluir detalhes técnicos'; @override String get feedbackTechnicalDetailsDisclosure => - 'When enabled, this adds only your Linux operating-system version and BusyMark application locale. No logs, files, account data, or other diagnostics are attached.'; + 'Quando esta opção está ativada, são adicionados apenas a versão do sistema operativo Linux e o idioma da aplicação BusyMark. Não são anexados registos, ficheiros, dados de conta nem outros diagnósticos.'; @override - String get feedbackSubmit => 'Submit'; + String get feedbackSubmit => 'Enviar'; @override - String get feedbackSubmitting => 'Submitting…'; + String get feedbackSubmitting => 'A enviar…'; @override - String get feedbackCategoryRequired => 'Choose a category.'; + String get feedbackCategoryRequired => 'Escolha uma categoria.'; @override String get feedbackSubjectLength => - 'Subject must be between 3 and 120 characters.'; + 'O assunto deve ter entre 3 e 120 carateres.'; @override String get feedbackMessageLength => - 'Message must be between 10 and 5,000 characters.'; + 'A mensagem deve ter entre 10 e 5000 carateres.'; @override String get feedbackReplyEmailInvalid => - 'Enter a valid email address or leave this field empty.'; + 'Introduza um endereço de e-mail válido ou deixe este campo vazio.'; @override String get feedbackConnectionFailure => - 'BusyMark could not connect. Check your internet connection and try again.'; + 'O BusyMark não conseguiu estabelecer ligação. Verifique a ligação à Internet e tente novamente.'; @override - String get feedbackTimeoutFailure => 'The request timed out. Try again.'; + String get feedbackTimeoutFailure => + 'O pedido excedeu o tempo limite. Tente novamente.'; @override String get feedbackRateLimitedFailure => - 'Too many reports were sent from this connection. Wait and try again.'; + 'Foram enviados demasiados relatórios a partir desta ligação. Aguarde e tente novamente.'; @override String get feedbackRejectedFailure => - 'The server rejected this report. Check the form fields and try again.'; + 'O servidor rejeitou o relatório. Verifique os campos do formulário e tente novamente.'; @override String get feedbackServerFailure => - 'The server could not accept the report. Try again later.'; + 'O servidor não conseguiu aceitar o relatório. Tente novamente mais tarde.'; @override String feedbackSuccess(String id) { - return 'Feedback sent. Reference ID: $id'; + return 'Comentários enviados. ID de referência: $id'; } @override - String get advanced => 'Advanced'; + String get advanced => 'Avançado'; @override - String get addToGit => 'Add to Git'; + String get addToGit => 'Adicionar ao Git'; @override - String get appearance => 'Appearance'; + String get appearance => 'Aparência'; @override - String get apply => 'Apply'; + String get apply => 'Aplicar'; @override - String get back => 'Back'; + String get back => 'Voltar'; @override - String get bottomLeft => 'Bottom left'; + String get bottomLeft => 'Canto inferior esquerdo'; @override - String get bottomRight => 'Bottom right'; + String get bottomRight => 'Canto inferior direito'; @override - String get cancel => 'Cancel'; + String get cancel => 'Cancelar'; @override - String get choose => 'Choose'; + String get choose => 'Escolher'; @override - String get chooseLocation => 'Choose location'; + String get chooseLocation => 'Escolher local'; @override - String get copy => 'Copy'; + String get copy => 'Copiar'; @override - String get copyPlainText => 'Copy Plain Text'; + String get copyPlainText => 'Copiar como texto simples'; @override String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + 'Não foi possível copiar a seleção para a área de transferência.'; @override - String get copyName => 'Copy name'; + String get copyName => 'Copiar nome'; @override - String get copyFileName => 'Copy file name'; + String get copyFileName => 'Copiar nome do ficheiro'; @override - String get copyPath => 'Copy path'; + String get copyPath => 'Copiar caminho'; @override - String get create => 'Create'; + String get create => 'Criar'; @override - String get creating => 'Creating...'; + String get creating => 'A criar…'; @override - String get cut => 'Cut'; + String get cut => 'Recortar'; @override - String get promoteSection => 'Promote section'; + String get promoteSection => 'Promover secção'; @override - String get demoteSection => 'Demote section'; + String get demoteSection => 'Rebaixar secção'; @override - String get moveSectionUp => 'Move section up'; + String get moveSectionUp => 'Mover secção para cima'; @override - String get moveSectionDown => 'Move section down'; + String get moveSectionDown => 'Mover secção para baixo'; @override - String get confirmDeleteSectionTitle => 'Delete section?'; + String get confirmDeleteSectionTitle => 'Eliminar secção?'; @override String confirmDeleteSectionMessage(String name) { - return 'Delete “$name” and all content in its section? This cannot be undone.'; + return 'Eliminar “$name” e todo o conteúdo da secção? Esta ação não pode ser anulada.'; } @override - String get darkTheme => 'Dark'; + String get darkTheme => 'Escuro'; @override - String get delete => 'Delete'; + String get delete => 'Eliminar'; @override - String get discard => 'Discard'; + String get discard => 'Descartar'; @override String get editor => 'Editor'; @override - String get file => 'File'; + String get file => 'Ficheiro'; @override - String get fileHistory => 'File History'; + String get fileHistory => 'Histórico do ficheiro'; @override - String get folder => 'Folder'; + String get folder => 'Pasta'; @override - String get insert => 'Insert'; + String get insert => 'Inserir'; @override - String get keyboardShortcuts => 'Keyboard Shortcuts'; + String get keyboardShortcuts => 'Atalhos de teclado'; @override - String get commandPalette => 'Command Palette'; + String get commandPalette => 'Paleta de comandos'; @override - String get commandPaletteHint => 'Type a command'; + String get commandPaletteHint => 'Introduza um comando'; @override - String get commandPaletteEmpty => 'No matching commands'; + String get commandPaletteEmpty => 'Nenhum comando correspondente'; @override String get commandUnavailableInContext => - 'Unavailable in the current editor context'; + 'Este comando não está disponível no contexto atual.'; @override - String get lightTheme => 'Light'; + String get lightTheme => 'Claro'; @override - String get mainMenu => 'Main menu'; + String get mainMenu => 'Menu principal'; @override - String get fullScreen => 'Full Screen'; + String get fullScreen => 'Ecrã inteiro'; @override String get markdown => 'Markdown'; @override - String get open => 'Open'; + String get open => 'Abrir'; @override - String get openInFiles => 'Open in Files'; + String get openInFiles => 'Abrir em Ficheiros'; @override - String get pathActions => 'Path actions'; + String get pathActions => 'Ações do caminho'; @override - String get outline => 'Outline'; + String get outline => 'Estrutura'; @override - String get overwrite => 'Overwrite'; + String get overwrite => 'Sobrescrever'; @override - String get paste => 'Paste'; + String get paste => 'Colar'; @override - String get reading => 'Reading'; + String get reading => 'Leitura'; @override - String get removeFromRecent => 'Remove from Recent'; + String get removeFromRecent => 'Remover dos recentes'; @override - String get recent => 'Recent'; + String get recent => 'Recentes'; @override - String get redo => 'Redo'; + String get redo => 'Refazer'; @override - String get save => 'Save'; + String get save => 'Guardar'; @override - String get search => 'Search'; + String get search => 'Pesquisar'; @override - String get selectAll => 'Select all'; + String get selectAll => 'Selecionar tudo'; @override - String get settings => 'Settings'; + String get settings => 'Definições'; @override - String get source => 'Source'; + String get source => 'Código-fonte'; @override - String get split => 'Split'; + String get split => 'Vista dividida'; @override - String get systemTheme => 'System'; + String get systemTheme => 'Sistema'; @override - String get theme => 'Theme'; + String get theme => 'Tema'; @override - String get appLanguage => 'Language'; + String get appLanguage => 'Idioma'; @override - String get systemLanguage => 'System'; + String get systemLanguage => 'Sistema'; @override String get languageEnglish => 'English'; @@ -374,28 +376,28 @@ class AppLocalizationsPt extends AppLocalizations { String get languageSimplifiedChinese => '简体中文'; @override - String get toggleSidebar => 'Sidebar panel'; + String get toggleSidebar => 'Painel lateral'; @override - String get topLeft => 'Top left'; + String get topLeft => 'Canto superior esquerdo'; @override - String get topRight => 'Top right'; + String get topRight => 'Canto superior direito'; @override - String get undo => 'Undo'; + String get undo => 'Desfazer'; @override - String get validate => 'Validate'; + String get validate => 'Validar'; @override - String get validation => 'Validation'; + String get validation => 'Validação'; @override - String get viewMode => 'View mode'; + String get viewMode => 'Modo de visualização'; @override - String get welcome => 'Welcome'; + String get welcome => 'Bem-vindo'; @override String get writerside => 'Writerside'; @@ -407,311 +409,317 @@ class AppLocalizationsPt extends AppLocalizations { String get fileTypeMarkdown => 'Markdown'; @override - String get fileTypeImages => 'Images'; + String get fileTypeImages => 'Imagens'; @override - String get openMarkdownFile => 'Open Markdown File'; + String get openMarkdownFile => 'Abrir ficheiro Markdown'; @override - String get markdownFileExtensions => '.md or .markdown'; + String get markdownFileExtensions => '.md ou .markdown'; @override String get openFolderOrWritersideProject => - 'Open Folder or Writerside Project'; + 'Abrir pasta ou projeto Writerside'; @override String get markdownFolderOrWritersideProject => - 'Markdown folder or Writerside-compatible project'; + 'Pasta Markdown ou projeto compatível com Writerside'; @override - String get noOpenFile => 'No open file'; + String get noOpenFile => 'Nenhum ficheiro aberto'; @override String get shortcutDeleteTreeItemDescription => - 'Delete the selected Files item, or remove the selected topic from the table of contents'; + 'Eliminar o item selecionado em Ficheiros ou remover o tópico selecionado do sumário'; @override - String get shortcutGroupGeneral => 'General'; + String get shortcutGroupGeneral => 'Geral'; @override - String get shortcutNewDocument => 'Create'; + String get shortcutNewDocument => 'Criar'; @override String get shortcutNewDocumentDescription => - 'Create a Markdown file or Writerside project'; + 'Criar ficheiro Markdown ou projeto Writerside'; @override String get shortcutOpenDescription => - 'Open a Markdown file, folder, or Writerside project'; + 'Abrir um ficheiro Markdown, uma pasta ou um projeto Writerside'; @override - String get shortcutSaveDescription => 'Save the current document'; + String get shortcutSaveDescription => 'Guardar o documento atual'; @override - String get shortcutSearchDescription => 'Search the current workspace'; + String get shortcutSearchDescription => + 'Pesquisar no espaço de trabalho atual'; @override String get shortcutKeyboardShortcutsDescription => - 'Show this keyboard shortcut reference'; + 'Mostrar esta referência de atalhos de teclado'; @override String get shortcutSyntaxReferenceDescription => 'Abrir a referência de sintaxe'; @override - String get shortcutSettingsDescription => 'Open BusyMark settings'; + String get shortcutSettingsDescription => 'Abrir as definições do BusyMark'; @override - String get shortcutNextTab => 'Next tab'; + String get shortcutNextTab => 'Próxima guia'; @override - String get shortcutNextTabDescription => 'Move to the next open tab'; + String get shortcutNextTabDescription => 'Ir para a próxima guia aberta'; @override - String get shortcutPreviousTab => 'Previous tab'; + String get shortcutPreviousTab => 'Guia anterior'; @override - String get shortcutPreviousTabDescription => 'Move to the previous open tab'; + String get shortcutPreviousTabDescription => 'Ir para a guia aberta anterior'; @override - String get shortcutCloseTab => 'Close tab'; + String get shortcutCloseTab => 'Fechar guia'; @override - String get shortcutCloseTabDescription => 'Close the active tab'; + String get shortcutCloseTabDescription => 'Fechar a guia ativa'; @override - String get shortcutCloseAllTabs => 'Close all tabs'; + String get shortcutCloseAllTabs => 'Fechar todas as guias'; @override - String get shortcutCloseAllTabsDescription => 'Close all open tabs'; + String get shortcutCloseAllTabsDescription => 'Fechar todas as guias abertas'; @override - String get shortcutGroupTextEditing => 'Text Editing'; + String get shortcutGroupTextEditing => 'Edição de texto'; @override String get shortcutSelectAllDescription => - 'In Source mode, select all text; in Editor mode, press twice to select every block'; + 'No modo Código-fonte, selecionar todo o texto; no modo Editor, pressionar duas vezes para selecionar todos os blocos'; @override - String get shortcutCutDescription => 'Cut the selected text'; + String get shortcutCutDescription => 'Recortar o texto selecionado'; @override - String get shortcutCopyDescription => 'Copy the selected text'; + String get shortcutCopyDescription => 'Copiar o texto selecionado'; @override - String get shortcutPasteDescription => 'Paste from the clipboard'; + String get shortcutPasteDescription => 'Colar da área de transferência'; @override String get shortcutPastePlainTextDescription => - 'Paste clipboard text without formatting'; + 'Colar o texto da área de transferência sem formatação'; @override - String get shortcutUndoDescription => 'Undo the last edit'; + String get shortcutUndoDescription => 'Desfazer a última edição'; @override - String get shortcutRedoDescription => 'Redo the last undone edit'; + String get shortcutRedoDescription => 'Refazer a última edição desfeita'; @override - String get shortcutInsertIndentation => 'Insert indentation'; + String get shortcutInsertIndentation => 'Inserir recuo'; @override String get shortcutInsertIndentationDescription => - 'Insert indentation at the cursor'; + 'Inserir recuo na posição do cursor'; @override - String get shortcutOutdentSource => 'Outdent source'; + String get shortcutOutdentSource => 'Diminuir recuo do código-fonte'; @override String get shortcutOutdentSourceDescription => - 'Remove one indentation level in Source mode'; + 'Remover um nível de recuo no modo Código-fonte'; @override - String get shortcutEscape => 'Close search or clear block selection'; + String get shortcutEscape => + 'Fechar a pesquisa ou limpar a seleção de blocos'; @override String get shortcutEscapeDescription => - 'Close workspace search or clear a block selection in Editor mode'; + 'Fechar a pesquisa do espaço de trabalho ou limpar uma seleção de blocos no modo Editor'; @override - String get shortcutGroupFormatting => 'Formatting'; + String get shortcutGroupFormatting => 'Formatação'; @override - String get shortcutBoldDescription => 'Toggle bold on the selected text'; + String get shortcutBoldDescription => 'Alternar negrito no texto selecionado'; @override - String get shortcutItalicDescription => 'Toggle italic on the selected text'; + String get shortcutItalicDescription => + 'Alternar itálico no texto selecionado'; @override String get shortcutUnderlineDescription => - 'Toggle underline on the selected text'; + 'Alternar sublinhado no texto selecionado'; @override - String get shortcutLinkDescription => 'Insert or edit a link'; + String get shortcutLinkDescription => 'Inserir ou editar uma ligação'; @override String get shortcutInlineCodeDescription => - 'Toggle inline code on the selected text'; + 'Alternar código embutido no texto selecionado'; @override String get shortcutStrikethroughDescription => - 'Toggle strikethrough on the selected text'; + 'Alternar tachado no texto selecionado'; @override - String get shortcutGroupBlocks => 'Blocks'; + String get shortcutGroupBlocks => 'Blocos'; @override String get shortcutParagraphDescription => - 'Set the current block to paragraph'; + 'Definir o bloco atual como parágrafo'; @override String get shortcutHeading1Description => - 'Set the current block to Heading 1'; + 'Definir o bloco atual como Título 1'; @override String get shortcutHeading2Description => - 'Set the current block to Heading 2'; + 'Definir o bloco atual como Título 2'; @override String get shortcutHeading3Description => - 'Set the current block to Heading 3'; + 'Definir o bloco atual como Título 3'; @override String get shortcutHeading4Description => - 'Set the current block to Heading 4'; + 'Definir o bloco atual como Título 4'; @override String get shortcutHeading5Description => - 'Set the current block to Heading 5'; + 'Definir o bloco atual como Título 5'; @override String get shortcutHeading6Description => - 'Set the current block to Heading 6'; + 'Definir o bloco atual como Título 6'; @override - String get shortcutGroupLists => 'Lists'; + String get shortcutGroupLists => 'Listas'; @override - String get numberedList => 'Numbered list'; + String get numberedList => 'Lista numerada'; @override String get shortcutNumberedListDescription => - 'Toggle numbered list formatting'; + 'Alternar formatação de lista numerada'; @override - String get bulletedList => 'Bulleted list'; + String get bulletedList => 'Lista com marcadores'; @override String get shortcutBulletedListDescription => - 'Toggle bulleted list formatting'; + 'Alternar formatação de lista com marcadores'; @override - String get checklist => 'Checklist'; + String get checklist => 'Lista de verificação'; @override - String get shortcutChecklistDescription => 'Toggle checklist formatting'; + String get shortcutChecklistDescription => + 'Alternar formatação de lista de verificação'; @override - String get shortcutGroupSidebar => 'Sidebar'; + String get shortcutGroupSidebar => 'Barra lateral'; @override - String get sidebarViewMenu => 'Sidebar view'; + String get sidebarViewMenu => 'Visualização da barra lateral'; @override - String get createMarkdownFile => 'Create Markdown File'; + String get createMarkdownFile => 'Criar ficheiro Markdown'; @override String get createMarkdownFileDescription => - 'Start an unsaved local Markdown document'; + 'Iniciar um documento Markdown local não guardado'; @override - String get createWritersideProject => 'Create Writerside Project'; + String get createWritersideProject => 'Criar projeto Writerside'; @override String get createWritersideProjectDescription => - 'Start a local Writerside-compatible project'; + 'Iniciar um projeto local compatível com Writerside'; @override - String get defaultProjectName => 'Documentation'; + String get defaultProjectName => 'Documentação'; @override - String get defaultInstanceName => 'User Guide'; + String get defaultInstanceName => 'Guia do utilizador'; @override - String get defaultStartTopicTitle => 'Getting started'; + String get defaultStartTopicTitle => 'Primeiros passos'; @override - String get projectName => 'Project name'; + String get projectName => 'Nome do projeto'; @override - String get directoryName => 'Directory name'; + String get directoryName => 'Nome do diretório'; @override - String get instanceName => 'Instance name'; + String get instanceName => 'Nome da instância'; @override - String get instanceId => 'Instance ID'; + String get instanceId => 'ID da instância'; @override - String get startTopicTitle => 'Start topic title'; + String get startTopicTitle => 'Título do tópico inicial'; @override - String get location => 'Location'; + String get location => 'Local'; @override - String get projectNameRequired => 'Project name is required.'; + String get projectNameRequired => 'O nome do projeto é obrigatório.'; @override - String get directoryNameRequired => 'Directory name is required.'; + String get directoryNameRequired => 'O nome do diretório é obrigatório.'; @override - String get useSingleSafeDirectoryName => 'Use a single safe directory name.'; + String get useSingleSafeDirectoryName => + 'Use um único nome de diretório seguro.'; @override String get useLowercaseIdentifier => - 'Use a lowercase identifier with letters, numbers, underscores, or hyphens.'; + 'Use um identificador em minúsculas com letras, números, sublinhados ou hifens.'; @override - String get startTopicTitleRequired => 'Start topic title is required.'; + String get startTopicTitleRequired => + 'O título do tópico inicial é obrigatório.'; @override String get createWritersideProjectFailed => - 'Could not create Writerside project.'; + 'Não foi possível criar o projeto Writerside.'; @override - String get settingsTitle => 'BusyMark Settings'; + String get settingsTitle => 'Definições do BusyMark'; @override - String get autoSave => 'Auto Save'; + String get autoSave => 'Gravação automática'; @override String get autoSaveDescription => - 'Save file changes automatically after a short idle delay.'; + 'Guarda automaticamente as alterações do ficheiro após um curto período de inatividade.'; @override - String get wordWrap => 'Word wrap'; + String get wordWrap => 'Quebra de linha'; @override - String get editorFontSize => 'Editor font size'; + String get editorFontSize => 'Tamanho da fonte do editor'; @override - String get validateOnEdit => 'Validate on edit'; + String get validateOnEdit => 'Validar ao editar'; @override - String get clearRecentWorkspaces => 'Clear recent workspaces'; + String get clearRecentWorkspaces => 'Limpar espaços de trabalho recentes'; @override - String get editingButtonsPosition => 'Editing buttons position'; + String get editingButtonsPosition => 'Posição dos botões de edição'; @override String get editingButtonsPositionDescription => - 'Choose where the floating WYSIWYG editing buttons appear.'; + 'Escolha onde os botões flutuantes de edição WYSIWYG aparecem.'; @override - String get editingButtonsDirection => 'Editing buttons direction'; + String get editingButtonsDirection => 'Orientação dos botões de edição'; @override String get editingButtonsDirectionDescription => - 'Choose whether the floating WYSIWYG editing buttons are arranged horizontally or vertically.'; + 'Escolha se os botões flutuantes de edição WYSIWYG ficam dispostos horizontalmente ou verticalmente.'; @override String get horizontal => 'Horizontal'; @@ -720,54 +728,56 @@ class AppLocalizationsPt extends AppLocalizations { String get vertical => 'Vertical'; @override - String get privacy => 'Privacy'; + String get privacy => 'Privacidade'; @override - String get allowRemoteImages => 'Load remote images'; + String get allowRemoteImages => 'Carregar imagens remotas'; @override String get allowRemoteImagesDescription => - 'Allow Markdown preview and editor images to load from http and https URLs.'; + 'Permitir que a pré-visualização do Markdown e o editor carreguem imagens de URLs HTTP e HTTPS.'; @override - String get clearRemoteImagePermissions => 'Clear remote image permissions'; + String get clearRemoteImagePermissions => + 'Limpar permissões de imagens remotas'; @override String get clearRemoteImagePermissionsDescription => - 'Forget workspaces that were allowed to load remote images.'; + 'Esquecer os espaços de trabalho autorizados a carregar imagens remotas.'; @override - String get clearGitWorkspaceTrust => 'Clear trusted Git workspaces'; + String get clearGitWorkspaceTrust => + 'Limpar espaços de trabalho confiáveis para o Git'; @override String get clearGitWorkspaceTrustDescription => - 'Ask before enabling Git features for previously trusted workspaces.'; + 'Perguntar antes de ativar recursos do Git em espaços de trabalho considerados confiáveis anteriormente.'; @override - String get settingsWindowSectionTitle => 'Window'; + String get settingsWindowSectionTitle => 'Janela'; @override String get settingsReopenWorkspaceOnStartupTitle => - 'Reopen previous workspace on startup'; + 'Reabrir o espaço de trabalho anterior ao iniciar'; @override String get settingsReopenWorkspaceOnStartupDescription => - 'Open the workspace and tabs from the previous session when BusyMark starts.'; + 'Abra o espaço de trabalho e as abas da sessão anterior quando o BusyMark iniciar.'; @override String get settingsConfirmCloseWithUnsavedChangesTitle => - 'Confirm before closing with unsaved changes'; + 'Confirmar antes de fechar com alterações não guardadas'; @override String get settingsConfirmCloseWithUnsavedChangesDescription => - 'Ask before closing BusyMark when documents have unsaved changes.'; + 'Perguntar antes de fechar o BusyMark quando documentos tiverem alterações não guardadas.'; @override - String get closeUnsavedChangesTitle => 'Unsaved changes'; + String get closeUnsavedChangesTitle => 'Alterações não guardadas'; @override String get closeUnsavedChangesSingleMessage => - 'This document has unsaved changes. Save changes before closing BusyMark?'; + 'Este documento tem alterações não guardadas. Guardar as alterações antes de fechar o BusyMark?'; @override String closeUnsavedChangesMultipleMessage(int count) { @@ -775,32 +785,32 @@ class AppLocalizationsPt extends AppLocalizations { count, locale: localeName, other: - '$count documents have unsaved changes. Save changes before closing BusyMark?', + '$count documentos têm alterações não guardadas. Guardar as alterações antes de fechar o BusyMark?', one: - '1 document has unsaved changes. Save changes before closing BusyMark?', - zero: 'Save changes before closing BusyMark?', + '1 documento tem alterações não guardadas. Guardar as alterações antes de fechar o BusyMark?', + zero: 'Guardar as alterações antes de fechar o BusyMark?', ); return '$_temp0'; } @override - String get closeUnsavedChangesCancel => 'Cancel'; + String get closeUnsavedChangesCancel => 'Cancelar'; @override - String get closeUnsavedChangesDiscard => 'Discard'; + String get closeUnsavedChangesDiscard => 'Descartar'; @override - String get closeUnsavedChangesSave => 'Save'; + String get closeUnsavedChangesSave => 'Guardar'; @override - String get currentFile => 'current file'; + String get currentFile => 'ficheiro atual'; @override - String get unsavedChanges => 'Unsaved changes'; + String get unsavedChanges => 'Alterações não guardadas'; @override String unsavedChangesMessage(String fileName) { - return 'You have unsaved changes in $fileName. Save them before continuing?'; + return 'Existem alterações não guardadas em $fileName. Pretende guardá-las antes de continuar?'; } @override @@ -809,157 +819,158 @@ class AppLocalizationsPt extends AppLocalizations { count, locale: localeName, other: - '$count documents have unsaved changes. Save them before continuing?', - one: '1 document has unsaved changes. Save it before continuing?', + 'Existem $count documentos com alterações não guardadas. Pretende guardá-los antes de continuar?', + one: + 'Existe 1 documento com alterações não guardadas. Pretende guardá-lo antes de continuar?', ); return '$_temp0'; } @override - String get fileChangedOnDisk => 'File changed on disk'; + String get fileChangedOnDisk => 'Ficheiro alterado no disco'; @override String get fileChangedOnDiskMessage => - 'This file changed on disk since you opened it. Overwrite it?'; + 'Este ficheiro foi alterado no disco desde que foi aberto. Sobrescrever?'; @override - String get untitledMarkdownFileName => 'Untitled.md'; + String get untitledMarkdownFileName => 'Sem título.md'; @override - String get unorderedList => 'Unordered list'; + String get unorderedList => 'Lista não ordenada'; @override - String get orderedList => 'Ordered list'; + String get orderedList => 'Lista ordenada'; @override - String get taskList => 'Task list'; + String get taskList => 'Lista de tarefas'; @override - String get toggleTaskChecked => 'Toggle task checked'; + String get toggleTaskChecked => 'Marcar/desmarcar tarefa'; @override - String get indentListItem => 'Indent list item'; + String get indentListItem => 'Recuar item da lista'; @override - String get outdentListItem => 'Outdent list item'; + String get outdentListItem => 'Remover recuo do item da lista'; @override - String get blockquote => 'Blockquote'; + String get blockquote => 'Citação em bloco'; @override - String get codeBlock => 'Code block'; + String get codeBlock => 'Bloco de código'; @override - String get codeBlockLanguage => 'Code block language'; + String get codeBlockLanguage => 'Linguagem do bloco de código'; @override - String get image => 'Image'; + String get image => 'Imagem'; @override - String get video => 'Video'; + String get video => 'Vídeo'; @override - String get openVideo => 'Play video'; + String get openVideo => 'Reproduzir vídeo'; @override - String get pauseVideo => 'Pause video'; + String get pauseVideo => 'Pausar vídeo'; @override - String get videoUnavailable => 'Video unavailable'; + String get videoUnavailable => 'Vídeo indisponível'; @override - String get videoPreview => 'Video preview'; + String get videoPreview => 'Pré-visualização do vídeo'; @override String get diagnosticWritersideVideoMissingSource => - 'Video is missing its src attribute.'; + 'O vídeo não tem o atributo src.'; @override String diagnosticWritersideVideoUnsupportedSource(String source) { - return 'Unsupported video source: $source'; + return 'Fonte de vídeo não suportada: $source'; } @override String diagnosticWritersideVideoMissingFile(String source) { - return 'Video file does not exist: $source'; + return 'O ficheiro de vídeo não existe: $source'; } @override String diagnosticWritersideVideoMissingPreview(String preview) { - return 'Video preview image does not exist: $preview'; + return 'A imagem de pré-visualização do vídeo não existe: $preview'; } @override - String get inlineImage => 'Inline image'; + String get inlineImage => 'Imagem embutida'; @override - String get table => 'Table'; + String get table => 'Tabela'; @override - String get htmlBlock => 'HTML block'; + String get htmlBlock => 'Bloco HTML'; @override - String get htmlContentDefault => 'HTML content'; + String get htmlContentDefault => 'Conteúdo HTML'; @override - String get shortcutHtmlBlockDescription => 'Insert or edit an HTML block'; + String get shortcutHtmlBlockDescription => 'Inserir ou editar um bloco HTML'; @override - String get renderedHtml => 'Rendered HTML'; + String get renderedHtml => 'HTML renderizado'; @override - String get editHtml => 'Edit HTML'; + String get editHtml => 'Editar HTML'; @override - String get htmlSource => 'HTML source'; + String get htmlSource => 'Código-fonte HTML'; @override - String get thematicBreak => 'Thematic break'; + String get thematicBreak => 'Separador temático'; @override - String get bold => 'Bold'; + String get bold => 'Negrito'; @override - String get italic => 'Italic'; + String get italic => 'Itálico'; @override - String get underline => 'Underline'; + String get underline => 'Sublinhado'; @override - String get strikethrough => 'Strikethrough'; + String get strikethrough => 'Tachado'; @override - String get inlineCode => 'Inline code'; + String get inlineCode => 'Código embutido'; @override - String get link => 'Link'; + String get link => 'Ligação'; @override - String get hardLineBreak => 'Hard line break'; + String get hardLineBreak => 'Quebra de linha forçada'; @override - String get textStyle => 'Text style'; + String get textStyle => 'Estilo de texto'; @override - String get paragraph => 'Paragraph'; + String get paragraph => 'Parágrafo'; @override - String get heading1 => 'Heading 1'; + String get heading1 => 'Título 1'; @override - String get heading2 => 'Heading 2'; + String get heading2 => 'Título 2'; @override - String get heading3 => 'Heading 3'; + String get heading3 => 'Título 3'; @override - String get heading4 => 'Heading 4'; + String get heading4 => 'Título 4'; @override - String get heading5 => 'Heading 5'; + String get heading5 => 'Título 5'; @override - String get heading6 => 'Heading 6'; + String get heading6 => 'Título 6'; @override String headingLevelAbbreviation(int level) { @@ -967,264 +978,266 @@ class AppLocalizationsPt extends AppLocalizations { } @override - String get deleteTable => 'Delete table'; + String get deleteTable => 'Eliminar tabela'; @override String tableColumnNumber(int columnNumber) { - return 'Column $columnNumber'; + return 'Coluna $columnNumber'; } @override - String get insertColumnLeft => 'Insert column left'; + String get insertColumnLeft => 'Inserir coluna à esquerda'; @override - String get insertColumnRight => 'Insert column right'; + String get insertColumnRight => 'Inserir coluna à direita'; @override - String get deleteColumn => 'Delete column'; + String get deleteColumn => 'Eliminar coluna'; @override - String get tableAlignmentUnspecified => 'Alignment: Unspecified'; + String get tableAlignmentUnspecified => 'Alinhamento: não especificado'; @override - String get tableAlignmentLeft => 'Alignment: Left'; + String get tableAlignmentLeft => 'Alinhamento: esquerda'; @override - String get tableAlignmentCenter => 'Alignment: Center'; + String get tableAlignmentCenter => 'Alinhamento: centro'; @override - String get tableAlignmentRight => 'Alignment: Right'; + String get tableAlignmentRight => 'Alinhamento: direita'; @override String tableRowNumber(int rowNumber) { - return 'Row $rowNumber'; + return 'Linha $rowNumber'; } @override - String get insertRowAbove => 'Insert row above'; + String get insertRowAbove => 'Inserir linha acima'; @override - String get insertRowBelow => 'Insert row below'; + String get insertRowBelow => 'Inserir linha abaixo'; @override - String get deleteRow => 'Delete row'; + String get deleteRow => 'Eliminar linha'; @override - String get tableHeaderHint => 'Header'; + String get tableHeaderHint => 'Cabeçalho'; @override - String get tableCellHint => 'Cell'; + String get tableCellHint => 'Célula'; @override - String get language => 'Language'; + String get language => 'Linguagem'; @override - String get hideEditingButtons => 'Hide editing buttons'; + String get hideEditingButtons => 'Ocultar botões de edição'; @override - String get showEditingButtons => 'Show editing buttons'; + String get showEditingButtons => 'Mostrar botões de edição'; @override - String get altText => 'Alt text'; + String get altText => 'Texto alternativo'; @override - String get editorPlaceholderText => 'text'; + String get editorPlaceholderText => 'texto'; @override - String get editorPlaceholderCode => 'code'; + String get editorPlaceholderCode => 'código'; @override - String get editorPlaceholderAltText => 'alt text'; + String get editorPlaceholderAltText => 'texto alternativo'; @override - String get describeTheImage => 'Describe the image'; + String get describeTheImage => 'Descreva a imagem'; @override - String get columns => 'Columns'; + String get columns => 'Colunas'; @override - String get rows => 'Rows'; + String get rows => 'Linhas'; @override String tableHeaderNumber(int columnNumber) { - return 'Header $columnNumber'; + return 'Cabeçalho $columnNumber'; } @override - String get tableCellDefault => 'Cell'; + String get tableCellDefault => 'Célula'; @override - String get noImageSource => 'No image source'; + String get noImageSource => 'Nenhuma origem de imagem'; @override - String get remoteImageBlocked => 'Remote image blocked'; + String get remoteImageBlocked => 'Imagem remota bloqueada'; @override String get remoteImageBlockedTooltip => - 'Choose whether BusyMark can load remote images.'; + 'Escolha se o BusyMark pode carregar imagens remotas.'; @override - String get remoteImagesBlockedTitle => 'Remote images are blocked'; + String get remoteImagesBlockedTitle => 'As imagens remotas estão bloqueadas'; @override String get remoteImagesBlockedMessage => - 'This document references images from the internet. Loading them can reveal network information to the image host.'; + 'Este documento faz referência a imagens da Internet. Carregá-las pode revelar informações de rede ao servidor que as hospeda.'; @override - String get loadRemoteImagesForWorkspace => 'Load for this workspace'; + String get loadRemoteImagesForWorkspace => + 'Carregar neste espaço de trabalho'; @override - String get alwaysLoadRemoteImages => 'Always load remote images'; + String get alwaysLoadRemoteImages => 'Sempre carregar imagens remotas'; @override - String get hideSidebar => 'Hide sidebar panel'; + String get hideSidebar => 'Ocultar painel lateral'; @override - String get showSidebar => 'Show sidebar panel'; + String get showSidebar => 'Mostrar painel lateral'; @override - String get showPreview => 'Show preview'; + String get showPreview => 'Mostrar pré-visualização'; @override - String get hidePreview => 'Hide preview'; + String get hidePreview => 'Ocultar pré-visualização'; @override - String get workspaceKindUnsavedMarkdown => 'Unsaved Markdown file'; + String get workspaceKindUnsavedMarkdown => 'Ficheiro Markdown não guardado'; @override - String get workspaceKindSingleMarkdown => 'Single Markdown file'; + String get workspaceKindSingleMarkdown => 'Ficheiro Markdown único'; @override - String get workspaceKindMarkdownFolder => 'Markdown folder'; + String get workspaceKindMarkdownFolder => 'Pasta Markdown'; @override - String get workspaceKindWritersideModule => 'Writerside module'; + String get workspaceKindWritersideModule => 'Módulo Writerside'; @override - String get problems => 'Problems'; + String get problems => 'Problemas'; @override String diagnosticCount(int count) { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count diagnostics', - one: '1 diagnostic', - zero: 'No diagnostics', + other: '$count diagnósticos', + one: '1 diagnóstico', + zero: 'Nenhum diagnóstico', ); return '$_temp0'; } @override - String get files => 'Files'; + String get files => 'Ficheiros'; @override String get toc => 'TOC'; @override - String get tocActions => 'TOC actions'; + String get tocActions => 'Ações do sumário'; @override - String get markdownUnsaved => 'Markdown - unsaved'; + String get markdownUnsaved => 'Markdown - não guardado'; @override String workspaceDetail(String kind, int count) { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count files', - one: '1 file', + other: '$count ficheiros', + one: '1 ficheiro', ); return '$kind - $_temp0'; } @override - String get noFiles => 'No files'; + String get noFiles => 'Nenhum ficheiro'; @override - String get newFile => 'New file'; + String get newFile => 'Novo ficheiro'; @override - String get noWritersideToc => 'No Writerside TOC'; + String get noWritersideToc => 'Nenhum TOC do Writerside'; @override - String get tocSection => 'TOC section'; + String get tocSection => 'Secção do TOC'; @override - String get newTopic => 'New Topic'; + String get newTopic => 'Novo tópico'; @override - String get newChildTopic => 'New Child Topic'; + String get newChildTopic => 'Novo subtópico'; @override - String get newSiblingTopic => 'New Sibling Topic'; + String get newSiblingTopic => 'Novo tópico no mesmo nível'; @override - String get renameTopicFile => 'Rename Topic File'; + String get renameTopicFile => 'Renomear ficheiro do tópico'; @override - String get topicPlacement => 'TOC placement'; + String get topicPlacement => 'Posição no TOC'; @override - String get tocRoot => 'At TOC root'; + String get tocRoot => 'Na raiz do TOC'; @override - String get afterSelectedTopic => 'After selected topic'; + String get afterSelectedTopic => 'Após o tópico selecionado'; @override - String get insideSelectedTopic => 'Inside selected topic'; + String get insideSelectedTopic => 'Dentro do tópico selecionado'; @override - String get pasteAfterTopic => 'Paste After'; + String get pasteAfterTopic => 'Colar depois'; @override - String get pasteAsChildTopic => 'Paste as Child'; + String get pasteAsChildTopic => 'Colar como subtópico'; @override - String get removeFromToc => 'Remove from TOC'; + String get removeFromToc => 'Remover do TOC'; @override - String get confirmRemoveFromTocTitle => 'Remove from TOC?'; + String get confirmRemoveFromTocTitle => 'Remover do TOC?'; @override String confirmRemoveFromTocMessage(String name) { - return 'Remove $name from this table of contents? The topic file will be kept.'; + return 'Remover $name deste TOC? O ficheiro do tópico será mantido.'; } @override - String get confirmDeleteTopicTitle => 'Delete topic file?'; + String get confirmDeleteTopicTitle => 'Eliminar o ficheiro do tópico?'; @override String confirmDeleteTopicMessage(String name) { - return 'Delete $name and remove it from every table of contents? This cannot be undone.'; + return 'Eliminar $name e removê-lo de todos os TOCs? Esta ação não pode ser anulada.'; } @override - String get safeDeleteTopicFile => 'Safe Delete Topic File…'; + String get safeDeleteTopicFile => + 'Eliminar o ficheiro do tópico com segurança…'; @override - String get removeTocElement => 'Remove TOC Element'; + String get removeTocElement => 'Remover elemento do TOC'; @override - String get removeTocElements => 'Remove TOC Elements'; + String get removeTocElements => 'Remover elementos do TOC'; @override - String get reviewUsages => 'Review Usages'; + String get reviewUsages => 'Rever usos'; @override - String get deleteTopicFile => 'Delete Topic File'; + String get deleteTopicFile => 'Eliminar ficheiro do tópico'; @override - String get removeAction => 'Remove'; + String get removeAction => 'Remover'; @override String topicRemovalSummary(String topic) { - return 'Remove “$topic” from the selected instance. The topic file will be kept.'; + return 'Remova “$topic” da instância selecionada. O ficheiro do tópico será mantido.'; } @override String safeDeleteTopicSummary(String topic) { - return 'Delete “$topic” and safely update its references throughout this Writerside project.'; + return 'Elimine “$topic” e atualize com segurança as referências a ele em todo este projeto Writerside.'; } @override @@ -1232,470 +1245,468 @@ class AppLocalizationsPt extends AppLocalizations { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count child topics will move up one level.', - one: '1 child topic will move up one level.', + other: 'Os $count tópicos filhos subirão um nível.', + one: 'O tópico filho subirá um nível.', ); return '$_temp0'; } @override String get topicIsStartPageRemovalWarning => - 'This topic is used as an instance start page. Review its usages and assign another start page before continuing.'; + 'Este tópico é usado como página inicial de uma instância. Reveja os usos dele e atribua outra página inicial antes de continuar.'; @override String topicUsagesCount(int count) { - return 'Usages ($count)'; + return 'Usos ($count)'; } @override String get noBreakingTopicUsages => - 'No references that would be broken were found.'; + 'Não foram encontradas referências que deixariam de funcionar.'; @override String get topicUsagesFound => - 'BusyMark found the following references to this topic.'; + 'O BusyMark encontrou as seguintes referências a este tópico.'; @override - String get topicUsageTocElements => 'TOC elements'; + String get topicUsageTocElements => 'Elementos do TOC'; @override - String get topicUsageStartPages => 'Start pages'; + String get topicUsageStartPages => 'Páginas iniciais'; @override - String get topicUsageTopicLinks => 'Topic links'; + String get topicUsageTopicLinks => 'Ligações para tópicos'; @override - String get topicUsageIncludes => 'Includes'; + String get topicUsageIncludes => 'Inclusões'; @override String usageCount(int count) { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count usages', - one: '1 usage', + other: '$count usos', + one: '1 uso', ); return '$_temp0'; } @override - String get refactoringOptions => 'Refactoring options'; + String get refactoringOptions => 'Opções de refatoração'; @override - String get updateUsagesAutomatically => 'Update usages automatically'; + String get updateUsagesAutomatically => 'Atualizar usos automaticamente'; @override String get updateUsagesAutomaticallyDescription => - 'Remove TOC references and includes, and preserve link text.'; + 'Remova referências dos TOCs e inclusões e preserve o texto dos ligações.'; @override String get manualUsageUpdatesRequired => - 'Some usages require manual changes before this refactoring.'; + 'Alguns usos exigem alterações manuais antes desta refatoração.'; @override - String get setRedirectTo => 'Set redirect to'; + String get setRedirectTo => 'Redirecionar para'; @override - String get noRedirectDescription => 'Do not redirect the old published page.'; + String get noRedirectDescription => + 'Não redirecionar a página publicada antiga.'; @override - String get redirectTarget => 'Redirect target'; + String get redirectTarget => 'Destino do redirecionamento'; @override String get remainingUsagesBlockRemoval => - 'Review and update the remaining usages before continuing, or enable automatic updates when available.'; + 'Reveja e atualize os usos restantes antes de continuar ou ative as atualizações automáticas quando estiverem disponíveis.'; @override String usagesOfTopic(String topic) { - return 'Usages of $topic'; + return 'Usos de $topic'; } @override - String get noUsagesFound => 'No usages found'; + String get noUsagesFound => 'Nenhum uso encontrado.'; @override - String get outsideSelectedInstance => 'outside selected instance'; + String get outsideSelectedInstance => 'Fora da instância selecionada'; @override - String get doRefactor => 'Do Refactor'; + String get doRefactor => 'Refatorar'; @override - String get orphanTopicTitle => 'Topic file is no longer used'; + String get orphanTopicTitle => 'O ficheiro do tópico não é mais usado'; @override - String get keepTopicFile => 'Keep Topic File'; + String get keepTopicFile => 'Manter o ficheiro do tópico'; @override String orphanTopicMessage(String topic) { - return '“$topic” is no longer used anywhere in this Writerside project. Delete the file, or keep it for use in another instance.'; + return '“$topic” não é mais usado em nenhum lugar deste projeto Writerside. Elimine o ficheiro ou mantenha-o para uso em outra instância.'; } @override - String get defaultNewTopicTitle => 'New topic'; + String get defaultNewTopicTitle => 'Novo tópico'; @override - String get topicTitle => 'Topic title'; + String get topicTitle => 'Título do tópico'; @override - String get fileName => 'File name'; + String get fileName => 'Nome do ficheiro'; @override - String get topicTitleRequired => 'Topic title is required.'; + String get topicTitleRequired => 'O título do tópico é obrigatório.'; @override - String get fileNameRequired => 'File name is required.'; + String get fileNameRequired => 'O nome do ficheiro é obrigatório.'; @override - String get rename => 'Rename'; + String get rename => 'Renomear'; @override - String get confirmDeleteFileTitle => 'Delete file?'; + String get confirmDeleteFileTitle => 'Eliminar ficheiro?'; @override - String get confirmDeleteFolderTitle => 'Delete folder?'; + String get confirmDeleteFolderTitle => 'Eliminar pasta?'; @override String confirmDeleteFileMessage(String name) { - return 'Delete $name? This cannot be undone.'; + return 'Eliminar $name? Esta ação não pode ser anulada.'; } @override String confirmDeleteFolderMessage(String name) { - return 'Delete $name and all files inside it? This cannot be undone.'; + return 'Eliminar $name e todos os ficheiros dentro dela? Esta ação não pode ser anulada.'; } @override - String get useSingleSafeFileName => 'Use a single safe file name.'; + String get useSingleSafeFileName => 'Use um único nome de ficheiro seguro.'; @override String useExpectedExtension(String extension) { - return 'Use the $extension extension for the selected format.'; + return 'Use a extensão $extension para o formato selecionado.'; } @override String get useIdentifierCharacters => - 'Use letters, numbers, underscores, or hyphens before the extension.'; + 'Use letras, números, sublinhados ou hifens antes da extensão.'; @override - String get topicIdAlreadyExists => 'Topic ID already exists.'; + String get topicIdAlreadyExists => 'O ID do tópico já existe.'; @override String get createWritersideTopicFailed => - 'Could not create Writerside topic.'; + 'Não foi possível criar o tópico do Writerside.'; @override - String get noOutline => 'No outline'; + String get noOutline => 'Sem estrutura'; @override String expandKind(String kind) { - return 'Expand $kind'; + return 'Expandir $kind'; } @override String collapseKind(String kind) { - return 'Collapse $kind'; + return 'Recolher $kind'; } @override - String get foldKindSection => 'section'; + String get foldKindSection => 'secção'; @override - String get foldKindList => 'list'; + String get foldKindList => 'lista'; @override - String get foldKindQuote => 'quote'; + String get foldKindQuote => 'citação'; @override String get foldKindTag => 'tag'; @override - String get sourceSearchPreviousMatch => 'Previous match'; + String get sourceSearchPreviousMatch => 'Correspondência anterior'; @override - String get sourceSearchNextMatch => 'Next match'; + String get sourceSearchNextMatch => 'Próxima correspondência'; @override - String get sourceSearchCaseSensitive => 'Case sensitive'; + String get sourceSearchCaseSensitive => + 'Diferenciar maiúsculas de minúsculas'; @override - String get sourceSearchWholeWord => 'Whole word'; + String get sourceSearchWholeWord => 'Palavra inteira'; @override - String get sourceSearchRegex => 'Regex'; + String get sourceSearchRegex => 'Expressão regular'; @override - String get sourceSearchReplacement => 'Replace with'; + String get sourceSearchReplacement => 'Substituir por'; @override - String get sourceSearchReplaceCurrent => 'Replace current match'; + String get sourceSearchReplaceCurrent => 'Substituir correspondência atual'; @override - String get sourceSearchReplaceAndFindNext => 'Replace and find next'; + String get sourceSearchReplaceAndFindNext => 'Substituir e localizar próximo'; @override - String get sourceSearchReplaceAll => 'Replace all'; + String get sourceSearchReplaceAll => 'Substituir tudo'; @override - String get workspaceReplace => 'Replace in Workspace'; + String get workspaceReplace => 'Substituir no espaço de trabalho'; @override - String get reviewReplacements => 'Review replacements'; + String get reviewReplacements => 'Rever substituições'; @override - String get applyReplacements => 'Apply replacements'; + String get applyReplacements => 'Aplicar substituições'; @override - String get skippedFiles => 'Skipped files'; + String get skippedFiles => 'Ficheiros ignorados'; @override - String get workspaceReplaceDirtyBuffer => 'Unsaved editor content'; + String get workspaceReplaceDirtyBuffer => 'Conteúdo não guardado do editor'; @override - String get workspaceReplaceDiskContent => 'Saved disk content'; + String get workspaceReplaceDiskContent => 'Conteúdo guardado no disco'; @override String selectFileMatches(int count) { - String _temp0 = intl.Intl.pluralLogic( - count, - locale: localeName, - other: 'Select all $count matches', - one: 'Select 1 match', - ); - return '$_temp0'; + return 'Selecionar todas as $count correspondências'; } @override String workspaceReplaceApplied(int matches, int files, int skipped) { - return 'Replaced $matches matches in $files files; skipped $skipped.'; + return 'Foram substituídas $matches correspondências em $files ficheiros; $skipped ignoradas.'; } @override String documentFormatWithFinalNewline(String encoding, String lineEnding) { - return '$encoding · $lineEnding · Final newline'; + return '$encoding · $lineEnding · Quebra de linha final'; } @override String documentFormatWithoutFinalNewline(String encoding, String lineEnding) { - return '$encoding · $lineEnding · No final newline'; + return '$encoding · $lineEnding · Sem quebra de linha final'; } @override - String get normalizeLineEndings => 'Normalize line endings'; + String get normalizeLineEndings => 'Normalizar finais de linha'; @override String get mixedLineEndingsSavePrompt => - 'This document contains mixed line endings. Choose a format.'; + 'Este documento contém finais de linha mistos. Escolha um formato.'; @override String workspaceReplaceMixedLineEndings(String fileName) { - return '$fileName uses mixed line endings. Choose the format to use before replacing.'; + return '$fileName usa finais de linha mistos. Escolha o formato antes de substituir.'; } @override - String get workspaceReplaceIssueOversized => 'Skipped an oversized file.'; + String get workspaceReplaceIssueOversized => + 'Foi ignorado um ficheiro demasiado grande.'; @override String get workspaceReplaceIssueUnreadable => - 'Skipped a file that could not be read.'; + 'Um ficheiro que não pôde ser lido foi ignorado.'; @override String get workspaceReplaceIssueInvalidUtf8 => - 'Skipped a file that is not valid UTF-8.'; + 'Um ficheiro que não é UTF-8 válido foi ignorado.'; @override String get workspaceReplaceIssueTruncated => - 'The replacement preview was truncated.'; + 'A pré-visualização de substituições foi truncada.'; @override String get workspaceReplaceIssueFileChanged => - 'Skipped a file that changed after the preview.'; + 'Um ficheiro alterado após a pré-visualização foi ignorado.'; @override String get workspaceReplaceIssueBufferChanged => - 'Skipped an editor buffer that changed after the preview.'; + 'Um buffer do editor alterado após a pré-visualização foi ignorado.'; @override String get workspaceReplaceIssueNormalizationRequired => - 'Choose LF or CRLF normalization before replacing.'; + 'Escolha a normalização LF ou CRLF antes de substituir.'; @override String get workspaceReplaceIssuePartialConflict => - 'Rollback stopped because the file changed concurrently. Some replacements may remain; displaced content was preserved at the path below.'; + 'A reversão foi interrompida porque o ficheiro foi alterado simultaneamente. Algumas substituições podem permanecer; o conteúdo deslocado foi preservado no caminho abaixo.'; @override String get workspaceReplaceIssueApplyFailed => - 'The reviewed replacement could not be committed; no files were changed.'; + 'Nenhuma substituição foi aplicada porque o conjunto revisto não pôde ser guardado com segurança.'; @override String externalChangesTitle(String fileName) { - return 'External changes — $fileName'; + return 'Alterações externas — $fileName'; } @override - String get externalFileDeleted => 'This file was deleted on disk.'; + String get externalFileDeleted => 'Este ficheiro foi eliminado do disco.'; @override String get externalFileChanged => - 'This file changed on disk while you have unsaved edits.'; + 'Este ficheiro foi alterado no disco enquanto existem alterações não guardadas no editor.'; @override String recoveredDocumentReview(String fileName) { - return 'Recovered unsaved content for $fileName. Inspect it, then save, save as, or discard it.'; + return 'O conteúdo não guardado de $fileName foi recuperado. Reveja-o e, em seguida, guarde-o, guarde-o como ou descarte-o.'; } @override - String get compare => 'Compare'; + String get compare => 'Comparar'; @override - String get reloadFromDisk => 'Reload from Disk'; + String get reloadFromDisk => 'Recarregar do disco'; @override - String get keepMine => 'Keep Mine'; + String get keepMine => 'Manter minha versão'; @override - String get saveAs => 'Save As'; + String get saveAs => 'Guardar como'; @override - String get sourceSearchInvalidRegex => 'Invalid regular expression'; + String get sourceSearchInvalidRegex => 'Expressão regular inválida'; @override String get sourceLargeFileFeaturesPaused => - 'Large file: highlighting and folding are paused'; + 'Ficheiro grande: o realce e o recolhimento estão pausados'; @override - String get nothingToRead => 'Nothing to read'; + String get nothingToRead => 'Nenhum conteúdo para ler'; @override - String get admonition => 'Admonition'; + String get admonition => 'Bloco de destaque'; @override - String get quote => 'Quote'; + String get quote => 'Citação'; @override - String get note => 'Note'; + String get note => 'Observação'; @override - String get tip => 'Tip'; + String get tip => 'Dica'; @override - String get warning => 'Warning'; + String get warning => 'Aviso'; @override - String get tabs => 'Tabs'; + String get tabs => 'Guias'; @override - String get tab => 'Tab'; + String get tab => 'Guia'; @override - String get procedure => 'Procedure'; + String get procedure => 'Procedimento'; @override - String get step => 'Step'; + String get step => 'Etapa'; @override - String get topic => 'Topic'; + String get topic => 'Tópico'; @override - String get chapter => 'Chapter'; + String get chapter => 'Capítulo'; @override String couldNotOpenTarget(String target) { - return 'Could not open $target'; + return 'Não foi possível abrir $target'; } @override String linkTargetNotFound(String targetPath) { - return 'Link target not found: $targetPath'; + return 'Destino da ligação não encontrado: $targetPath'; } @override String get cannotOpenFileTypeInEditor => - 'Cannot open this file type in editor'; + 'Não é possível abrir este tipo de ficheiro no editor'; @override String anchorNotFound(String anchor) { - return 'Anchor not found: $anchor'; + return 'Âncora não encontrada: $anchor'; } @override - String get noProblemsFound => 'No problems found'; + String get noProblemsFound => 'Nenhum problema encontrado'; @override - String get noResults => 'No results'; + String get noResults => 'Nenhum resultado'; @override String searchResultLine(String relativePath, int lineNumber) { - return '$relativePath - Line $lineNumber'; + return '$relativePath - linha $lineNumber'; } @override - String get untitledResult => 'Untitled result'; + String get untitledResult => 'Resultado sem título'; @override - String get documentKindMarkdownFile => 'Markdown file'; + String get documentKindMarkdownFile => 'Ficheiro Markdown'; @override - String get documentKindWritersideMarkdownTopic => 'Writerside Markdown topic'; + String get documentKindWritersideMarkdownTopic => + 'Tópico Markdown do Writerside'; @override - String get documentKindWritersideXmlTopic => 'Writerside XML topic'; + String get documentKindWritersideXmlTopic => 'Tópico XML do Writerside'; @override - String get documentKindWritersideTree => 'Writerside tree'; + String get documentKindWritersideTree => 'Árvore do Writerside'; @override - String get documentKindConfigurationFile => 'Configuration file'; + String get documentKindConfigurationFile => 'Ficheiro de configuração'; @override - String get documentKindVariablesFile => 'Variables file'; + String get documentKindVariablesFile => 'Ficheiro de variáveis'; @override - String get documentKindCategoriesFile => 'Categories file'; + String get documentKindCategoriesFile => 'Ficheiro de categorias'; @override - String get documentKindResourceFile => 'Resource file'; + String get documentKindResourceFile => 'Ficheiro de recursos'; @override String workspaceErrorOpenFailed(String error) { - return 'Open failed: $error'; + return 'Falha ao abrir: $error'; } @override String workspaceErrorCreateWritersideProjectFailed(String error) { - return 'Could not create Writerside project: $error'; + return 'Não foi possível criar o projeto Writerside: $error'; } @override String workspaceErrorCreateWritersideTopicFailed(String error) { - return 'Could not create Writerside topic: $error'; + return 'Não foi possível criar o tópico do Writerside: $error'; } @override String workspaceErrorCouldNotOpenFile(String error) { - return 'Could not open file: $error'; + return 'Não foi possível abrir o ficheiro: $error'; } @override String get workspaceErrorChooseWhereToSaveMarkdown => - 'Choose where to save this Markdown file.'; + 'Escolha onde guardar este ficheiro Markdown.'; @override String get workspaceErrorSaveBlockedFileChangedOnDisk => - 'Save blocked: file changed on disk.'; + 'Gravação bloqueada: o ficheiro foi alterado no disco.'; @override String workspaceErrorSaveFailed(String error) { - return 'Save failed: $error'; + return 'Falha ao guardar: $error'; } @override String workspaceErrorFileOperationFailed(String error) { - return 'File operation failed: $error'; + return 'Falha na operação de ficheiro: $error'; } @override String workspaceErrorValidationFailed(String error) { - return 'Validation failed: $error'; + return 'Falha na validação: $error'; } @override @@ -1704,9 +1715,9 @@ class AppLocalizationsPt extends AppLocalizations { count, locale: localeName, other: - 'Recovered $count unsaved documents. Review each one before saving or discarding it.', + 'Foram recuperados $count documentos não guardados. Reveja cada um antes de o guardar ou descartar.', one: - 'Recovered 1 unsaved document. Review it before saving or discarding it.', + 'Foi recuperado 1 documento não guardado. Reveja-o antes de o guardar ou descartar.', ); return '$_temp0'; } @@ -1717,449 +1728,450 @@ class AppLocalizationsPt extends AppLocalizations { count, locale: localeName, other: - '$count damaged recovery records could not be restored. Valid recovery records remain available.', + 'Não foi possível restaurar $count registos de recuperação danificados. Os registos de recuperação válidos continuam disponíveis.', one: - 'One damaged recovery record could not be restored. The original recovery file was preserved for inspection.', + 'Não foi possível restaurar 1 registo de recuperação danificado. O ficheiro de recuperação original foi preservado para inspeção.', ); return '$_temp0'; } @override String errorPathDoesNotExist(String path) { - return 'Path does not exist: $path'; + return 'O caminho não existe: $path'; } @override String errorTargetDirectoryNotEmpty(String path) { - return 'Target directory already exists and is not empty: $path'; + return 'O diretório de destino já existe e não está vazio: $path'; } @override String errorTargetPathNotDirectory(String path) { - return 'Target path already exists and is not a directory: $path'; + return 'O caminho de destino já existe e não é um diretório: $path'; } @override String errorGeneratedFileAlreadyExists(String path) { - return 'Generated file already exists: $path'; + return 'O ficheiro gerado já existe: $path'; } @override - String get errorParentDirectoryRequired => 'Parent directory is required.'; + String get errorParentDirectoryRequired => 'O diretório pai é obrigatório.'; @override String errorParentDirectoryMissing(String path) { - return 'Parent directory does not exist: $path'; + return 'O diretório pai não existe: $path'; } @override String errorDirectoryMissing(String path) { - return 'Directory does not exist: $path'; + return 'O diretório não existe: $path'; } @override String errorPathAlreadyExists(String path) { - return 'Path already exists: $path'; + return 'O caminho já existe: $path'; } @override - String get errorFileNameRequired => 'File name is required.'; + String get errorFileNameRequired => 'O nome do ficheiro é obrigatório.'; @override String get errorFileNameUnsafe => - 'File name must be a single safe path segment.'; + 'O nome do ficheiro deve ser um único segmento de caminho seguro.'; @override String get errorFileOperationInvalidTarget => - 'Cannot move a folder into itself.'; + 'Não é possível mover uma pasta para dentro dela mesma.'; @override String get errorFileOperationOutsideRoot => - 'File operation must stay inside the workspace.'; + 'A operação de ficheiro deve permanecer dentro do espaço de trabalho.'; @override String get errorFileOperationRoot => - 'The workspace root cannot be changed from the file tree.'; + 'A raiz do espaço de trabalho não pode ser alterada pela árvore de ficheiros.'; @override - String get errorProjectNameRequired => 'Project name is required.'; + String get errorProjectNameRequired => 'O nome do projeto é obrigatório.'; @override - String get errorDirectoryNameRequired => 'Directory name is required.'; + String get errorDirectoryNameRequired => 'O nome do diretório é obrigatório.'; @override String get errorDirectoryNameUnsafe => - 'Directory name must be a single safe path segment.'; + 'O nome do diretório deve ser um único segmento de caminho seguro.'; @override String get errorInstanceIdInvalid => - 'Instance ID must start with a lowercase letter and contain only lowercase letters, numbers, underscores, and hyphens.'; + 'O ID da instância deve começar com uma letra minúscula e conter apenas letras minúsculas, números, sublinhados e hifens.'; @override String get errorTopicFileInvalid => - 'Topic file name must be a Markdown file name without path separators.'; + 'O nome do ficheiro do tópico deve ser um nome de ficheiro Markdown sem separadores de caminho.'; @override - String get errorTopicTitleRequired => 'Topic title is required.'; + String get errorTopicTitleRequired => 'O título do tópico é obrigatório.'; @override String errorWritersideModuleRootMissing(String path) { - return 'Writerside module root does not exist: $path'; + return 'A raiz do módulo Writerside não existe: $path'; } @override String get errorWritersideModuleNotOpen => - 'A Writerside module must be open to create a topic.'; + 'Um módulo Writerside deve estar aberto para criar um tópico.'; @override String get errorWritersideInstanceTreeMissing => - 'The Writerside module has no instance tree.'; + 'O módulo Writerside não tem uma árvore de instância.'; @override String errorWritersideTreeFileMissing(String path) { - return 'Writerside tree file does not exist: $path'; + return 'O ficheiro de árvore do Writerside não existe: $path'; } @override String errorTopicIdAlreadyExists(String topicId) { - return 'Topic ID \"$topicId\" already exists in this help module.'; + return 'O ID do tópico \"$topicId\" já existe neste módulo de ajuda.'; } @override String errorTopicFileAlreadyExists(String path) { - return 'Topic file already exists: $path'; + return 'O ficheiro do tópico já existe: $path'; } @override String errorReferenceTopicMissing(String topic) { - return 'Reference topic is not present in the selected tree: $topic'; + return 'O tópico de referência não está presente na árvore selecionada: $topic'; } @override String get errorWritersideTocNodeMissing => - 'The selected TOC entry no longer exists.'; + 'A entrada selecionada do TOC não existe mais.'; @override String get errorWritersideTocInvalidMove => - 'A TOC entry cannot be moved into itself or one of its children.'; + 'Uma entrada do TOC não pode ser movida para dentro de si mesma nem de um de seus descendentes.'; @override String errorWritersideStartTopicDelete(String topic) { - return 'The start topic $topic cannot be deleted. Choose another start page first.'; + return 'O tópico inicial $topic não pode ser eliminado. Escolha primeiro outra página inicial.'; } @override String get errorWritersideSafeDeleteRequired => - 'Use Safe Delete for Writerside topic files.'; + 'Use a eliminação segura para ficheiros de tópicos do Writerside.'; @override String get errorWritersideTopicUsageScanFailed => - 'Could not complete the topic usage scan. No files were changed.'; + 'Não foi possível concluir a verificação dos usos do tópico. Nenhum ficheiro foi alterado.'; @override String get errorWritersideTopicUsagesRemain => - 'Some topic usages still require attention. Review them before continuing.'; + 'Alguns usos do tópico ainda precisam de atenção. Reveja-os antes de continuar.'; @override String get errorWritersideRedirectInvalid => - 'The selected redirect target is no longer valid. Choose it again.'; + 'O destino de redirecionamento selecionado não é mais válido. Selecione-o novamente.'; @override String errorWritersideRollbackFailed(String paths) { - return 'Topic removal could not be fully rolled back. Review these paths before continuing: $paths'; + return 'Não foi possível reverter completamente a remoção do tópico. Reveja estes caminhos antes de continuar: $paths'; } @override String get errorTopicsRootUnsafe => - 'Topics root must be a safe relative directory.'; + 'A raiz dos tópicos deve ser um diretório relativo seguro.'; @override String get errorTopicFileNameUnsafe => - 'Topic file name must be a single safe path segment.'; + 'O nome do ficheiro do tópico deve ser um único segmento de caminho seguro.'; @override String errorTopicFileExtensionMismatch(String extension) { - return 'Topic file extension must match the selected format ($extension).'; + return 'A extensão do ficheiro do tópico deve corresponder ao formato selecionado ($extension).'; } @override String get errorTopicFileNameInvalid => - 'Topic file name must contain only letters, numbers, underscores, and hyphens.'; + 'O nome do ficheiro do tópico deve conter apenas letras, números, sublinhados e hifens.'; @override String errorUnknown(String code) { - return 'Unknown error: $code'; + return 'Erro desconhecido: $code'; } @override String diagnosticWorkspaceFileStatFailed(String error) { - return 'Could not read file metadata: $error'; + return 'Não foi possível ler os metadados do ficheiro: $error'; } @override String get diagnosticWorkspaceScanSkipped => - 'Large workspace detected. Some files were skipped to keep the app responsive.'; + 'Foi detetado um espaço de trabalho grande. Alguns ficheiros foram ignorados para manter a aplicação responsiva.'; @override String diagnosticWorkspaceScanInspectFailed(String error) { - return 'Could not inspect workspace entry: $error'; + return 'Não foi possível inspecionar a entrada do espaço de trabalho: $error'; } @override String get diagnosticWorkspaceFileTooLarge => - 'File is larger than the beta auto-parse limit.'; + 'O ficheiro excede o limite beta de análise automática.'; @override String diagnosticWorkspaceFileReadFailed(String error) { - return 'Could not read Markdown file: $error'; + return 'Não foi possível ler o ficheiro Markdown: $error'; } @override String get diagnosticMarkdownAttributeMalformed => - 'Malformed Writerside heading attribute block.'; + 'O bloco de atributos de título do Writerside está malformado.'; @override String diagnosticMarkdownHeadingDuplicateId(String id) { - return 'Duplicate heading ID \"$id\".'; + return 'ID de título duplicado \"$id\".'; } @override String get diagnosticWritersideTopicH1ConvertedToChapter => - 'Additional top-level H1 headings are treated as chapters.'; + 'Títulos H1 adicionais no nível superior são tratados como capítulos.'; @override String get diagnosticWritersideMarkdownTopicMissingTitle => - 'Writerside Markdown topic has no H1 or front matter title.'; + 'O tópico Markdown do Writerside não tem H1 nem título no front matter.'; @override String get diagnosticWritersideXmlTopicMissingTitle => - 'XML topic is missing title.'; + 'O tópico XML não tem título.'; @override String diagnosticWritersideTopicFileMissingTitle(String fileName) { - return 'Topic \"$fileName\" is missing a title.'; + return 'O tópico \"$fileName\" não tem título.'; } @override String get diagnosticMarkdownFrontMatterMalformed => - 'Front matter is not closed.'; + 'O front matter não foi fechado.'; @override - String get diagnosticMarkdownRawHtmlUnsafe => 'Unsafe HTML element.'; + String get diagnosticMarkdownRawHtmlUnsafe => 'Elemento HTML inseguro.'; @override String diagnosticMarkdownLinkUnresolvedTarget(String targetPath) { - return 'Link target does not exist: $targetPath'; + return 'O destino da ligação não existe: $targetPath'; } @override String diagnosticMarkdownLinkUnresolvedAnchor(String anchor) { - return 'Anchor \"$anchor\" does not exist.'; + return 'A âncora \"$anchor\" não existe.'; } @override String diagnosticMarkdownImageMissingAlt(String destination) { - return 'Image \"$destination\" is missing alt text.'; + return 'A imagem \"$destination\" não tem texto alternativo.'; } @override String diagnosticMarkdownImageMissingFile(String destination) { - return 'Image does not exist: $destination'; + return 'A imagem não existe: $destination'; } @override String diagnosticInvalidXml(String message) { - return 'Invalid XML: $message'; + return 'XML inválido: $message'; } @override String get diagnosticWritersideConfigInvalidRoot => - 'writerside.cfg root must be <ihp>.'; + 'A raiz do ficheiro writerside.cfg deve ser <ihp>.'; @override String get diagnosticWritersideConfigMissingSnippetsSrc => - 'snippets declaration is missing src.'; + 'A declaração de snippets está sem o atributo src.'; @override String get diagnosticWritersideConfigMissingInstanceGroupsSrc => - 'instance-groups declaration is missing src.'; + 'A declaração de instance-groups está sem o atributo src.'; @override String diagnosticWritersideConfigInvalidKeymapsMode(String mode) { - return 'Unsupported keymaps mode: $mode'; + return 'Modo de keymaps não suportado: $mode'; } @override String get diagnosticWritersideConfigMissingInstanceSrc => - 'Instance declaration is missing src.'; + 'A declaração de instância está sem o atributo src.'; @override String get diagnosticWritersideConfigMissingInstance => - 'writerside.cfg does not register an instance.'; + 'O ficheiro writerside.cfg não regista uma instância.'; @override String get diagnosticWritersideTreeInvalidRoot => - '.tree root must be <instance-profile>.'; + 'A raiz do ficheiro .tree deve ser <instance-profile>.'; @override String get diagnosticWritersideTreeMissingId => - 'Instance profile is missing id.'; + 'O perfil da instância está sem o atributo id.'; @override String diagnosticWritersideTreeIdMismatch(String id) { - return 'Tree file stem does not match instance id \"$id\".'; + return 'O nome-base do ficheiro .tree não corresponde ao ID da instância \"$id\".'; } @override String get diagnosticWritersideTreeMissingStartPage => - 'Non-library instance is missing start-page.'; + 'A instância que não é de biblioteca não tem start-page.'; @override String diagnosticWritersideStartPageMissing(String startPage) { - return 'Start page \"$startPage\" does not exist.'; + return 'A página inicial \"$startPage\" não existe.'; } @override String diagnosticWritersideTreeDuplicateTopic(String topic) { - return 'Topic \"$topic\" appears more than once in this instance TOC.'; + return 'O tópico \"$topic\" aparece mais de uma vez no TOC desta instância.'; } @override String get diagnosticWritersideVariableMalformedDeclaration => - 'Variable declaration must have name and value.'; + 'A declaração de variável deve ter nome e valor.'; @override String diagnosticWritersideVariableDuplicateName(String name) { - return 'Variable \"$name\" is declared more than once.'; + return 'A variável \"$name\" é declarada mais de uma vez.'; } @override - String get diagnosticWritersideCategoryMissingId => 'Category is missing id.'; + String get diagnosticWritersideCategoryMissingId => + 'A categoria está sem o atributo id.'; @override String diagnosticWritersideCategoryDuplicateId(String id) { - return 'Category \"$id\" is declared more than once.'; + return 'A categoria \"$id\" é declarada mais de uma vez.'; } @override String diagnosticWritersideCategoryDuplicateOrder(String order) { - return 'Category order \"$order\" is declared more than once.'; + return 'A ordem da categoria \"$order\" foi declarada mais de uma vez.'; } @override String get diagnosticWritersideTopicInvalidRoot => - '.topic root must be <topic>.'; + 'A raiz do ficheiro .topic deve ser <topic>.'; @override String get diagnosticWritersideTopicMissingRootId => - 'XML topic is missing root id.'; + 'A raiz do tópico XML está sem o atributo id.'; @override String diagnosticWritersideTopicRootIdMismatch(String id, String expectedId) { - return 'XML topic root id \"$id\" must match filename \"$expectedId\".'; + return 'O ID raiz do tópico XML \"$id\" deve corresponder ao nome do ficheiro \"$expectedId\".'; } @override String diagnosticWritersideTopicDuplicateElementId(String elementId) { - return 'Element id \"$elementId\" appears more than once.'; + return 'O ID do elemento \"$elementId\" aparece mais de uma vez.'; } @override String get diagnosticWritersideTopicAnchorMissingHref => - '<a> is missing href.'; + '<a> está sem o atributo href.'; @override String get diagnosticWritersideConfigMissing => - 'Writerside mode requires writerside.cfg.'; + 'O modo Writerside requer o ficheiro writerside.cfg.'; @override String diagnosticWritersideConfigMissingBuildConfigDirectory( String relativePath, ) { - return 'Configured build config directory is missing: $relativePath'; + return 'O diretório configurado para a compilação está ausente: $relativePath'; } @override String diagnosticWritersideConfigMissingApiSpecificationsDirectory( String relativePath, ) { - return 'Configured API specifications directory is missing: $relativePath'; + return 'O diretório de especificações de API configurado está ausente: $relativePath'; } @override String diagnosticWritersideConfigMissingSnippetsDirectory( String relativePath, ) { - return 'Configured snippets directory is missing: $relativePath'; + return 'O diretório de snippets configurado está ausente: $relativePath'; } @override String diagnosticWritersideConfigMissingVarsFile(String relativePath) { - return 'Configured variables file is missing: $relativePath'; + return 'O ficheiro de variáveis configurado está ausente: $relativePath'; } @override String diagnosticWritersideConfigMissingCategoriesFile(String relativePath) { - return 'Configured categories file is missing: $relativePath'; + return 'O ficheiro de categorias configurado está ausente: $relativePath'; } @override String diagnosticWritersideConfigMissingInstanceGroupsFile( String relativePath, ) { - return 'Configured instance groups file is missing: $relativePath'; + return 'O ficheiro de grupos de instâncias configurado está ausente: $relativePath'; } @override String diagnosticWritersideConfigMissingInstanceTree(String source) { - return 'Registered instance tree \"$source\" does not exist.'; + return 'A árvore de instância registada \"$source\" não existe.'; } @override String diagnosticWritersideTopicReadFailed(String error) { - return 'Could not read topic file: $error'; + return 'Não foi possível ler o ficheiro do tópico: $error'; } @override String diagnosticWritersideDefaultTopicsDirectoryMissing( String relativePath, ) { - return 'Default topics directory is missing: $relativePath'; + return 'O diretório de tópicos predefinido está ausente: $relativePath'; } @override String diagnosticWritersideTopicsDirectoryMissing(String relativePath) { - return 'Configured topics directory is missing: $relativePath'; + return 'O diretório de tópicos configurado está ausente: $relativePath'; } @override String diagnosticWritersideImagesDirectoryMissing(String relativePath) { - return 'Configured images directory is missing: $relativePath'; + return 'O diretório de imagens configurado está ausente: $relativePath'; } @override String diagnosticWritersideTopicDuplicateId(String id) { - return 'Element id \"$id\" appears more than once.'; + return 'O ID do elemento \"$id\" aparece mais de uma vez.'; } @override String diagnosticWritersideTreeMissingTopic(String topic) { - return 'TOC references missing topic \"$topic\".'; + return 'O TOC faz referência ao tópico ausente \"$topic\".'; } @override String diagnosticWritersideTreeInvalidHref(String href) { - return 'External href \"$href\" is invalid.'; + return 'O href externo \"$href\" é inválido.'; } @override String diagnosticWritersideVariableUnresolved(String name) { - return 'Variable \"%$name%\" is not declared.'; + return 'A variável \"%$name%\" não foi declarada.'; } @override String diagnosticWritersideTopicLinkUnresolved(String destination) { - return 'Topic link \"$destination\" does not resolve.'; + return 'Não foi possível resolver a ligação para o tópico \"$destination\".'; } @override @@ -2167,16 +2179,16 @@ class AppLocalizationsPt extends AppLocalizations { String anchor, String targetName, ) { - return 'Anchor \"$anchor\" does not exist in \"$targetName\".'; + return 'A âncora \"$anchor\" não existe em \"$targetName\".'; } @override String get diagnosticWritersideIncludeMissingFrom => - '<include> is missing the from attribute.'; + '<include> está sem o atributo from.'; @override String diagnosticWritersideIncludeSourceMissing(String from) { - return 'Include source \"$from\" does not exist.'; + return 'A origem da inclusão \"$from\" não existe.'; } @override @@ -2184,94 +2196,95 @@ class AppLocalizationsPt extends AppLocalizations { String elementId, String from, ) { - return 'Include element \"$elementId\" does not exist in \"$from\".'; + return 'O elemento incluído \"$elementId\" não existe em \"$from\".'; } @override String diagnosticWritersideCategoryUnresolved(String ref) { - return 'Seealso category \"$ref\" is not declared.'; + return 'A categoria seealso \"$ref\" não foi declarada.'; } @override String diagnosticWritersideTopicAmbiguousReference(String reference) { - return 'Topic reference \"$reference\" is ambiguous.'; + return 'A referência de tópico \"$reference\" é ambígua.'; } @override String diagnosticUnknown(String code) { - return 'Unknown diagnostic: $code'; + return 'Diagnóstico desconhecido: $code'; } @override - String get close => 'Close'; + String get close => 'Fechar'; @override String get git => 'Git'; @override - String get gitDiff => 'Git diff'; + String get gitDiff => 'Diff do Git'; @override - String get gitShowDiff => 'Show diff'; + String get gitShowDiff => 'Mostrar diff'; @override String gitDiffHunkRange(String oldRange, String newRange) { - return 'old $oldRange → new $newRange'; + return 'anterior $oldRange → novo $newRange'; } @override - String get gitDiffNoLines => 'no lines'; + String get gitDiffNoLines => 'sem linhas'; @override - String get gitUnavailableTitle => 'Git is unavailable'; + String get gitUnavailableTitle => 'Git não está disponível'; @override String gitUnavailableMessage(String reason) { String _temp0 = intl.Intl.selectLogic(reason, { 'other': - 'Install Git or configure BusyMark to use an available Git executable. $reason', + 'Instale o Git ou configure o BusyMark para usar um executável do Git disponível. $reason', }); return '$_temp0'; } @override - String get gitTrustRequiredTitle => 'Trust this workspace for Git?'; + String get gitTrustRequiredTitle => + 'Confiar neste espaço de trabalho para o Git?'; @override String get gitTrustRequiredMessage => - 'Git repositories can run programs through hooks, filters, and other configuration. Trust this workspace before BusyMark reads repository data or enables Git actions.'; + 'Os repositórios Git podem executar programas por meio de hooks, filtros e outras definições. Confie neste espaço de trabalho antes que o BusyMark leia os dados do repositório ou ative ações do Git.'; @override - String get gitTrustWorkspace => 'Trust workspace'; + String get gitTrustWorkspace => 'Confiar no espaço de trabalho'; @override - String get gitNotRepositoryTitle => 'Not a Git repository'; + String get gitNotRepositoryTitle => 'Não é um repositório Git'; @override String get gitNotRepositoryMessage => - 'This workspace is not inside a Git repository.'; + 'Este espaço de trabalho não está em um repositório Git.'; @override - String get gitInitializeRepository => 'Initialize repository'; + String get gitInitializeRepository => 'Inicializar repositório'; @override - String get gitDetachedHead => 'Detached HEAD'; + String get gitDetachedHead => 'HEAD desanexado'; @override String gitDetachedHeadAt(String commit) { - return 'Detached at $commit'; + return 'Desanexado em $commit'; } @override - String get gitNoUpstream => 'No upstream'; + String get gitNoUpstream => 'Sem upstream'; @override String gitAheadCount(int count) { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count unpushed commits', - one: '1 unpushed commit', + other: '$count commits não enviados', + one: '1 commit não enviado', ); return '$_temp0'; } @@ -2281,41 +2294,41 @@ class AppLocalizationsPt extends AppLocalizations { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count commits to pull', - one: '1 commit to pull', + other: '$count commits para obter', + one: '1 commit para obter', ); return '$_temp0'; } @override - String get gitClean => 'Clean'; + String get gitClean => 'Limpo'; @override - String get gitConflicts => 'Conflicts'; + String get gitConflicts => 'Conflitos'; @override - String get gitChanges => 'Changes'; + String get gitChanges => 'Alterações'; @override - String get gitStaged => 'Staged'; + String get gitStaged => 'Indexadas'; @override - String get gitUnstaged => 'Unstaged'; + String get gitUnstaged => 'Não indexadas'; @override - String get gitHistory => 'History'; + String get gitHistory => 'Histórico'; @override - String get gitBranches => 'Branches'; + String get gitBranches => 'Ramificações'; @override - String get gitActions => 'Git actions'; + String get gitActions => 'Ações do Git'; @override String get gitPull => 'Pull'; @override - String get gitFetch => 'Fetch'; + String get gitFetch => 'Buscar'; @override String get gitPush => 'Push'; @@ -2324,89 +2337,89 @@ class AppLocalizationsPt extends AppLocalizations { String get gitCommit => 'Commit'; @override - String get gitSelectForCommit => 'Stage file'; + String get gitSelectForCommit => 'Adicionar ficheiro ao índice'; @override - String get gitRemoveFromCommit => 'Unstage file'; + String get gitRemoveFromCommit => 'Remover ficheiro do índice'; @override - String get gitDiscard => 'Rollback'; + String get gitDiscard => 'Descartar'; @override - String get gitOpenFile => 'Open file'; + String get gitOpenFile => 'Abrir ficheiro'; @override - String get gitMarkResolved => 'Mark resolved'; + String get gitMarkResolved => 'Marcar como resolvido'; @override - String get gitUntracked => 'Untracked'; + String get gitUntracked => 'Ficheiros não monitorizados'; @override - String get gitCommitMessage => 'Commit message'; + String get gitCommitMessage => 'Mensagem de commit'; @override - String get gitCommitSelectedFiles => 'Selected files'; + String get gitCommitSelectedFiles => 'Ficheiros selecionados'; @override String get gitCommitNoSelectedFiles => - 'Stage at least one file before committing.'; + 'Adicione pelo menos um ficheiro ao índice antes de criar o commit.'; @override String gitStagedFileCount(int count) { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count staged files', - one: '1 staged file', + other: '$count ficheiros no índice', + one: '1 ficheiro no índice', ); return '$_temp0'; } @override - String get gitOutsideWorkspace => 'Outside workspace'; + String get gitOutsideWorkspace => 'Fora do espaço de trabalho'; @override - String get gitCommitMessageRequired => 'Enter a commit message.'; + String get gitCommitMessageRequired => 'Introduza uma mensagem de commit.'; @override - String get gitCreateBranch => 'Create branch'; + String get gitCreateBranch => 'Criar ramificação'; @override - String get gitNewBranch => 'New Branch'; + String get gitNewBranch => 'Nova ramificação'; @override - String get gitBranchName => 'Branch name'; + String get gitBranchName => 'Nome da ramificação'; @override - String get gitSwitchBranch => 'Switch'; + String get gitSwitchBranch => 'Trocar'; @override - String get gitNoChanges => 'No changes'; + String get gitNoChanges => 'Nenhuma alteração'; @override - String get gitNoHistory => 'No history'; + String get gitNoHistory => 'Nenhum histórico'; @override - String get gitNoBranches => 'No branches'; + String get gitNoBranches => 'Nenhuma ramificação'; @override - String get gitNoDiff => 'No diff to show'; + String get gitNoDiff => 'Nenhuma diferença para apresentar'; @override String get gitBinaryFile => - 'Binary file. BusyMark does not render binary patches.'; + 'Ficheiro binário. O BusyMark não apresenta patches binários.'; @override String gitBinaryFileInfo(int size) { - return 'Binary file ($size bytes). BusyMark does not render binary patches.'; + return 'Ficheiro binário ($size bytes). O BusyMark não apresenta patches binários.'; } @override String get gitUnsavedChangesBanner => - 'Unsaved editor changes are not included until saved.'; + 'As alterações não guardadas do editor não são incluídas até serem guardadas.'; @override - String get gitConfirmDiscardTitle => 'Discard Git changes?'; + String get gitConfirmDiscardTitle => 'Descartar alterações do Git?'; @override String gitConfirmDiscardTracked(int count) { @@ -2414,9 +2427,9 @@ class AppLocalizationsPt extends AppLocalizations { count, locale: localeName, other: - 'All staged and unstaged changes in the selected tracked files will be restored to HEAD.', + 'Todas as alterações indexadas e não indexadas nos ficheiros monitorizados selecionados serão repostas para HEAD.', one: - 'All staged and unstaged changes in the selected tracked file will be restored to HEAD.', + 'Todas as alterações indexadas e não indexadas no ficheiro monitorizado selecionado serão repostas para HEAD.', ); return '$_temp0'; } @@ -2426,8 +2439,8 @@ class AppLocalizationsPt extends AppLocalizations { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: 'The selected untracked files will be deleted.', - one: 'The selected untracked file will be deleted.', + other: 'Os ficheiros não monitorizados selecionados serão eliminados.', + one: 'O ficheiro não monitorizado selecionado será eliminado.', ); return '$_temp0'; } @@ -2438,105 +2451,106 @@ class AppLocalizationsPt extends AppLocalizations { count, locale: localeName, other: - 'The selected files will be restored or deleted based on their Git status.', + 'Os ficheiros selecionados serão repostos ou eliminados consoante o respetivo estado no Git.', one: - 'The selected file will be restored or deleted based on its Git status.', + 'O ficheiro selecionado será reposto ou eliminado consoante o respetivo estado no Git.', ); return '$_temp0'; } @override String gitConfirmSwitchBranchTitle(String branch) { - return 'Switch to $branch?'; + return 'Trocar para $branch?'; } @override String get gitConfirmSwitchBranchMessage => - 'BusyMark will reload the workspace from disk after Git switches branches.'; + 'O BusyMark voltará a carregar o espaço de trabalho a partir do disco depois de o Git mudar de ramificação.'; @override - String get gitConfirmPushSetUpstreamTitle => 'Set upstream branch?'; + String get gitConfirmPushSetUpstreamTitle => 'Definir ramificação upstream?'; @override String gitConfirmPushSetUpstreamMessage(String branch) { - return 'This branch has no upstream. BusyMark can push $branch and set its upstream when exactly one remote is configured.'; + return 'Esta ramificação não tem upstream. O BusyMark pode enviar $branch e definir o respetivo upstream quando existir exatamente um remoto configurado.'; } @override - String get gitProjectHistory => 'Project History'; + String get gitProjectHistory => 'Histórico do projeto'; @override - String get gitFileHistory => 'File History'; + String get gitFileHistory => 'Histórico do ficheiro'; @override String get gitFileHistoryRequiresOpenFile => - 'File History requires an open Markdown file.'; + 'O histórico do ficheiro requer um ficheiro Markdown aberto.'; @override - String get gitLoadMore => 'Load More'; + String get gitLoadMore => 'Carregar mais'; @override - String get gitChangesInCommit => 'Changes in this commit'; + String get gitChangesInCommit => 'Alterações neste commit'; @override - String get gitCompareWithCurrent => 'Compare with current'; + String get gitCompareWithCurrent => 'Comparar com a versão atual'; @override - String get gitRestoreVersion => 'Restore this version'; + String get gitRestoreVersion => 'Restaurar esta versão'; @override - String get gitConfirmRestoreTitle => 'Restore this file version?'; + String get gitConfirmRestoreTitle => 'Restaurar esta versão do ficheiro?'; @override String get gitConfirmRestoreMessage => - 'BusyMark will replace the current working-tree file with the selected committed version. The restored file will remain unstaged.'; + 'O BusyMark substituirá o ficheiro atual da árvore de trabalho pela versão selecionada do commit. O ficheiro reposto permanecerá fora do índice.'; @override - String get gitCommitActions => 'Commit actions'; + String get gitCommitActions => 'Ações do commit'; @override - String get gitResetCurrentBranchToHere => 'Reset current branch to here…'; + String get gitResetCurrentBranchToHere => + 'Redefinir a ramificação atual aqui…'; @override String gitResetCurrentBranchTitle(String branch, String commit) { - return 'Reset $branch to $commit?'; + return 'Redefinir $branch para $commit?'; } @override String gitResetCurrentBranchMessage(String branch, String commit) { - return 'This moves branch $branch to commit $commit. Choose how Git updates the index and working tree.'; + return 'Isto move a ramificação $branch para o commit $commit. Escolha como o Git deve atualizar o índice e a árvore de trabalho.'; } @override - String get gitReset => 'Reset'; + String get gitReset => 'Redefinir'; @override String get gitResetModeSoft => 'Soft'; @override String get gitResetModeSoftDescription => - 'Move the branch only. Keep the index and working tree unchanged; differences from the selected commit remain staged.'; + 'Mover apenas a ramificação. Manter o índice e a árvore de trabalho inalterados; as diferenças em relação ao commit selecionado permanecem no índice.'; @override String get gitResetModeMixed => 'Mixed'; @override String get gitResetModeMixedDescription => - 'Move the branch and reset the index. Keep the working tree unchanged, leaving differences unstaged.'; + 'Mover a ramificação e redefinir o índice. Manter a árvore de trabalho inalterada, deixando as diferenças fora do índice.'; @override String get gitResetModeHard => 'Hard'; @override String get gitResetModeHardDescription => - 'Move the branch and reset the index and working tree. Tracked changes are discarded; obstructing untracked files may be deleted.'; + 'Mover a ramificação e redefinir o índice e a árvore de trabalho. As alterações monitorizadas são descartadas; os ficheiros não monitorizados que bloqueiam a operação podem ser eliminados.'; @override String get gitResetModeKeep => 'Keep'; @override String get gitResetModeKeepDescription => - 'Move the branch and reset tracked files while preserving local changes. Git aborts if those changes conflict with the reset.'; + 'Mover a ramificação e redefinir os ficheiros monitorizados, preservando as alterações locais. O Git aborta se essas alterações entrarem em conflito com a redefinição.'; @override String gitAdditionsDeletions(int additions, int deletions) { @@ -2544,121 +2558,125 @@ class AppLocalizationsPt extends AppLocalizations { } @override - String get fileActions => 'File actions'; + String get fileActions => 'Ações do ficheiro'; @override - String get actions => 'Actions'; + String get actions => 'Ações'; @override - String get gitStatusAdded => 'Added'; + String get gitStatusAdded => 'Adicionado'; @override - String get gitStatusDeleted => 'Deleted'; + String get gitStatusDeleted => 'Eliminado'; @override - String get gitStatusRenamed => 'Renamed'; + String get gitStatusRenamed => 'Renomeado'; @override - String get gitStatusCopied => 'Copied'; + String get gitStatusCopied => 'Copiado'; @override - String get gitStatusUntracked => 'Untracked'; + String get gitStatusUntracked => 'Não monitorizado'; @override - String get gitStatusConflicted => 'Conflicted'; + String get gitStatusConflicted => 'Em conflito'; @override - String get gitStatusIgnored => 'Ignored'; + String get gitStatusIgnored => 'Ignorado'; @override - String get gitStatusTypeChanged => 'Type changed'; + String get gitStatusTypeChanged => 'Tipo alterado'; @override - String get gitStatusModified => 'Modified'; + String get gitStatusModified => 'Modificado'; @override - String get gitStatusUnknown => 'Unknown'; + String get gitStatusUnknown => 'Desconhecido'; @override - String get gitErrorUnavailable => 'Git is unavailable.'; + String get gitErrorUnavailable => 'Git não está disponível.'; @override - String get gitErrorNotRepository => 'This workspace is not a Git repository.'; + String get gitErrorNotRepository => + 'Este espaço de trabalho não é um repositório Git.'; @override - String get gitErrorUnsafePath => 'BusyMark blocked an unsafe Git path.'; + String get gitErrorUnsafePath => + 'O BusyMark bloqueou um caminho Git inseguro.'; @override - String get gitErrorInvalidBranchName => 'Enter a valid branch name.'; + String get gitErrorInvalidBranchName => + 'Introduza um nome de ramificação válido.'; @override - String get gitErrorNoRemote => 'No Git remote is configured.'; + String get gitErrorNoRemote => 'Nenhum remoto Git está configurado.'; @override - String get gitErrorNoUpstream => 'No upstream branch is configured.'; + String get gitErrorNoUpstream => + 'Nenhuma ramificação upstream está configurada.'; @override String get gitErrorMultipleRemotes => - 'Multiple remotes are configured. Choose an upstream outside this BusyMark version.'; + 'Há vários remotos configurados. Escolha um upstream fora desta versão do BusyMark.'; @override String get gitErrorDirtyWorkspace => - 'Save or discard BusyMark editor changes before switching branches.'; + 'Guarde ou descarte as alterações do editor do BusyMark antes de trocar de ramificação.'; @override String get gitErrorResetDirtyWorkspace => - 'Save or discard BusyMark editor changes before resetting the current branch.'; + 'Guarde ou descarte as alterações no editor do BusyMark antes de redefinir a ramificação atual.'; @override String get gitErrorRestoreStagedFile => - 'Unstage this file before restoring a historical version.'; + 'Retire o ficheiro do índice antes de repor uma versão anterior.'; @override String get gitErrorResetDetachedHead => - 'Check out a branch before resetting it.'; + 'Alterne para uma ramificação antes de redefini-la.'; @override String get gitErrorDiverged => - 'Branch has diverged. Resolve merge or rebase outside this BusyMark version.'; + 'A ramificação divergiu. Resolva o merge ou o rebase fora desta versão do BusyMark.'; @override String get gitErrorAuthorIdentity => - 'Git needs an author name and email address before it can commit.'; + 'O Git precisa do nome e do e-mail do autor antes de criar um commit.'; @override - String get gitAuthorIdentityTitle => 'Git Author Identity'; + String get gitAuthorIdentityTitle => 'Identidade do autor do Git'; @override String get gitAuthorIdentityMessage => - 'Enter the identity Git should record on commits. BusyMark will save it and retry this commit.'; + 'Indique a identidade que o Git deve registar nos commits. O BusyMark irá guardá-la e tentar este commit novamente.'; @override - String get gitAuthorName => 'Name'; + String get gitAuthorName => 'Nome'; @override - String get gitAuthorEmail => 'Email'; + String get gitAuthorEmail => 'E-mail'; @override - String get gitAuthorIdentityGlobal => 'Use for all repositories'; + String get gitAuthorIdentityGlobal => 'Usar em todos os repositórios'; @override String get gitAuthorIdentityGlobalDescription => - 'When installed as a Snap, this applies to repositories opened in BusyMark.'; + 'Quando instalado como Snap, isto se aplica aos repositórios abertos no BusyMark.'; @override - String get gitSaveIdentityAndCommit => 'Save and Commit'; + String get gitSaveIdentityAndCommit => 'Guardar e criar commit'; @override - String get gitErrorAuthentication => 'Git authentication failed.'; + String get gitErrorAuthentication => 'A autenticação do Git falhou.'; @override - String get gitErrorNetwork => 'Git network operation failed.'; + String get gitErrorNetwork => 'A operação de rede do Git falhou.'; @override - String get gitErrorConflict => 'Git reported unresolved conflicts.'; + String get gitErrorConflict => 'O Git relatou conflitos não resolvidos.'; @override - String get gitErrorCommandFailed => 'Git command failed.'; + String get gitErrorCommandFailed => 'O comando Git falhou.'; @override String get syntaxReference => 'Referência de sintaxe'; @@ -2733,11 +2751,11 @@ class AppLocalizationsPt extends AppLocalizations { @override String get syntaxReferenceSourcePreservedDescription => - 'HTML bruto não editado é salvo exatamente como texto fonte.'; + 'HTML bruto não editado é guardado exatamente como texto fonte.'; @override String get syntaxReferenceMarkdownInsideHtmlDescription => - 'Marcadores Markdown dentro de HTML bruto são exibidos como texto literal.'; + 'Marcadores Markdown dentro de HTML bruto são apresentados como texto literal.'; @override String get syntaxReferenceBlockedContentDescription => @@ -2745,7 +2763,7 @@ class AppLocalizationsPt extends AppLocalizations { @override String get syntaxReferenceSafeUrlsDescription => - 'Links permitem http, https, mailto, tel, URLs relativas e fragmentos; esquemas inseguros são bloqueados.'; + 'Ligações permitem http, https, mailto, tel, URLs relativas e fragmentos; esquemas inseguros são bloqueados.'; @override String get syntaxReferenceCategory => 'Categoria'; @@ -2776,11 +2794,11 @@ class AppLocalizationsPt extends AppLocalizations { @override String get syntaxReferenceScopeWritersideMarkdown => - 'Somente Markdown do Writerside'; + 'Apenas Markdown do Writerside'; @override String get syntaxReferenceScopeWritersideMarkdownAndXml => - 'Somente Markdown e XML do Writerside'; + 'Apenas Markdown e XML do Writerside'; @override String get syntaxReferenceMarkdownDescription => @@ -2827,7 +2845,7 @@ class AppLocalizationsPt extends AppLocalizations { @override String get syntaxReferenceSemanticDiagramLimitation => - 'As formas semânticas code-block e src aceitam Mermaid, PlantUML e D2, não OpenAPI, e somente em projetos Writerside.'; + 'As formas semânticas code-block e src aceitam Mermaid, PlantUML e D2, não OpenAPI, e apenas em projetos Writerside.'; @override String get syntaxReferenceReferencedDiagramSource => @@ -2878,7 +2896,7 @@ class AppLocalizationsPt extends AppLocalizations { @override String get syntaxReferenceWritersideDescription => - 'Estas extensões específicas são interpretadas somente em projetos Writerside abertos.'; + 'Estas extensões específicas são interpretadas apenas em projetos Writerside abertos.'; @override String get syntaxReferenceAdmonitionBlockquote => 'Citação de aviso'; @@ -2920,61 +2938,61 @@ class AppLocalizationsPt extends AppLocalizations { 'Vídeo local usa uma imagem preview-src local; fontes hospedadas devem ser URLs HTTPS compatíveis do YouTube ou Vimeo.'; @override - String get exportAsPdf => 'Export as PDF'; + String get exportAsPdf => 'Exportar como PDF'; @override String get pdfExportDescription => - 'Choose the page layout for a polished, self-contained PDF.'; + 'Escolha o esquema da página para criar um PDF bem acabado e independente.'; @override String get pdfRemoteImagesNote => - 'Remote images are not downloaded during export. Local images are included when available.'; + 'As imagens remotas não são transferidas durante a exportação. As imagens locais são incluídas quando disponíveis.'; @override - String get pdfPageSize => 'Page size'; + String get pdfPageSize => 'Tamanho da página'; @override String get pdfPageSizeA4 => 'A4'; @override - String get pdfPageSizeLetter => 'Letter'; + String get pdfPageSizeLetter => 'Carta'; @override - String get pdfOrientation => 'Orientation'; + String get pdfOrientation => 'Orientação'; @override - String get pdfPortrait => 'Portrait'; + String get pdfPortrait => 'Vertical'; @override - String get pdfLandscape => 'Landscape'; + String get pdfLandscape => 'Horizontal'; @override - String get pdfMargins => 'Margins'; + String get pdfMargins => 'Margens'; @override - String get pdfMarginNarrow => 'Narrow'; + String get pdfMarginNarrow => 'Estreitas'; @override - String get pdfMarginNormal => 'Normal'; + String get pdfMarginNormal => 'Normais'; @override - String get pdfMarginWide => 'Wide'; + String get pdfMarginWide => 'Largas'; @override - String get pdfIncludePageNumbers => 'Include page numbers'; + String get pdfIncludePageNumbers => 'Incluir números de página'; @override - String get export => 'Export'; + String get export => 'Exportar'; @override - String get exportingPdf => 'Exporting PDF…'; + String get exportingPdf => 'A exportar PDF…'; @override - String get fileTypePdf => 'PDF document'; + String get fileTypePdf => 'Documento PDF'; @override String pdfExported(String fileName) { - return '$fileName was exported.'; + return '$fileName foi exportado.'; } @override @@ -2982,364 +3000,368 @@ class AppLocalizationsPt extends AppLocalizations { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count warnings', - one: '1 warning', + other: '$count avisos', + one: '1 aviso', ); - return '$fileName was exported with $_temp0.'; + return '$fileName foi exportado com $_temp0.'; } @override String get pdfExportUnavailable => - 'The PDF export component is missing. Reinstall BusyMark and try again.'; + 'O componente de exportação para PDF está ausente. Reinstale o BusyMark e tente novamente.'; @override - String get pdfExportTimedOut => 'PDF export took too long and was stopped.'; + String get pdfExportTimedOut => + 'A exportação para PDF demorou demasiado e foi interrompida.'; @override String get pdfExportFailed => - 'BusyMark could not export this document as PDF.'; + 'O BusyMark não conseguiu exportar este documento como PDF.'; @override - String get visualizationRendering => 'Rendering…'; + String get visualizationRendering => 'A renderizar…'; @override - String get visualizationStale => 'Showing the last valid render'; + String get visualizationStale => 'A apresentar a última renderização válida'; @override - String get visualizationShowSource => 'Show source'; + String get visualizationShowSource => 'Mostrar código-fonte'; @override - String get visualizationShowRender => 'Show render'; + String get visualizationShowRender => 'Mostrar renderização'; @override - String get visualizationFitWidth => 'Fit to width'; + String get visualizationFitWidth => 'Ajustar à largura'; @override - String get visualizationSaveImage => 'Save image'; + String get visualizationSaveImage => 'Guardar imagem'; @override - String get visualizationCopyImage => 'Copy image'; + String get visualizationCopyImage => 'Copiar imagem'; @override - String get visualizationImageCopied => 'Image copied'; + String get visualizationImageCopied => 'Imagem copiada'; @override - String get visualizationOpenApiReference => 'Open API Reference'; + String get visualizationOpenApiReference => 'Abrir referência da API'; @override - String get visualizationValid => 'Valid'; + String get visualizationValid => 'Válido'; @override - String get visualizationInvalid => 'Invalid'; + String get visualizationInvalid => 'Inválido'; @override - String get visualizationServers => 'Servers'; + String get visualizationServers => 'Servidores'; @override - String get visualizationPaths => 'Paths'; + String get visualizationPaths => 'Caminhos'; @override - String get visualizationOperations => 'Operations'; + String get visualizationOperations => 'Operações'; @override - String get visualizationTags => 'Tags'; + String get visualizationTags => 'Etiquetas'; @override - String get visualizationNoOperations => 'No matching operations'; + String get visualizationNoOperations => 'Nenhuma operação correspondente'; @override - String get visualizationSearchOperations => 'Search operations'; + String get visualizationSearchOperations => 'Pesquisar operações'; @override String get visualizationRenderFailed => - 'This visualization could not be rendered.'; + 'Não foi possível renderizar esta visualização.'; @override - String get visualizationRetry => 'Retry'; + String get visualizationRetry => 'Tentar novamente'; @override String visualizationSaved(String fileName) { - return 'Saved $fileName'; + return '$fileName guardado'; } @override String get shortcutExportPdfDescription => - 'Export the active document or Writerside module as a PDF.'; + 'Exportar o documento ativo ou o módulo do Writerside como PDF.'; @override - String get instances => 'Instances'; + String get instances => 'Instâncias'; @override - String get newInstance => 'New instance'; + String get newInstance => 'Nova instância'; @override - String get newTocLibrary => 'New TOC library'; + String get newTocLibrary => 'Nova biblioteca de sumário'; @override - String get editInstance => 'Edit instance'; + String get editInstance => 'Editar instância'; @override - String get openTocFile => 'Open TOC file'; + String get openTocFile => 'Abrir ficheiro do índice'; @override - String get createInstance => 'Create instance'; + String get createInstance => 'Criar instância'; @override - String get createTocLibrary => 'Create TOC library'; + String get createTocLibrary => 'Criar biblioteca de sumário'; @override - String get instanceContent => 'Content'; + String get instanceContent => 'Conteúdo'; @override - String get instanceContentSource => 'Create from'; + String get instanceContentSource => 'Criar a partir de'; @override - String get emptyInstance => 'Empty instance'; + String get emptyInstance => 'Instância vazia'; @override - String get markdownFiles => 'Local Markdown files'; + String get markdownFiles => 'Ficheiros Markdown locais'; @override - String get chooseMarkdownFolder => 'Choose Markdown folder'; + String get chooseMarkdownFolder => 'Escolher pasta de Markdown'; @override String get errorWritersideInstanceImportSourceRequired => - 'Choose a folder containing Markdown files.'; + 'Escolha uma pasta que contenha ficheiros Markdown.'; @override - String get instanceAppearance => 'Appearance'; + String get instanceAppearance => 'Aparência'; @override - String get instanceColor => 'Icon color'; + String get instanceColor => 'Cor do ícone'; @override - String get instanceVersion => 'Version'; + String get instanceVersion => 'Versão'; @override String instanceVersionInherited(String version) { - return 'The project version is $version when this field is empty.'; + return 'Quando este campo está vazio, é usada a versão do projeto $version.'; } @override - String get instanceWebPath => 'Web path'; + String get instanceWebPath => 'Caminho web'; @override - String get instanceStatus => 'Status'; + String get instanceStatus => 'Estado'; @override - String get instanceStatusRelease => 'Release'; + String get instanceStatusRelease => 'Lançamento'; @override - String get instanceStatusEap => 'Early access'; + String get instanceStatusEap => 'Acesso antecipado'; @override - String get instanceStatusDeprecated => 'Deprecated'; + String get instanceStatusDeprecated => 'Obsoleta'; @override - String get allowSearchEngineIndexing => 'Allow search engine indexing'; + String get allowSearchEngineIndexing => + 'Permitir indexação por mecanismos de busca'; @override String get allowSearchEngineIndexingDescription => - 'Allow external search engines to index this output.'; + 'Permita que mecanismos de busca externos indexem esta saída.'; @override - String get offlineArtifact => 'Offline artifact'; + String get offlineArtifact => 'Artefato offline'; @override String get offlineArtifactDescription => - 'Bundle resources so the built documentation is self-contained.'; + 'Inclua os recursos para que a documentação gerada funcione de forma autônoma.'; @override - String get instanceOutputSettings => 'Output settings'; + String get instanceOutputSettings => 'Definições de saída'; @override - String get markdownImportSource => 'Markdown source'; + String get markdownImportSource => 'Origem Markdown'; @override - String get markdownImportFiles => 'Markdown files'; + String get markdownImportFiles => 'Ficheiros Markdown'; @override - String get selectNone => 'Select none'; + String get selectNone => 'Não selecionar nenhum'; @override String markdownFilesFound(int count) { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count Markdown files found', - one: '1 Markdown file found', + other: 'Foram encontrados $count ficheiros Markdown', + one: 'Foi encontrado 1 ficheiro Markdown', ); return '$_temp0'; } @override String get noMarkdownFilesFound => - 'No Markdown files were found in this directory.'; + 'Não foram encontrados ficheiros Markdown neste diretório.'; @override - String get copyReferencedMedia => 'Copy referenced media'; + String get copyReferencedMedia => 'Copiar multimédia referenciada'; @override String get copyReferencedMediaDescription => - 'Copy local images and video referenced by the selected files while preserving relative paths.'; + 'Copie imagens e vídeos locais referenciados pelos ficheiros selecionados, preservando os caminhos relativos.'; @override - String get instanceIdRenameWarningTitle => 'Rename instance ID?'; + String get instanceIdRenameWarningTitle => 'Mudar o nome do ID da instância?'; @override String instanceIdRenameWarning(String oldId, String newId) { - return 'BusyMark will rename the .tree file and update Writerside project references from “$oldId” to “$newId”. Publication scripts are not changed and must be updated separately.'; + return 'O BusyMark mudará o nome do ficheiro .tree e atualizará as referências do projeto Writerside de “$oldId” para “$newId”. Os scripts de publicação não são alterados e devem ser atualizados separadamente.'; } @override - String get renameAndUpdateReferences => 'Rename and update references'; + String get renameAndUpdateReferences => + 'Mudar o nome e atualizar referências'; @override String get tocLibraryDescription => - 'A TOC library stores reusable sections and does not produce its own output.'; + 'Uma biblioteca de sumário armazena secções reutilizáveis e não produz uma saída própria.'; @override - String get defaultTocLibraryName => 'Shared TOC'; + String get defaultTocLibraryName => 'Sumário partilhado'; @override - String get instanceColorAutomatic => 'Automatic'; + String get instanceColorAutomatic => 'Automático'; @override - String get instanceColorBlue => 'Blue'; + String get instanceColorBlue => 'Azul'; @override - String get instanceColorGreen => 'Green'; + String get instanceColorGreen => 'Verde'; @override - String get instanceColorOrange => 'Orange'; + String get instanceColorOrange => 'Laranja'; @override - String get instanceColorPurple => 'Purple'; + String get instanceColorPurple => 'Roxo'; @override - String get instanceColorRed => 'Red'; + String get instanceColorRed => 'Vermelho'; @override - String get instanceColorTeal => 'Teal'; + String get instanceColorTeal => 'Verde-azulado'; @override - String get instanceColorYellow => 'Yellow'; + String get instanceColorYellow => 'Amarelo'; @override - String get errorWritersideInstanceNameRequired => 'Enter an instance name.'; + String get errorWritersideInstanceNameRequired => + 'Introduza um nome para a instância.'; @override String errorWritersideInstanceIdExists(String id) { - return 'An instance with ID “$id” already exists.'; + return 'Já existe uma instância com o ID “$id”.'; } @override String errorWritersideInstanceTreeExists(String path) { - return 'The instance tree already exists: $path'; + return 'A árvore da instância já existe: $path'; } @override String errorWritersideInstanceImportSourceMissing(String path) { - return 'The Markdown source directory does not exist: $path'; + return 'O diretório de origem Markdown não existe: $path'; } @override String get errorWritersideInstanceImportSelectionRequired => - 'Select at least one Markdown file to import.'; + 'Selecione pelo menos um ficheiro Markdown para importar.'; @override String errorWritersideInstanceImportFileInvalid(String path) { - return 'This is not a readable Markdown file inside the selected source: $path'; + return 'Este não é um ficheiro Markdown legível dentro da origem selecionada: $path'; } @override String errorWritersideInstanceImportTargetExists(String path) { - return 'Import would overwrite an existing project file: $path'; + return 'A importação substituiria um ficheiro existente do projeto: $path'; } @override String get errorWritersideInstanceFilesChanged => - 'Instance files changed on disk. Review them and try again.'; + 'Os ficheiros da instância foram alterados no disco. Reveja-os e tente novamente.'; @override String errorWritersideInstanceRollbackFailed(String paths) { - return 'BusyMark could not completely roll back the instance change. Review these files before continuing: $paths'; + return 'O BusyMark não conseguiu reverter completamente a alteração da instância. Reveja estes ficheiros antes de continuar: $paths'; } @override String get errorWritersideInstanceLibraryImport => - 'A TOC library cannot import Markdown topics.'; + 'Uma biblioteca de sumário não pode importar tópicos Markdown.'; @override String get errorWritersideInstanceWebPathInvalid => - 'The web path must be a single line.'; + 'O caminho web deve ter uma única linha.'; @override String get errorWritersideInstanceConfigurationInvalid => - 'The Writerside instance configuration is invalid. Correct its diagnostics and try again.'; + 'A configuração da instância do Writerside é inválida. Corrija os diagnósticos e tente novamente.'; @override String get errorWritersideInstanceTemporaryFile => - 'BusyMark could not stage the instance changes safely.'; + 'O BusyMark não conseguiu preparar com segurança as alterações da instância.'; @override String diagnosticWritersideTreeInvalidStatus(String status) { - return 'Unknown instance status “$status”. Use release, eap, or deprecated.'; + return 'Estado de instância desconhecido “$status”. Use release, eap ou deprecated.'; } @override String diagnosticWritersideDuplicateInstanceId(String id) { - return 'The instance ID “$id” is used by more than one tree file.'; + return 'O ID de instância “$id” é usado por mais de um ficheiro de árvore.'; } @override String get diagnosticWritersideBuildProfilesInvalidRoot => - 'buildprofiles.xml must have a <buildprofiles> root element.'; + 'buildprofiles.xml deve ter um elemento raiz <buildprofiles>.'; @override String diagnosticWritersideBuildProfilesInvalidBoolean( String name, String value, ) { - return 'The $name value “$value” must be true or false.'; + return 'O valor $name “$value” deve ser true ou false.'; } @override String get diagnosticWritersideBuildProfileMissingInstance => - 'A <build-profile> element must specify an instance ID.'; + 'Um elemento <build-profile> deve especificar um ID de instância.'; @override String get diagnosticWritersideTreeInvalidInclude => - 'A tree <include> must specify both from and element-id.'; + 'Um <include> da árvore deve especificar from e element-id.'; @override String get diagnosticWritersideTreeMissingSnippetId => - 'A tree <snippet> must specify an id.'; + 'Um <snippet> da árvore deve especificar um id.'; @override String get diagnosticWritersideTreeInvalidCrossInstanceReference => - 'A cross-instance TOC reference must specify both ref and in.'; + 'Uma referência de sumário entre instâncias deve especificar ref e in.'; @override String get diagnosticWritersideTreeConflictingTargets => - 'A TOC element cannot target more than one topic, reference, link, or redirect.'; + 'Um elemento do sumário não pode apontar para mais do que um tópico, referência, ligação ou redirecionamento.'; @override String diagnosticWritersideTreeDuplicateElementId(String id) { - return 'Tree element ID “$id” is declared more than once.'; + return 'O ID de elemento da árvore “$id” foi declarado mais de uma vez.'; } @override String get diagnosticWritersideInstanceGroupsInvalidRoot => - 'The instance groups file must have an <instance-groups> root element.'; + 'O ficheiro de grupos de instâncias deve ter um elemento raiz <instance-groups>.'; @override String get diagnosticWritersideInstanceGroupInvalid => - 'An instance group must specify a non-empty id and instances list.'; + 'Um grupo de instâncias deve especificar um id e uma lista de instâncias não vazios.'; @override String diagnosticWritersideInstanceGroupDuplicateId(String id) { - return 'Instance group ID “$id” is declared more than once.'; + return 'O ID do grupo de instâncias “$id” foi declarado mais de uma vez.'; } @override @@ -3348,7 +3370,7 @@ class AppLocalizationsPt extends AppLocalizations { String id, String origin, ) { - return 'TOC include “$source#$id” belongs to external module “$origin” and cannot be expanded in this workspace.'; + return 'A inclusão de sumário “$source#$id” pertence ao módulo externo “$origin” e não pode ser expandida neste espaço de trabalho.'; } @override @@ -3356,22 +3378,22 @@ class AppLocalizationsPt extends AppLocalizations { String source, String id, ) { - return 'Tree element “$id” does not exist in registered tree “$source”.'; + return 'O elemento de árvore “$id” não existe na árvore registada “$source”.'; } @override String diagnosticWritersideTreeCircularInclude(String source, String id) { - return 'Tree include “$source#$id” creates a cycle.'; + return 'A inclusão de árvore “$source#$id” cria um ciclo.'; } @override String diagnosticWritersideUnknownInstanceGroup(String group) { - return 'Instance condition references unknown group “@$group”.'; + return 'A condição de instância referencia o grupo desconhecido “@$group”.'; } @override String diagnosticWritersideReferenceInstanceMissing(String instance) { - return 'Cross-instance reference targets unknown instance “$instance”.'; + return 'A referência entre instâncias aponta para a instância desconhecida “$instance”.'; } @override @@ -3379,329 +3401,312 @@ class AppLocalizationsPt extends AppLocalizations { String topic, String instance, ) { - return 'Topic “$topic” is not in referenced instance “$instance”.'; + return 'O tópico “$topic” não está na instância referenciada “$instance”.'; } @override - String get download => 'Download'; + String get download => 'Transferir'; @override - String get exportWritersideAsPdf => 'Export Writerside as PDF'; + String get exportWritersideAsPdf => 'Exportar Writerside como PDF'; @override - String get writersidePdfContent => 'Export content'; + String get writersidePdfContent => 'Conteúdo da exportação'; @override - String get writersidePdfPage => 'Page'; + String get writersidePdfPage => 'Página'; @override - String get exportingWritersidePdf => 'Exporting Writerside PDF…'; + String get exportingWritersidePdf => 'A exportar PDF do Writerside…'; @override - String get ai => 'AI'; + String get ai => 'IA'; @override - String get aiLocalOllama => 'Local Ollama'; + String get aiLocalOllama => 'Ollama local'; @override - String get aiDisabled => 'Disabled'; + String get aiDisabled => 'Desativado'; @override String get aiExplicitEditingDescription => - 'AI editing is explicit. BusyMark sends only the context shown for the selected provider and never applies a proposal without review.'; + 'A edição com IA é iniciada apenas de forma explícita. O BusyMark envia apenas o contexto apresentado ao fornecedor selecionado e nunca aplica uma proposta sem revisão.'; @override - String get aiProvider => 'AI provider'; + String get aiProvider => 'Fornecedor de IA'; @override - String get aiDefaultProvider => 'Default provider'; + String get aiDefaultProvider => 'Fornecedor predefinido'; @override - String get aiConfigureProvider => 'Configure provider'; + String get aiConfigureProvider => 'Configurar fornecedor'; @override - String get aiChooseProvider => 'Choose AI provider'; + String get aiChooseProvider => 'Escolher fornecedor de IA'; @override - String get aiOllamaEndpoint => 'Ollama endpoint'; + String get aiOllamaEndpoint => 'Endpoint do Ollama'; @override - String get aiOllamaModel => 'Ollama model'; + String get aiOllamaModel => 'Modelo do Ollama'; @override - String get aiTestConnection => 'Test connection'; + String get aiTestConnection => 'Testar ligação'; @override - String get aiTestingConnection => 'Testing…'; + String get aiTestingConnection => 'A testar…'; @override String aiConnectionReady(int count) { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count installed models found', - one: '1 installed model found', + other: 'Foram encontrados $count modelos instalados', + one: 'Foi encontrado 1 modelo instalado', ); - return 'Connected. $_temp0.'; + return 'Conectado. $_temp0.'; } @override - String get aiNoModels => 'No model selected.'; + String get aiNoModels => 'Nenhum modelo selecionado.'; @override String get aiConnectionFailed => - 'BusyMark could not verify AI text generation.'; + 'O BusyMark não conseguiu verificar a geração de texto por IA.'; @override String get aiConfigureFirst => - 'Enable an AI provider and verify a model in Settings → AI.'; + 'Ative um fornecedor de IA e verifique um modelo em Definições → IA.'; @override - String get aiEditWithAi => 'Edit with AI'; + String get aiEditWithAi => 'Editar com IA'; @override - String get aiRefineWithAi => 'Refine with AI'; + String get aiRefineWithAi => 'Melhorar com IA'; @override - String get aiInstruction => 'Instruction'; + String get aiInstruction => 'Instrução'; @override - String get aiChangeTarget => 'What may change'; + String get aiChangeTarget => 'O que pode ser alterado'; @override - String get aiSharedContext => 'Context shared with AI'; + String get aiSharedContext => 'Contexto partilhado com a IA'; @override - String get aiTargetSelection => 'Selected content'; + String get aiTargetSelection => 'Conteúdo selecionado'; @override - String get aiTargetInsertAfterBlock => 'Insert after current block'; + String get aiTargetInsertAfterBlock => 'Inserir após o bloco atual'; @override - String get aiTargetCurrentBlock => 'Current block'; + String get aiTargetCurrentBlock => 'Bloco atual'; @override - String get aiTargetCurrentSection => 'Current section'; + String get aiTargetCurrentSection => 'Secção atual'; @override - String get aiTargetCompleteDocument => 'Complete document'; + String get aiTargetCompleteDocument => 'Documento completo'; @override - String get aiContextNone => 'No document context'; + String get aiContextNone => 'Sem contexto do documento'; @override - String get aiContextSelection => 'Selected content'; + String get aiContextSelection => 'Conteúdo selecionado'; @override - String get aiContextCurrentBlock => 'Current block'; + String get aiContextCurrentBlock => 'Bloco atual'; @override - String get aiContextCurrentSection => 'Current section'; + String get aiContextCurrentSection => 'Secção atual'; @override - String get aiContextCompleteDocument => 'Complete document'; + String get aiContextCompleteDocument => 'Documento completo'; @override - String get aiGenerating => 'Generating proposal…'; + String get aiGenerating => 'A gerar proposta…'; @override - String get aiProposal => 'AI proposal'; + String get aiProposal => 'Proposta de IA'; @override - String get aiGenerateProposal => 'Generate proposal'; + String get aiGenerateProposal => 'Gerar proposta'; @override String aiContextDisclosure(int count) { - String _temp0 = intl.Intl.pluralLogic( - count, - locale: localeName, - other: '$count characters', - one: '1 character', - ); - return 'The selected provider will receive $_temp0 from the displayed context.'; + return 'O fornecedor selecionado receberá $count carateres do contexto apresentado.'; } @override - String get aiOriginal => 'Original'; + String get aiOriginal => 'Texto original'; @override - String get aiSuggested => 'Suggested'; + String get aiSuggested => 'Sugestão'; @override - String get aiApplyProposal => 'Apply proposal'; + String get aiApplyProposal => 'Aplicar proposta'; @override String aiTokenUsage(int input, int output) { - return '$input input tokens · $output output tokens'; + return '$input tokens de entrada · $output tokens de saída'; } @override String get aiStaleProposal => - 'The document changed while this proposal was generated. Run the action again.'; + 'O documento foi alterado enquanto esta proposta era gerada. Execute a ação novamente.'; @override String get gitAiStagedChangesChanged => - 'The staged changes changed while this commit message was generated. Run the action again.'; + 'As alterações no índice mudaram enquanto esta mensagem de commit era gerada. Execute a ação novamente.'; @override - String get aiViewContext => 'View context sent'; + String get aiViewContext => 'Ver contexto enviado'; @override - String get aiReviewExactContent => 'Review exact content'; + String get aiReviewExactContent => 'Rever conteúdo exato'; @override - String get aiContentToChange => 'Content to change'; + String get aiContentToChange => 'Conteúdo a alterar'; @override - String get aiContentSentToAi => 'Content sent to AI'; + String get aiContentSentToAi => 'Conteúdo enviado à IA'; @override - String get aiApiKey => 'API key'; + String get aiApiKey => 'Chave de API'; @override String get aiApiKeyStoredHint => - 'A key is stored in the system credential store'; + 'Uma chave está armazenada no cofre de credenciais do sistema'; @override - String get aiApiKeyEnterHint => 'Enter a provider API key'; + String get aiApiKeyEnterHint => 'Introduza uma chave de API do fornecedor'; @override - String get aiReplaceApiKey => 'Replace API key'; + String get aiReplaceApiKey => 'Substituir chave de API'; @override - String get aiSaveApiKey => 'Save API key securely'; + String get aiSaveApiKey => 'Guardar chave de API com segurança'; @override - String get aiRemoveApiKey => 'Remove saved API key'; + String get aiRemoveApiKey => 'Remover chave de API guardada'; @override String get aiCredentialSaved => - 'API key saved in the system credential store.'; + 'A chave de API foi guardada no cofre de credenciais do sistema.'; @override - String get aiCredentialRemoved => 'The saved API key was removed.'; + String get aiCredentialRemoved => 'A chave de API guardada foi removida.'; @override - String get aiModelRouting => 'Model routing'; + String get aiModelRouting => 'Seleção de modelo'; @override - String get aiAutomaticRouting => 'Automatic by task'; + String get aiAutomaticRouting => 'Automática conforme a tarefa'; @override - String get aiFixedModelRouting => 'Use selected model'; + String get aiFixedModelRouting => 'Usar o modelo selecionado'; @override - String get aiPreferredModel => 'Preferred model'; + String get aiPreferredModel => 'Modelo preferido'; @override - String get aiModel => 'Model'; + String get aiModel => 'Modelo'; @override String aiUsageThisMonth(int requests, int input, int output) { - return '$requests requests · $input input tokens · $output output tokens'; + return '$requests pedidos · $input tokens de entrada · $output tokens de saída'; } @override String aiCloudConsentTitle(String provider) { - return 'Send content to $provider?'; + return 'Enviar conteúdo para $provider?'; } @override String aiCloudConsentEnable(String provider) { - return 'Enable $provider'; + return 'Ativar $provider'; } @override String get aiCloudConsentMessage => - 'Only content shown in each AI review dialog is sent. Requests are stateless, proposals require review, and the API key is stored in the Linux system credential store.'; + 'Apenas o conteúdo apresentado em cada caixa de diálogo de revisão de IA é enviado. Os pedidos não mantêm estado, as propostas exigem revisão e a chave de API é guardada no cofre de credenciais do sistema Linux.'; @override String aiCloudConsentRequired(String provider) { - return 'Confirm $provider data sharing in Settings → AI first.'; + return 'Primeiro, confirme o partilha de dados com $provider em Definições → IA.'; } @override String aiGenerationVerified(String model, int count) { - String _temp0 = intl.Intl.pluralLogic( - count, - locale: localeName, - other: '$count compatible models available', - one: '1 compatible model available', - ); - return 'Generation verified with $model. $_temp0.'; + return 'Geração verificada com $model. Há $count modelos compatíveis disponíveis.'; } @override - String get aiColdStartObserved => 'A local model cold start was observed.'; + String get aiColdStartObserved => + 'Foi detetado um arranque a frio do modelo local.'; @override String get aiNoCompatibleModels => - 'No compatible text-generation model is available.'; + 'Não há nenhum modelo compatível de geração de texto disponível.'; @override - String get aiEnableProvider => 'Enable an AI provider first.'; + String get aiEnableProvider => 'Primeiro, ative um fornecedor de IA.'; @override - String get aiDraftCommitMessage => 'Draft commit message'; + String get aiDraftCommitMessage => 'Criar rascunho da mensagem de commit'; @override - String get aiDrafting => 'Drafting…'; + String get aiDrafting => 'A criar rascunho…'; @override - String get aiDraftWithAi => 'Draft with AI'; + String get aiDraftWithAi => 'Criar rascunho com IA'; @override - String get generateOrUpdateMarkdownToc => 'Generate/update table of contents'; + String get generateOrUpdateMarkdownToc => 'Gerar/atualizar sumário'; @override - String get markdownTocTitle => 'Table of contents'; + String get markdownTocTitle => 'Sumário'; @override String markdownTocUpdated(int count) { - String _temp0 = intl.Intl.pluralLogic( - count, - locale: localeName, - other: '$count entries', - one: '1 entry', - ); - return 'Table of contents updated with $_temp0.'; + return 'Sumário atualizado com $count entradas.'; } @override String get markdownTocNoHeadings => - 'Add at least one section heading before generating a table of contents.'; + 'Adicione pelo menos um título de secção antes de gerar um sumário.'; @override String get markdownTocMalformedMarkers => - 'The BusyMark table-of-contents markers are missing, duplicated, or out of order.'; + 'Os marcadores de sumário do BusyMark estão ausentes, duplicados ou fora de ordem.'; @override String diagnosticMarkdownHeadingSkippedLevel(int level, int previousLevel) { - return 'Heading level $level follows level $previousLevel; review the section nesting.'; + return 'O título de nível $level vem após o nível $previousLevel; reveja o aninhamento das secções.'; } @override String get diagnosticMarkdownLinkEmptyText => - 'Link text is empty; provide an accessible name that describes its purpose.'; + 'O texto da ligação está vazio; forneça um nome acessível que descreva a respetiva finalidade.'; @override String diagnosticMarkdownLinkReviewText(String text) { - return 'Review whether the link text “$text” describes its purpose in context.'; + return 'Verifique se o texto da ligação “$text” descreve a respetiva finalidade no contexto.'; } @override String get diagnosticMarkdownTableEmptyHeader => - 'Table header cells must identify their columns; complete each empty header.'; + 'Os cabeçalhos da tabela devem identificar suas colunas; preencha cada cabeçalho vazio.'; @override String get mathRenderFailed => - 'The mathematical expression could not be rendered.'; + 'Não foi possível renderizar a expressão matemática.'; @override - String get inlineMath => 'Inline math'; + String get inlineMath => 'Matemática em linha'; @override - String get displayMath => 'Display math'; + String get displayMath => 'Matemática em bloco'; @override String get goToDeclaration => 'Ir para a declaração'; @@ -4074,6 +4079,10 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { @override String get copyPlainText => 'Copiar como texto simples'; + @override + String get clipboardCopyFailed => + 'Não foi possível copiar a seleção para a área de transferência.'; + @override String get copyName => 'Copiar nome'; @@ -5628,9 +5637,9 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { count, locale: localeName, other: - '$count documentos sem salvamento recuperados. Revise cada um antes de salvar ou descartar.', + '$count documentos não salvos foram recuperados. Revise cada um antes de salvar ou descartar.', one: - '1 documento sem salvamento recuperado. Revise antes de salvar ou descartar.', + '1 documento não salvo foi recuperado. Revise-o antes de salvar ou descartar.', ); return '$_temp0'; } @@ -6340,9 +6349,9 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { count, locale: localeName, other: - 'Todas as mudanças staged e unstaged nos arquivos rastreados selecionados serão restauradas para HEAD.', + 'Todas as alterações preparadas e não preparadas nos arquivos rastreados selecionados serão restauradas para HEAD.', one: - 'Todas as mudanças staged e unstaged no arquivo selecionado rastreado serão restauradas para HEAD.', + 'Todas as alterações preparadas e não preparadas no arquivo rastreado selecionado serão restauradas para HEAD.', ); return '$_temp0'; } diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart index 80b96f87..9b1e8063 100644 --- a/lib/l10n/generated/app_localizations_ru.dart +++ b/lib/l10n/generated/app_localizations_ru.dart @@ -160,7 +160,7 @@ class AppLocalizationsRu extends AppLocalizations { @override String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + 'Не удалось скопировать выделенный фрагмент в буфер обмена.'; @override String get copyName => 'Копировать имя'; diff --git a/lib/l10n/generated/app_localizations_tr.dart b/lib/l10n/generated/app_localizations_tr.dart index 1b0c3b6a..8fe377f8 100644 --- a/lib/l10n/generated/app_localizations_tr.dart +++ b/lib/l10n/generated/app_localizations_tr.dart @@ -159,8 +159,7 @@ class AppLocalizationsTr extends AppLocalizations { String get copyPlainText => 'Düz metin olarak kopyala'; @override - String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + String get clipboardCopyFailed => 'Seçili içerik panoya kopyalanamadı.'; @override String get copyName => 'Adı kopyala'; diff --git a/lib/l10n/generated/app_localizations_uk.dart b/lib/l10n/generated/app_localizations_uk.dart index e06eb62f..b7201613 100644 --- a/lib/l10n/generated/app_localizations_uk.dart +++ b/lib/l10n/generated/app_localizations_uk.dart @@ -159,7 +159,7 @@ class AppLocalizationsUk extends AppLocalizations { @override String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + 'Не вдалося скопіювати виділений фрагмент до буфера обміну.'; @override String get copyName => 'Копіювати назву'; diff --git a/lib/l10n/generated/app_localizations_vi.dart b/lib/l10n/generated/app_localizations_vi.dart index 2e55517e..2251752b 100644 --- a/lib/l10n/generated/app_localizations_vi.dart +++ b/lib/l10n/generated/app_localizations_vi.dart @@ -158,7 +158,7 @@ class AppLocalizationsVi extends AppLocalizations { @override String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + 'Không thể sao chép nội dung đã chọn vào bảng nhớ tạm.'; @override String get copyName => 'Sao chép tên'; diff --git a/lib/l10n/generated/app_localizations_zh.dart b/lib/l10n/generated/app_localizations_zh.dart index e4b1a00f..8a0500b1 100644 --- a/lib/l10n/generated/app_localizations_zh.dart +++ b/lib/l10n/generated/app_localizations_zh.dart @@ -14,301 +14,291 @@ class AppLocalizationsZh extends AppLocalizations { String get appTitle => 'BusyMark'; @override - String get appSubtitle => - 'Editor for Markdown files and Writerside-compatible documentation projects.'; + String get appSubtitle => 'Markdown 文件和兼容 Writerside 的文档项目编辑器。'; @override - String get aboutBusyMark => 'About BusyMark'; + String get aboutBusyMark => '关于 BusyMark'; @override - String get aboutTagline => 'Markdown and Writerside Editor'; + String get aboutTagline => 'Markdown 和 Writerside 编辑器'; @override - String get aboutLicenseLabel => 'License'; + String get aboutLicenseLabel => '许可证'; @override String get aboutLicenseName => 'Apache License 2.0'; @override - String get aboutWebsite => 'Website'; + String get aboutWebsite => '网站'; @override - String get aboutSourceCode => 'Source code'; + String get aboutSourceCode => '源代码'; @override - String get reportIssue => 'Report an issue'; + String get reportIssue => '报告问题'; @override - String get feedbackCategory => 'Category'; + String get feedbackCategory => '类别'; @override - String get feedbackChooseCategory => 'Choose a category'; + String get feedbackChooseCategory => '选择类别'; @override - String get feedbackCategoryProblem => 'Problem or bug'; + String get feedbackCategoryProblem => '问题或错误'; @override - String get feedbackCategoryFeature => 'Feature request'; + String get feedbackCategoryFeature => '功能请求'; @override - String get feedbackCategoryPrivacySecurity => 'Privacy or security concern'; + String get feedbackCategoryPrivacySecurity => '隐私或安全问题'; @override - String get feedbackCategoryUsability => 'Usability concern'; + String get feedbackCategoryUsability => '可用性问题'; @override - String get feedbackCategoryOther => 'Other'; + String get feedbackCategoryOther => '其他'; @override - String get feedbackSubject => 'Subject'; + String get feedbackSubject => '主题'; @override - String get feedbackMessage => 'Detailed message'; + String get feedbackMessage => '详细留言'; @override - String get feedbackReplyEmail => 'Email address for replies (optional)'; + String get feedbackReplyEmail => '回复邮箱(可选)'; @override - String get feedbackIncludeTechnicalDetails => 'Include technical details'; + String get feedbackIncludeTechnicalDetails => '包含技术详细信息'; @override String get feedbackTechnicalDetailsDisclosure => - 'When enabled, this adds only your Linux operating-system version and BusyMark application locale. No logs, files, account data, or other diagnostics are attached.'; + '启用后,此选项仅会添加您的 Linux 操作系统版本和 BusyMark 应用语言。不会附加日志、文件、账户数据或其他诊断信息。'; @override - String get feedbackSubmit => 'Submit'; + String get feedbackSubmit => '提交'; @override - String get feedbackSubmitting => 'Submitting…'; + String get feedbackSubmitting => '正在提交…'; @override - String get feedbackCategoryRequired => 'Choose a category.'; + String get feedbackCategoryRequired => '请选择类别。'; @override - String get feedbackSubjectLength => - 'Subject must be between 3 and 120 characters.'; + String get feedbackSubjectLength => '主题必须包含 3 到 120 个字符。'; @override - String get feedbackMessageLength => - 'Message must be between 10 and 5,000 characters.'; + String get feedbackMessageLength => '信息必须包含 10 到 5,000 个字符。'; @override - String get feedbackReplyEmailInvalid => - 'Enter a valid email address or leave this field empty.'; + String get feedbackReplyEmailInvalid => '请输入有效的邮箱地址,或将此字段留空。'; @override - String get feedbackConnectionFailure => - 'BusyMark could not connect. Check your internet connection and try again.'; + String get feedbackConnectionFailure => 'BusyMark 无法连接。请检查网络连接后重试。'; @override - String get feedbackTimeoutFailure => 'The request timed out. Try again.'; + String get feedbackTimeoutFailure => '请求超时。请重试。'; @override - String get feedbackRateLimitedFailure => - 'Too many reports were sent from this connection. Wait and try again.'; + String get feedbackRateLimitedFailure => '此连接发送的报告过多。请稍候再试。'; @override - String get feedbackRejectedFailure => - 'The server rejected this report. Check the form fields and try again.'; + String get feedbackRejectedFailure => '服务器拒绝了此报告。请检查表单字段后重试。'; @override - String get feedbackServerFailure => - 'The server could not accept the report. Try again later.'; + String get feedbackServerFailure => '服务器无法接收此报告。请稍后重试。'; @override String feedbackSuccess(String id) { - return 'Feedback sent. Reference ID: $id'; + return '反馈已发送。参考 ID:$id'; } @override - String get advanced => 'Advanced'; + String get advanced => '高级'; @override - String get addToGit => 'Add to Git'; + String get addToGit => '添加到 Git'; @override - String get appearance => 'Appearance'; + String get appearance => '外观'; @override - String get apply => 'Apply'; + String get apply => '应用'; @override - String get back => 'Back'; + String get back => '返回'; @override - String get bottomLeft => 'Bottom left'; + String get bottomLeft => '左下'; @override - String get bottomRight => 'Bottom right'; + String get bottomRight => '右下'; @override - String get cancel => 'Cancel'; + String get cancel => '取消'; @override - String get choose => 'Choose'; + String get choose => '选择'; @override - String get chooseLocation => 'Choose location'; + String get chooseLocation => '选择位置'; @override - String get copy => 'Copy'; + String get copy => '复制'; @override - String get copyPlainText => 'Copy Plain Text'; + String get copyPlainText => '复制为纯文本'; @override - String get clipboardCopyFailed => - 'Could not copy the selection to the clipboard.'; + String get clipboardCopyFailed => '无法将所选内容复制到剪贴板。'; @override - String get copyName => 'Copy name'; + String get copyName => '复制名称'; @override - String get copyFileName => 'Copy file name'; + String get copyFileName => '复制文件名'; @override - String get copyPath => 'Copy path'; + String get copyPath => '复制路径'; @override - String get create => 'Create'; + String get create => '创建'; @override - String get creating => 'Creating...'; + String get creating => '正在创建…'; @override - String get cut => 'Cut'; + String get cut => '剪切'; @override - String get promoteSection => 'Promote section'; + String get promoteSection => '提升节级别'; @override - String get demoteSection => 'Demote section'; + String get demoteSection => '降低节级别'; @override - String get moveSectionUp => 'Move section up'; + String get moveSectionUp => '上移节'; @override - String get moveSectionDown => 'Move section down'; + String get moveSectionDown => '下移节'; @override - String get confirmDeleteSectionTitle => 'Delete section?'; + String get confirmDeleteSectionTitle => '删除此节?'; @override String confirmDeleteSectionMessage(String name) { - return 'Delete “$name” and all content in its section? This cannot be undone.'; + return '删除“$name”及其节中的全部内容?此操作无法撤销。'; } @override - String get darkTheme => 'Dark'; + String get darkTheme => '深色'; @override - String get delete => 'Delete'; + String get delete => '删除'; @override - String get discard => 'Discard'; + String get discard => '放弃'; @override - String get editor => 'Editor'; + String get editor => '编辑器'; @override - String get file => 'File'; + String get file => '文件'; @override - String get fileHistory => 'File History'; + String get fileHistory => '文件历史记录'; @override - String get folder => 'Folder'; + String get folder => '文件夹'; @override - String get insert => 'Insert'; + String get insert => '插入'; @override - String get keyboardShortcuts => 'Keyboard Shortcuts'; + String get keyboardShortcuts => '键盘快捷键'; @override - String get commandPalette => 'Command Palette'; + String get commandPalette => '命令面板'; @override - String get commandPaletteHint => 'Type a command'; + String get commandPaletteHint => '输入命令'; @override - String get commandPaletteEmpty => 'No matching commands'; + String get commandPaletteEmpty => '没有匹配的命令'; @override - String get commandUnavailableInContext => - 'Unavailable in the current editor context'; + String get commandUnavailableInContext => '当前编辑器上下文中无法使用此命令'; @override - String get lightTheme => 'Light'; + String get lightTheme => '浅色'; @override - String get mainMenu => 'Main menu'; + String get mainMenu => '主菜单'; @override - String get fullScreen => 'Full Screen'; + String get fullScreen => '全屏'; @override String get markdown => 'Markdown'; @override - String get open => 'Open'; + String get open => '打开'; @override - String get openInFiles => 'Open in Files'; + String get openInFiles => '在文件中打开'; @override - String get pathActions => 'Path actions'; + String get pathActions => '路径操作'; @override - String get outline => 'Outline'; + String get outline => '大纲'; @override - String get overwrite => 'Overwrite'; + String get overwrite => '覆盖'; @override - String get paste => 'Paste'; + String get paste => '粘贴'; @override - String get reading => 'Reading'; + String get reading => '阅读'; @override - String get removeFromRecent => 'Remove from Recent'; + String get removeFromRecent => '从最近使用记录中移除'; @override - String get recent => 'Recent'; + String get recent => '最近使用'; @override - String get redo => 'Redo'; + String get redo => '重做'; @override - String get save => 'Save'; + String get save => '保存'; @override - String get search => 'Search'; + String get search => '搜索'; @override - String get selectAll => 'Select all'; + String get selectAll => '全选'; @override - String get settings => 'Settings'; + String get settings => '设置'; @override - String get source => 'Source'; + String get source => '源代码'; @override - String get split => 'Split'; + String get split => '拆分'; @override - String get systemTheme => 'System'; + String get systemTheme => '系统'; @override - String get theme => 'Theme'; + String get theme => '主题'; @override - String get appLanguage => 'Language'; + String get appLanguage => '语言'; @override - String get systemLanguage => 'System'; + String get systemLanguage => '系统'; @override String get languageEnglish => 'English'; @@ -374,28 +364,28 @@ class AppLocalizationsZh extends AppLocalizations { String get languageSimplifiedChinese => '简体中文'; @override - String get toggleSidebar => 'Sidebar panel'; + String get toggleSidebar => '侧边栏面板'; @override - String get topLeft => 'Top left'; + String get topLeft => '左上'; @override - String get topRight => 'Top right'; + String get topRight => '右上'; @override - String get undo => 'Undo'; + String get undo => '撤销'; @override - String get validate => 'Validate'; + String get validate => '验证'; @override - String get validation => 'Validation'; + String get validation => '验证'; @override - String get viewMode => 'View mode'; + String get viewMode => '视图模式'; @override - String get welcome => 'Welcome'; + String get welcome => '欢迎'; @override String get writerside => 'Writerside'; @@ -407,399 +397,364 @@ class AppLocalizationsZh extends AppLocalizations { String get fileTypeMarkdown => 'Markdown'; @override - String get fileTypeImages => 'Images'; + String get fileTypeImages => '图像'; @override - String get openMarkdownFile => 'Open Markdown File'; + String get openMarkdownFile => '打开 Markdown 文件'; @override - String get markdownFileExtensions => '.md or .markdown'; + String get markdownFileExtensions => '.md 或 .markdown'; @override - String get openFolderOrWritersideProject => - 'Open Folder or Writerside Project'; + String get openFolderOrWritersideProject => '打开文件夹或 Writerside 项目'; @override String get markdownFolderOrWritersideProject => - 'Markdown folder or Writerside-compatible project'; + 'Markdown 文件夹或兼容 Writerside 的项目'; @override - String get noOpenFile => 'No open file'; + String get noOpenFile => '没有打开的文件'; @override - String get shortcutDeleteTreeItemDescription => - 'Delete the selected Files item, or remove the selected topic from the table of contents'; + String get shortcutDeleteTreeItemDescription => '删除选中的文件项,或从目录中移除选中的主题'; @override - String get shortcutGroupGeneral => 'General'; + String get shortcutGroupGeneral => '常规'; @override - String get shortcutNewDocument => 'Create'; + String get shortcutNewDocument => '创建'; @override - String get shortcutNewDocumentDescription => - 'Create a Markdown file or Writerside project'; + String get shortcutNewDocumentDescription => '创建 Markdown 文件或 Writerside 项目'; @override - String get shortcutOpenDescription => - 'Open a Markdown file, folder, or Writerside project'; + String get shortcutOpenDescription => '打开 Markdown 文件、文件夹或 Writerside 项目'; @override - String get shortcutSaveDescription => 'Save the current document'; + String get shortcutSaveDescription => '保存当前文档'; @override - String get shortcutSearchDescription => 'Search the current workspace'; + String get shortcutSearchDescription => '搜索当前工作区'; @override - String get shortcutKeyboardShortcutsDescription => - 'Show this keyboard shortcut reference'; + String get shortcutKeyboardShortcutsDescription => '显示此键盘快捷键参考'; @override String get shortcutSyntaxReferenceDescription => '打开语法参考'; @override - String get shortcutSettingsDescription => 'Open BusyMark settings'; + String get shortcutSettingsDescription => '打开 BusyMark 设置'; @override - String get shortcutNextTab => 'Next tab'; + String get shortcutNextTab => '下一个标签页'; @override - String get shortcutNextTabDescription => 'Move to the next open tab'; + String get shortcutNextTabDescription => '移至下一个打开的标签页'; @override - String get shortcutPreviousTab => 'Previous tab'; + String get shortcutPreviousTab => '上一个标签页'; @override - String get shortcutPreviousTabDescription => 'Move to the previous open tab'; + String get shortcutPreviousTabDescription => '移至上一个打开的标签页'; @override - String get shortcutCloseTab => 'Close tab'; + String get shortcutCloseTab => '关闭标签页'; @override - String get shortcutCloseTabDescription => 'Close the active tab'; + String get shortcutCloseTabDescription => '关闭当前标签页'; @override - String get shortcutCloseAllTabs => 'Close all tabs'; + String get shortcutCloseAllTabs => '关闭所有标签页'; @override - String get shortcutCloseAllTabsDescription => 'Close all open tabs'; + String get shortcutCloseAllTabsDescription => '关闭所有打开的标签页'; @override - String get shortcutGroupTextEditing => 'Text Editing'; + String get shortcutGroupTextEditing => '文本编辑'; @override - String get shortcutSelectAllDescription => - 'In Source mode, select all text; in Editor mode, press twice to select every block'; + String get shortcutSelectAllDescription => '在源代码模式下选择全部文本;在编辑器模式下按两次以选择所有块'; @override - String get shortcutCutDescription => 'Cut the selected text'; + String get shortcutCutDescription => '剪切选中的文本'; @override - String get shortcutCopyDescription => 'Copy the selected text'; + String get shortcutCopyDescription => '复制选中的文本'; @override - String get shortcutPasteDescription => 'Paste from the clipboard'; + String get shortcutPasteDescription => '从剪贴板粘贴'; @override - String get shortcutPastePlainTextDescription => - 'Paste clipboard text without formatting'; + String get shortcutPastePlainTextDescription => '粘贴剪贴板中的无格式文本'; @override - String get shortcutUndoDescription => 'Undo the last edit'; + String get shortcutUndoDescription => '撤销上次编辑'; @override - String get shortcutRedoDescription => 'Redo the last undone edit'; + String get shortcutRedoDescription => '重做上次撤销的编辑'; @override - String get shortcutInsertIndentation => 'Insert indentation'; + String get shortcutInsertIndentation => '插入缩进'; @override - String get shortcutInsertIndentationDescription => - 'Insert indentation at the cursor'; + String get shortcutInsertIndentationDescription => '在光标处插入缩进'; @override - String get shortcutOutdentSource => 'Outdent source'; + String get shortcutOutdentSource => '减少源代码缩进'; @override - String get shortcutOutdentSourceDescription => - 'Remove one indentation level in Source mode'; + String get shortcutOutdentSourceDescription => '在源代码模式下减少一级缩进'; @override - String get shortcutEscape => 'Close search or clear block selection'; + String get shortcutEscape => '关闭搜索或清除块选择'; @override - String get shortcutEscapeDescription => - 'Close workspace search or clear a block selection in Editor mode'; + String get shortcutEscapeDescription => '关闭工作区搜索,或在编辑器模式下清除块选择'; @override - String get shortcutGroupFormatting => 'Formatting'; + String get shortcutGroupFormatting => '格式'; @override - String get shortcutBoldDescription => 'Toggle bold on the selected text'; + String get shortcutBoldDescription => '切换选中文本的粗体'; @override - String get shortcutItalicDescription => 'Toggle italic on the selected text'; + String get shortcutItalicDescription => '切换选中文本的斜体'; @override - String get shortcutUnderlineDescription => - 'Toggle underline on the selected text'; + String get shortcutUnderlineDescription => '切换选中文本的下划线'; @override - String get shortcutLinkDescription => 'Insert or edit a link'; + String get shortcutLinkDescription => '插入或编辑链接'; @override - String get shortcutInlineCodeDescription => - 'Toggle inline code on the selected text'; + String get shortcutInlineCodeDescription => '切换选中文本的行内代码格式'; @override - String get shortcutStrikethroughDescription => - 'Toggle strikethrough on the selected text'; + String get shortcutStrikethroughDescription => '切换选中文本的删除线'; @override - String get shortcutGroupBlocks => 'Blocks'; + String get shortcutGroupBlocks => '块'; @override - String get shortcutParagraphDescription => - 'Set the current block to paragraph'; + String get shortcutParagraphDescription => '将当前块设为段落'; @override - String get shortcutHeading1Description => - 'Set the current block to Heading 1'; + String get shortcutHeading1Description => '将当前块设为标题 1'; @override - String get shortcutHeading2Description => - 'Set the current block to Heading 2'; + String get shortcutHeading2Description => '将当前块设为标题 2'; @override - String get shortcutHeading3Description => - 'Set the current block to Heading 3'; + String get shortcutHeading3Description => '将当前块设为标题 3'; @override - String get shortcutHeading4Description => - 'Set the current block to Heading 4'; + String get shortcutHeading4Description => '将当前块设为标题 4'; @override - String get shortcutHeading5Description => - 'Set the current block to Heading 5'; + String get shortcutHeading5Description => '将当前块设为标题 5'; @override - String get shortcutHeading6Description => - 'Set the current block to Heading 6'; + String get shortcutHeading6Description => '将当前块设为标题 6'; @override - String get shortcutGroupLists => 'Lists'; + String get shortcutGroupLists => '列表'; @override - String get numberedList => 'Numbered list'; + String get numberedList => '编号列表'; @override - String get shortcutNumberedListDescription => - 'Toggle numbered list formatting'; + String get shortcutNumberedListDescription => '切换编号列表格式'; @override - String get bulletedList => 'Bulleted list'; + String get bulletedList => '项目符号列表'; @override - String get shortcutBulletedListDescription => - 'Toggle bulleted list formatting'; + String get shortcutBulletedListDescription => '切换项目符号列表格式'; @override - String get checklist => 'Checklist'; + String get checklist => '检查清单'; @override - String get shortcutChecklistDescription => 'Toggle checklist formatting'; + String get shortcutChecklistDescription => '切换检查清单格式'; @override - String get shortcutGroupSidebar => 'Sidebar'; + String get shortcutGroupSidebar => '侧边栏'; @override - String get sidebarViewMenu => 'Sidebar view'; + String get sidebarViewMenu => '侧边栏视图'; @override - String get createMarkdownFile => 'Create Markdown File'; + String get createMarkdownFile => '创建 Markdown 文件'; @override - String get createMarkdownFileDescription => - 'Start an unsaved local Markdown document'; + String get createMarkdownFileDescription => '开始创建未保存的本地 Markdown 文档'; @override - String get createWritersideProject => 'Create Writerside Project'; + String get createWritersideProject => '创建 Writerside 项目'; @override - String get createWritersideProjectDescription => - 'Start a local Writerside-compatible project'; + String get createWritersideProjectDescription => '开始创建本地兼容 Writerside 的项目'; @override - String get defaultProjectName => 'Documentation'; + String get defaultProjectName => '文档'; @override - String get defaultInstanceName => 'User Guide'; + String get defaultInstanceName => '用户指南'; @override - String get defaultStartTopicTitle => 'Getting started'; + String get defaultStartTopicTitle => '开始使用'; @override - String get projectName => 'Project name'; + String get projectName => '项目名称'; @override - String get directoryName => 'Directory name'; + String get directoryName => '目录名称'; @override - String get instanceName => 'Instance name'; + String get instanceName => '实例名称'; @override - String get instanceId => 'Instance ID'; + String get instanceId => '实例 ID'; @override - String get startTopicTitle => 'Start topic title'; + String get startTopicTitle => '起始主题标题'; @override - String get location => 'Location'; + String get location => '位置'; @override - String get projectNameRequired => 'Project name is required.'; + String get projectNameRequired => '项目名称为必填项。'; @override - String get directoryNameRequired => 'Directory name is required.'; + String get directoryNameRequired => '目录名称为必填项。'; @override - String get useSingleSafeDirectoryName => 'Use a single safe directory name.'; + String get useSingleSafeDirectoryName => '使用单一且安全的目录名称。'; @override - String get useLowercaseIdentifier => - 'Use a lowercase identifier with letters, numbers, underscores, or hyphens.'; + String get useLowercaseIdentifier => '使用仅包含小写字母、数字、下划线或连字符的小写标识符。'; @override - String get startTopicTitleRequired => 'Start topic title is required.'; + String get startTopicTitleRequired => '起始主题标题为必填项。'; @override - String get createWritersideProjectFailed => - 'Could not create Writerside project.'; + String get createWritersideProjectFailed => '无法创建 Writerside 项目。'; @override - String get settingsTitle => 'BusyMark Settings'; + String get settingsTitle => 'BusyMark 设置'; @override - String get autoSave => 'Auto Save'; + String get autoSave => '自动保存'; @override - String get autoSaveDescription => - 'Save file changes automatically after a short idle delay.'; + String get autoSaveDescription => '在短暂空闲后自动保存文件更改。'; @override - String get wordWrap => 'Word wrap'; + String get wordWrap => '自动换行'; @override - String get editorFontSize => 'Editor font size'; + String get editorFontSize => '编辑器字体大小'; @override - String get validateOnEdit => 'Validate on edit'; + String get validateOnEdit => '编辑时验证'; @override - String get clearRecentWorkspaces => 'Clear recent workspaces'; + String get clearRecentWorkspaces => '清除最近使用的工作区'; @override - String get editingButtonsPosition => 'Editing buttons position'; + String get editingButtonsPosition => '编辑按钮位置'; @override - String get editingButtonsPositionDescription => - 'Choose where the floating WYSIWYG editing buttons appear.'; + String get editingButtonsPositionDescription => '选择浮动 WYSIWYG 编辑按钮的显示位置。'; @override - String get editingButtonsDirection => 'Editing buttons direction'; + String get editingButtonsDirection => '编辑按钮方向'; @override - String get editingButtonsDirectionDescription => - 'Choose whether the floating WYSIWYG editing buttons are arranged horizontally or vertically.'; + String get editingButtonsDirectionDescription => '选择水平或垂直排列浮动 WYSIWYG 编辑按钮。'; @override - String get horizontal => 'Horizontal'; + String get horizontal => '水平'; @override - String get vertical => 'Vertical'; + String get vertical => '垂直'; @override - String get privacy => 'Privacy'; + String get privacy => '隐私'; @override - String get allowRemoteImages => 'Load remote images'; + String get allowRemoteImages => '加载远程图像'; @override String get allowRemoteImagesDescription => - 'Allow Markdown preview and editor images to load from http and https URLs.'; + '允许 Markdown 预览和编辑器从 http 和 https URL 加载图像。'; @override - String get clearRemoteImagePermissions => 'Clear remote image permissions'; + String get clearRemoteImagePermissions => '清除远程图像权限'; @override - String get clearRemoteImagePermissionsDescription => - 'Forget workspaces that were allowed to load remote images.'; + String get clearRemoteImagePermissionsDescription => '忘记已获准加载远程图像的工作区。'; @override - String get clearGitWorkspaceTrust => 'Clear trusted Git workspaces'; + String get clearGitWorkspaceTrust => '清除受信任的 Git 工作区'; @override - String get clearGitWorkspaceTrustDescription => - 'Ask before enabling Git features for previously trusted workspaces.'; + String get clearGitWorkspaceTrustDescription => '为之前受信任的工作区启用 Git 功能前先进行询问。'; @override - String get settingsWindowSectionTitle => 'Window'; + String get settingsWindowSectionTitle => '窗口'; @override - String get settingsReopenWorkspaceOnStartupTitle => - 'Reopen previous workspace on startup'; + String get settingsReopenWorkspaceOnStartupTitle => '启动时重新打开上次的工作区'; @override String get settingsReopenWorkspaceOnStartupDescription => - 'Open the workspace and tabs from the previous session when BusyMark starts.'; + 'BusyMark 启动时打开上次会话中的工作区和标签页。'; @override - String get settingsConfirmCloseWithUnsavedChangesTitle => - 'Confirm before closing with unsaved changes'; + String get settingsConfirmCloseWithUnsavedChangesTitle => '有未保存更改时关闭前进行确认'; @override String get settingsConfirmCloseWithUnsavedChangesDescription => - 'Ask before closing BusyMark when documents have unsaved changes.'; + '文档有未保存更改时,关闭 BusyMark 前先进行询问。'; @override - String get closeUnsavedChangesTitle => 'Unsaved changes'; + String get closeUnsavedChangesTitle => '未保存的更改'; @override String get closeUnsavedChangesSingleMessage => - 'This document has unsaved changes. Save changes before closing BusyMark?'; + '此文档有未保存的更改。关闭 BusyMark 前保存更改?'; @override String closeUnsavedChangesMultipleMessage(int count) { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: - '$count documents have unsaved changes. Save changes before closing BusyMark?', - one: - '1 document has unsaved changes. Save changes before closing BusyMark?', - zero: 'Save changes before closing BusyMark?', + other: '有 $count 个文档包含未保存的更改。关闭 BusyMark 前保存更改?', + one: '有 1 个文档包含未保存的更改。关闭 BusyMark 前保存更改?', + zero: '关闭 BusyMark 前保存更改?', ); return '$_temp0'; } @override - String get closeUnsavedChangesCancel => 'Cancel'; + String get closeUnsavedChangesCancel => '取消'; @override - String get closeUnsavedChangesDiscard => 'Discard'; + String get closeUnsavedChangesDiscard => '放弃'; @override - String get closeUnsavedChangesSave => 'Save'; + String get closeUnsavedChangesSave => '保存'; @override - String get currentFile => 'current file'; + String get currentFile => '当前文件'; @override - String get unsavedChanges => 'Unsaved changes'; + String get unsavedChanges => '未保存的更改'; @override String unsavedChangesMessage(String fileName) { - return 'You have unsaved changes in $fileName. Save them before continuing?'; + return '$fileName 中有未保存的更改。继续前保存这些更改?'; } @override @@ -807,158 +762,155 @@ class AppLocalizationsZh extends AppLocalizations { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: - '$count documents have unsaved changes. Save them before continuing?', - one: '1 document has unsaved changes. Save it before continuing?', + other: '有 $count 个文档包含未保存的更改。继续前保存它们?', + one: '有 1 个文档包含未保存的更改。继续前保存它?', ); return '$_temp0'; } @override - String get fileChangedOnDisk => 'File changed on disk'; + String get fileChangedOnDisk => '文件已在磁盘上更改'; @override - String get fileChangedOnDiskMessage => - 'This file changed on disk since you opened it. Overwrite it?'; + String get fileChangedOnDiskMessage => '自打开此文件后,它已在磁盘上发生更改。覆盖它?'; @override - String get untitledMarkdownFileName => 'Untitled.md'; + String get untitledMarkdownFileName => '未命名.md'; @override - String get unorderedList => 'Unordered list'; + String get unorderedList => '无序列表'; @override - String get orderedList => 'Ordered list'; + String get orderedList => '有序列表'; @override - String get taskList => 'Task list'; + String get taskList => '任务列表'; @override - String get toggleTaskChecked => 'Toggle task checked'; + String get toggleTaskChecked => '切换任务选中状态'; @override - String get indentListItem => 'Indent list item'; + String get indentListItem => '增加列表项缩进'; @override - String get outdentListItem => 'Outdent list item'; + String get outdentListItem => '减少列表项缩进'; @override - String get blockquote => 'Blockquote'; + String get blockquote => '引用块'; @override - String get codeBlock => 'Code block'; + String get codeBlock => '代码块'; @override - String get codeBlockLanguage => 'Code block language'; + String get codeBlockLanguage => '代码块语言'; @override - String get image => 'Image'; + String get image => '图像'; @override - String get video => 'Video'; + String get video => '视频'; @override - String get openVideo => 'Play video'; + String get openVideo => '播放视频'; @override - String get pauseVideo => 'Pause video'; + String get pauseVideo => '暂停视频'; @override - String get videoUnavailable => 'Video unavailable'; + String get videoUnavailable => '视频不可用'; @override - String get videoPreview => 'Video preview'; + String get videoPreview => '视频预览'; @override - String get diagnosticWritersideVideoMissingSource => - 'Video is missing its src attribute.'; + String get diagnosticWritersideVideoMissingSource => '视频缺少 src 属性。'; @override String diagnosticWritersideVideoUnsupportedSource(String source) { - return 'Unsupported video source: $source'; + return '不支持的视频源:$source'; } @override String diagnosticWritersideVideoMissingFile(String source) { - return 'Video file does not exist: $source'; + return '视频文件不存在:$source'; } @override String diagnosticWritersideVideoMissingPreview(String preview) { - return 'Video preview image does not exist: $preview'; + return '视频预览图像不存在:$preview'; } @override - String get inlineImage => 'Inline image'; + String get inlineImage => '行内图像'; @override - String get table => 'Table'; + String get table => '表格'; @override - String get htmlBlock => 'HTML block'; + String get htmlBlock => 'HTML 块'; @override - String get htmlContentDefault => 'HTML content'; + String get htmlContentDefault => 'HTML 内容'; @override - String get shortcutHtmlBlockDescription => 'Insert or edit an HTML block'; + String get shortcutHtmlBlockDescription => '插入或编辑 HTML 块'; @override - String get renderedHtml => 'Rendered HTML'; + String get renderedHtml => '已渲染的 HTML'; @override - String get editHtml => 'Edit HTML'; + String get editHtml => '编辑 HTML'; @override - String get htmlSource => 'HTML source'; + String get htmlSource => 'HTML 源代码'; @override - String get thematicBreak => 'Thematic break'; + String get thematicBreak => '分隔线'; @override - String get bold => 'Bold'; + String get bold => '粗体'; @override - String get italic => 'Italic'; + String get italic => '斜体'; @override - String get underline => 'Underline'; + String get underline => '下划线'; @override - String get strikethrough => 'Strikethrough'; + String get strikethrough => '删除线'; @override - String get inlineCode => 'Inline code'; + String get inlineCode => '行内代码'; @override - String get link => 'Link'; + String get link => '链接'; @override - String get hardLineBreak => 'Hard line break'; + String get hardLineBreak => '硬换行'; @override - String get textStyle => 'Text style'; + String get textStyle => '文本样式'; @override - String get paragraph => 'Paragraph'; + String get paragraph => '段落'; @override - String get heading1 => 'Heading 1'; + String get heading1 => '标题 1'; @override - String get heading2 => 'Heading 2'; + String get heading2 => '标题 2'; @override - String get heading3 => 'Heading 3'; + String get heading3 => '标题 3'; @override - String get heading4 => 'Heading 4'; + String get heading4 => '标题 4'; @override - String get heading5 => 'Heading 5'; + String get heading5 => '标题 5'; @override - String get heading6 => 'Heading 6'; + String get heading6 => '标题 6'; @override String headingLevelAbbreviation(int level) { @@ -966,264 +918,263 @@ class AppLocalizationsZh extends AppLocalizations { } @override - String get deleteTable => 'Delete table'; + String get deleteTable => '删除表格'; @override String tableColumnNumber(int columnNumber) { - return 'Column $columnNumber'; + return '列 $columnNumber'; } @override - String get insertColumnLeft => 'Insert column left'; + String get insertColumnLeft => '在左侧插入列'; @override - String get insertColumnRight => 'Insert column right'; + String get insertColumnRight => '在右侧插入列'; @override - String get deleteColumn => 'Delete column'; + String get deleteColumn => '删除列'; @override - String get tableAlignmentUnspecified => 'Alignment: Unspecified'; + String get tableAlignmentUnspecified => '对齐方式:未指定'; @override - String get tableAlignmentLeft => 'Alignment: Left'; + String get tableAlignmentLeft => '对齐方式:左对齐'; @override - String get tableAlignmentCenter => 'Alignment: Center'; + String get tableAlignmentCenter => '对齐方式:居中'; @override - String get tableAlignmentRight => 'Alignment: Right'; + String get tableAlignmentRight => '对齐方式:右对齐'; @override String tableRowNumber(int rowNumber) { - return 'Row $rowNumber'; + return '行 $rowNumber'; } @override - String get insertRowAbove => 'Insert row above'; + String get insertRowAbove => '在上方插入行'; @override - String get insertRowBelow => 'Insert row below'; + String get insertRowBelow => '在下方插入行'; @override - String get deleteRow => 'Delete row'; + String get deleteRow => '删除行'; @override - String get tableHeaderHint => 'Header'; + String get tableHeaderHint => '标题'; @override - String get tableCellHint => 'Cell'; + String get tableCellHint => '单元格'; @override - String get language => 'Language'; + String get language => '语言'; @override - String get hideEditingButtons => 'Hide editing buttons'; + String get hideEditingButtons => '隐藏编辑按钮'; @override - String get showEditingButtons => 'Show editing buttons'; + String get showEditingButtons => '显示编辑按钮'; @override - String get altText => 'Alt text'; + String get altText => '替代文本'; @override - String get editorPlaceholderText => 'text'; + String get editorPlaceholderText => '文本'; @override - String get editorPlaceholderCode => 'code'; + String get editorPlaceholderCode => '代码'; @override - String get editorPlaceholderAltText => 'alt text'; + String get editorPlaceholderAltText => '替代文本'; @override - String get describeTheImage => 'Describe the image'; + String get describeTheImage => '描述图像'; @override - String get columns => 'Columns'; + String get columns => '列'; @override - String get rows => 'Rows'; + String get rows => '行'; @override String tableHeaderNumber(int columnNumber) { - return 'Header $columnNumber'; + return '标题 $columnNumber'; } @override - String get tableCellDefault => 'Cell'; + String get tableCellDefault => '单元格'; @override - String get noImageSource => 'No image source'; + String get noImageSource => '没有图像源'; @override - String get remoteImageBlocked => 'Remote image blocked'; + String get remoteImageBlocked => '远程图像已阻止'; @override - String get remoteImageBlockedTooltip => - 'Choose whether BusyMark can load remote images.'; + String get remoteImageBlockedTooltip => '选择是否允许 BusyMark 加载远程图像。'; @override - String get remoteImagesBlockedTitle => 'Remote images are blocked'; + String get remoteImagesBlockedTitle => '远程图像已阻止'; @override String get remoteImagesBlockedMessage => - 'This document references images from the internet. Loading them can reveal network information to the image host.'; + '本文档引用了来自互联网的图像。加载这些图像可能会向图像托管方泄露网络信息。'; @override - String get loadRemoteImagesForWorkspace => 'Load for this workspace'; + String get loadRemoteImagesForWorkspace => '为此工作区加载'; @override - String get alwaysLoadRemoteImages => 'Always load remote images'; + String get alwaysLoadRemoteImages => '始终加载远程图像'; @override - String get hideSidebar => 'Hide sidebar panel'; + String get hideSidebar => '隐藏侧边栏面板'; @override - String get showSidebar => 'Show sidebar panel'; + String get showSidebar => '显示侧边栏面板'; @override - String get showPreview => 'Show preview'; + String get showPreview => '显示预览'; @override - String get hidePreview => 'Hide preview'; + String get hidePreview => '隐藏预览'; @override - String get workspaceKindUnsavedMarkdown => 'Unsaved Markdown file'; + String get workspaceKindUnsavedMarkdown => '未保存的 Markdown 文件'; @override - String get workspaceKindSingleMarkdown => 'Single Markdown file'; + String get workspaceKindSingleMarkdown => '单个 Markdown 文件'; @override - String get workspaceKindMarkdownFolder => 'Markdown folder'; + String get workspaceKindMarkdownFolder => 'Markdown 文件夹'; @override - String get workspaceKindWritersideModule => 'Writerside module'; + String get workspaceKindWritersideModule => 'Writerside 模块'; @override - String get problems => 'Problems'; + String get problems => '问题'; @override String diagnosticCount(int count) { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count diagnostics', - one: '1 diagnostic', - zero: 'No diagnostics', + other: '$count 条诊断信息', + one: '1 条诊断信息', + zero: '没有诊断信息', ); return '$_temp0'; } @override - String get files => 'Files'; + String get files => '文件'; @override - String get toc => 'TOC'; + String get toc => '目录'; @override - String get tocActions => 'TOC actions'; + String get tocActions => '目录操作'; @override - String get markdownUnsaved => 'Markdown - unsaved'; + String get markdownUnsaved => 'Markdown - 未保存'; @override String workspaceDetail(String kind, int count) { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count files', - one: '1 file', + other: '$count 个文件', + one: '1 个文件', ); return '$kind - $_temp0'; } @override - String get noFiles => 'No files'; + String get noFiles => '没有文件'; @override - String get newFile => 'New file'; + String get newFile => '新建文件'; @override - String get noWritersideToc => 'No Writerside TOC'; + String get noWritersideToc => '没有 Writerside 目录'; @override - String get tocSection => 'TOC section'; + String get tocSection => '目录节'; @override - String get newTopic => 'New Topic'; + String get newTopic => '新建主题'; @override - String get newChildTopic => 'New Child Topic'; + String get newChildTopic => '新建子主题'; @override - String get newSiblingTopic => 'New Sibling Topic'; + String get newSiblingTopic => '新建同级主题'; @override - String get renameTopicFile => 'Rename Topic File'; + String get renameTopicFile => '重命名主题文件'; @override - String get topicPlacement => 'TOC placement'; + String get topicPlacement => '目录位置'; @override - String get tocRoot => 'At TOC root'; + String get tocRoot => '位于目录根级别'; @override - String get afterSelectedTopic => 'After selected topic'; + String get afterSelectedTopic => '位于选中主题之后'; @override - String get insideSelectedTopic => 'Inside selected topic'; + String get insideSelectedTopic => '位于选中主题内'; @override - String get pasteAfterTopic => 'Paste After'; + String get pasteAfterTopic => '粘贴到主题之后'; @override - String get pasteAsChildTopic => 'Paste as Child'; + String get pasteAsChildTopic => '粘贴为子主题'; @override - String get removeFromToc => 'Remove from TOC'; + String get removeFromToc => '从目录中移除'; @override - String get confirmRemoveFromTocTitle => 'Remove from TOC?'; + String get confirmRemoveFromTocTitle => '从目录中移除?'; @override String confirmRemoveFromTocMessage(String name) { - return 'Remove $name from this table of contents? The topic file will be kept.'; + return '从此目录中移除 $name?主题文件将被保留。'; } @override - String get confirmDeleteTopicTitle => 'Delete topic file?'; + String get confirmDeleteTopicTitle => '删除主题文件?'; @override String confirmDeleteTopicMessage(String name) { - return 'Delete $name and remove it from every table of contents? This cannot be undone.'; + return '删除 $name 并从每个目录中移除它?此操作无法撤销。'; } @override - String get safeDeleteTopicFile => 'Safe Delete Topic File…'; + String get safeDeleteTopicFile => '安全删除主题文件…'; @override - String get removeTocElement => 'Remove TOC Element'; + String get removeTocElement => '移除目录元素'; @override - String get removeTocElements => 'Remove TOC Elements'; + String get removeTocElements => '移除目录元素'; @override - String get reviewUsages => 'Review Usages'; + String get reviewUsages => '查看使用情况'; @override - String get deleteTopicFile => 'Delete Topic File'; + String get deleteTopicFile => '删除主题文件'; @override - String get removeAction => 'Remove'; + String get removeAction => '移除'; @override String topicRemovalSummary(String topic) { - return 'Remove “$topic” from the selected instance. The topic file will be kept.'; + return '从选中的实例中移除“$topic”。主题文件将被保留。'; } @override String safeDeleteTopicSummary(String topic) { - return 'Delete “$topic” and safely update its references throughout this Writerside project.'; + return '删除“$topic”,并在整个 Writerside 项目中安全更新其引用。'; } @override @@ -1231,470 +1182,445 @@ class AppLocalizationsZh extends AppLocalizations { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count child topics will move up one level.', - one: '1 child topic will move up one level.', + other: '$count 个子主题将上移一级。', + one: '1 个子主题将上移一级。', ); return '$_temp0'; } @override String get topicIsStartPageRemovalWarning => - 'This topic is used as an instance start page. Review its usages and assign another start page before continuing.'; + '此主题被用作实例的起始页。请查看其使用情况,并在继续前指定其他起始页。'; @override String topicUsagesCount(int count) { - return 'Usages ($count)'; + return '使用情况($count)'; } @override - String get noBreakingTopicUsages => - 'No references that would be broken were found.'; + String get noBreakingTopicUsages => '未找到会导致引用失效的引用。'; @override - String get topicUsagesFound => - 'BusyMark found the following references to this topic.'; + String get topicUsagesFound => 'BusyMark 找到了以下对该主题的引用。'; @override - String get topicUsageTocElements => 'TOC elements'; + String get topicUsageTocElements => '目录元素'; @override - String get topicUsageStartPages => 'Start pages'; + String get topicUsageStartPages => '起始页'; @override - String get topicUsageTopicLinks => 'Topic links'; + String get topicUsageTopicLinks => '主题链接'; @override - String get topicUsageIncludes => 'Includes'; + String get topicUsageIncludes => '包含项'; @override String usageCount(int count) { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count usages', - one: '1 usage', + other: '$count 次使用', + one: '1 次使用', ); return '$_temp0'; } @override - String get refactoringOptions => 'Refactoring options'; + String get refactoringOptions => '重构选项'; @override - String get updateUsagesAutomatically => 'Update usages automatically'; + String get updateUsagesAutomatically => '自动更新使用情况'; @override - String get updateUsagesAutomaticallyDescription => - 'Remove TOC references and includes, and preserve link text.'; + String get updateUsagesAutomaticallyDescription => '移除目录引用和包含项,同时保留链接文本。'; @override - String get manualUsageUpdatesRequired => - 'Some usages require manual changes before this refactoring.'; + String get manualUsageUpdatesRequired => '执行此重构前,某些使用情况需要手动更改。'; @override - String get setRedirectTo => 'Set redirect to'; + String get setRedirectTo => '设置重定向到'; @override - String get noRedirectDescription => 'Do not redirect the old published page.'; + String get noRedirectDescription => '不重定向旧的已发布页面。'; @override - String get redirectTarget => 'Redirect target'; + String get redirectTarget => '重定向目标'; @override - String get remainingUsagesBlockRemoval => - 'Review and update the remaining usages before continuing, or enable automatic updates when available.'; + String get remainingUsagesBlockRemoval => '请在继续前查看并更新剩余的使用情况,或在可用时启用自动更新。'; @override String usagesOfTopic(String topic) { - return 'Usages of $topic'; + return '$topic 的使用情况'; } @override - String get noUsagesFound => 'No usages found'; + String get noUsagesFound => '未找到使用情况'; @override - String get outsideSelectedInstance => 'outside selected instance'; + String get outsideSelectedInstance => '在选中的实例之外'; @override - String get doRefactor => 'Do Refactor'; + String get doRefactor => '执行重构'; @override - String get orphanTopicTitle => 'Topic file is no longer used'; + String get orphanTopicTitle => '主题文件已不再使用'; @override - String get keepTopicFile => 'Keep Topic File'; + String get keepTopicFile => '保留主题文件'; @override String orphanTopicMessage(String topic) { - return '“$topic” is no longer used anywhere in this Writerside project. Delete the file, or keep it for use in another instance.'; + return '“$topic”在此 Writerside 项目中已不再使用。删除该文件,或保留它以供其他实例使用。'; } @override - String get defaultNewTopicTitle => 'New topic'; + String get defaultNewTopicTitle => '新主题'; @override - String get topicTitle => 'Topic title'; + String get topicTitle => '主题标题'; @override - String get fileName => 'File name'; + String get fileName => '文件名'; @override - String get topicTitleRequired => 'Topic title is required.'; + String get topicTitleRequired => '主题标题为必填项。'; @override - String get fileNameRequired => 'File name is required.'; + String get fileNameRequired => '文件名为必填项。'; @override - String get rename => 'Rename'; + String get rename => '重命名'; @override - String get confirmDeleteFileTitle => 'Delete file?'; + String get confirmDeleteFileTitle => '删除文件?'; @override - String get confirmDeleteFolderTitle => 'Delete folder?'; + String get confirmDeleteFolderTitle => '删除文件夹?'; @override String confirmDeleteFileMessage(String name) { - return 'Delete $name? This cannot be undone.'; + return '删除 $name?此操作无法撤销。'; } @override String confirmDeleteFolderMessage(String name) { - return 'Delete $name and all files inside it? This cannot be undone.'; + return '删除 $name 及其中的所有文件?此操作无法撤销。'; } @override - String get useSingleSafeFileName => 'Use a single safe file name.'; + String get useSingleSafeFileName => '使用单一且安全的文件名。'; @override String useExpectedExtension(String extension) { - return 'Use the $extension extension for the selected format.'; + return '为选中的格式使用 $extension 扩展名。'; } @override - String get useIdentifierCharacters => - 'Use letters, numbers, underscores, or hyphens before the extension.'; + String get useIdentifierCharacters => '在扩展名之前仅使用字母、数字、下划线或连字符。'; @override - String get topicIdAlreadyExists => 'Topic ID already exists.'; + String get topicIdAlreadyExists => '主题 ID 已存在。'; @override - String get createWritersideTopicFailed => - 'Could not create Writerside topic.'; + String get createWritersideTopicFailed => '无法创建 Writerside 主题。'; @override - String get noOutline => 'No outline'; + String get noOutline => '没有大纲'; @override String expandKind(String kind) { - return 'Expand $kind'; + return '展开 $kind'; } @override String collapseKind(String kind) { - return 'Collapse $kind'; + return '折叠 $kind'; } @override - String get foldKindSection => 'section'; + String get foldKindSection => '节'; @override - String get foldKindList => 'list'; + String get foldKindList => '列表'; @override - String get foldKindQuote => 'quote'; + String get foldKindQuote => '引用'; @override - String get foldKindTag => 'tag'; + String get foldKindTag => '标签'; @override - String get sourceSearchPreviousMatch => 'Previous match'; + String get sourceSearchPreviousMatch => '上一个匹配项'; @override - String get sourceSearchNextMatch => 'Next match'; + String get sourceSearchNextMatch => '下一个匹配项'; @override - String get sourceSearchCaseSensitive => 'Case sensitive'; + String get sourceSearchCaseSensitive => '区分大小写'; @override - String get sourceSearchWholeWord => 'Whole word'; + String get sourceSearchWholeWord => '全字匹配'; @override - String get sourceSearchRegex => 'Regex'; + String get sourceSearchRegex => '正则表达式'; @override - String get sourceSearchReplacement => 'Replace with'; + String get sourceSearchReplacement => '替换为'; @override - String get sourceSearchReplaceCurrent => 'Replace current match'; + String get sourceSearchReplaceCurrent => '替换当前匹配项'; @override - String get sourceSearchReplaceAndFindNext => 'Replace and find next'; + String get sourceSearchReplaceAndFindNext => '替换并查找下一个'; @override - String get sourceSearchReplaceAll => 'Replace all'; + String get sourceSearchReplaceAll => '全部替换'; @override - String get workspaceReplace => 'Replace in Workspace'; + String get workspaceReplace => '在工作区中替换'; @override - String get reviewReplacements => 'Review replacements'; + String get reviewReplacements => '查看替换内容'; @override - String get applyReplacements => 'Apply replacements'; + String get applyReplacements => '应用替换'; @override - String get skippedFiles => 'Skipped files'; + String get skippedFiles => '跳过的文件'; @override - String get workspaceReplaceDirtyBuffer => 'Unsaved editor content'; + String get workspaceReplaceDirtyBuffer => '未保存的编辑器内容'; @override - String get workspaceReplaceDiskContent => 'Saved disk content'; + String get workspaceReplaceDiskContent => '磁盘上的已保存内容'; @override String selectFileMatches(int count) { - String _temp0 = intl.Intl.pluralLogic( - count, - locale: localeName, - other: 'Select all $count matches', - one: 'Select 1 match', - ); - return '$_temp0'; + return '选择全部 $count 个匹配项'; } @override String workspaceReplaceApplied(int matches, int files, int skipped) { - return 'Replaced $matches matches in $files files; skipped $skipped.'; + return '已在 $files 个文件中替换 $matches 个匹配项;跳过 $skipped 个。'; } @override String documentFormatWithFinalNewline(String encoding, String lineEnding) { - return '$encoding · $lineEnding · Final newline'; + return '$encoding · $lineEnding · 末尾有换行符'; } @override String documentFormatWithoutFinalNewline(String encoding, String lineEnding) { - return '$encoding · $lineEnding · No final newline'; + return '$encoding · $lineEnding · 末尾无换行符'; } @override - String get normalizeLineEndings => 'Normalize line endings'; + String get normalizeLineEndings => '规范化行尾'; @override - String get mixedLineEndingsSavePrompt => - 'This document contains mixed line endings. Choose a format.'; + String get mixedLineEndingsSavePrompt => '此文档包含混合的行尾格式。请选择一种格式。'; @override String workspaceReplaceMixedLineEndings(String fileName) { - return '$fileName uses mixed line endings. Choose the format to use before replacing.'; + return '$fileName 使用混合的行尾格式。请在替换前选择要使用的格式。'; } @override - String get workspaceReplaceIssueOversized => 'Skipped an oversized file.'; + String get workspaceReplaceIssueOversized => '已跳过过大的文件。'; @override - String get workspaceReplaceIssueUnreadable => - 'Skipped a file that could not be read.'; + String get workspaceReplaceIssueUnreadable => '已跳过无法读取的文件。'; @override - String get workspaceReplaceIssueInvalidUtf8 => - 'Skipped a file that is not valid UTF-8.'; + String get workspaceReplaceIssueInvalidUtf8 => '已跳过不是有效 UTF-8 的文件。'; @override - String get workspaceReplaceIssueTruncated => - 'The replacement preview was truncated.'; + String get workspaceReplaceIssueTruncated => '替换预览已被截断。'; @override - String get workspaceReplaceIssueFileChanged => - 'Skipped a file that changed after the preview.'; + String get workspaceReplaceIssueFileChanged => '已跳过预览后发生变化的文件。'; @override - String get workspaceReplaceIssueBufferChanged => - 'Skipped an editor buffer that changed after the preview.'; + String get workspaceReplaceIssueBufferChanged => '已跳过预览后发生变化的编辑器缓冲区。'; @override String get workspaceReplaceIssueNormalizationRequired => - 'Choose LF or CRLF normalization before replacing.'; + '请在替换前选择 LF 或 CRLF 规范化。'; @override String get workspaceReplaceIssuePartialConflict => - 'Rollback stopped because the file changed concurrently. Some replacements may remain; displaced content was preserved at the path below.'; + '由于文件同时发生了变化,回滚已停止。部分替换可能仍然存在;被移出的内容已保留在下方路径中。'; @override - String get workspaceReplaceIssueApplyFailed => - 'The reviewed replacement could not be committed; no files were changed.'; + String get workspaceReplaceIssueApplyFailed => '无法提交经过审查的替换;没有文件发生更改。'; @override String externalChangesTitle(String fileName) { - return 'External changes — $fileName'; + return '外部更改 — $fileName'; } @override - String get externalFileDeleted => 'This file was deleted on disk.'; + String get externalFileDeleted => '此文件已从磁盘删除。'; @override - String get externalFileChanged => - 'This file changed on disk while you have unsaved edits.'; + String get externalFileChanged => '在您有未保存编辑时,此文件已在磁盘上发生变化。'; @override String recoveredDocumentReview(String fileName) { - return 'Recovered unsaved content for $fileName. Inspect it, then save, save as, or discard it.'; + return '已恢复 $fileName 的未保存内容。请检查后保存、另存为或放弃。'; } @override - String get compare => 'Compare'; + String get compare => '比较'; @override - String get reloadFromDisk => 'Reload from Disk'; + String get reloadFromDisk => '从磁盘重新加载'; @override - String get keepMine => 'Keep Mine'; + String get keepMine => '保留我的版本'; @override - String get saveAs => 'Save As'; + String get saveAs => '另存为'; @override - String get sourceSearchInvalidRegex => 'Invalid regular expression'; + String get sourceSearchInvalidRegex => '无效的正则表达式'; @override - String get sourceLargeFileFeaturesPaused => - 'Large file: highlighting and folding are paused'; + String get sourceLargeFileFeaturesPaused => '大文件:已暂停语法突出显示和折叠'; @override - String get nothingToRead => 'Nothing to read'; + String get nothingToRead => '没有可读取的内容'; @override - String get admonition => 'Admonition'; + String get admonition => '提示块'; @override - String get quote => 'Quote'; + String get quote => '引用'; @override - String get note => 'Note'; + String get note => '备注'; @override - String get tip => 'Tip'; + String get tip => '提示'; @override - String get warning => 'Warning'; + String get warning => '警告'; @override - String get tabs => 'Tabs'; + String get tabs => '标签页'; @override - String get tab => 'Tab'; + String get tab => '标签页'; @override - String get procedure => 'Procedure'; + String get procedure => '操作步骤'; @override - String get step => 'Step'; + String get step => '步骤'; @override - String get topic => 'Topic'; + String get topic => '主题'; @override - String get chapter => 'Chapter'; + String get chapter => '章节'; @override String couldNotOpenTarget(String target) { - return 'Could not open $target'; + return '无法打开 $target'; } @override String linkTargetNotFound(String targetPath) { - return 'Link target not found: $targetPath'; + return '找不到链接目标:$targetPath'; } @override - String get cannotOpenFileTypeInEditor => - 'Cannot open this file type in editor'; + String get cannotOpenFileTypeInEditor => '无法在编辑器中打开此文件类型'; @override String anchorNotFound(String anchor) { - return 'Anchor not found: $anchor'; + return '找不到锚点:$anchor'; } @override - String get noProblemsFound => 'No problems found'; + String get noProblemsFound => '未发现问题'; @override - String get noResults => 'No results'; + String get noResults => '无结果'; @override String searchResultLine(String relativePath, int lineNumber) { - return '$relativePath - Line $lineNumber'; + return '$relativePath - 第 $lineNumber 行'; } @override - String get untitledResult => 'Untitled result'; + String get untitledResult => '未命名结果'; @override - String get documentKindMarkdownFile => 'Markdown file'; + String get documentKindMarkdownFile => 'Markdown 文件'; @override - String get documentKindWritersideMarkdownTopic => 'Writerside Markdown topic'; + String get documentKindWritersideMarkdownTopic => 'Writerside Markdown 主题'; @override - String get documentKindWritersideXmlTopic => 'Writerside XML topic'; + String get documentKindWritersideXmlTopic => 'Writerside XML 主题'; @override - String get documentKindWritersideTree => 'Writerside tree'; + String get documentKindWritersideTree => 'Writerside 树'; @override - String get documentKindConfigurationFile => 'Configuration file'; + String get documentKindConfigurationFile => '配置文件'; @override - String get documentKindVariablesFile => 'Variables file'; + String get documentKindVariablesFile => '变量文件'; @override - String get documentKindCategoriesFile => 'Categories file'; + String get documentKindCategoriesFile => '类别文件'; @override - String get documentKindResourceFile => 'Resource file'; + String get documentKindResourceFile => '资源文件'; @override String workspaceErrorOpenFailed(String error) { - return 'Open failed: $error'; + return '打开失败:$error'; } @override String workspaceErrorCreateWritersideProjectFailed(String error) { - return 'Could not create Writerside project: $error'; + return '无法创建 Writerside 项目:$error'; } @override String workspaceErrorCreateWritersideTopicFailed(String error) { - return 'Could not create Writerside topic: $error'; + return '无法创建 Writerside 主题:$error'; } @override String workspaceErrorCouldNotOpenFile(String error) { - return 'Could not open file: $error'; + return '无法打开文件:$error'; } @override - String get workspaceErrorChooseWhereToSaveMarkdown => - 'Choose where to save this Markdown file.'; + String get workspaceErrorChooseWhereToSaveMarkdown => '选择保存此 Markdown 文件的位置。'; @override - String get workspaceErrorSaveBlockedFileChangedOnDisk => - 'Save blocked: file changed on disk.'; + String get workspaceErrorSaveBlockedFileChangedOnDisk => '保存已阻止:文件已在磁盘上发生变化。'; @override String workspaceErrorSaveFailed(String error) { - return 'Save failed: $error'; + return '保存失败:$error'; } @override String workspaceErrorFileOperationFailed(String error) { - return 'File operation failed: $error'; + return '文件操作失败:$error'; } @override String workspaceErrorValidationFailed(String error) { - return 'Validation failed: $error'; + return '验证失败:$error'; } @override @@ -1702,10 +1628,8 @@ class AppLocalizationsZh extends AppLocalizations { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: - 'Recovered $count unsaved documents. Review each one before saving or discarding it.', - one: - 'Recovered 1 unsaved document. Review it before saving or discarding it.', + other: '已恢复 $count 个未保存的文档。请在保存或放弃前逐一检查。', + one: '已恢复 1 个未保存的文档。请在保存或放弃前进行检查。', ); return '$_temp0'; } @@ -1715,450 +1639,420 @@ class AppLocalizationsZh extends AppLocalizations { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: - '$count damaged recovery records could not be restored. Valid recovery records remain available.', - one: - 'One damaged recovery record could not be restored. The original recovery file was preserved for inspection.', + other: '无法恢复 $count 条损坏的恢复记录。有效的恢复记录仍可用。', + one: '无法恢复一条损坏的恢复记录。原始恢复文件已保留以供检查。', ); return '$_temp0'; } @override String errorPathDoesNotExist(String path) { - return 'Path does not exist: $path'; + return '路径不存在:$path'; } @override String errorTargetDirectoryNotEmpty(String path) { - return 'Target directory already exists and is not empty: $path'; + return '目标目录已存在且不为空:$path'; } @override String errorTargetPathNotDirectory(String path) { - return 'Target path already exists and is not a directory: $path'; + return '目标路径已存在但不是目录:$path'; } @override String errorGeneratedFileAlreadyExists(String path) { - return 'Generated file already exists: $path'; + return '生成的文件已存在:$path'; } @override - String get errorParentDirectoryRequired => 'Parent directory is required.'; + String get errorParentDirectoryRequired => '必须指定父目录。'; @override String errorParentDirectoryMissing(String path) { - return 'Parent directory does not exist: $path'; + return '父目录不存在:$path'; } @override String errorDirectoryMissing(String path) { - return 'Directory does not exist: $path'; + return '目录不存在:$path'; } @override String errorPathAlreadyExists(String path) { - return 'Path already exists: $path'; + return '路径已存在:$path'; } @override - String get errorFileNameRequired => 'File name is required.'; + String get errorFileNameRequired => '文件名为必填项。'; @override - String get errorFileNameUnsafe => - 'File name must be a single safe path segment.'; + String get errorFileNameUnsafe => '文件名必须是单一且安全的路径段。'; @override - String get errorFileOperationInvalidTarget => - 'Cannot move a folder into itself.'; + String get errorFileOperationInvalidTarget => '无法将文件夹移动到其自身中。'; @override - String get errorFileOperationOutsideRoot => - 'File operation must stay inside the workspace.'; + String get errorFileOperationOutsideRoot => '文件操作必须在工作区内进行。'; @override - String get errorFileOperationRoot => - 'The workspace root cannot be changed from the file tree.'; + String get errorFileOperationRoot => '无法从文件树更改工作区根目录。'; @override - String get errorProjectNameRequired => 'Project name is required.'; + String get errorProjectNameRequired => '项目名称为必填项。'; @override - String get errorDirectoryNameRequired => 'Directory name is required.'; + String get errorDirectoryNameRequired => '目录名称为必填项。'; @override - String get errorDirectoryNameUnsafe => - 'Directory name must be a single safe path segment.'; + String get errorDirectoryNameUnsafe => '目录名称必须是单一且安全的路径段。'; @override - String get errorInstanceIdInvalid => - 'Instance ID must start with a lowercase letter and contain only lowercase letters, numbers, underscores, and hyphens.'; + String get errorInstanceIdInvalid => '实例 ID 必须以小写字母开头,且只能包含小写字母、数字、下划线和连字符。'; @override - String get errorTopicFileInvalid => - 'Topic file name must be a Markdown file name without path separators.'; + String get errorTopicFileInvalid => '主题文件名必须是没有路径分隔符的 Markdown 文件名。'; @override - String get errorTopicTitleRequired => 'Topic title is required.'; + String get errorTopicTitleRequired => '主题标题为必填项。'; @override String errorWritersideModuleRootMissing(String path) { - return 'Writerside module root does not exist: $path'; + return 'Writerside 模块根目录不存在:$path'; } @override - String get errorWritersideModuleNotOpen => - 'A Writerside module must be open to create a topic.'; + String get errorWritersideModuleNotOpen => '必须打开 Writerside 模块才能创建主题。'; @override - String get errorWritersideInstanceTreeMissing => - 'The Writerside module has no instance tree.'; + String get errorWritersideInstanceTreeMissing => 'Writerside 模块没有实例树。'; @override String errorWritersideTreeFileMissing(String path) { - return 'Writerside tree file does not exist: $path'; + return 'Writerside 树文件不存在:$path'; } @override String errorTopicIdAlreadyExists(String topicId) { - return 'Topic ID \"$topicId\" already exists in this help module.'; + return '主题 ID \"$topicId\" 已存在于此帮助模块中。'; } @override String errorTopicFileAlreadyExists(String path) { - return 'Topic file already exists: $path'; + return '主题文件已存在:$path'; } @override String errorReferenceTopicMissing(String topic) { - return 'Reference topic is not present in the selected tree: $topic'; + return '选中的树中不存在引用主题:$topic'; } @override - String get errorWritersideTocNodeMissing => - 'The selected TOC entry no longer exists.'; + String get errorWritersideTocNodeMissing => '选中的目录项已不存在。'; @override - String get errorWritersideTocInvalidMove => - 'A TOC entry cannot be moved into itself or one of its children.'; + String get errorWritersideTocInvalidMove => '目录项无法移动到自身或其子项中。'; @override String errorWritersideStartTopicDelete(String topic) { - return 'The start topic $topic cannot be deleted. Choose another start page first.'; + return '无法删除起始主题 $topic。请先选择其他起始页。'; } @override - String get errorWritersideSafeDeleteRequired => - 'Use Safe Delete for Writerside topic files.'; + String get errorWritersideSafeDeleteRequired => '请对 Writerside 主题文件使用安全删除。'; @override - String get errorWritersideTopicUsageScanFailed => - 'Could not complete the topic usage scan. No files were changed.'; + String get errorWritersideTopicUsageScanFailed => '无法完成主题使用情况扫描。没有文件发生更改。'; @override - String get errorWritersideTopicUsagesRemain => - 'Some topic usages still require attention. Review them before continuing.'; + String get errorWritersideTopicUsagesRemain => '某些主题使用情况仍需处理。请先查看后再继续。'; @override - String get errorWritersideRedirectInvalid => - 'The selected redirect target is no longer valid. Choose it again.'; + String get errorWritersideRedirectInvalid => '选中的重定向目标已无效。请重新选择。'; @override String errorWritersideRollbackFailed(String paths) { - return 'Topic removal could not be fully rolled back. Review these paths before continuing: $paths'; + return '无法完全回滚主题移除。请在继续前查看这些路径:$paths'; } @override - String get errorTopicsRootUnsafe => - 'Topics root must be a safe relative directory.'; + String get errorTopicsRootUnsafe => '主题根目录必须是安全的相对目录。'; @override - String get errorTopicFileNameUnsafe => - 'Topic file name must be a single safe path segment.'; + String get errorTopicFileNameUnsafe => '主题文件名必须是单一且安全的路径段。'; @override String errorTopicFileExtensionMismatch(String extension) { - return 'Topic file extension must match the selected format ($extension).'; + return '主题文件扩展名必须与选中的格式匹配($extension)。'; } @override - String get errorTopicFileNameInvalid => - 'Topic file name must contain only letters, numbers, underscores, and hyphens.'; + String get errorTopicFileNameInvalid => '主题文件名只能包含字母、数字、下划线和连字符。'; @override String errorUnknown(String code) { - return 'Unknown error: $code'; + return '未知错误:$code'; } @override String diagnosticWorkspaceFileStatFailed(String error) { - return 'Could not read file metadata: $error'; + return '无法读取文件元数据:$error'; } @override - String get diagnosticWorkspaceScanSkipped => - 'Large workspace detected. Some files were skipped to keep the app responsive.'; + String get diagnosticWorkspaceScanSkipped => '检测到大型工作区。为保持应用响应速度,已跳过部分文件。'; @override String diagnosticWorkspaceScanInspectFailed(String error) { - return 'Could not inspect workspace entry: $error'; + return '无法检查工作区项:$error'; } @override - String get diagnosticWorkspaceFileTooLarge => - 'File is larger than the beta auto-parse limit.'; + String get diagnosticWorkspaceFileTooLarge => '文件超过 beta 自动解析限制。'; @override String diagnosticWorkspaceFileReadFailed(String error) { - return 'Could not read Markdown file: $error'; + return '无法读取 Markdown 文件:$error'; } @override - String get diagnosticMarkdownAttributeMalformed => - 'Malformed Writerside heading attribute block.'; + String get diagnosticMarkdownAttributeMalformed => 'Writerside 标题属性块格式错误。'; @override String diagnosticMarkdownHeadingDuplicateId(String id) { - return 'Duplicate heading ID \"$id\".'; + return '标题 ID“$id”重复。'; } @override String get diagnosticWritersideTopicH1ConvertedToChapter => - 'Additional top-level H1 headings are treated as chapters.'; + '额外的顶级 H1 标题将被视为章节。'; @override String get diagnosticWritersideMarkdownTopicMissingTitle => - 'Writerside Markdown topic has no H1 or front matter title.'; + 'Writerside Markdown 主题没有 H1 或 front matter 标题。'; @override - String get diagnosticWritersideXmlTopicMissingTitle => - 'XML topic is missing title.'; + String get diagnosticWritersideXmlTopicMissingTitle => 'XML 主题缺少标题。'; @override String diagnosticWritersideTopicFileMissingTitle(String fileName) { - return 'Topic \"$fileName\" is missing a title.'; + return '主题“$fileName”缺少标题。'; } @override - String get diagnosticMarkdownFrontMatterMalformed => - 'Front matter is not closed.'; + String get diagnosticMarkdownFrontMatterMalformed => 'front matter 未闭合。'; @override - String get diagnosticMarkdownRawHtmlUnsafe => 'Unsafe HTML element.'; + String get diagnosticMarkdownRawHtmlUnsafe => '不安全的 HTML 元素。'; @override String diagnosticMarkdownLinkUnresolvedTarget(String targetPath) { - return 'Link target does not exist: $targetPath'; + return '链接目标不存在:$targetPath'; } @override String diagnosticMarkdownLinkUnresolvedAnchor(String anchor) { - return 'Anchor \"$anchor\" does not exist.'; + return '锚点“$anchor”不存在。'; } @override String diagnosticMarkdownImageMissingAlt(String destination) { - return 'Image \"$destination\" is missing alt text.'; + return '图像“$destination”缺少替代文本。'; } @override String diagnosticMarkdownImageMissingFile(String destination) { - return 'Image does not exist: $destination'; + return '图像不存在:$destination'; } @override String diagnosticInvalidXml(String message) { - return 'Invalid XML: $message'; + return '无效的 XML:$message'; } @override String get diagnosticWritersideConfigInvalidRoot => - 'writerside.cfg root must be <ihp>.'; + 'writerside.cfg 根元素必须是 <ihp>。'; @override String get diagnosticWritersideConfigMissingSnippetsSrc => - 'snippets declaration is missing src.'; + 'snippets 声明缺少 src。'; @override String get diagnosticWritersideConfigMissingInstanceGroupsSrc => - 'instance-groups declaration is missing src.'; + 'instance-groups 声明缺少 src。'; @override String diagnosticWritersideConfigInvalidKeymapsMode(String mode) { - return 'Unsupported keymaps mode: $mode'; + return '不支持的 keymaps 模式:$mode'; } @override String get diagnosticWritersideConfigMissingInstanceSrc => - 'Instance declaration is missing src.'; + 'instance 声明缺少 src。'; @override String get diagnosticWritersideConfigMissingInstance => - 'writerside.cfg does not register an instance.'; + 'writerside.cfg 未注册实例。'; @override String get diagnosticWritersideTreeInvalidRoot => - '.tree root must be <instance-profile>.'; + '.tree 根元素必须是 <instance-profile>。'; @override - String get diagnosticWritersideTreeMissingId => - 'Instance profile is missing id.'; + String get diagnosticWritersideTreeMissingId => '实例配置文件缺少 id。'; @override String diagnosticWritersideTreeIdMismatch(String id) { - return 'Tree file stem does not match instance id \"$id\".'; + return '树文件名(不含扩展名)与实例 ID“$id”不匹配。'; } @override - String get diagnosticWritersideTreeMissingStartPage => - 'Non-library instance is missing start-page.'; + String get diagnosticWritersideTreeMissingStartPage => '非库实例缺少 start-page。'; @override String diagnosticWritersideStartPageMissing(String startPage) { - return 'Start page \"$startPage\" does not exist.'; + return '起始页“$startPage”不存在。'; } @override String diagnosticWritersideTreeDuplicateTopic(String topic) { - return 'Topic \"$topic\" appears more than once in this instance TOC.'; + return '主题“$topic”在此实例目录中出现多次。'; } @override String get diagnosticWritersideVariableMalformedDeclaration => - 'Variable declaration must have name and value.'; + '变量声明必须包含名称和值。'; @override String diagnosticWritersideVariableDuplicateName(String name) { - return 'Variable \"$name\" is declared more than once.'; + return '变量“$name”被声明了多次。'; } @override - String get diagnosticWritersideCategoryMissingId => 'Category is missing id.'; + String get diagnosticWritersideCategoryMissingId => '类别缺少 id。'; @override String diagnosticWritersideCategoryDuplicateId(String id) { - return 'Category \"$id\" is declared more than once.'; + return '类别“$id”被声明了多次。'; } @override String diagnosticWritersideCategoryDuplicateOrder(String order) { - return 'Category order \"$order\" is declared more than once.'; + return '类别顺序“$order”被声明了多次。'; } @override - String get diagnosticWritersideTopicInvalidRoot => - '.topic root must be <topic>.'; + String get diagnosticWritersideTopicInvalidRoot => '.topic 根元素必须是 <topic>。'; @override - String get diagnosticWritersideTopicMissingRootId => - 'XML topic is missing root id.'; + String get diagnosticWritersideTopicMissingRootId => 'XML 主题缺少根 id。'; @override String diagnosticWritersideTopicRootIdMismatch(String id, String expectedId) { - return 'XML topic root id \"$id\" must match filename \"$expectedId\".'; + return 'XML 主题根 ID“$id”必须与文件名“$expectedId”匹配。'; } @override String diagnosticWritersideTopicDuplicateElementId(String elementId) { - return 'Element id \"$elementId\" appears more than once.'; + return '元素 ID“$elementId”出现多次。'; } @override - String get diagnosticWritersideTopicAnchorMissingHref => - '<a> is missing href.'; + String get diagnosticWritersideTopicAnchorMissingHref => '<a> 缺少 href。'; @override String get diagnosticWritersideConfigMissing => - 'Writerside mode requires writerside.cfg.'; + 'Writerside 模式需要 writerside.cfg。'; @override String diagnosticWritersideConfigMissingBuildConfigDirectory( String relativePath, ) { - return 'Configured build config directory is missing: $relativePath'; + return '配置的构建配置目录不存在:$relativePath'; } @override String diagnosticWritersideConfigMissingApiSpecificationsDirectory( String relativePath, ) { - return 'Configured API specifications directory is missing: $relativePath'; + return '配置的 API 规范目录不存在:$relativePath'; } @override String diagnosticWritersideConfigMissingSnippetsDirectory( String relativePath, ) { - return 'Configured snippets directory is missing: $relativePath'; + return '配置的 snippets 目录不存在:$relativePath'; } @override String diagnosticWritersideConfigMissingVarsFile(String relativePath) { - return 'Configured variables file is missing: $relativePath'; + return '配置的变量文件不存在:$relativePath'; } @override String diagnosticWritersideConfigMissingCategoriesFile(String relativePath) { - return 'Configured categories file is missing: $relativePath'; + return '配置的类别文件不存在:$relativePath'; } @override String diagnosticWritersideConfigMissingInstanceGroupsFile( String relativePath, ) { - return 'Configured instance groups file is missing: $relativePath'; + return '配置的实例组文件不存在:$relativePath'; } @override String diagnosticWritersideConfigMissingInstanceTree(String source) { - return 'Registered instance tree \"$source\" does not exist.'; + return '已注册的实例树“$source”不存在。'; } @override String diagnosticWritersideTopicReadFailed(String error) { - return 'Could not read topic file: $error'; + return '无法读取主题文件:$error'; } @override String diagnosticWritersideDefaultTopicsDirectoryMissing( String relativePath, ) { - return 'Default topics directory is missing: $relativePath'; + return '默认主题目录不存在:$relativePath'; } @override String diagnosticWritersideTopicsDirectoryMissing(String relativePath) { - return 'Configured topics directory is missing: $relativePath'; + return '配置的主题目录不存在:$relativePath'; } @override String diagnosticWritersideImagesDirectoryMissing(String relativePath) { - return 'Configured images directory is missing: $relativePath'; + return '配置的图像目录不存在:$relativePath'; } @override String diagnosticWritersideTopicDuplicateId(String id) { - return 'Element id \"$id\" appears more than once.'; + return '元素 ID“$id”出现多次。'; } @override String diagnosticWritersideTreeMissingTopic(String topic) { - return 'TOC references missing topic \"$topic\".'; + return '目录引用了缺失的主题“$topic”。'; } @override String diagnosticWritersideTreeInvalidHref(String href) { - return 'External href \"$href\" is invalid.'; + return '外部 href“$href”无效。'; } @override String diagnosticWritersideVariableUnresolved(String name) { - return 'Variable \"%$name%\" is not declared.'; + return '变量“%$name%”未声明。'; } @override String diagnosticWritersideTopicLinkUnresolved(String destination) { - return 'Topic link \"$destination\" does not resolve.'; + return '主题链接“$destination”无法解析。'; } @override @@ -2166,16 +2060,15 @@ class AppLocalizationsZh extends AppLocalizations { String anchor, String targetName, ) { - return 'Anchor \"$anchor\" does not exist in \"$targetName\".'; + return '“$targetName”中不存在锚点“$anchor”。'; } @override - String get diagnosticWritersideIncludeMissingFrom => - '<include> is missing the from attribute.'; + String get diagnosticWritersideIncludeMissingFrom => '<include> 缺少 from。'; @override String diagnosticWritersideIncludeSourceMissing(String from) { - return 'Include source \"$from\" does not exist.'; + return '包含源“$from”不存在。'; } @override @@ -2183,94 +2076,92 @@ class AppLocalizationsZh extends AppLocalizations { String elementId, String from, ) { - return 'Include element \"$elementId\" does not exist in \"$from\".'; + return '“$from”中不存在包含元素“$elementId”。'; } @override String diagnosticWritersideCategoryUnresolved(String ref) { - return 'Seealso category \"$ref\" is not declared.'; + return 'seealso 类别“$ref”未声明。'; } @override String diagnosticWritersideTopicAmbiguousReference(String reference) { - return 'Topic reference \"$reference\" is ambiguous.'; + return '主题引用“$reference”不明确。'; } @override String diagnosticUnknown(String code) { - return 'Unknown diagnostic: $code'; + return '未知诊断信息:$code'; } @override - String get close => 'Close'; + String get close => '关闭'; @override String get git => 'Git'; @override - String get gitDiff => 'Git diff'; + String get gitDiff => 'Git 差异'; @override - String get gitShowDiff => 'Show diff'; + String get gitShowDiff => '显示差异'; @override String gitDiffHunkRange(String oldRange, String newRange) { - return 'old $oldRange → new $newRange'; + return '旧 $oldRange → 新 $newRange'; } @override - String get gitDiffNoLines => 'no lines'; + String get gitDiffNoLines => '无行'; @override - String get gitUnavailableTitle => 'Git is unavailable'; + String get gitUnavailableTitle => 'Git 不可用'; @override String gitUnavailableMessage(String reason) { String _temp0 = intl.Intl.selectLogic(reason, { - 'other': - 'Install Git or configure BusyMark to use an available Git executable. $reason', + 'other': '安装 Git,或配置 BusyMark 以使用可用的 Git 可执行文件。$reason', }); return '$_temp0'; } @override - String get gitTrustRequiredTitle => 'Trust this workspace for Git?'; + String get gitTrustRequiredTitle => '信任此工作区以使用 Git?'; @override String get gitTrustRequiredMessage => - 'Git repositories can run programs through hooks, filters, and other configuration. Trust this workspace before BusyMark reads repository data or enables Git actions.'; + 'Git 存储库可以通过 hook、过滤器和其他配置运行程序。在 BusyMark 读取存储库数据或启用 Git 操作前,请先信任此工作区。'; @override - String get gitTrustWorkspace => 'Trust workspace'; + String get gitTrustWorkspace => '信任工作区'; @override - String get gitNotRepositoryTitle => 'Not a Git repository'; + String get gitNotRepositoryTitle => '不是 Git 存储库'; @override - String get gitNotRepositoryMessage => - 'This workspace is not inside a Git repository.'; + String get gitNotRepositoryMessage => '此工作区不在 Git 存储库中。'; @override - String get gitInitializeRepository => 'Initialize repository'; + String get gitInitializeRepository => '初始化存储库'; @override - String get gitDetachedHead => 'Detached HEAD'; + String get gitDetachedHead => '分离的 HEAD'; @override String gitDetachedHeadAt(String commit) { - return 'Detached at $commit'; + return '分离于 $commit'; } @override - String get gitNoUpstream => 'No upstream'; + String get gitNoUpstream => '没有上游分支'; @override String gitAheadCount(int count) { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count unpushed commits', - one: '1 unpushed commit', + other: '$count 个未推送的提交', + one: '1 个未推送的提交', ); return '$_temp0'; } @@ -2280,35 +2171,35 @@ class AppLocalizationsZh extends AppLocalizations { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count commits to pull', - one: '1 commit to pull', + other: '$count 个待拉取的提交', + one: '1 个待拉取的提交', ); return '$_temp0'; } @override - String get gitClean => 'Clean'; + String get gitClean => '干净'; @override - String get gitConflicts => 'Conflicts'; + String get gitConflicts => '冲突'; @override - String get gitChanges => 'Changes'; + String get gitChanges => '更改'; @override - String get gitStaged => 'Staged'; + String get gitStaged => '已暂存'; @override - String get gitUnstaged => 'Unstaged'; + String get gitUnstaged => '未暂存'; @override - String get gitHistory => 'History'; + String get gitHistory => '历史记录'; @override - String get gitBranches => 'Branches'; + String get gitBranches => '分支'; @override - String get gitActions => 'Git actions'; + String get gitActions => 'Git 操作'; @override String get gitPull => 'Pull'; @@ -2323,99 +2214,94 @@ class AppLocalizationsZh extends AppLocalizations { String get gitCommit => 'Commit'; @override - String get gitSelectForCommit => 'Stage file'; + String get gitSelectForCommit => '暂存文件'; @override - String get gitRemoveFromCommit => 'Unstage file'; + String get gitRemoveFromCommit => '取消暂存文件'; @override - String get gitDiscard => 'Rollback'; + String get gitDiscard => '还原'; @override - String get gitOpenFile => 'Open file'; + String get gitOpenFile => '打开文件'; @override - String get gitMarkResolved => 'Mark resolved'; + String get gitMarkResolved => '标记为已解决'; @override - String get gitUntracked => 'Untracked'; + String get gitUntracked => '未跟踪'; @override - String get gitCommitMessage => 'Commit message'; + String get gitCommitMessage => '提交消息'; @override - String get gitCommitSelectedFiles => 'Selected files'; + String get gitCommitSelectedFiles => '选中的文件'; @override - String get gitCommitNoSelectedFiles => - 'Stage at least one file before committing.'; + String get gitCommitNoSelectedFiles => '提交前至少暂存一个文件。'; @override String gitStagedFileCount(int count) { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count staged files', - one: '1 staged file', + other: '$count 个已暂存文件', + one: '1 个已暂存文件', ); return '$_temp0'; } @override - String get gitOutsideWorkspace => 'Outside workspace'; + String get gitOutsideWorkspace => '工作区之外'; @override - String get gitCommitMessageRequired => 'Enter a commit message.'; + String get gitCommitMessageRequired => '请输入提交消息。'; @override - String get gitCreateBranch => 'Create branch'; + String get gitCreateBranch => '创建分支'; @override - String get gitNewBranch => 'New Branch'; + String get gitNewBranch => '新分支'; @override - String get gitBranchName => 'Branch name'; + String get gitBranchName => '分支名称'; @override - String get gitSwitchBranch => 'Switch'; + String get gitSwitchBranch => '切换'; @override - String get gitNoChanges => 'No changes'; + String get gitNoChanges => '没有更改'; @override - String get gitNoHistory => 'No history'; + String get gitNoHistory => '没有历史记录'; @override - String get gitNoBranches => 'No branches'; + String get gitNoBranches => '没有分支'; @override - String get gitNoDiff => 'No diff to show'; + String get gitNoDiff => '没有可显示的差异'; @override - String get gitBinaryFile => - 'Binary file. BusyMark does not render binary patches.'; + String get gitBinaryFile => '二进制文件。BusyMark 不渲染二进制补丁。'; @override String gitBinaryFileInfo(int size) { - return 'Binary file ($size bytes). BusyMark does not render binary patches.'; + return '二进制文件($size 字节)。BusyMark 不渲染二进制补丁。'; } @override - String get gitUnsavedChangesBanner => - 'Unsaved editor changes are not included until saved.'; + String get gitUnsavedChangesBanner => '保存前不会包含未保存的编辑器更改。'; @override - String get gitConfirmDiscardTitle => 'Discard Git changes?'; + String get gitConfirmDiscardTitle => '放弃 Git 更改?'; @override String gitConfirmDiscardTracked(int count) { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: - 'All staged and unstaged changes in the selected tracked files will be restored to HEAD.', - one: - 'All staged and unstaged changes in the selected tracked file will be restored to HEAD.', + other: '选中的已跟踪文件中的所有已暂存和未暂存更改都将还原到 HEAD。', + one: '选中的已跟踪文件中的所有已暂存和未暂存更改都将还原到 HEAD。', ); return '$_temp0'; } @@ -2425,8 +2311,8 @@ class AppLocalizationsZh extends AppLocalizations { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: 'The selected untracked files will be deleted.', - one: 'The selected untracked file will be deleted.', + other: '选中的未跟踪文件将被删除。', + one: '选中的未跟踪文件将被删除。', ); return '$_temp0'; } @@ -2436,106 +2322,101 @@ class AppLocalizationsZh extends AppLocalizations { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: - 'The selected files will be restored or deleted based on their Git status.', - one: - 'The selected file will be restored or deleted based on its Git status.', + other: '将根据其 Git 状态还原或删除选中的文件。', + one: '将根据其 Git 状态还原或删除选中的文件。', ); return '$_temp0'; } @override String gitConfirmSwitchBranchTitle(String branch) { - return 'Switch to $branch?'; + return '切换到 $branch?'; } @override - String get gitConfirmSwitchBranchMessage => - 'BusyMark will reload the workspace from disk after Git switches branches.'; + String get gitConfirmSwitchBranchMessage => 'Git 切换分支后,BusyMark 将从磁盘重新加载工作区。'; @override - String get gitConfirmPushSetUpstreamTitle => 'Set upstream branch?'; + String get gitConfirmPushSetUpstreamTitle => '设置上游分支?'; @override String gitConfirmPushSetUpstreamMessage(String branch) { - return 'This branch has no upstream. BusyMark can push $branch and set its upstream when exactly one remote is configured.'; + return '此分支没有上游分支。当只配置了一个远程仓库时,BusyMark 可以推送 $branch 并设置其上游分支。'; } @override - String get gitProjectHistory => 'Project History'; + String get gitProjectHistory => '项目历史记录'; @override - String get gitFileHistory => 'File History'; + String get gitFileHistory => '文件历史记录'; @override - String get gitFileHistoryRequiresOpenFile => - 'File History requires an open Markdown file.'; + String get gitFileHistoryRequiresOpenFile => '文件历史记录需要打开的 Markdown 文件。'; @override - String get gitLoadMore => 'Load More'; + String get gitLoadMore => '加载更多'; @override - String get gitChangesInCommit => 'Changes in this commit'; + String get gitChangesInCommit => '此提交中的更改'; @override - String get gitCompareWithCurrent => 'Compare with current'; + String get gitCompareWithCurrent => '与当前版本比较'; @override - String get gitRestoreVersion => 'Restore this version'; + String get gitRestoreVersion => '还原此版本'; @override - String get gitConfirmRestoreTitle => 'Restore this file version?'; + String get gitConfirmRestoreTitle => '还原此文件版本?'; @override String get gitConfirmRestoreMessage => - 'BusyMark will replace the current working-tree file with the selected committed version. The restored file will remain unstaged.'; + 'BusyMark 将使用选中的已提交版本替换当前工作树中的文件。还原后的文件将保持未暂存状态。'; @override - String get gitCommitActions => 'Commit actions'; + String get gitCommitActions => '提交操作'; @override - String get gitResetCurrentBranchToHere => 'Reset current branch to here…'; + String get gitResetCurrentBranchToHere => '将当前分支重置到此处…'; @override String gitResetCurrentBranchTitle(String branch, String commit) { - return 'Reset $branch to $commit?'; + return '将 $branch 重置到 $commit?'; } @override String gitResetCurrentBranchMessage(String branch, String commit) { - return 'This moves branch $branch to commit $commit. Choose how Git updates the index and working tree.'; + return '这会将分支 $branch 移动到提交 $commit。请选择 Git 更新索引和工作树的方式。'; } @override - String get gitReset => 'Reset'; + String get gitReset => '重置'; @override - String get gitResetModeSoft => 'Soft'; + String get gitResetModeSoft => '软'; @override String get gitResetModeSoftDescription => - 'Move the branch only. Keep the index and working tree unchanged; differences from the selected commit remain staged.'; + '仅移动分支。保持索引和工作树不变;与选中提交之间的差异仍会保持暂存状态。'; @override - String get gitResetModeMixed => 'Mixed'; + String get gitResetModeMixed => '混合'; @override - String get gitResetModeMixedDescription => - 'Move the branch and reset the index. Keep the working tree unchanged, leaving differences unstaged.'; + String get gitResetModeMixedDescription => '移动分支并重置索引。保持工作树不变,使差异处于未暂存状态。'; @override - String get gitResetModeHard => 'Hard'; + String get gitResetModeHard => '硬'; @override String get gitResetModeHardDescription => - 'Move the branch and reset the index and working tree. Tracked changes are discarded; obstructing untracked files may be deleted.'; + '移动分支并重置索引和工作树。已跟踪的更改将被放弃;造成阻碍的未跟踪文件可能会被删除。'; @override - String get gitResetModeKeep => 'Keep'; + String get gitResetModeKeep => '保留'; @override String get gitResetModeKeepDescription => - 'Move the branch and reset tracked files while preserving local changes. Git aborts if those changes conflict with the reset.'; + '移动分支并重置已跟踪文件,同时保留本地更改。如果这些更改与重置冲突,Git 将中止操作。'; @override String gitAdditionsDeletions(int additions, int deletions) { @@ -2543,121 +2424,114 @@ class AppLocalizationsZh extends AppLocalizations { } @override - String get fileActions => 'File actions'; + String get fileActions => '文件操作'; @override - String get actions => 'Actions'; + String get actions => '操作'; @override - String get gitStatusAdded => 'Added'; + String get gitStatusAdded => '已添加'; @override - String get gitStatusDeleted => 'Deleted'; + String get gitStatusDeleted => '已删除'; @override - String get gitStatusRenamed => 'Renamed'; + String get gitStatusRenamed => '已重命名'; @override - String get gitStatusCopied => 'Copied'; + String get gitStatusCopied => '已复制'; @override - String get gitStatusUntracked => 'Untracked'; + String get gitStatusUntracked => '未跟踪'; @override - String get gitStatusConflicted => 'Conflicted'; + String get gitStatusConflicted => '有冲突'; @override - String get gitStatusIgnored => 'Ignored'; + String get gitStatusIgnored => '已忽略'; @override - String get gitStatusTypeChanged => 'Type changed'; + String get gitStatusTypeChanged => '类型已更改'; @override - String get gitStatusModified => 'Modified'; + String get gitStatusModified => '已修改'; @override - String get gitStatusUnknown => 'Unknown'; + String get gitStatusUnknown => '未知'; @override - String get gitErrorUnavailable => 'Git is unavailable.'; + String get gitErrorUnavailable => 'Git 不可用。'; @override - String get gitErrorNotRepository => 'This workspace is not a Git repository.'; + String get gitErrorNotRepository => '此工作区不是 Git 存储库。'; @override - String get gitErrorUnsafePath => 'BusyMark blocked an unsafe Git path.'; + String get gitErrorUnsafePath => 'BusyMark 阻止了不安全的 Git 路径。'; @override - String get gitErrorInvalidBranchName => 'Enter a valid branch name.'; + String get gitErrorInvalidBranchName => '请输入有效的分支名称。'; @override - String get gitErrorNoRemote => 'No Git remote is configured.'; + String get gitErrorNoRemote => '未配置 Git 远程仓库。'; @override - String get gitErrorNoUpstream => 'No upstream branch is configured.'; + String get gitErrorNoUpstream => '未配置上游分支。'; @override - String get gitErrorMultipleRemotes => - 'Multiple remotes are configured. Choose an upstream outside this BusyMark version.'; + String get gitErrorMultipleRemotes => '配置了多个远程仓库。请在此 BusyMark 版本之外选择上游分支。'; @override - String get gitErrorDirtyWorkspace => - 'Save or discard BusyMark editor changes before switching branches.'; + String get gitErrorDirtyWorkspace => '切换分支前,请保存或放弃 BusyMark 编辑器中的更改。'; @override - String get gitErrorResetDirtyWorkspace => - 'Save or discard BusyMark editor changes before resetting the current branch.'; + String get gitErrorResetDirtyWorkspace => '重置当前分支前,请保存或放弃 BusyMark 编辑器中的更改。'; @override - String get gitErrorRestoreStagedFile => - 'Unstage this file before restoring a historical version.'; + String get gitErrorRestoreStagedFile => '还原历史版本前,请取消暂存此文件。'; @override - String get gitErrorResetDetachedHead => - 'Check out a branch before resetting it.'; + String get gitErrorResetDetachedHead => '重置前请先检出一个分支。'; @override - String get gitErrorDiverged => - 'Branch has diverged. Resolve merge or rebase outside this BusyMark version.'; + String get gitErrorDiverged => '分支已发生分歧。请在此 BusyMark 版本之外解决合并或变基问题。'; @override - String get gitErrorAuthorIdentity => - 'Git needs an author name and email address before it can commit.'; + String get gitErrorAuthorIdentity => 'Git 需要作者姓名和邮箱地址才能提交。'; @override - String get gitAuthorIdentityTitle => 'Git Author Identity'; + String get gitAuthorIdentityTitle => 'Git 作者身份'; @override String get gitAuthorIdentityMessage => - 'Enter the identity Git should record on commits. BusyMark will save it and retry this commit.'; + '请输入 Git 应记录在提交中的身份信息。BusyMark 将保存它并重试此次提交。'; @override - String get gitAuthorName => 'Name'; + String get gitAuthorName => '姓名'; @override String get gitAuthorEmail => 'Email'; @override - String get gitAuthorIdentityGlobal => 'Use for all repositories'; + String get gitAuthorIdentityGlobal => '用于所有存储库'; @override String get gitAuthorIdentityGlobalDescription => - 'When installed as a Snap, this applies to repositories opened in BusyMark.'; + '作为 Snap 安装时,此设置适用于在 BusyMark 中打开的存储库。'; @override - String get gitSaveIdentityAndCommit => 'Save and Commit'; + String get gitSaveIdentityAndCommit => '保存并提交'; @override - String get gitErrorAuthentication => 'Git authentication failed.'; + String get gitErrorAuthentication => 'Git 身份验证失败。'; @override - String get gitErrorNetwork => 'Git network operation failed.'; + String get gitErrorNetwork => 'Git 网络操作失败。'; @override - String get gitErrorConflict => 'Git reported unresolved conflicts.'; + String get gitErrorConflict => 'Git 报告存在未解决的冲突。'; @override - String get gitErrorCommandFailed => 'Git command failed.'; + String get gitErrorCommandFailed => 'Git 命令失败。'; @override String get syntaxReference => '语法参考'; @@ -2911,18 +2785,16 @@ class AppLocalizationsZh extends AppLocalizations { '本地视频使用本地 preview-src 图像;托管视频源必须是受支持的 YouTube 或 Vimeo HTTPS URL。'; @override - String get exportAsPdf => 'Export as PDF'; + String get exportAsPdf => '导出为 PDF'; @override - String get pdfExportDescription => - 'Choose the page layout for a polished, self-contained PDF.'; + String get pdfExportDescription => '选择页面布局,生成精美且自包含的 PDF。'; @override - String get pdfRemoteImagesNote => - 'Remote images are not downloaded during export. Local images are included when available.'; + String get pdfRemoteImagesNote => '导出过程中不会下载远程图像。有可用的本地图像时将包含它们。'; @override - String get pdfPageSize => 'Page size'; + String get pdfPageSize => '页面大小'; @override String get pdfPageSizeA4 => 'A4'; @@ -2931,41 +2803,41 @@ class AppLocalizationsZh extends AppLocalizations { String get pdfPageSizeLetter => 'Letter'; @override - String get pdfOrientation => 'Orientation'; + String get pdfOrientation => '方向'; @override - String get pdfPortrait => 'Portrait'; + String get pdfPortrait => '纵向'; @override - String get pdfLandscape => 'Landscape'; + String get pdfLandscape => '横向'; @override - String get pdfMargins => 'Margins'; + String get pdfMargins => '页边距'; @override - String get pdfMarginNarrow => 'Narrow'; + String get pdfMarginNarrow => '窄'; @override - String get pdfMarginNormal => 'Normal'; + String get pdfMarginNormal => '普通'; @override - String get pdfMarginWide => 'Wide'; + String get pdfMarginWide => '宽'; @override - String get pdfIncludePageNumbers => 'Include page numbers'; + String get pdfIncludePageNumbers => '包含页码'; @override - String get export => 'Export'; + String get export => '导出'; @override - String get exportingPdf => 'Exporting PDF…'; + String get exportingPdf => '正在导出 PDF…'; @override - String get fileTypePdf => 'PDF document'; + String get fileTypePdf => 'PDF 文档'; @override String pdfExported(String fileName) { - return '$fileName was exported.'; + return '已导出 $fileName。'; } @override @@ -2973,364 +2845,344 @@ class AppLocalizationsZh extends AppLocalizations { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: '$count warnings', - one: '1 warning', + other: '$count 条警告', + one: '1 条警告', ); - return '$fileName was exported with $_temp0.'; + return '$fileName 已导出,包含 $_temp0。'; } @override - String get pdfExportUnavailable => - 'The PDF export component is missing. Reinstall BusyMark and try again.'; + String get pdfExportUnavailable => '缺少 PDF 导出组件。请重新安装 BusyMark 后重试。'; @override - String get pdfExportTimedOut => 'PDF export took too long and was stopped.'; + String get pdfExportTimedOut => 'PDF 导出耗时过长,已停止。'; @override - String get pdfExportFailed => - 'BusyMark could not export this document as PDF.'; + String get pdfExportFailed => 'BusyMark 无法将此文档导出为 PDF。'; @override - String get visualizationRendering => 'Rendering…'; + String get visualizationRendering => '正在渲染…'; @override - String get visualizationStale => 'Showing the last valid render'; + String get visualizationStale => '正在显示上次有效的渲染结果'; @override - String get visualizationShowSource => 'Show source'; + String get visualizationShowSource => '显示源代码'; @override - String get visualizationShowRender => 'Show render'; + String get visualizationShowRender => '显示渲染结果'; @override - String get visualizationFitWidth => 'Fit to width'; + String get visualizationFitWidth => '适应宽度'; @override - String get visualizationSaveImage => 'Save image'; + String get visualizationSaveImage => '保存图像'; @override - String get visualizationCopyImage => 'Copy image'; + String get visualizationCopyImage => '复制图像'; @override - String get visualizationImageCopied => 'Image copied'; + String get visualizationImageCopied => '图像已复制'; @override - String get visualizationOpenApiReference => 'Open API Reference'; + String get visualizationOpenApiReference => '打开 API 参考'; @override - String get visualizationValid => 'Valid'; + String get visualizationValid => '有效'; @override - String get visualizationInvalid => 'Invalid'; + String get visualizationInvalid => '无效'; @override - String get visualizationServers => 'Servers'; + String get visualizationServers => '服务器'; @override - String get visualizationPaths => 'Paths'; + String get visualizationPaths => '路径'; @override - String get visualizationOperations => 'Operations'; + String get visualizationOperations => '操作'; @override - String get visualizationTags => 'Tags'; + String get visualizationTags => '标签'; @override - String get visualizationNoOperations => 'No matching operations'; + String get visualizationNoOperations => '没有匹配的操作'; @override - String get visualizationSearchOperations => 'Search operations'; + String get visualizationSearchOperations => '搜索操作'; @override - String get visualizationRenderFailed => - 'This visualization could not be rendered.'; + String get visualizationRenderFailed => '无法渲染此可视化内容。'; @override - String get visualizationRetry => 'Retry'; + String get visualizationRetry => '重试'; @override String visualizationSaved(String fileName) { - return 'Saved $fileName'; + return '已保存 $fileName'; } @override - String get shortcutExportPdfDescription => - 'Export the active document or Writerside module as a PDF.'; + String get shortcutExportPdfDescription => '将当前文档或 Writerside 模块导出为 PDF。'; @override - String get instances => 'Instances'; + String get instances => '实例'; @override - String get newInstance => 'New instance'; + String get newInstance => '新建实例'; @override - String get newTocLibrary => 'New TOC library'; + String get newTocLibrary => '新建目录库'; @override - String get editInstance => 'Edit instance'; + String get editInstance => '编辑实例'; @override - String get openTocFile => 'Open TOC file'; + String get openTocFile => '打开目录文件'; @override - String get createInstance => 'Create instance'; + String get createInstance => '创建实例'; @override - String get createTocLibrary => 'Create TOC library'; + String get createTocLibrary => '创建目录库'; @override - String get instanceContent => 'Content'; + String get instanceContent => '内容'; @override - String get instanceContentSource => 'Create from'; + String get instanceContentSource => '创建来源'; @override - String get emptyInstance => 'Empty instance'; + String get emptyInstance => '空实例'; @override - String get markdownFiles => 'Local Markdown files'; + String get markdownFiles => '本地 Markdown 文件'; @override - String get chooseMarkdownFolder => 'Choose Markdown folder'; + String get chooseMarkdownFolder => '选择 Markdown 文件夹'; @override String get errorWritersideInstanceImportSourceRequired => - 'Choose a folder containing Markdown files.'; + '选择包含 Markdown 文件的文件夹。'; @override - String get instanceAppearance => 'Appearance'; + String get instanceAppearance => '外观'; @override - String get instanceColor => 'Icon color'; + String get instanceColor => '图标颜色'; @override - String get instanceVersion => 'Version'; + String get instanceVersion => '版本'; @override String instanceVersionInherited(String version) { - return 'The project version is $version when this field is empty.'; + return '此字段为空时,项目版本为 $version。'; } @override - String get instanceWebPath => 'Web path'; + String get instanceWebPath => 'Web 路径'; @override - String get instanceStatus => 'Status'; + String get instanceStatus => '状态'; @override - String get instanceStatusRelease => 'Release'; + String get instanceStatusRelease => '发布'; @override - String get instanceStatusEap => 'Early access'; + String get instanceStatusEap => '抢先体验'; @override - String get instanceStatusDeprecated => 'Deprecated'; + String get instanceStatusDeprecated => '已弃用'; @override - String get allowSearchEngineIndexing => 'Allow search engine indexing'; + String get allowSearchEngineIndexing => '允许搜索引擎建立索引'; @override - String get allowSearchEngineIndexingDescription => - 'Allow external search engines to index this output.'; + String get allowSearchEngineIndexingDescription => '允许外部搜索引擎为此输出建立索引。'; @override - String get offlineArtifact => 'Offline artifact'; + String get offlineArtifact => '离线构件'; @override - String get offlineArtifactDescription => - 'Bundle resources so the built documentation is self-contained.'; + String get offlineArtifactDescription => '捆绑资源,使构建的文档可以自包含。'; @override - String get instanceOutputSettings => 'Output settings'; + String get instanceOutputSettings => '输出设置'; @override - String get markdownImportSource => 'Markdown source'; + String get markdownImportSource => 'Markdown 源'; @override - String get markdownImportFiles => 'Markdown files'; + String get markdownImportFiles => 'Markdown 文件'; @override - String get selectNone => 'Select none'; + String get selectNone => '全部取消选择'; @override String markdownFilesFound(int count) { - String _temp0 = intl.Intl.pluralLogic( - count, - locale: localeName, - other: '$count Markdown files found', - one: '1 Markdown file found', - ); - return '$_temp0'; + return '找到 $count 个 Markdown 文件'; } @override - String get noMarkdownFilesFound => - 'No Markdown files were found in this directory.'; + String get noMarkdownFilesFound => '在此目录中未找到 Markdown 文件。'; @override - String get copyReferencedMedia => 'Copy referenced media'; + String get copyReferencedMedia => '复制引用的媒体'; @override - String get copyReferencedMediaDescription => - 'Copy local images and video referenced by the selected files while preserving relative paths.'; + String get copyReferencedMediaDescription => '复制选中文件引用的本地图像和视频,同时保留相对路径。'; @override - String get instanceIdRenameWarningTitle => 'Rename instance ID?'; + String get instanceIdRenameWarningTitle => '重命名实例 ID?'; @override String instanceIdRenameWarning(String oldId, String newId) { - return 'BusyMark will rename the .tree file and update Writerside project references from “$oldId” to “$newId”. Publication scripts are not changed and must be updated separately.'; + return 'BusyMark 将重命名 .tree 文件,并将 Writerside 项目引用从“$oldId”更新为“$newId”。发布脚本不会更改,必须单独更新。'; } @override - String get renameAndUpdateReferences => 'Rename and update references'; + String get renameAndUpdateReferences => '重命名并更新引用'; @override - String get tocLibraryDescription => - 'A TOC library stores reusable sections and does not produce its own output.'; + String get tocLibraryDescription => '目录库用于存储可复用的节,不会生成自己的输出。'; @override - String get defaultTocLibraryName => 'Shared TOC'; + String get defaultTocLibraryName => '共享目录'; @override - String get instanceColorAutomatic => 'Automatic'; + String get instanceColorAutomatic => '自动'; @override - String get instanceColorBlue => 'Blue'; + String get instanceColorBlue => '蓝色'; @override - String get instanceColorGreen => 'Green'; + String get instanceColorGreen => '绿色'; @override - String get instanceColorOrange => 'Orange'; + String get instanceColorOrange => '橙色'; @override - String get instanceColorPurple => 'Purple'; + String get instanceColorPurple => '紫色'; @override - String get instanceColorRed => 'Red'; + String get instanceColorRed => '红色'; @override - String get instanceColorTeal => 'Teal'; + String get instanceColorTeal => '青绿色'; @override - String get instanceColorYellow => 'Yellow'; + String get instanceColorYellow => '黄色'; @override - String get errorWritersideInstanceNameRequired => 'Enter an instance name.'; + String get errorWritersideInstanceNameRequired => '请输入实例名称。'; @override String errorWritersideInstanceIdExists(String id) { - return 'An instance with ID “$id” already exists.'; + return '已存在 ID 为“$id”的实例。'; } @override String errorWritersideInstanceTreeExists(String path) { - return 'The instance tree already exists: $path'; + return '实例树已存在:$path'; } @override String errorWritersideInstanceImportSourceMissing(String path) { - return 'The Markdown source directory does not exist: $path'; + return 'Markdown 源目录不存在:$path'; } @override String get errorWritersideInstanceImportSelectionRequired => - 'Select at least one Markdown file to import.'; + '请选择至少一个 Markdown 文件进行导入。'; @override String errorWritersideInstanceImportFileInvalid(String path) { - return 'This is not a readable Markdown file inside the selected source: $path'; + return '选中的源中有一个不是可读取的 Markdown 文件:$path'; } @override String errorWritersideInstanceImportTargetExists(String path) { - return 'Import would overwrite an existing project file: $path'; + return '导入将覆盖现有项目文件:$path'; } @override - String get errorWritersideInstanceFilesChanged => - 'Instance files changed on disk. Review them and try again.'; + String get errorWritersideInstanceFilesChanged => '实例文件已在磁盘上发生变化。请查看后重试。'; @override String errorWritersideInstanceRollbackFailed(String paths) { - return 'BusyMark could not completely roll back the instance change. Review these files before continuing: $paths'; + return 'BusyMark 无法完全回滚实例更改。请在继续前查看这些文件:$paths'; } @override - String get errorWritersideInstanceLibraryImport => - 'A TOC library cannot import Markdown topics.'; + String get errorWritersideInstanceLibraryImport => '目录库无法导入 Markdown 主题。'; @override - String get errorWritersideInstanceWebPathInvalid => - 'The web path must be a single line.'; + String get errorWritersideInstanceWebPathInvalid => 'Web 路径必须为单行文本。'; @override String get errorWritersideInstanceConfigurationInvalid => - 'The Writerside instance configuration is invalid. Correct its diagnostics and try again.'; + 'Writerside 实例配置无效。请修正其诊断信息后重试。'; @override - String get errorWritersideInstanceTemporaryFile => - 'BusyMark could not stage the instance changes safely.'; + String get errorWritersideInstanceTemporaryFile => 'BusyMark 无法安全暂存实例更改。'; @override String diagnosticWritersideTreeInvalidStatus(String status) { - return 'Unknown instance status “$status”. Use release, eap, or deprecated.'; + return '未知的实例状态“$status”。请使用 release、eap 或 deprecated。'; } @override String diagnosticWritersideDuplicateInstanceId(String id) { - return 'The instance ID “$id” is used by more than one tree file.'; + return '实例 ID“$id”被多个树文件使用。'; } @override String get diagnosticWritersideBuildProfilesInvalidRoot => - 'buildprofiles.xml must have a <buildprofiles> root element.'; + 'buildprofiles.xml 必须包含 <buildprofiles> 根元素。'; @override String diagnosticWritersideBuildProfilesInvalidBoolean( String name, String value, ) { - return 'The $name value “$value” must be true or false.'; + return '$name 值“$value”必须为 true 或 false。'; } @override String get diagnosticWritersideBuildProfileMissingInstance => - 'A <build-profile> element must specify an instance ID.'; + '<build-profile> 元素必须指定实例 ID。'; @override String get diagnosticWritersideTreeInvalidInclude => - 'A tree <include> must specify both from and element-id.'; + '树中的 <include> 必须同时指定 from 和 element-id。'; @override String get diagnosticWritersideTreeMissingSnippetId => - 'A tree <snippet> must specify an id.'; + '树中的 <snippet> 必须指定 id。'; @override String get diagnosticWritersideTreeInvalidCrossInstanceReference => - 'A cross-instance TOC reference must specify both ref and in.'; + '跨实例目录引用必须同时指定 ref 和 in。'; @override String get diagnosticWritersideTreeConflictingTargets => - 'A TOC element cannot target more than one topic, reference, link, or redirect.'; + '目录元素不能同时指向多个主题、引用、链接或重定向。'; @override String diagnosticWritersideTreeDuplicateElementId(String id) { - return 'Tree element ID “$id” is declared more than once.'; + return '树元素 ID“$id”被声明了多次。'; } @override String get diagnosticWritersideInstanceGroupsInvalidRoot => - 'The instance groups file must have an <instance-groups> root element.'; + '实例组文件必须包含 <instance-groups> 根元素。'; @override - String get diagnosticWritersideInstanceGroupInvalid => - 'An instance group must specify a non-empty id and instances list.'; + String get diagnosticWritersideInstanceGroupInvalid => '实例组必须指定非空 ID 和实例列表。'; @override String diagnosticWritersideInstanceGroupDuplicateId(String id) { - return 'Instance group ID “$id” is declared more than once.'; + return '实例组 ID“$id”被声明了多次。'; } @override @@ -3339,7 +3191,7 @@ class AppLocalizationsZh extends AppLocalizations { String id, String origin, ) { - return 'TOC include “$source#$id” belongs to external module “$origin” and cannot be expanded in this workspace.'; + return '目录包含项“$source#$id”属于外部模块“$origin”,无法在此工作区中展开。'; } @override @@ -3347,22 +3199,22 @@ class AppLocalizationsZh extends AppLocalizations { String source, String id, ) { - return 'Tree element “$id” does not exist in registered tree “$source”.'; + return '已注册树“$source”中不存在树元素“$id”。'; } @override String diagnosticWritersideTreeCircularInclude(String source, String id) { - return 'Tree include “$source#$id” creates a cycle.'; + return '树包含项“$source#$id”创建了循环。'; } @override String diagnosticWritersideUnknownInstanceGroup(String group) { - return 'Instance condition references unknown group “@$group”.'; + return '实例条件引用了未知组“@$group”。'; } @override String diagnosticWritersideReferenceInstanceMissing(String instance) { - return 'Cross-instance reference targets unknown instance “$instance”.'; + return '跨实例引用指向未知实例“$instance”。'; } @override @@ -3370,329 +3222,293 @@ class AppLocalizationsZh extends AppLocalizations { String topic, String instance, ) { - return 'Topic “$topic” is not in referenced instance “$instance”.'; + return '主题“$topic”不在被引用的实例“$instance”中。'; } @override - String get download => 'Download'; + String get download => '下载'; @override - String get exportWritersideAsPdf => 'Export Writerside as PDF'; + String get exportWritersideAsPdf => '将 Writerside 导出为 PDF'; @override - String get writersidePdfContent => 'Export content'; + String get writersidePdfContent => '导出内容'; @override - String get writersidePdfPage => 'Page'; + String get writersidePdfPage => '页面'; @override - String get exportingWritersidePdf => 'Exporting Writerside PDF…'; + String get exportingWritersidePdf => '正在导出 Writerside PDF…'; @override String get ai => 'AI'; @override - String get aiLocalOllama => 'Local Ollama'; + String get aiLocalOllama => '本地 Ollama'; @override - String get aiDisabled => 'Disabled'; + String get aiDisabled => '已禁用'; @override String get aiExplicitEditingDescription => - 'AI editing is explicit. BusyMark sends only the context shown for the selected provider and never applies a proposal without review.'; + 'AI 编辑需要明确发起。BusyMark 只会将所选提供商对应的显示上下文发送出去,且不会在未经审核的情况下应用建议。'; @override - String get aiProvider => 'AI provider'; + String get aiProvider => 'AI 提供商'; @override - String get aiDefaultProvider => 'Default provider'; + String get aiDefaultProvider => '默认提供商'; @override - String get aiConfigureProvider => 'Configure provider'; + String get aiConfigureProvider => '配置提供商'; @override - String get aiChooseProvider => 'Choose AI provider'; + String get aiChooseProvider => '选择 AI 提供商'; @override - String get aiOllamaEndpoint => 'Ollama endpoint'; + String get aiOllamaEndpoint => 'Ollama 端点'; @override - String get aiOllamaModel => 'Ollama model'; + String get aiOllamaModel => 'Ollama 模型'; @override - String get aiTestConnection => 'Test connection'; + String get aiTestConnection => '测试连接'; @override - String get aiTestingConnection => 'Testing…'; + String get aiTestingConnection => '正在测试…'; @override String aiConnectionReady(int count) { - String _temp0 = intl.Intl.pluralLogic( - count, - locale: localeName, - other: '$count installed models found', - one: '1 installed model found', - ); - return 'Connected. $_temp0.'; + return '已连接。找到 $count 个已安装模型。'; } @override - String get aiNoModels => 'No model selected.'; + String get aiNoModels => '未选择模型。'; @override - String get aiConnectionFailed => - 'BusyMark could not verify AI text generation.'; + String get aiConnectionFailed => 'BusyMark 无法验证 AI 文本生成。'; @override - String get aiConfigureFirst => - 'Enable an AI provider and verify a model in Settings → AI.'; + String get aiConfigureFirst => '请先在设置 → AI 中启用 AI 提供商并验证模型。'; @override - String get aiEditWithAi => 'Edit with AI'; + String get aiEditWithAi => '使用 AI 编辑'; @override - String get aiRefineWithAi => 'Refine with AI'; + String get aiRefineWithAi => '使用 AI 优化'; @override - String get aiInstruction => 'Instruction'; + String get aiInstruction => '指令'; @override - String get aiChangeTarget => 'What may change'; + String get aiChangeTarget => '可更改内容'; @override - String get aiSharedContext => 'Context shared with AI'; + String get aiSharedContext => '与 AI 共享的上下文'; @override - String get aiTargetSelection => 'Selected content'; + String get aiTargetSelection => '选中的内容'; @override - String get aiTargetInsertAfterBlock => 'Insert after current block'; + String get aiTargetInsertAfterBlock => '插入到当前块之后'; @override - String get aiTargetCurrentBlock => 'Current block'; + String get aiTargetCurrentBlock => '当前块'; @override - String get aiTargetCurrentSection => 'Current section'; + String get aiTargetCurrentSection => '当前节'; @override - String get aiTargetCompleteDocument => 'Complete document'; + String get aiTargetCompleteDocument => '完整文档'; @override - String get aiContextNone => 'No document context'; + String get aiContextNone => '没有文档上下文'; @override - String get aiContextSelection => 'Selected content'; + String get aiContextSelection => '选中的内容'; @override - String get aiContextCurrentBlock => 'Current block'; + String get aiContextCurrentBlock => '当前块'; @override - String get aiContextCurrentSection => 'Current section'; + String get aiContextCurrentSection => '当前节'; @override - String get aiContextCompleteDocument => 'Complete document'; + String get aiContextCompleteDocument => '完整文档'; @override - String get aiGenerating => 'Generating proposal…'; + String get aiGenerating => '正在生成建议…'; @override - String get aiProposal => 'AI proposal'; + String get aiProposal => 'AI 建议'; @override - String get aiGenerateProposal => 'Generate proposal'; + String get aiGenerateProposal => '生成建议'; @override String aiContextDisclosure(int count) { - String _temp0 = intl.Intl.pluralLogic( - count, - locale: localeName, - other: '$count characters', - one: '1 character', - ); - return 'The selected provider will receive $_temp0 from the displayed context.'; + return '所选提供商将接收显示上下文中的 $count 个字符。'; } @override - String get aiOriginal => 'Original'; + String get aiOriginal => '原始内容'; @override - String get aiSuggested => 'Suggested'; + String get aiSuggested => '建议内容'; @override - String get aiApplyProposal => 'Apply proposal'; + String get aiApplyProposal => '应用建议'; @override String aiTokenUsage(int input, int output) { - return '$input input tokens · $output output tokens'; + return '输入 token:$input · 输出 token:$output'; } @override - String get aiStaleProposal => - 'The document changed while this proposal was generated. Run the action again.'; + String get aiStaleProposal => '生成此建议期间文档发生了变化。请重新执行操作。'; @override - String get gitAiStagedChangesChanged => - 'The staged changes changed while this commit message was generated. Run the action again.'; + String get gitAiStagedChangesChanged => '生成此提交消息期间,已暂存的更改发生了变化。请重新执行操作。'; @override - String get aiViewContext => 'View context sent'; + String get aiViewContext => '查看已发送的上下文'; @override - String get aiReviewExactContent => 'Review exact content'; + String get aiReviewExactContent => '查看确切内容'; @override - String get aiContentToChange => 'Content to change'; + String get aiContentToChange => '要更改的内容'; @override - String get aiContentSentToAi => 'Content sent to AI'; + String get aiContentSentToAi => '发送给 AI 的内容'; @override - String get aiApiKey => 'API key'; + String get aiApiKey => 'API 密钥'; @override - String get aiApiKeyStoredHint => - 'A key is stored in the system credential store'; + String get aiApiKeyStoredHint => '密钥已存储在系统凭据存储中'; @override - String get aiApiKeyEnterHint => 'Enter a provider API key'; + String get aiApiKeyEnterHint => '输入提供商 API 密钥'; @override - String get aiReplaceApiKey => 'Replace API key'; + String get aiReplaceApiKey => '替换 API 密钥'; @override - String get aiSaveApiKey => 'Save API key securely'; + String get aiSaveApiKey => '安全保存 API 密钥'; @override - String get aiRemoveApiKey => 'Remove saved API key'; + String get aiRemoveApiKey => '移除已保存的 API 密钥'; @override - String get aiCredentialSaved => - 'API key saved in the system credential store.'; + String get aiCredentialSaved => 'API 密钥已保存到系统凭据存储中。'; @override - String get aiCredentialRemoved => 'The saved API key was removed.'; + String get aiCredentialRemoved => '已移除保存的 API 密钥。'; @override - String get aiModelRouting => 'Model routing'; + String get aiModelRouting => '模型路由'; @override - String get aiAutomaticRouting => 'Automatic by task'; + String get aiAutomaticRouting => '按任务自动选择'; @override - String get aiFixedModelRouting => 'Use selected model'; + String get aiFixedModelRouting => '使用选中的模型'; @override - String get aiPreferredModel => 'Preferred model'; + String get aiPreferredModel => '首选模型'; @override - String get aiModel => 'Model'; + String get aiModel => '模型'; @override String aiUsageThisMonth(int requests, int input, int output) { - return '$requests requests · $input input tokens · $output output tokens'; + return '$requests 个请求 · $input 个输入 token · $output 个输出 token'; } @override String aiCloudConsentTitle(String provider) { - return 'Send content to $provider?'; + return '将内容发送给 $provider?'; } @override String aiCloudConsentEnable(String provider) { - return 'Enable $provider'; + return '启用 $provider'; } @override String get aiCloudConsentMessage => - 'Only content shown in each AI review dialog is sent. Requests are stateless, proposals require review, and the API key is stored in the Linux system credential store.'; + '只会发送每个 AI 审核对话框中显示的内容。请求不保存状态,建议需要审核,API 密钥存储在 Linux 系统凭据存储中。'; @override String aiCloudConsentRequired(String provider) { - return 'Confirm $provider data sharing in Settings → AI first.'; + return '请先在设置 → AI 中确认与 $provider 共享数据。'; } @override String aiGenerationVerified(String model, int count) { - String _temp0 = intl.Intl.pluralLogic( - count, - locale: localeName, - other: '$count compatible models available', - one: '1 compatible model available', - ); - return 'Generation verified with $model. $_temp0.'; + return '已通过 $model 验证生成能力。有 $count 个兼容模型可用。'; } @override - String get aiColdStartObserved => 'A local model cold start was observed.'; + String get aiColdStartObserved => '检测到本地模型冷启动。'; @override - String get aiNoCompatibleModels => - 'No compatible text-generation model is available.'; + String get aiNoCompatibleModels => '没有可用的兼容文本生成模型。'; @override - String get aiEnableProvider => 'Enable an AI provider first.'; + String get aiEnableProvider => '请先启用 AI 提供商。'; @override - String get aiDraftCommitMessage => 'Draft commit message'; + String get aiDraftCommitMessage => '起草提交消息'; @override - String get aiDrafting => 'Drafting…'; + String get aiDrafting => '正在起草…'; @override - String get aiDraftWithAi => 'Draft with AI'; + String get aiDraftWithAi => '使用 AI 起草'; @override - String get generateOrUpdateMarkdownToc => 'Generate/update table of contents'; + String get generateOrUpdateMarkdownToc => '生成/更新目录'; @override - String get markdownTocTitle => 'Table of contents'; + String get markdownTocTitle => '目录'; @override String markdownTocUpdated(int count) { - String _temp0 = intl.Intl.pluralLogic( - count, - locale: localeName, - other: '$count entries', - one: '1 entry', - ); - return 'Table of contents updated with $_temp0.'; + return '目录已更新,包含 $count 个条目。'; } @override - String get markdownTocNoHeadings => - 'Add at least one section heading before generating a table of contents.'; + String get markdownTocNoHeadings => '请先添加至少一个节标题,再生成目录。'; @override - String get markdownTocMalformedMarkers => - 'The BusyMark table-of-contents markers are missing, duplicated, or out of order.'; + String get markdownTocMalformedMarkers => 'BusyMark 目录标记缺失、重复或顺序错误。'; @override String diagnosticMarkdownHeadingSkippedLevel(int level, int previousLevel) { - return 'Heading level $level follows level $previousLevel; review the section nesting.'; + return '标题级别 $level 跟在级别 $previousLevel 之后;请检查节的嵌套结构。'; } @override - String get diagnosticMarkdownLinkEmptyText => - 'Link text is empty; provide an accessible name that describes its purpose.'; + String get diagnosticMarkdownLinkEmptyText => '链接文本为空;请提供能描述其用途的可访问名称。'; @override String diagnosticMarkdownLinkReviewText(String text) { - return 'Review whether the link text “$text” describes its purpose in context.'; + return '请检查链接文本“$text”是否在上下文中描述了其用途。'; } @override - String get diagnosticMarkdownTableEmptyHeader => - 'Table header cells must identify their columns; complete each empty header.'; + String get diagnosticMarkdownTableEmptyHeader => '表头单元格必须标识其列;请补全每个空表头。'; @override - String get mathRenderFailed => - 'The mathematical expression could not be rendered.'; + String get mathRenderFailed => '无法渲染数学表达式。'; @override - String get inlineMath => 'Inline math'; + String get inlineMath => '行内数学'; @override - String get displayMath => 'Display math'; + String get displayMath => '显示数学'; @override String get goToDeclaration => '转到声明'; @@ -4050,6 +3866,9 @@ class AppLocalizationsZhCn extends AppLocalizationsZh { @override String get copyPlainText => '复制为纯文本'; + @override + String get clipboardCopyFailed => '无法将所选内容复制到剪贴板。'; + @override String get copyName => '复制名称'; diff --git a/lib/src/app/busymark_design.dart b/lib/src/app/busymark_design.dart index e66fbd5e..e9a5ed2e 100644 --- a/lib/src/app/busymark_design.dart +++ b/lib/src/app/busymark_design.dart @@ -1853,6 +1853,7 @@ class BusyMarkPopupSelector<T> extends StatelessWidget { this.leading, this.fullWidth = false, this.contentPadding, + this.buttonHeight, }); final T? value; @@ -1867,6 +1868,7 @@ class BusyMarkPopupSelector<T> extends StatelessWidget { final Widget? leading; final bool fullWidth; final EdgeInsetsGeometry? contentPadding; + final double? buttonHeight; @override Widget build(BuildContext context) { @@ -1910,6 +1912,17 @@ class BusyMarkPopupSelector<T> extends StatelessWidget { padding: contentPadding == null ? null : WidgetStatePropertyAll(contentPadding), + minimumSize: buttonHeight == null + ? null + : WidgetStatePropertyAll(Size(0, buttonHeight!)), + maximumSize: buttonHeight == null + ? null + : WidgetStatePropertyAll( + Size(double.infinity, buttonHeight!), + ), + tapTargetSize: buttonHeight == null + ? null + : MaterialTapTargetSize.shrinkWrap, ), child: Row( mainAxisSize: fullWidth diff --git a/lib/src/workspace/presentation/workspace_screen.dart b/lib/src/workspace/presentation/workspace_screen.dart index 62eada75..56e6535d 100644 --- a/lib/src/workspace/presentation/workspace_screen.dart +++ b/lib/src/workspace/presentation/workspace_screen.dart @@ -6573,6 +6573,7 @@ class _WritersideInstanceSelector extends StatelessWidget { start: BusyMarkSpacing.headerInset, end: BusyMarkSpacing.sm, ), + buttonHeight: BusyMarkSizes.iconButton, ); } } diff --git a/test/src/app_smoke_test.dart b/test/src/app_smoke_test.dart index a2200510..cd33e91c 100644 --- a/test/src/app_smoke_test.dart +++ b/test/src/app_smoke_test.dart @@ -791,6 +791,59 @@ void main() { expect(find.text(de.validateOnEdit), findsOneWidget); }); + for (final localeCase in <({String name, Locale requested, Locale expected})>[ + ( + name: 'European Portuguese', + requested: const Locale('pt', 'PT'), + expected: const Locale('pt'), + ), + ( + name: 'language-only Chinese', + requested: const Locale('zh'), + expected: const Locale('zh'), + ), + ]) { + testWidgets( + '${localeCase.name} system locale renders the completed base catalog', + (tester) async { + tester.view.physicalSize = const Size(1200, 800); + tester.view.devicePixelRatio = 1; + tester.binding.platformDispatcher.localesTestValue = <Locale>[ + localeCase.requested, + ]; + addTearDown(() { + tester.view.resetPhysicalSize(); + tester.view.resetDevicePixelRatio(); + tester.binding.platformDispatcher.clearLocalesTestValue(); + }); + final translated = lookupAppLocalizations(localeCase.expected); + final settingsStore = _MemorySettingsStore(); + + await tester.pumpWidget( + ProviderScope( + overrides: [ + linuxHeaderBarServiceProvider.overrideWithValue(headerBarService), + localSettingsStoreProvider.overrideWithValue(settingsStore), + ], + child: const BusyMarkApp(), + ), + ); + await tester.pumpAndSettle(); + + expect(find.text(translated.createMarkdownFile), findsOneWidget); + expect(find.text(l10n.createMarkdownFile), findsNothing); + await tester.tap(find.byTooltip(translated.mainMenu)); + await tester.pumpAndSettle(); + await tester.tap(find.text(translated.settings)); + await tester.pumpAndSettle(); + + expect(find.text(translated.appLanguage), findsOneWidget); + expect(find.text(l10n.appLanguage), findsNothing); + expect(tester.takeException(), isNull); + }, + ); + } + testWidgets('Writerside project dialog syncs generated fields until edited', ( tester, ) async { @@ -1950,6 +2003,8 @@ void main() { matching: find.byType(IconButton), ), ); + expect(instanceSelectorRect.height, tocMenuRect.height); + expect(instanceSelectorRect.center.dy, tocMenuRect.center.dy); final mouse = await tester.createGesture(kind: PointerDeviceKind.mouse); addTearDown(mouse.removePointer); await mouse.addPointer(location: Offset.zero); diff --git a/test/src/localization_audit_test.dart b/test/src/localization_audit_test.dart index 55025e10..59de635a 100644 --- a/test/src/localization_audit_test.dart +++ b/test/src/localization_audit_test.dart @@ -170,7 +170,67 @@ void main() { } }); - test('target ARBs match the English messages and placeholders', () { + test('duplicate JSON key scanning respects nested object scopes', () { + expect( + _duplicateJsonKeys( + '{"message":"one","message":"two",' + '"metadata":{"description":"one","description":"two"},' + '"separate":{"description":"allowed"}}', + ), + <String>[r'$.message', r'$.metadata.description'], + ); + }); + + test('ARB catalogs have valid, unique message structure and locale IDs', () { + final failures = <String>[]; + + for (final file in _arbFiles()) { + final source = file.readAsStringSync(); + Map<String, Object?> arb; + try { + arb = _arbMessages(file); + } on FormatException catch (error) { + failures.add('${file.path}: invalid JSON: ${error.message}'); + continue; + } + for (final duplicate in _duplicateJsonKeys(source)) { + failures.add('${file.path}: duplicate JSON key $duplicate'); + } + + final name = file.uri.pathSegments.last; + final match = RegExp(r'^app_([A-Za-z_]+)\.arb$').firstMatch(name); + final fileLocale = match?.group(1); + final declaredLocale = arb['@@locale']; + if (fileLocale == null) { + failures.add('${file.path}: filename does not identify an ARB locale'); + } else if (declaredLocale is! String || declaredLocale != fileLocale) { + failures.add( + '${file.path}: filename locale $fileLocale conflicts with ' + '@@locale ${declaredLocale ?? '<missing>'}', + ); + } + + for (final entry in arb.entries) { + if (entry.key.startsWith('@')) { + continue; + } + if (entry.value is! String) { + failures.add( + '${file.path}: ${entry.key} has non-string message value ' + '${entry.value.runtimeType}', + ); + continue; + } + if ((entry.value! as String).trim().isEmpty) { + failures.add('${file.path}: ${entry.key} has a blank translation'); + } + } + } + + expect(failures, isEmpty, reason: failures.join('\n')); + }); + + test('all ARBs match the English messages and placeholders', () { final templateFile = File('lib/l10n/app_en.arb'); final templateArb = _arbMessages(templateFile); final template = _arbMessageStrings(templateFile); @@ -191,21 +251,33 @@ void main() { for (final key in template.keys.toSet().intersection( messages.keys.toSet(), )) { - for (final placeholder in _declaredPlaceholders(templateArb, key)) { - if (_usesPlaceholder(messages[key]!, placeholder)) { - continue; - } + final declared = _declaredPlaceholders(templateArb, key); + final used = _messageArguments(messages[key]!); + for (final placeholder in declared.difference(used).toList()..sort()) { failures.add( '${file.path}: $key is missing placeholder {$placeholder}', ); } + for (final placeholder in used.difference(declared).toList()..sort()) { + failures.add( + '${file.path}: $key has unexpected placeholder {$placeholder}', + ); + } + for (final placeholder in declared) { + if (!_usesPlaceholder(messages[key]!, placeholder)) { + failures.add( + '${file.path}: $key does not use declared placeholder ' + '{$placeholder}', + ); + } + } } } expect(failures, isEmpty, reason: failures.join('\n')); }); - test('unsaved-changes discard actions are distinct from cancel', () { + test('destructive, save, and Git history actions remain distinct', () { for (final locale in AppLocalizations.supportedLocales) { final localizations = lookupAppLocalizations(locale); expect( @@ -221,6 +293,18 @@ void main() { '${locale.toLanguageTag()} must not translate window-close ' 'Discard as Cancel', ); + expect( + localizations.save, + isNot(localizations.gitCommit), + reason: '${locale.toLanguageTag()} must distinguish Save from Commit', + ); + expect( + localizations.gitFileHistory, + isNot(localizations.gitProjectHistory), + reason: + '${locale.toLanguageTag()} must distinguish File History from ' + 'Project History', + ); } final russian = lookupAppLocalizations(const Locale('ru')); @@ -286,6 +370,117 @@ void main() { } }); + test('clipboard write failures are localized in every target locale', () { + const expected = <String, String>{ + 'ar': 'تعذّر نسخ المحتوى المحدد إلى الحافظة.', + 'de': 'Die Auswahl konnte nicht in die Zwischenablage kopiert werden.', + 'es': 'No se pudo copiar la selección al portapapeles.', + 'et': 'Valikut ei saanud lõikelauale kopeerida.', + 'fa': 'امکان کپی کردن محتوای انتخاب‌شده در کلیپ‌بورد وجود نداشت.', + 'fr': 'Impossible de copier la sélection dans le presse-papiers.', + 'hi': 'चयनित सामग्री को क्लिपबोर्ड पर कॉपी नहीं किया जा सका।', + 'id': 'Konten yang dipilih tidak dapat disalin ke papan klip.', + 'it': 'Impossibile copiare la selezione negli appunti.', + 'ja': '選択内容をクリップボードにコピーできませんでした。', + 'ko': '선택한 내용을 클립보드에 복사할 수 없습니다.', + 'nb': 'Utvalget kunne ikke kopieres til utklippstavlen.', + 'nl': 'De selectie kon niet naar het klembord worden gekopieerd.', + 'pl': 'Nie udało się skopiować zaznaczenia do schowka.', + 'pt': 'Não foi possível copiar a seleção para a área de transferência.', + 'pt-BR': + 'Não foi possível copiar a seleção para a área de transferência.', + 'ru': 'Не удалось скопировать выделенный фрагмент в буфер обмена.', + 'tr': 'Seçili içerik panoya kopyalanamadı.', + 'uk': 'Не вдалося скопіювати виділений фрагмент до буфера обміну.', + 'vi': 'Không thể sao chép nội dung đã chọn vào bảng nhớ tạm.', + 'zh': '无法将所选内容复制到剪贴板。', + 'zh-CN': '无法将所选内容复制到剪贴板。', + }; + + final locales = AppLocalizations.supportedLocales.where( + (locale) => locale.languageCode != 'en', + ); + expect( + locales.map((locale) => locale.toLanguageTag()).toSet(), + expected.keys, + ); + for (final locale in locales) { + expect( + lookupAppLocalizations(locale).clipboardCopyFailed, + expected[locale.toLanguageTag()], + reason: locale.toLanguageTag(), + ); + } + }); + + test('Portuguese and Chinese base catalogs contain reviewed UI prose', () { + final english = lookupAppLocalizations(const Locale('en')); + final portuguese = lookupAppLocalizations(const Locale('pt')); + final chinese = lookupAppLocalizations(const Locale('zh')); + + for (final translated in <String>[ + portuguese.appSubtitle, + portuguese.settings, + portuguese.gitProjectHistory, + portuguese.gitFileHistory, + portuguese.exportAsPdf, + chinese.appSubtitle, + chinese.settings, + chinese.gitProjectHistory, + chinese.gitFileHistory, + chinese.exportAsPdf, + ]) { + expect( + translated, + isNot( + anyOf(<String>[ + english.appSubtitle, + english.settings, + english.gitProjectHistory, + english.gitFileHistory, + english.exportAsPdf, + ]), + ), + ); + } + + expect(portuguese.file, 'Ficheiro'); + expect(portuguese.link, 'Ligação'); + expect(portuguese.exportReset, 'Restaurar predefinições'); + final brazilian = lookupAppLocalizations(const Locale('pt', 'BR')); + expect(brazilian.file, 'Arquivo'); + expect(brazilian.link, 'Link'); + expect(brazilian.exportReset, 'Restaurar padrões'); + + final zh = _arbMessageStrings(File('lib/l10n/app_zh.arb')); + final zhCn = _arbMessageStrings(File('lib/l10n/app_zh_CN.arb')); + expect(zh, zhCn); + }); + + test('completed base-catalog plurals reach their supported branches', () { + final portuguese = lookupAppLocalizations(const Locale('pt')); + expect(portuguese.diagnosticCount(0), 'Nenhum diagnóstico'); + expect(portuguese.diagnosticCount(1), '1 diagnóstico'); + expect(portuguese.diagnosticCount(2), '2 diagnósticos'); + expect( + portuguese.workspaceRecoveryRestored(1), + 'Foi recuperado 1 documento não guardado. Reveja-o antes de o guardar ' + 'ou descartar.', + ); + expect( + portuguese.workspaceRecoveryRestored(3), + 'Foram recuperados 3 documentos não guardados. Reveja cada um antes ' + 'de o guardar ou descartar.', + ); + + final chinese = lookupAppLocalizations(const Locale('zh')); + expect(chinese.diagnosticCount(0), '没有诊断信息'); + expect(chinese.diagnosticCount(1), '1 条诊断信息'); + expect(chinese.diagnosticCount(2), '2 条诊断信息'); + expect(chinese.workspaceRecoveryRestored(1), '已恢复 1 个未保存的文档。请在保存或放弃前进行检查。'); + expect(chinese.workspaceRecoveryRestored(3), '已恢复 3 个未保存的文档。请在保存或放弃前逐一检查。'); + }); + test('RTL translations isolate technical interpolations', () { const fsi = '\u2068'; const pdi = '\u2069'; @@ -378,6 +573,36 @@ void main() { ], AppLocalizations.supportedLocales), const Locale('en'), ); + expect( + resolveBusyMarkLocales(const [ + Locale('pt'), + ], AppLocalizations.supportedLocales), + const Locale('pt'), + ); + expect( + resolveBusyMarkLocales(const [ + Locale('pt', 'PT'), + ], AppLocalizations.supportedLocales), + const Locale('pt'), + ); + expect( + resolveBusyMarkLocales(const [ + Locale('pt', 'BR'), + ], AppLocalizations.supportedLocales), + const Locale('pt', 'BR'), + ); + expect( + resolveBusyMarkLocales(const [ + Locale('zh'), + ], AppLocalizations.supportedLocales), + const Locale('zh'), + ); + expect( + resolveBusyMarkLocales(const [ + Locale('zh', 'CN'), + ], AppLocalizations.supportedLocales), + const Locale('zh', 'CN'), + ); }, ); @@ -443,19 +668,12 @@ Iterable<File> _productionDartFiles() sync* { Iterable<File> _arbFiles() sync* { for (final entity in Directory('lib/l10n').listSync()) { - if (entity is File && - entity.path.endsWith('.arb') && - !_isFlutterFallbackArb(entity)) { + if (entity is File && entity.path.endsWith('.arb')) { yield entity; } } } -bool _isFlutterFallbackArb(File file) { - final name = file.uri.pathSegments.last; - return name == 'app_pt.arb' || name == 'app_zh.arb'; -} - Map<String, Object?> _arbMessages(File file) { return jsonDecode(file.readAsStringSync()) as Map<String, Object?>; } @@ -484,6 +702,132 @@ Set<String> _declaredPlaceholders(Map<String, Object?> arb, String key) { bool _usesPlaceholder(String message, String placeholder) => RegExp('\\{${RegExp.escape(placeholder)}(?:\\}|\\s*,)').hasMatch(message); +Set<String> _messageArguments(String message) => { + for (final match in RegExp( + r'\{([A-Za-z][A-Za-z0-9_]*)\s*(?:\}|,\s*(?:plural|select|selectordinal)\s*,)', + ).allMatches(message)) + match.group(1)!, +}; + +List<String> _duplicateJsonKeys(String source) => + _JsonKeyScanner(source).scan(); + +class _JsonKeyScanner { + _JsonKeyScanner(this.source); + + final String source; + final duplicates = <String>[]; + var _offset = 0; + + List<String> scan() { + _skipWhitespace(); + _scanValue(r'$'); + return duplicates; + } + + void _scanValue(String path) { + _skipWhitespace(); + switch (source[_offset]) { + case '{': + _scanObject(path); + return; + case '[': + _scanArray(path); + return; + case '"': + _scanString(); + return; + default: + _scanScalar(); + return; + } + } + + void _scanObject(String path) { + _offset++; + _skipWhitespace(); + if (source[_offset] == '}') { + _offset++; + return; + } + + final keys = <String>{}; + while (true) { + _skipWhitespace(); + final key = _scanString(); + final keyPath = '$path.$key'; + if (!keys.add(key)) { + duplicates.add(keyPath); + } + _skipWhitespace(); + _offset++; // Colon; jsonDecode performs the syntax validation. + _scanValue(keyPath); + _skipWhitespace(); + if (source[_offset] == '}') { + _offset++; + return; + } + _offset++; // Comma. + } + } + + void _scanArray(String path) { + _offset++; + _skipWhitespace(); + if (source[_offset] == ']') { + _offset++; + return; + } + + var index = 0; + while (true) { + _scanValue('$path[$index]'); + index++; + _skipWhitespace(); + if (source[_offset] == ']') { + _offset++; + return; + } + _offset++; // Comma. + } + } + + String _scanString() { + final start = _offset; + _offset++; + while (true) { + final codeUnit = source.codeUnitAt(_offset++); + if (codeUnit == 0x5c) { + _offset++; + } else if (codeUnit == 0x22) { + return jsonDecode(source.substring(start, _offset)) as String; + } + } + } + + void _scanScalar() { + while (_offset < source.length && + !const { + ' ', + '\t', + '\r', + '\n', + ',', + ']', + '}', + }.contains(source[_offset])) { + _offset++; + } + } + + void _skipWhitespace() { + while (_offset < source.length && + const {' ', '\t', '\r', '\n'}.contains(source[_offset])) { + _offset++; + } + } +} + Iterable<File> _nativeLinuxSourceFiles() sync* { for (final entity in Directory('linux/runner').listSync(recursive: true)) { if (entity is! File) { @@ -758,6 +1102,7 @@ const _localeSpecificEnglishMatches = <String, Set<String>>{ 'horizontal', 'vertical', }, + 'pt': {'editor', 'horizontal', 'vertical', 'toc', 'foldKindTag', 'gitCommit'}, 'hi': {'toc'}, 'ja': {'gitFetch', 'gitCommit', 'pdfPageSizeLetter'}, 'ko': {'gitDiff', 'gitFetch', 'gitCommit', 'pdfPageSizeLetter'}, @@ -811,4 +1156,5 @@ const _localeSpecificEnglishMatches = <String, Set<String>>{ }, 'vi': {'tab', 'gitFetch', 'gitCommit', 'gitAuthorEmail', 'pdfPageSizeLetter'}, 'zh_CN': {'gitFetch', 'gitCommit', 'gitAuthorEmail', 'pdfPageSizeLetter'}, + 'zh': {'gitFetch', 'gitCommit', 'gitAuthorEmail', 'pdfPageSizeLetter'}, }; From b99e891e45202268d1384b870c4af8a14a772ac8 Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Tue, 8 Sep 2026 13:30:07 -0700 Subject: [PATCH 25/37] =?UTF-8?q?Fix=20translations=20-=20CLDR=E2=80=99s?= =?UTF-8?q?=20Russian/Ukrainian=20one=20category=20included=20values=20suc?= =?UTF-8?q?h=20as=2021=20and=2031,=20so=20literal=201=20branches=20were=20?= =?UTF-8?q?unsafe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/l10n/app_hi.arb | 2 +- lib/l10n/app_pt.arb | 6 +- lib/l10n/app_pt_BR.arb | 6 +- lib/l10n/app_ru.arb | 20 +++---- lib/l10n/app_uk.arb | 20 +++---- lib/l10n/generated/app_localizations_hi.dart | 7 ++- lib/l10n/generated/app_localizations_pt.dart | 54 ++++++++++++++++-- lib/l10n/generated/app_localizations_ru.dart | 58 ++++++++++---------- lib/l10n/generated/app_localizations_uk.dart | 58 ++++++++++---------- 9 files changed, 140 insertions(+), 91 deletions(-) diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index 702c97ba..10b8c704 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -3063,7 +3063,7 @@ "reloadFromDisk": "डिस्क से फिर लोड करें", "keepMine": "मेरा संस्करण रखें", "saveAs": "इस रूप में सहेजें", - "unsavedChangesMultipleMessage": "{count, plural, =1{1 दस्तावेज़ में असुरक्षित बदलाव हैं। इसे जारी रखने से पहले सहेजें।} other{{count} दस्तावेज़ों में असुरक्षित बदलाव हैं। इन्हें जारी रखने से पहले सहेजें।}}", + "unsavedChangesMultipleMessage": "{count, plural, =0{0 दस्तावेज़ों में न सहेजे गए बदलाव हैं। जारी रखने से पहले उन्हें सहेजें?} =1{1 दस्तावेज़ में न सहेजे गए बदलाव हैं। जारी रखने से पहले इसे सहेजें?} other{{count} दस्तावेज़ों में न सहेजे गए बदलाव हैं। जारी रखने से पहले उन्हें सहेजें?}}", "workspaceReplaceIssuePartialConflict": "रोलबैक रोक दिया गया क्योंकि फ़ाइल उसी समय बदल गई थी। कुछ प्रतिस्थापन बने रह सकते हैं; हटाई गई सामग्री नीचे दिए गए पथ पर सुरक्षित रखी गई है।", "workspaceReplaceIssueApplyFailed": "कोई प्रतिस्थापन लागू नहीं किया गया क्योंकि समीक्षा किए गए समूह को सुरक्षित रूप से सहेजा नहीं जा सका।", "workspaceRecoveryRestored": "{count, plural, =1{1 बिना सहेजा दस्तावेज़ पुनर्प्राप्त किया गया। इसे सहेजने या हटाने से पहले समीक्षा करें।} other{{count} बिना सहेजे दस्तावेज़ पुनर्प्राप्त किए गए। प्रत्येक की समीक्षा करके सहेजें या हटाएँ।}}", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index adbb0a5c..d8764f80 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -2980,7 +2980,7 @@ "aiGenerating": "A gerar proposta…", "aiProposal": "Proposta de IA", "aiGenerateProposal": "Gerar proposta", - "aiContextDisclosure": "O fornecedor selecionado receberá {count} carateres do contexto apresentado.", + "aiContextDisclosure": "O fornecedor selecionado receberá {count, plural, =0{0 carateres} =1{1 caráter} other{{count} carateres}} do contexto apresentado.", "aiOriginal": "Texto original", "aiSuggested": "Sugestão", "aiApplyProposal": "Aplicar proposta", @@ -3009,7 +3009,7 @@ "aiCloudConsentEnable": "Ativar {provider}", "aiCloudConsentMessage": "Apenas o conteúdo apresentado em cada caixa de diálogo de revisão de IA é enviado. Os pedidos não mantêm estado, as propostas exigem revisão e a chave de API é guardada no cofre de credenciais do sistema Linux.", "aiCloudConsentRequired": "Primeiro, confirme o partilha de dados com {provider} em Definições → IA.", - "aiGenerationVerified": "Geração verificada com {model}. Há {count} modelos compatíveis disponíveis.", + "aiGenerationVerified": "Geração verificada com {model}. {count, plural, =0{Há 0 modelos compatíveis disponíveis} =1{Há 1 modelo compatível disponível} other{Há {count} modelos compatíveis disponíveis}}.", "aiColdStartObserved": "Foi detetado um arranque a frio do modelo local.", "aiNoCompatibleModels": "Não há nenhum modelo compatível de geração de texto disponível.", "aiEnableProvider": "Primeiro, ative um fornecedor de IA.", @@ -3018,7 +3018,7 @@ "aiDraftWithAi": "Criar rascunho com IA", "generateOrUpdateMarkdownToc": "Gerar/atualizar sumário", "markdownTocTitle": "Sumário", - "markdownTocUpdated": "Sumário atualizado com {count} entradas.", + "markdownTocUpdated": "Sumário atualizado com {count, plural, =0{0 entradas} =1{1 entrada} other{{count} entradas}}.", "markdownTocNoHeadings": "Adicione pelo menos um título de secção antes de gerar um sumário.", "markdownTocMalformedMarkers": "Os marcadores de sumário do BusyMark estão ausentes, duplicados ou fora de ordem.", "diagnosticMarkdownHeadingSkippedLevel": "O título de nível {level} vem após o nível {previousLevel}; reveja o aninhamento das secções.", diff --git a/lib/l10n/app_pt_BR.arb b/lib/l10n/app_pt_BR.arb index 108e41db..17c75eca 100644 --- a/lib/l10n/app_pt_BR.arb +++ b/lib/l10n/app_pt_BR.arb @@ -2980,7 +2980,7 @@ "aiGenerating": "Gerando proposta…", "aiProposal": "Proposta de IA", "aiGenerateProposal": "Gerar proposta", - "aiContextDisclosure": "O provedor selecionado receberá {count} caracteres do contexto exibido.", + "aiContextDisclosure": "O provedor selecionado receberá {count, plural, =0{0 caracteres} =1{1 caractere} other{{count} caracteres}} do contexto exibido.", "aiOriginal": "Texto original", "aiSuggested": "Sugestão", "aiApplyProposal": "Aplicar proposta", @@ -3009,7 +3009,7 @@ "aiCloudConsentEnable": "Ativar {provider}", "aiCloudConsentMessage": "Somente o conteúdo exibido em cada caixa de diálogo de revisão de IA é enviado. As solicitações não mantêm estado, as propostas exigem revisão e a chave de API é armazenada no cofre de credenciais do sistema Linux.", "aiCloudConsentRequired": "Primeiro, confirme o compartilhamento de dados com {provider} em Configurações → IA.", - "aiGenerationVerified": "Geração verificada com {model}. Há {count} modelos compatíveis disponíveis.", + "aiGenerationVerified": "Geração verificada com {model}. {count, plural, =0{Há 0 modelos compatíveis disponíveis} =1{Há 1 modelo compatível disponível} other{Há {count} modelos compatíveis disponíveis}}.", "aiColdStartObserved": "Foi detetado um arranque a frio do modelo local.", "aiNoCompatibleModels": "Não há nenhum modelo compatível de geração de texto disponível.", "aiEnableProvider": "Primeiro, ative um provedor de IA.", @@ -3018,7 +3018,7 @@ "aiDraftWithAi": "Criar rascunho com IA", "generateOrUpdateMarkdownToc": "Gerar/atualizar sumário", "markdownTocTitle": "Sumário", - "markdownTocUpdated": "Sumário atualizado com {count} entradas.", + "markdownTocUpdated": "Sumário atualizado com {count, plural, =0{0 entradas} =1{1 entrada} other{{count} entradas}}.", "markdownTocNoHeadings": "Adicione pelo menos um título de seção antes de gerar um sumário.", "markdownTocMalformedMarkers": "Os marcadores de sumário do BusyMark estão ausentes, duplicados ou fora de ordem.", "diagnosticMarkdownHeadingSkippedLevel": "O título de nível {level} vem após o nível {previousLevel}; revise o aninhamento das seções.", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index be2a0027..622fe46b 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -2331,9 +2331,9 @@ "gitBinaryFile": "Двоичный файл. BusyMark не отображает двоичные патчи.", "gitUnsavedChangesBanner": "Несохранённые изменения в редакторе не будут включены, пока вы их не сохраните.", "gitConfirmDiscardTitle": "Отменить изменения Git?", - "gitConfirmDiscardTracked": "{count, plural, one{Все проиндексированные и непроиндексированные изменения в выбранном отслеживаемом файле будут отменены, а файл будет восстановлен до состояния HEAD.} few{Все проиндексированные и непроиндексированные изменения в выбранных отслеживаемых файлах будут отменены, а файлы будут восстановлены до состояния HEAD.} many{Все проиндексированные и непроиндексированные изменения в выбранных отслеживаемых файлах будут отменены, а файлы будут восстановлены до состояния HEAD.} other{Все проиндексированные и непроиндексированные изменения в выбранных отслеживаемых файлах будут отменены, а файлы будут восстановлены до состояния HEAD.}}", - "gitConfirmDiscardUntracked": "{count, plural, one{Выбранный неотслеживаемый файл будет удалён.} few{Выбранные неотслеживаемые файлы будут удалены.} many{Выбранные неотслеживаемые файлы будут удалены.} other{Выбранные неотслеживаемые файлы будут удалены.}}", - "gitConfirmDiscardMixed": "{count, plural, one{Выбранный файл будет восстановлен или удалён в зависимости от его статуса Git.} few{Выбранные файлы будут восстановлены или удалены в зависимости от их статуса Git.} many{Выбранные файлы будут восстановлены или удалены в зависимости от их статуса Git.} other{Выбранные файлы будут восстановлены или удалены в зависимости от их статуса Git.}}", + "gitConfirmDiscardTracked": "{count, plural, one{Все проиндексированные и непроиндексированные изменения в {count} выбранном отслеживаемом файле будут отменены, а содержимое будет восстановлено до состояния HEAD.} few{Все проиндексированные и непроиндексированные изменения в {count} выбранных отслеживаемых файлах будут отменены, а файлы будут восстановлены до состояния HEAD.} many{Все проиндексированные и непроиндексированные изменения в {count} выбранных отслеживаемых файлах будут отменены, а файлы будут восстановлены до состояния HEAD.} other{Все проиндексированные и непроиндексированные изменения в {count} выбранных отслеживаемых файлах будут отменены, а файлы будут восстановлены до состояния HEAD.}}", + "gitConfirmDiscardUntracked": "{count, plural, one{Будет удалён {count} выбранный неотслеживаемый файл.} few{Будут удалены {count} выбранных неотслеживаемых файла.} many{Будут удалены {count} выбранных неотслеживаемых файлов.} other{Будут удалены {count} выбранных неотслеживаемых файла.}}", + "gitConfirmDiscardMixed": "{count, plural, one{{count} выбранный файл будет восстановлен или удалён в зависимости от статуса Git.} few{{count} выбранных файла будут восстановлены или удалены в зависимости от их статуса Git.} many{{count} выбранных файлов будут восстановлены или удалены в зависимости от их статуса Git.} other{{count} выбранного файла будут восстановлены или удалены в зависимости от их статуса Git.}}", "gitConfirmSwitchBranchTitle": "Переключиться на {branch}?", "gitConfirmSwitchBranchMessage": "BusyMark перезагрузит рабочую область с диска после переключения ветки в Git.", "gitConfirmPushSetUpstreamTitle": "Настроить upstream-ветку?", @@ -2536,7 +2536,7 @@ } } }, - "childTopicsPromoted": "{count, plural, one{1 дочерняя тема будет перемещена на уровень выше.} few{{count} дочерние темы будут перемещены на уровень выше.} many{{count} дочерних тем будут перемещены на уровень выше.} other{{count} дочерней темы будут перемещены на уровень выше.}}", + "childTopicsPromoted": "{count, plural, one{{count} дочерняя тема будет перемещена на уровень выше.} few{{count} дочерние темы будут перемещены на уровень выше.} many{{count} дочерних тем будут перемещены на уровень выше.} other{{count} дочерней темы будут перемещены на уровень выше.}}", "@childTopicsPromoted": { "description": "Explains that direct child topics will be promoted when their parent TOC element is removed.", "placeholders": { @@ -2582,7 +2582,7 @@ "@topicUsageIncludes": { "description": "Usage group label for topic includes." }, - "usageCount": "{count, plural, one{1 использование} few{{count} использования} many{{count} использований} other{{count} использования}}", + "usageCount": "{count, plural, one{{count} использование} few{{count} использования} many{{count} использований} other{{count} использования}}", "@usageCount": { "description": "Compact topic usage count.", "placeholders": { @@ -2812,7 +2812,7 @@ } } }, - "pdfExportedWithWarnings": "{fileName} экспортирован с {count, plural, =1{1 предупреждением} other{{count} предупреждениями}}.", + "pdfExportedWithWarnings": "{fileName} экспортирован с {count, plural, one{{count} предупреждением} few{{count} предупреждениями} many{{count} предупреждениями} other{{count} предупреждениями}}.", "@pdfExportedWithWarnings": { "description": "PDF export success message when some images were omitted.", "placeholders": { @@ -2863,7 +2863,7 @@ "gitStaged": "Индексированные", "gitUnstaged": "Неиндексированные", "gitFetch": "Получить", - "gitStagedFileCount": "{count, plural, =1{1 файл в индексе} few{{count} файла в индексе} many{{count} файлов в индексе} other{{count} файлов в индексе}}", + "gitStagedFileCount": "{count, plural, one{{count} файл в индексе} few{{count} файла в индексе} many{{count} файлов в индексе} other{{count} файлов в индексе}}", "gitOutsideWorkspace": "Вне рабочего пространства", "gitFileHistoryRequiresOpenFile": "Для истории файла требуется открытый файл Markdown.", "gitLoadMore": "Загрузить ещё", @@ -3089,11 +3089,11 @@ "reloadFromDisk": "Перезагрузить с диска", "keepMine": "Оставить мою версию", "saveAs": "Сохранить как", - "unsavedChangesMultipleMessage": "{count, plural, one{1 документ содержит несохранённые изменения. Сохраните его перед продолжением.} few{{count} документа содержат несохранённые изменения. Сохраните их перед продолжением.} many{{count} документов содержат несохранённые изменения. Сохраните их перед продолжением.} other{{count} документа содержит несохранённые изменения. Сохраните их перед продолжением.}}", + "unsavedChangesMultipleMessage": "{count, plural, one{{count} документ содержит несохранённые изменения. Сохранить каждый перед продолжением?} few{{count} документа содержат несохранённые изменения. Сохранить каждый перед продолжением?} many{{count} документов содержат несохранённые изменения. Сохранить каждый перед продолжением?} other{{count} документа содержит несохранённые изменения. Сохранить каждый перед продолжением?}}", "workspaceReplaceIssuePartialConflict": "Откат остановлен, поскольку файл был одновременно изменён. Некоторые замены могли сохраниться; вытесненное содержимое сохранено по указанному ниже пути.", "workspaceReplaceIssueApplyFailed": "Замены не применены, поскольку проверенный набор не удалось безопасно сохранить.", - "workspaceRecoveryRestored": "{count, plural, one{Восстановлен 1 несохранённый документ. Проверьте его перед сохранением или отменой.} few{Восстановлено {count} несохранённых документа. Проверьте каждый перед сохранением или отменой.} many{Восстановлено {count} несохранённых документов. Проверьте каждый перед сохранением или отменой.} other{Восстановлено {count} несохранённого документа. Проверьте его перед сохранением или отменой.}}", - "workspaceRecoveryDamaged": "{count, plural, one{Не удалось восстановить 1 повреждённую запись восстановления. Оригинальный файл восстановления сохранён для проверки.} few{Не удалось восстановить {count} повреждённые записи восстановления. Корректные записи восстановления остаются доступны.} many{Не удалось восстановить {count} повреждённых записей восстановления. Корректные записи восстановления остаются доступны.} other{Не удалось восстановить {count} повреждённой записи восстановления. Корректные записи восстановления остаются доступны.}}", + "workspaceRecoveryRestored": "{count, plural, one{Восстановлен {count} несохранённый документ. Проверьте каждый документ, прежде чем сохранить или отбросить его.} few{Восстановлено {count} несохранённых документа. Проверьте каждый документ, прежде чем сохранить или отбросить его.} many{Восстановлено {count} несохранённых документов. Проверьте каждый документ, прежде чем сохранить или отбросить его.} other{Восстановлено {count} несохранённого документа. Проверьте каждый документ, прежде чем сохранить или отбросить его.}}", + "workspaceRecoveryDamaged": "{count, plural, one{Не удалось восстановить {count} повреждённую запись восстановления. Исходный файл восстановления сохранён для проверки; корректные записи остаются доступны.} few{Не удалось восстановить {count} повреждённые записи восстановления. Исходный файл восстановления сохранён для проверки; корректные записи остаются доступны.} many{Не удалось восстановить {count} повреждённых записей восстановления. Исходный файл восстановления сохранён для проверки; корректные записи остаются доступны.} other{Не удалось восстановить {count} повреждённой записи восстановления. Исходный файл восстановления сохранён для проверки; корректные записи остаются доступны.}}", "recoveredDocumentReview": "Восстановлено несохранённое содержимое файла {fileName}. Проверьте его, затем сохраните, сохраните как новый файл или отбросьте.", "commandUnavailableInContext": "Эта команда недоступна в текущем контексте.", "mathRenderFailed": "Не удалось отобразить математическое выражение.", diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index b562bbb6..c4e4437a 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -2331,9 +2331,9 @@ "gitBinaryFile": "Двійковий файл. BusyMark не відображає двійкові патчі.", "gitUnsavedChangesBanner": "Незбережені зміни в редакторі не буде враховано, доки ви їх не збережете.", "gitConfirmDiscardTitle": "Відкинути зміни Git?", - "gitConfirmDiscardTracked": "{count, plural, one{Усі індексовані та неіндексовані зміни у вибраному файлі з відстеженням буде скасовано, а файл буде відновлено до стану HEAD.} few{Усі індексовані та неіндексовані зміни у вибраних файлах з відстеженням буде скасовано, а файли буде відновлено до стану HEAD.} many{Усі індексовані та неіндексовані зміни у вибраних файлах з відстеженням буде скасовано, а файли буде відновлено до стану HEAD.} other{Усі індексовані та неіндексовані зміни у вибраних файлах з відстеженням буде скасовано, а файли буде відновлено до стану HEAD.}}", - "gitConfirmDiscardUntracked": "{count, plural, one{Вибраний невідстежуваний файл буде видалено.} few{Вибрані невідстежувані файли буде видалено.} many{Вибрані невідстежувані файли буде видалено.} other{Вибрані невідстежувані файли буде видалено.}}", - "gitConfirmDiscardMixed": "{count, plural, one{Вибраний файл буде відновлено або видалено залежно від його стану Git.} few{Вибрані файли буде відновлено або видалено залежно від їхнього стану Git.} many{Вибрані файли буде відновлено або видалено залежно від їхнього стану Git.} other{Вибрані файли буде відновлено або видалено залежно від їхнього стану Git.}}", + "gitConfirmDiscardTracked": "{count, plural, one{Усі індексовані та неіндексовані зміни в {count} вибраному файлі з відстеженням буде скасовано, а вміст буде відновлено до стану HEAD.} few{Усі індексовані та неіндексовані зміни у {count} вибраних файлах з відстеженням буде скасовано, а файли буде відновлено до стану HEAD.} many{Усі індексовані та неіндексовані зміни у {count} вибраних файлах з відстеженням буде скасовано, а файли буде відновлено до стану HEAD.} other{Усі індексовані та неіндексовані зміни у {count} вибраних файлах з відстеженням буде скасовано, а файли буде відновлено до стану HEAD.}}", + "gitConfirmDiscardUntracked": "{count, plural, one{{count} вибраний невідстежуваний файл буде видалено.} few{{count} вибрані невідстежувані файли буде видалено.} many{{count} вибраних невідстежуваних файлів буде видалено.} other{{count} вибраного невідстежуваного файла буде видалено.}}", + "gitConfirmDiscardMixed": "{count, plural, one{{count} вибраний файл буде відновлено або видалено залежно від статусу Git.} few{{count} вибрані файли буде відновлено або видалено залежно від їхнього статусу Git.} many{{count} вибраних файлів буде відновлено або видалено залежно від їхнього статусу Git.} other{{count} вибраного файла буде відновлено або видалено залежно від його статусу Git.}}", "gitConfirmSwitchBranchTitle": "Перемкнутися на {branch}?", "gitConfirmSwitchBranchMessage": "BusyMark перезавантажить робочу область із диска після перемикання гілки в Git.", "gitConfirmPushSetUpstreamTitle": "Налаштувати upstream-гілку?", @@ -2536,7 +2536,7 @@ } } }, - "childTopicsPromoted": "{count, plural, one{1 дочірню тему буде переміщено на рівень вище.} few{{count} дочірні теми буде переміщено на рівень вище.} many{{count} дочірніх тем буде переміщено на рівень вище.} other{{count} дочірньої теми буде переміщено на рівень вище.}}", + "childTopicsPromoted": "{count, plural, one{{count} дочірню тему буде переміщено на рівень вище.} few{{count} дочірні теми буде переміщено на рівень вище.} many{{count} дочірніх тем буде переміщено на рівень вище.} other{{count} дочірньої теми буде переміщено на рівень вище.}}", "@childTopicsPromoted": { "description": "Explains that direct child topics will be promoted when their parent TOC element is removed.", "placeholders": { @@ -2582,7 +2582,7 @@ "@topicUsageIncludes": { "description": "Usage group label for topic includes." }, - "usageCount": "{count, plural, one{1 використання} few{{count} використання} many{{count} використань} other{{count} використання}}", + "usageCount": "{count, plural, one{{count} використання} few{{count} використання} many{{count} використань} other{{count} використання}}", "@usageCount": { "description": "Compact topic usage count.", "placeholders": { @@ -2812,7 +2812,7 @@ } } }, - "pdfExportedWithWarnings": "{fileName} експортовано з {count, plural, =1{1 попередженням} other{{count} попередженнями}}.", + "pdfExportedWithWarnings": "{fileName} експортовано з {count, plural, one{{count} попередженням} few{{count} попередженнями} many{{count} попередженнями} other{{count} попередженнями}}.", "@pdfExportedWithWarnings": { "description": "PDF export success message when some images were omitted.", "placeholders": { @@ -2863,7 +2863,7 @@ "gitStaged": "Індексовані", "gitUnstaged": "Неіндексовані", "gitFetch": "Отримати", - "gitStagedFileCount": "{count, plural, =1{1 проіндексований файл} few{{count} проіндексовані файли} many{{count} проіндексованих файлів} other{{count} проіндексованих файлів}}", + "gitStagedFileCount": "{count, plural, one{{count} проіндексований файл} few{{count} проіндексовані файли} many{{count} проіндексованих файлів} other{{count} проіндексованих файлів}}", "gitOutsideWorkspace": "Поза робочим простором", "gitFileHistoryRequiresOpenFile": "Для історії файлу потрібен відкритий файл Markdown.", "gitLoadMore": "Завантажити ще", @@ -3089,11 +3089,11 @@ "reloadFromDisk": "Перезавантажити з диска", "keepMine": "Залишити мою версію", "saveAs": "Зберегти як", - "unsavedChangesMultipleMessage": "{count, plural, one{1 документ має незбережені зміни. Збережіть його перед продовженням.} few{{count} документи мають незбережені зміни. Збережіть їх перед продовженням.} many{{count} документів мають незбережені зміни. Збережіть їх перед продовженням.} other{{count} документа має незбережені зміни. Збережіть їх перед продовженням.}}", + "unsavedChangesMultipleMessage": "{count, plural, one{{count} документ має незбережені зміни. Зберегти кожен перед продовженням?} few{{count} документи мають незбережені зміни. Зберегти кожен перед продовженням?} many{{count} документів мають незбережені зміни. Зберегти кожен перед продовженням?} other{{count} документа має незбережені зміни. Зберегти кожен перед продовженням?}}", "workspaceReplaceIssuePartialConflict": "Відкат зупинено, оскільки файл було одночасно змінено. Деякі заміни могли залишитися; витіснений вміст збережено за шляхом нижче.", "workspaceReplaceIssueApplyFailed": "Заміни не застосовано, оскільки перевірений набір не вдалося безпечно зберегти.", - "workspaceRecoveryRestored": "{count, plural, one{Відновлено 1 незбережений документ. Перегляньте його перед збереженням або відхиленням.} few{Відновлено {count} незбережені документи. Перегляньте кожен перед збереженням або відхиленням.} many{Відновлено {count} незбережених документів. Перегляньте кожен перед збереженням або відхиленням.} other{Відновлено {count} незбереженого документа. Перегляньте його перед збереженням або відхиленням.}}", - "workspaceRecoveryDamaged": "{count, plural, one{Не вдалося відновити 1 пошкоджений запис відновлення. Оригінальний файл відновлення збережено для перегляду.} few{Не вдалося відновити {count} пошкоджені записи відновлення. Дійсні записи відновлення залишаються доступними.} many{Не вдалося відновити {count} пошкоджених записів відновлення. Дійсні записи відновлення залишаються доступними.} other{Не вдалося відновити {count} пошкодженого запису відновлення. Дійсні записи відновлення залишаються доступними.}}", + "workspaceRecoveryRestored": "{count, plural, one{Відновлено {count} незбережений документ. Перегляньте кожен документ, перш ніж зберегти або відхилити його.} few{Відновлено {count} незбережені документи. Перегляньте кожен документ, перш ніж зберегти або відхилити його.} many{Відновлено {count} незбережених документів. Перегляньте кожен документ, перш ніж зберегти або відхилити його.} other{Відновлено {count} незбереженого документа. Перегляньте кожен документ, перш ніж зберегти або відхилити його.}}", + "workspaceRecoveryDamaged": "{count, plural, one{Не вдалося відновити {count} пошкоджений запис відновлення. Оригінальний файл відновлення збережено для перевірки; дійсні записи залишаються доступними.} few{Не вдалося відновити {count} пошкоджені записи відновлення. Оригінальний файл відновлення збережено для перевірки; дійсні записи залишаються доступними.} many{Не вдалося відновити {count} пошкоджених записів відновлення. Оригінальний файл відновлення збережено для перевірки; дійсні записи залишаються доступними.} other{Не вдалося відновити {count} пошкодженого запису відновлення. Оригінальний файл відновлення збережено для перевірки; дійсні записи залишаються доступними.}}", "recoveredDocumentReview": "Відновлено незбережений вміст файлу {fileName}. Перегляньте його, потім збережіть, збережіть як новий файл або відкиньте.", "commandUnavailableInContext": "Ця команда недоступна в поточному контексті.", "mathRenderFailed": "Не вдалося відобразити математичний вираз.", diff --git a/lib/l10n/generated/app_localizations_hi.dart b/lib/l10n/generated/app_localizations_hi.dart index 3673d44e..94566127 100644 --- a/lib/l10n/generated/app_localizations_hi.dart +++ b/lib/l10n/generated/app_localizations_hi.dart @@ -804,8 +804,11 @@ class AppLocalizationsHi extends AppLocalizations { count, locale: localeName, other: - '$count दस्तावेज़ों में असुरक्षित बदलाव हैं। इन्हें जारी रखने से पहले सहेजें।', - one: '1 दस्तावेज़ में असुरक्षित बदलाव हैं। इसे जारी रखने से पहले सहेजें।', + '$count दस्तावेज़ों में न सहेजे गए बदलाव हैं। जारी रखने से पहले उन्हें सहेजें?', + one: + '1 दस्तावेज़ में न सहेजे गए बदलाव हैं। जारी रखने से पहले इसे सहेजें?', + zero: + '0 दस्तावेज़ों में न सहेजे गए बदलाव हैं। जारी रखने से पहले उन्हें सहेजें?', ); return '$_temp0'; } diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart index c2e39da8..84fc7915 100644 --- a/lib/l10n/generated/app_localizations_pt.dart +++ b/lib/l10n/generated/app_localizations_pt.dart @@ -3534,7 +3534,14 @@ class AppLocalizationsPt extends AppLocalizations { @override String aiContextDisclosure(int count) { - return 'O fornecedor selecionado receberá $count carateres do contexto apresentado.'; + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count carateres', + one: '1 caráter', + zero: '0 carateres', + ); + return 'O fornecedor selecionado receberá $_temp0 do contexto apresentado.'; } @override @@ -3638,7 +3645,14 @@ class AppLocalizationsPt extends AppLocalizations { @override String aiGenerationVerified(String model, int count) { - return 'Geração verificada com $model. Há $count modelos compatíveis disponíveis.'; + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'Há $count modelos compatíveis disponíveis', + one: 'Há 1 modelo compatível disponível', + zero: 'Há 0 modelos compatíveis disponíveis', + ); + return 'Geração verificada com $model. $_temp0.'; } @override @@ -3669,7 +3683,14 @@ class AppLocalizationsPt extends AppLocalizations { @override String markdownTocUpdated(int count) { - return 'Sumário atualizado com $count entradas.'; + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count entradas', + one: '1 entrada', + zero: '0 entradas', + ); + return 'Sumário atualizado com $_temp0.'; } @override @@ -7453,7 +7474,14 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { @override String aiContextDisclosure(int count) { - return 'O provedor selecionado receberá $count caracteres do contexto exibido.'; + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count caracteres', + one: '1 caractere', + zero: '0 caracteres', + ); + return 'O provedor selecionado receberá $_temp0 do contexto exibido.'; } @override @@ -7557,7 +7585,14 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { @override String aiGenerationVerified(String model, int count) { - return 'Geração verificada com $model. Há $count modelos compatíveis disponíveis.'; + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: 'Há $count modelos compatíveis disponíveis', + one: 'Há 1 modelo compatível disponível', + zero: 'Há 0 modelos compatíveis disponíveis', + ); + return 'Geração verificada com $model. $_temp0.'; } @override @@ -7588,7 +7623,14 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { @override String markdownTocUpdated(int count) { - return 'Sumário atualizado com $count entradas.'; + String _temp0 = intl.Intl.pluralLogic( + count, + locale: localeName, + other: '$count entradas', + one: '1 entrada', + zero: '0 entradas', + ); + return 'Sumário atualizado com $_temp0.'; } @override diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart index 9b1e8063..7195407e 100644 --- a/lib/l10n/generated/app_localizations_ru.dart +++ b/lib/l10n/generated/app_localizations_ru.dart @@ -819,13 +819,13 @@ class AppLocalizationsRu extends AppLocalizations { count, locale: localeName, other: - '$count документа содержит несохранённые изменения. Сохраните их перед продолжением.', + '$count документа содержит несохранённые изменения. Сохранить каждый перед продолжением?', many: - '$count документов содержат несохранённые изменения. Сохраните их перед продолжением.', + '$count документов содержат несохранённые изменения. Сохранить каждый перед продолжением?', few: - '$count документа содержат несохранённые изменения. Сохраните их перед продолжением.', + '$count документа содержат несохранённые изменения. Сохранить каждый перед продолжением?', one: - '1 документ содержит несохранённые изменения. Сохраните его перед продолжением.', + '$count документ содержит несохранённые изменения. Сохранить каждый перед продолжением?', ); return '$_temp0'; } @@ -1255,7 +1255,7 @@ class AppLocalizationsRu extends AppLocalizations { other: '$count дочерней темы будут перемещены на уровень выше.', many: '$count дочерних тем будут перемещены на уровень выше.', few: '$count дочерние темы будут перемещены на уровень выше.', - one: '1 дочерняя тема будет перемещена на уровень выше.', + one: '$count дочерняя тема будет перемещена на уровень выше.', ); return '$_temp0'; } @@ -1296,7 +1296,7 @@ class AppLocalizationsRu extends AppLocalizations { other: '$count использования', many: '$count использований', few: '$count использования', - one: '1 использование', + one: '$count использование', ); return '$_temp0'; } @@ -1723,13 +1723,13 @@ class AppLocalizationsRu extends AppLocalizations { count, locale: localeName, other: - 'Восстановлено $count несохранённого документа. Проверьте его перед сохранением или отменой.', + 'Восстановлено $count несохранённого документа. Проверьте каждый документ, прежде чем сохранить или отбросить его.', many: - 'Восстановлено $count несохранённых документов. Проверьте каждый перед сохранением или отменой.', + 'Восстановлено $count несохранённых документов. Проверьте каждый документ, прежде чем сохранить или отбросить его.', few: - 'Восстановлено $count несохранённых документа. Проверьте каждый перед сохранением или отменой.', + 'Восстановлено $count несохранённых документа. Проверьте каждый документ, прежде чем сохранить или отбросить его.', one: - 'Восстановлен 1 несохранённый документ. Проверьте его перед сохранением или отменой.', + 'Восстановлен $count несохранённый документ. Проверьте каждый документ, прежде чем сохранить или отбросить его.', ); return '$_temp0'; } @@ -1740,13 +1740,13 @@ class AppLocalizationsRu extends AppLocalizations { count, locale: localeName, other: - 'Не удалось восстановить $count повреждённой записи восстановления. Корректные записи восстановления остаются доступны.', + 'Не удалось восстановить $count повреждённой записи восстановления. Исходный файл восстановления сохранён для проверки; корректные записи остаются доступны.', many: - 'Не удалось восстановить $count повреждённых записей восстановления. Корректные записи восстановления остаются доступны.', + 'Не удалось восстановить $count повреждённых записей восстановления. Исходный файл восстановления сохранён для проверки; корректные записи остаются доступны.', few: - 'Не удалось восстановить $count повреждённые записи восстановления. Корректные записи восстановления остаются доступны.', + 'Не удалось восстановить $count повреждённые записи восстановления. Исходный файл восстановления сохранён для проверки; корректные записи остаются доступны.', one: - 'Не удалось восстановить 1 повреждённую запись восстановления. Оригинальный файл восстановления сохранён для проверки.', + 'Не удалось восстановить $count повреждённую запись восстановления. Исходный файл восстановления сохранён для проверки; корректные записи остаются доступны.', ); return '$_temp0'; } @@ -2392,7 +2392,7 @@ class AppLocalizationsRu extends AppLocalizations { other: '$count файлов в индексе', many: '$count файлов в индексе', few: '$count файла в индексе', - one: '1 файл в индексе', + one: '$count файл в индексе', ); return '$_temp0'; } @@ -2449,13 +2449,13 @@ class AppLocalizationsRu extends AppLocalizations { count, locale: localeName, other: - 'Все проиндексированные и непроиндексированные изменения в выбранных отслеживаемых файлах будут отменены, а файлы будут восстановлены до состояния HEAD.', + 'Все проиндексированные и непроиндексированные изменения в $count выбранных отслеживаемых файлах будут отменены, а файлы будут восстановлены до состояния HEAD.', many: - 'Все проиндексированные и непроиндексированные изменения в выбранных отслеживаемых файлах будут отменены, а файлы будут восстановлены до состояния HEAD.', + 'Все проиндексированные и непроиндексированные изменения в $count выбранных отслеживаемых файлах будут отменены, а файлы будут восстановлены до состояния HEAD.', few: - 'Все проиндексированные и непроиндексированные изменения в выбранных отслеживаемых файлах будут отменены, а файлы будут восстановлены до состояния HEAD.', + 'Все проиндексированные и непроиндексированные изменения в $count выбранных отслеживаемых файлах будут отменены, а файлы будут восстановлены до состояния HEAD.', one: - 'Все проиндексированные и непроиндексированные изменения в выбранном отслеживаемом файле будут отменены, а файл будет восстановлен до состояния HEAD.', + 'Все проиндексированные и непроиндексированные изменения в $count выбранном отслеживаемом файле будут отменены, а содержимое будет восстановлено до состояния HEAD.', ); return '$_temp0'; } @@ -2465,10 +2465,10 @@ class AppLocalizationsRu extends AppLocalizations { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: 'Выбранные неотслеживаемые файлы будут удалены.', - many: 'Выбранные неотслеживаемые файлы будут удалены.', - few: 'Выбранные неотслеживаемые файлы будут удалены.', - one: 'Выбранный неотслеживаемый файл будет удалён.', + other: 'Будут удалены $count выбранных неотслеживаемых файла.', + many: 'Будут удалены $count выбранных неотслеживаемых файлов.', + few: 'Будут удалены $count выбранных неотслеживаемых файла.', + one: 'Будет удалён $count выбранный неотслеживаемый файл.', ); return '$_temp0'; } @@ -2479,13 +2479,13 @@ class AppLocalizationsRu extends AppLocalizations { count, locale: localeName, other: - 'Выбранные файлы будут восстановлены или удалены в зависимости от их статуса Git.', + '$count выбранного файла будут восстановлены или удалены в зависимости от их статуса Git.', many: - 'Выбранные файлы будут восстановлены или удалены в зависимости от их статуса Git.', + '$count выбранных файлов будут восстановлены или удалены в зависимости от их статуса Git.', few: - 'Выбранные файлы будут восстановлены или удалены в зависимости от их статуса Git.', + '$count выбранных файла будут восстановлены или удалены в зависимости от их статуса Git.', one: - 'Выбранный файл будет восстановлен или удалён в зависимости от его статуса Git.', + '$count выбранный файл будет восстановлен или удалён в зависимости от статуса Git.', ); return '$_temp0'; } @@ -3030,7 +3030,9 @@ class AppLocalizationsRu extends AppLocalizations { count, locale: localeName, other: '$count предупреждениями', - one: '1 предупреждением', + many: '$count предупреждениями', + few: '$count предупреждениями', + one: '$count предупреждением', ); return '$fileName экспортирован с $_temp0.'; } diff --git a/lib/l10n/generated/app_localizations_uk.dart b/lib/l10n/generated/app_localizations_uk.dart index b7201613..4b18a58f 100644 --- a/lib/l10n/generated/app_localizations_uk.dart +++ b/lib/l10n/generated/app_localizations_uk.dart @@ -824,13 +824,13 @@ class AppLocalizationsUk extends AppLocalizations { count, locale: localeName, other: - '$count документа має незбережені зміни. Збережіть їх перед продовженням.', + '$count документа має незбережені зміни. Зберегти кожен перед продовженням?', many: - '$count документів мають незбережені зміни. Збережіть їх перед продовженням.', + '$count документів мають незбережені зміни. Зберегти кожен перед продовженням?', few: - '$count документи мають незбережені зміни. Збережіть їх перед продовженням.', + '$count документи мають незбережені зміни. Зберегти кожен перед продовженням?', one: - '1 документ має незбережені зміни. Збережіть його перед продовженням.', + '$count документ має незбережені зміни. Зберегти кожен перед продовженням?', ); return '$_temp0'; } @@ -1262,7 +1262,7 @@ class AppLocalizationsUk extends AppLocalizations { other: '$count дочірньої теми буде переміщено на рівень вище.', many: '$count дочірніх тем буде переміщено на рівень вище.', few: '$count дочірні теми буде переміщено на рівень вище.', - one: '1 дочірню тему буде переміщено на рівень вище.', + one: '$count дочірню тему буде переміщено на рівень вище.', ); return '$_temp0'; } @@ -1304,7 +1304,7 @@ class AppLocalizationsUk extends AppLocalizations { other: '$count використання', many: '$count використань', few: '$count використання', - one: '1 використання', + one: '$count використання', ); return '$_temp0'; } @@ -1731,13 +1731,13 @@ class AppLocalizationsUk extends AppLocalizations { count, locale: localeName, other: - 'Відновлено $count незбереженого документа. Перегляньте його перед збереженням або відхиленням.', + 'Відновлено $count незбереженого документа. Перегляньте кожен документ, перш ніж зберегти або відхилити його.', many: - 'Відновлено $count незбережених документів. Перегляньте кожен перед збереженням або відхиленням.', + 'Відновлено $count незбережених документів. Перегляньте кожен документ, перш ніж зберегти або відхилити його.', few: - 'Відновлено $count незбережені документи. Перегляньте кожен перед збереженням або відхиленням.', + 'Відновлено $count незбережені документи. Перегляньте кожен документ, перш ніж зберегти або відхилити його.', one: - 'Відновлено 1 незбережений документ. Перегляньте його перед збереженням або відхиленням.', + 'Відновлено $count незбережений документ. Перегляньте кожен документ, перш ніж зберегти або відхилити його.', ); return '$_temp0'; } @@ -1748,13 +1748,13 @@ class AppLocalizationsUk extends AppLocalizations { count, locale: localeName, other: - 'Не вдалося відновити $count пошкодженого запису відновлення. Дійсні записи відновлення залишаються доступними.', + 'Не вдалося відновити $count пошкодженого запису відновлення. Оригінальний файл відновлення збережено для перевірки; дійсні записи залишаються доступними.', many: - 'Не вдалося відновити $count пошкоджених записів відновлення. Дійсні записи відновлення залишаються доступними.', + 'Не вдалося відновити $count пошкоджених записів відновлення. Оригінальний файл відновлення збережено для перевірки; дійсні записи залишаються доступними.', few: - 'Не вдалося відновити $count пошкоджені записи відновлення. Дійсні записи відновлення залишаються доступними.', + 'Не вдалося відновити $count пошкоджені записи відновлення. Оригінальний файл відновлення збережено для перевірки; дійсні записи залишаються доступними.', one: - 'Не вдалося відновити 1 пошкоджений запис відновлення. Оригінальний файл відновлення збережено для перегляду.', + 'Не вдалося відновити $count пошкоджений запис відновлення. Оригінальний файл відновлення збережено для перевірки; дійсні записи залишаються доступними.', ); return '$_temp0'; } @@ -2401,7 +2401,7 @@ class AppLocalizationsUk extends AppLocalizations { other: '$count проіндексованих файлів', many: '$count проіндексованих файлів', few: '$count проіндексовані файли', - one: '1 проіндексований файл', + one: '$count проіндексований файл', ); return '$_temp0'; } @@ -2458,13 +2458,13 @@ class AppLocalizationsUk extends AppLocalizations { count, locale: localeName, other: - 'Усі індексовані та неіндексовані зміни у вибраних файлах з відстеженням буде скасовано, а файли буде відновлено до стану HEAD.', + 'Усі індексовані та неіндексовані зміни у $count вибраних файлах з відстеженням буде скасовано, а файли буде відновлено до стану HEAD.', many: - 'Усі індексовані та неіндексовані зміни у вибраних файлах з відстеженням буде скасовано, а файли буде відновлено до стану HEAD.', + 'Усі індексовані та неіндексовані зміни у $count вибраних файлах з відстеженням буде скасовано, а файли буде відновлено до стану HEAD.', few: - 'Усі індексовані та неіндексовані зміни у вибраних файлах з відстеженням буде скасовано, а файли буде відновлено до стану HEAD.', + 'Усі індексовані та неіндексовані зміни у $count вибраних файлах з відстеженням буде скасовано, а файли буде відновлено до стану HEAD.', one: - 'Усі індексовані та неіндексовані зміни у вибраному файлі з відстеженням буде скасовано, а файл буде відновлено до стану HEAD.', + 'Усі індексовані та неіндексовані зміни в $count вибраному файлі з відстеженням буде скасовано, а вміст буде відновлено до стану HEAD.', ); return '$_temp0'; } @@ -2474,10 +2474,10 @@ class AppLocalizationsUk extends AppLocalizations { String _temp0 = intl.Intl.pluralLogic( count, locale: localeName, - other: 'Вибрані невідстежувані файли буде видалено.', - many: 'Вибрані невідстежувані файли буде видалено.', - few: 'Вибрані невідстежувані файли буде видалено.', - one: 'Вибраний невідстежуваний файл буде видалено.', + other: '$count вибраного невідстежуваного файла буде видалено.', + many: '$count вибраних невідстежуваних файлів буде видалено.', + few: '$count вибрані невідстежувані файли буде видалено.', + one: '$count вибраний невідстежуваний файл буде видалено.', ); return '$_temp0'; } @@ -2488,13 +2488,13 @@ class AppLocalizationsUk extends AppLocalizations { count, locale: localeName, other: - 'Вибрані файли буде відновлено або видалено залежно від їхнього стану Git.', + '$count вибраного файла буде відновлено або видалено залежно від його статусу Git.', many: - 'Вибрані файли буде відновлено або видалено залежно від їхнього стану Git.', + '$count вибраних файлів буде відновлено або видалено залежно від їхнього статусу Git.', few: - 'Вибрані файли буде відновлено або видалено залежно від їхнього стану Git.', + '$count вибрані файли буде відновлено або видалено залежно від їхнього статусу Git.', one: - 'Вибраний файл буде відновлено або видалено залежно від його стану Git.', + '$count вибраний файл буде відновлено або видалено залежно від статусу Git.', ); return '$_temp0'; } @@ -3037,7 +3037,9 @@ class AppLocalizationsUk extends AppLocalizations { count, locale: localeName, other: '$count попередженнями', - one: '1 попередженням', + many: '$count попередженнями', + few: '$count попередженнями', + one: '$count попередженням', ); return '$fileName експортовано з $_temp0.'; } From 3268fff95d37d7af95cd7e9de78bc74834930571 Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Tue, 8 Sep 2026 13:31:34 -0700 Subject: [PATCH 26/37] Extract `_SidebarRowSurface` as a reusable widget and update `_SidebarTreeRow` and instance selector to use it for improved consistency and modularity. --- lib/src/app/busymark_design.dart | 18 +- .../presentation/workspace_screen.dart | 327 +++++++++++------- test/src/app_smoke_test.dart | 56 ++- test/src/localization_audit_test.dart | 118 +++++++ test/src/source_audit_test.dart | 7 +- 5 files changed, 373 insertions(+), 153 deletions(-) diff --git a/lib/src/app/busymark_design.dart b/lib/src/app/busymark_design.dart index e9a5ed2e..71de1096 100644 --- a/lib/src/app/busymark_design.dart +++ b/lib/src/app/busymark_design.dart @@ -79,7 +79,10 @@ abstract final class BusyMarkSizes { static const double aboutLogoViewport = 136; static const double aboutLogoAsset = 216; static const double sidebarSeparatorHeight = 22; - static const double sidebarTreeRowHeight = 30; + // The surrounding hairline insets bring tree rows to the same outer height + // as sidebar header controls. + static const double sidebarTreeRowHeight = + iconButton - BusyMarkStroke.hairline * 2; static const double sidebarTreeDepthBase = 4; static const double sidebarTreeDepthIndent = 14; static const double sidebarTreeControl = 18; @@ -1853,7 +1856,6 @@ class BusyMarkPopupSelector<T> extends StatelessWidget { this.leading, this.fullWidth = false, this.contentPadding, - this.buttonHeight, }); final T? value; @@ -1868,7 +1870,6 @@ class BusyMarkPopupSelector<T> extends StatelessWidget { final Widget? leading; final bool fullWidth; final EdgeInsetsGeometry? contentPadding; - final double? buttonHeight; @override Widget build(BuildContext context) { @@ -1912,17 +1913,6 @@ class BusyMarkPopupSelector<T> extends StatelessWidget { padding: contentPadding == null ? null : WidgetStatePropertyAll(contentPadding), - minimumSize: buttonHeight == null - ? null - : WidgetStatePropertyAll(Size(0, buttonHeight!)), - maximumSize: buttonHeight == null - ? null - : WidgetStatePropertyAll( - Size(double.infinity, buttonHeight!), - ), - tapTargetSize: buttonHeight == null - ? null - : MaterialTapTargetSize.shrinkWrap, ), child: Row( mainAxisSize: fullWidth diff --git a/lib/src/workspace/presentation/workspace_screen.dart b/lib/src/workspace/presentation/workspace_screen.dart index 56e6535d..bbbfa17d 100644 --- a/lib/src/workspace/presentation/workspace_screen.dart +++ b/lib/src/workspace/presentation/workspace_screen.dart @@ -4346,6 +4346,67 @@ Future<bool> _confirmDeleteFileTreeEntry( typedef _SidebarTreeMenuRequest = void Function(BuildContext anchorContext, Offset globalPosition); +class _SidebarRowSurface extends StatelessWidget { + const _SidebarRowSurface({ + super.key, + required this.child, + required this.enabled, + required this.clickable, + this.selected = false, + this.focusNode, + this.onKeyEvent, + this.onTap, + this.onSecondaryTapUp, + this.onHoverChanged, + this.onFocusChange, + }); + + final Widget child; + final bool enabled; + final bool clickable; + final bool selected; + final FocusNode? focusNode; + final FocusOnKeyEventCallback? onKeyEvent; + final VoidCallback? onTap; + final GestureTapUpCallback? onSecondaryTapUp; + final ValueChanged<bool>? onHoverChanged; + final ValueChanged<bool>? onFocusChange; + + @override + Widget build(BuildContext context) { + return MouseRegion( + onEnter: onHoverChanged == null ? null : (_) => onHoverChanged!(true), + onExit: onHoverChanged == null ? null : (_) => onHoverChanged!(false), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: BusyMarkStroke.hairline), + child: Material( + color: selected + ? busyMarkSelectedBackground(context) + : BusyMarkLinuxPalette.transparent, + borderRadius: BorderRadius.circular(BusyMarkRadius.md), + clipBehavior: Clip.antiAlias, + child: Focus( + onKeyEvent: onKeyEvent, + child: InkWell( + focusNode: focusNode, + hoverColor: clickable + ? busyMarkRowHoverColor(context) + : BusyMarkLinuxPalette.transparent, + onTap: enabled ? onTap : null, + onSecondaryTapUp: enabled ? onSecondaryTapUp : null, + onFocusChange: onFocusChange, + child: SizedBox( + height: BusyMarkSizes.sidebarTreeRowHeight, + child: child, + ), + ), + ), + ), + ), + ); + } +} + class _SidebarTreeRow extends StatefulWidget { const _SidebarTreeRow({ super.key, @@ -4439,120 +4500,91 @@ class _SidebarTreeRowState extends State<_SidebarTreeRow> { final expanderGap = widget.compactHierarchyIndent ? 0.0 : BusyMarkSpacing.xs; - return MouseRegion( - onEnter: (_) => setState(() => _hovered = true), - onExit: (_) => setState(() => _hovered = false), - child: Padding( - padding: const EdgeInsets.symmetric(vertical: BusyMarkStroke.hairline), - child: Material( - color: widget.selected - ? busyMarkSelectedBackground(context) - : BusyMarkLinuxPalette.transparent, - borderRadius: BorderRadius.circular(BusyMarkRadius.md), - clipBehavior: Clip.antiAlias, - child: Focus( - onKeyEvent: _handleKeyEvent, - child: InkWell( - hoverColor: clickable - ? busyMarkRowHoverColor(context) - : BusyMarkLinuxPalette.transparent, - onTap: widget.enabled ? widget.onTap : null, - onSecondaryTapUp: widget.enabled - ? widget.onMenuRequested == null - ? null - : (details) => widget.onMenuRequested!( - context, - details.globalPosition, - ) - : null, - onFocusChange: (focused) => setState(() => _focused = focused), - child: SizedBox( - height: BusyMarkSizes.sidebarTreeRowHeight, - child: Row( - children: [ - SizedBox( - width: - depthBase + - widget.depth * BusyMarkSizes.sidebarTreeDepthIndent, - ), - SizedBox.square( - dimension: expanderWidth, - child: widget.hasChildren - ? GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: widget.enabled - ? widget.onToggle ?? widget.onTap - : null, - child: AnimatedRotation( - turns: widget.expanded - ? direction == TextDirection.rtl - ? -0.25 - : 0.25 - : 0, - duration: BusyMarkMotion.sidebarExpand, - child: Icon( - BusyMarkGlyphs.collapsedTreeArrowFor( - direction, - ), - size: BusyMarkSizes.sidebarTreeArrow, - color: foreground, - ), - ), - ) - : const SizedBox.shrink(), - ), - SizedBox(width: expanderGap), - SizedBox.square( - dimension: BusyMarkSizes.sidebarTreeControl, - child: Center( - child: - widget.leading ?? - Icon( - widget.icon, - size: BusyMarkSizes.iconSm, - color: foreground, - ), - ), - ), - const SizedBox(width: BusyMarkSpacing.sm), - Expanded( - child: Text( - widget.title, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: titleStyle, + return _SidebarRowSurface( + enabled: widget.enabled, + clickable: clickable, + selected: widget.selected, + onKeyEvent: _handleKeyEvent, + onTap: widget.onTap, + onSecondaryTapUp: widget.onMenuRequested == null + ? null + : (details) => + widget.onMenuRequested!(context, details.globalPosition), + onHoverChanged: (hovered) => setState(() => _hovered = hovered), + onFocusChange: (focused) => setState(() => _focused = focused), + child: Row( + children: [ + SizedBox( + width: + depthBase + widget.depth * BusyMarkSizes.sidebarTreeDepthIndent, + ), + SizedBox.square( + dimension: expanderWidth, + child: widget.hasChildren + ? GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: widget.enabled + ? widget.onToggle ?? widget.onTap + : null, + child: AnimatedRotation( + turns: widget.expanded + ? direction == TextDirection.rtl + ? -0.25 + : 0.25 + : 0, + duration: BusyMarkMotion.sidebarExpand, + child: Icon( + BusyMarkGlyphs.collapsedTreeArrowFor(direction), + size: BusyMarkSizes.sidebarTreeArrow, + color: foreground, ), ), - if (widget.onMenuRequested != null) - SizedBox( - width: BusyMarkSizes.iconButton, - child: Center( - child: menuVisible - ? Builder( - builder: (buttonContext) => - BusyMarkCompactIconButton( - tooltip: context.l10n.actions, - icon: BusyMarkGlyphs.menuVertical, - onPressed: () => - widget.onMenuRequested!( - buttonContext, - _sidebarTreeMenuAnchor( - buttonContext, - ), - ), - ), - ) - : const SizedBox.shrink(), + ) + : const SizedBox.shrink(), + ), + SizedBox(width: expanderGap), + SizedBox.square( + dimension: BusyMarkSizes.sidebarTreeControl, + child: Center( + child: + widget.leading ?? + Icon( + widget.icon, + size: BusyMarkSizes.iconSm, + color: foreground, + ), + ), + ), + const SizedBox(width: BusyMarkSpacing.sm), + Expanded( + child: Text( + widget.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: titleStyle, + ), + ), + if (widget.onMenuRequested != null) + SizedBox( + width: BusyMarkSizes.iconButton, + child: Center( + child: menuVisible + ? Builder( + builder: (buttonContext) => BusyMarkCompactIconButton( + tooltip: context.l10n.actions, + icon: BusyMarkGlyphs.menuVertical, + onPressed: () => widget.onMenuRequested!( + buttonContext, + _sidebarTreeMenuAnchor(buttonContext), + ), ), ) - else - const SizedBox(width: BusyMarkSpacing.xs), - ], - ), + : const SizedBox.shrink(), ), - ), - ), - ), + ) + else + const SizedBox(width: BusyMarkSpacing.xs), + ], ), ); } @@ -6544,14 +6576,15 @@ class _WritersideInstanceSelector extends StatelessWidget { context, instanceColors[selectedPath] ?? WritersideInstanceIconColor.blue, ); - return BusyMarkPopupSelector<String>( + final selectorEnabled = instances.isNotEmpty; + return BusyMarkMenuButton<String>( key: const ValueKey('writerside-instance-selector'), - value: selectedPath, - label: selectedLabel, tooltip: context.l10n.instances, - options: [ + enabled: selectorEnabled, + fallbackMenuWidth: BusyMarkSizes.languagePopupMaxWidth, + items: [ for (final instance in instances) - BusyMarkPopupSelectorOption<String>( + BusyMarkPopupMenuItem<String>( value: instance.sourceTreePath, label: busyMarkLtrIsolateFor(context, instance.name), icon: BusyMarkGlyphs.tree, @@ -6560,20 +6593,66 @@ class _WritersideInstanceSelector extends StatelessWidget { instanceColors[instance.sourceTreePath] ?? WritersideInstanceIconColor.blue, ), + checked: instance.sourceTreePath == selectedPath, + trailingCheck: true, ), ], onSelected: onSelected, - leading: Icon( - BusyMarkGlyphs.tree, - size: BusyMarkSizes.iconSm, - color: selectedColor, - ), - fullWidth: true, - contentPadding: const EdgeInsetsDirectional.only( - start: BusyMarkSpacing.headerInset, - end: BusyMarkSpacing.sm, + triggerBuilder: (context, trigger) => trigger.anchor( + child: Tooltip( + message: context.l10n.instances, + child: Semantics( + expanded: trigger.isOpen, + child: _SidebarRowSurface( + key: const ValueKey('writerside-instance-selector-trigger'), + enabled: selectorEnabled, + clickable: selectorEnabled, + focusNode: trigger.focusNode, + onTap: trigger.onPressed, + child: Row( + children: [ + const SizedBox(width: BusyMarkSpacing.headerInset), + Icon( + BusyMarkGlyphs.tree, + size: BusyMarkSizes.iconSm, + color: selectedColor, + ), + const SizedBox(width: BusyMarkSpacing.sm), + Expanded( + child: Text( + selectedLabel, + maxLines: 1, + overflow: TextOverflow.ellipsis, + softWrap: false, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: selectorEnabled + ? BusyMarkSurfaceColors.of(context).foreground + : BusyMarkSurfaceColors.of( + context, + ).disabledForeground, + ), + ), + ), + SizedBox( + width: BusyMarkSizes.iconButton, + child: Center( + child: Icon( + BusyMarkGlyphs.downArrow, + size: BusyMarkSizes.iconSm, + color: selectorEnabled + ? BusyMarkSurfaceColors.of(context).mutedForeground + : BusyMarkSurfaceColors.of( + context, + ).disabledForeground, + ), + ), + ), + ], + ), + ), + ), + ), ), - buttonHeight: BusyMarkSizes.iconButton, ); } } diff --git a/test/src/app_smoke_test.dart b/test/src/app_smoke_test.dart index cd33e91c..91096407 100644 --- a/test/src/app_smoke_test.dart +++ b/test/src/app_smoke_test.dart @@ -1946,25 +1946,56 @@ void main() { const ValueKey('writerside-instance-selector'), ); expect(instanceSelector, findsOneWidget); - final instanceSelectorButton = find.descendant( - of: instanceSelector, - matching: find.byType(FilledButton), + final instanceSelectorTrigger = find.byKey( + const ValueKey('writerside-instance-selector-trigger'), ); - expect(instanceSelectorButton, findsOneWidget); + expect(instanceSelectorTrigger, findsOneWidget); expect( - tester - .widget<FilledButton>(instanceSelectorButton) - .style - ?.backgroundColor - ?.resolve({}), + find.descendant( + of: instanceSelector, + matching: find.byType(FilledButton), + ), + findsNothing, + ); + final instanceSelectorSurface = find.descendant( + of: instanceSelectorTrigger, + matching: find.byType(Material), + ); + final instanceSelectorInkWell = find.descendant( + of: instanceSelectorTrigger, + matching: find.byType(InkWell), + ); + expect(instanceSelectorSurface, findsOneWidget); + expect(instanceSelectorInkWell, findsOneWidget); + expect( + tester.widget<Material>(instanceSelectorSurface).color, BusyMarkLinuxPalette.transparent, ); - final instanceSelectorRect = tester.getRect(instanceSelectorButton); + final instanceSelectorRect = tester.getRect(instanceSelectorTrigger); final tocHeaderRowRect = tester.getRect( find.byKey(const ValueKey('workspace-sidebar-first-content')), ); - final firstTocRowRect = tester.getRect( - find.byKey(const ValueKey('workspace-sidebar-toc-row-0')), + final firstTocRow = find.byKey( + const ValueKey('workspace-sidebar-toc-row-0'), + ); + final firstTocRowRect = tester.getRect(firstTocRow); + final firstTocRowSurface = find.descendant( + of: firstTocRow, + matching: find.byType(Material), + ); + final firstTocRowInkWell = find.descendant( + of: firstTocRow, + matching: find.byType(InkWell), + ); + expect(firstTocRowSurface, findsOneWidget); + expect(firstTocRowInkWell, findsOneWidget); + expect( + tester.widget<Material>(instanceSelectorSurface).borderRadius, + tester.widget<Material>(firstTocRowSurface).borderRadius, + ); + expect( + tester.widget<InkWell>(instanceSelectorInkWell).hoverColor, + tester.widget<InkWell>(firstTocRowInkWell).hoverColor, ); final primaryIconRect = tester.getRect( find.descendant( @@ -2005,6 +2036,7 @@ void main() { ); expect(instanceSelectorRect.height, tocMenuRect.height); expect(instanceSelectorRect.center.dy, tocMenuRect.center.dy); + expect(instanceSelectorRect.height, firstTocRowRect.height); final mouse = await tester.createGesture(kind: PointerDeviceKind.mouse); addTearDown(mouse.removePointer); await mouse.addPointer(location: Offset.zero); diff --git a/test/src/localization_audit_test.dart b/test/src/localization_audit_test.dart index 59de635a..0da992ca 100644 --- a/test/src/localization_audit_test.dart +++ b/test/src/localization_audit_test.dart @@ -481,6 +481,124 @@ void main() { expect(chinese.workspaceRecoveryRestored(3), '已恢复 3 个未保存的文档。请在保存或放弃前逐一检查。'); }); + test('Russian and Ukrainian count messages preserve the supplied count', () { + const counts = <int>[1, 2, 5, 11, 21, 22, 31]; + final localizations = <String, AppLocalizations>{ + 'ru': lookupAppLocalizations(const Locale('ru')), + 'uk': lookupAppLocalizations(const Locale('uk')), + }; + + for (final localeEntry in localizations.entries) { + final l10n = localeEntry.value; + for (final count in counts) { + final messages = <String, String>{ + 'unsavedChangesMultipleMessage': l10n.unsavedChangesMultipleMessage( + count, + ), + 'childTopicsPromoted': l10n.childTopicsPromoted(count), + 'usageCount': l10n.usageCount(count), + 'workspaceRecoveryRestored': l10n.workspaceRecoveryRestored(count), + 'workspaceRecoveryDamaged': l10n.workspaceRecoveryDamaged(count), + 'gitStagedFileCount': l10n.gitStagedFileCount(count), + 'pdfExportedWithWarnings': l10n.pdfExportedWithWarnings( + 'document.pdf', + count, + ), + 'gitConfirmDiscardTracked': l10n.gitConfirmDiscardTracked(count), + 'gitConfirmDiscardUntracked': l10n.gitConfirmDiscardUntracked(count), + 'gitConfirmDiscardMixed': l10n.gitConfirmDiscardMixed(count), + }; + for (final messageEntry in messages.entries) { + expect( + messageEntry.value, + contains('$count'), + reason: + '${localeEntry.key}.${messageEntry.key} must display $count', + ); + } + expect( + l10n.unsavedChangesMultipleMessage(count), + endsWith('?'), + reason: '${localeEntry.key} must preserve the save question', + ); + } + } + + final russian = localizations['ru']!; + expect(russian.usageCount(1), '1 использование'); + expect(russian.usageCount(2), '2 использования'); + expect(russian.usageCount(5), '5 использований'); + expect(russian.usageCount(11), '11 использований'); + expect(russian.usageCount(21), '21 использование'); + expect(russian.usageCount(22), '22 использования'); + expect(russian.usageCount(31), '31 использование'); + + final ukrainian = localizations['uk']!; + expect(ukrainian.usageCount(1), '1 використання'); + expect(ukrainian.usageCount(2), '2 використання'); + expect(ukrainian.usageCount(5), '5 використань'); + expect(ukrainian.usageCount(11), '11 використань'); + expect(ukrainian.usageCount(21), '21 використання'); + expect(ukrainian.usageCount(22), '22 використання'); + expect(ukrainian.usageCount(31), '31 використання'); + }); + + test('Portuguese count messages distinguish singular and plural', () { + final locales = <String, AppLocalizations>{ + 'pt': lookupAppLocalizations(const Locale('pt')), + 'pt-BR': lookupAppLocalizations(const Locale('pt', 'BR')), + }; + + for (final localeEntry in locales.entries) { + final l10n = localeEntry.value; + expect(l10n.markdownTocUpdated(0), 'Sumário atualizado com 0 entradas.'); + expect(l10n.markdownTocUpdated(1), 'Sumário atualizado com 1 entrada.'); + expect(l10n.markdownTocUpdated(2), 'Sumário atualizado com 2 entradas.'); + expect( + l10n.aiGenerationVerified('BusyAI', 0), + 'Geração verificada com BusyAI. Há 0 modelos compatíveis disponíveis.', + ); + expect( + l10n.aiGenerationVerified('BusyAI', 1), + 'Geração verificada com BusyAI. Há 1 modelo compatível disponível.', + ); + expect( + l10n.aiGenerationVerified('BusyAI', 2), + 'Geração verificada com BusyAI. Há 2 modelos compatíveis disponíveis.', + ); + } + + final portuguese = locales['pt']!; + expect( + portuguese.aiContextDisclosure(1), + 'O fornecedor selecionado receberá 1 caráter do contexto apresentado.', + ); + expect( + portuguese.aiContextDisclosure(2), + 'O fornecedor selecionado receberá 2 carateres do contexto apresentado.', + ); + + final brazilian = locales['pt-BR']!; + expect( + brazilian.aiContextDisclosure(1), + 'O provedor selecionado receberá 1 caractere do contexto exibido.', + ); + expect( + brazilian.aiContextDisclosure(2), + 'O provedor selecionado receberá 2 caracteres do contexto exibido.', + ); + }); + + test('Hindi unsaved-document prompt uses saved-state terminology', () { + final hindi = lookupAppLocalizations(const Locale('hi')); + for (final count in <int>[1, 2]) { + final message = hindi.unsavedChangesMultipleMessage(count); + expect(message, contains('न सहेजे गए बदलाव')); + expect(message, isNot(contains('असुरक्षित बदलाव'))); + expect(message, endsWith('?')); + } + }); + test('RTL translations isolate technical interpolations', () { const fsi = '\u2068'; const pdi = '\u2069'; diff --git a/test/src/source_audit_test.dart b/test/src/source_audit_test.dart index dc4dcc14..52426439 100644 --- a/test/src/source_audit_test.dart +++ b/test/src/source_audit_test.dart @@ -1423,9 +1423,10 @@ void main() { contains('BusyMarkHeaderPopupMenuButton<_TocHeaderAction>'), ); expect(tocHeader, contains('class _WritersideInstanceSelector')); - expect(tocHeader, contains('BusyMarkPopupSelector<String>')); - expect(tocHeader, contains('fullWidth: true')); - expect(tocHeader, contains('contentPadding: const EdgeInsetsDirectional')); + expect(tocHeader, contains('BusyMarkMenuButton<String>')); + expect(tocHeader, contains('_SidebarRowSurface')); + expect(tocHeader, isNot(contains('BusyMarkPopupSelector<String>'))); + expect(tocHeader, isNot(contains('FilledButton'))); expect(tocHeader, contains('iconColor: writersideInstanceIconColorValue')); expect(tocHeader, contains("ValueKey('writerside-instance-selector')")); expect( From 31e664bb0a6d16694082739ef10948f1aab97f9e Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Tue, 8 Sep 2026 13:48:33 -0700 Subject: [PATCH 27/37] Fix translations (PT) --- lib/l10n/app_pt.arb | 2 +- lib/l10n/generated/app_localizations_pt.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index d8764f80..6fa058f1 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -3008,7 +3008,7 @@ "aiCloudConsentTitle": "Enviar conteúdo para {provider}?", "aiCloudConsentEnable": "Ativar {provider}", "aiCloudConsentMessage": "Apenas o conteúdo apresentado em cada caixa de diálogo de revisão de IA é enviado. Os pedidos não mantêm estado, as propostas exigem revisão e a chave de API é guardada no cofre de credenciais do sistema Linux.", - "aiCloudConsentRequired": "Primeiro, confirme o partilha de dados com {provider} em Definições → IA.", + "aiCloudConsentRequired": "Primeiro, confirme a partilha de dados com {provider} em Definições → IA.", "aiGenerationVerified": "Geração verificada com {model}. {count, plural, =0{Há 0 modelos compatíveis disponíveis} =1{Há 1 modelo compatível disponível} other{Há {count} modelos compatíveis disponíveis}}.", "aiColdStartObserved": "Foi detetado um arranque a frio do modelo local.", "aiNoCompatibleModels": "Não há nenhum modelo compatível de geração de texto disponível.", diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart index 84fc7915..487f921a 100644 --- a/lib/l10n/generated/app_localizations_pt.dart +++ b/lib/l10n/generated/app_localizations_pt.dart @@ -3640,7 +3640,7 @@ class AppLocalizationsPt extends AppLocalizations { @override String aiCloudConsentRequired(String provider) { - return 'Primeiro, confirme o partilha de dados com $provider em Definições → IA.'; + return 'Primeiro, confirme a partilha de dados com $provider em Definições → IA.'; } @override From 3eafd84ca1c971554d2fd39d5aec7cfc9e9db26c Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Tue, 8 Sep 2026 14:33:46 -0700 Subject: [PATCH 28/37] Refactor table menu buttons in Editor view --- lib/src/app/busymark_design.dart | 11 +- .../editor/wysiwyg/wysiwyg_block_widgets.dart | 465 +++++++++++++----- lib/src/writerside/writerside_table_view.dart | 12 +- test/src/busymark_document_test.dart | 137 +++++- test/src/editor_ui_primitives_audit_test.dart | 15 +- test/src/localization_audit_test.dart | 235 +++++++-- test/src/source_audit_test.dart | 6 +- .../src/writerside_semantic_widgets_test.dart | 112 +++++ 8 files changed, 797 insertions(+), 196 deletions(-) diff --git a/lib/src/app/busymark_design.dart b/lib/src/app/busymark_design.dart index 71de1096..61e244a2 100644 --- a/lib/src/app/busymark_design.dart +++ b/lib/src/app/busymark_design.dart @@ -109,10 +109,7 @@ abstract final class BusyMarkSizes { BusyMarkSpacing.sm + wysiwygToolbarReserve + BusyMarkSpacing.sm; static const double wysiwygPrefixWidth = 30; static const double tableDialogWidth = 360; - static const double tableColumnBaseWidth = 164; static const double tableMinWidth = 360; - static const double tableMaxWidth = 980; - static const double tableControl = 34; static const double markerDot = 6; static const double listMarkerTopInset = 7; static const double thematicBreakHandleWidth = 44; @@ -138,6 +135,7 @@ abstract final class BusyMarkElevation { abstract final class BusyMarkStroke { static const double hairline = 1; + static const double tableGrid = 0.5; static const double focus = kYaruFocusBorderWidth; static const double sourceCursor = 1.4; static const double thematicBreak = 1.6; @@ -319,10 +317,7 @@ abstract final class BusyMarkInsets { vertical: BusyMarkSpacing.sm, ); static const documentCalloutContent = EdgeInsets.all(BusyMarkSpacing.md); - static const documentTableCell = EdgeInsets.symmetric( - horizontal: BusyMarkSpacing.sm, - vertical: BusyMarkSpacing.xs, - ); + static const documentTableCell = EdgeInsets.all(BusyMarkSpacing.smPlus); static const sectionLabel = EdgeInsets.fromLTRB( BusyMarkSpacing.md, BusyMarkSpacing.mdPlus, @@ -344,7 +339,7 @@ abstract final class BusyMarkInsets { ); static const wysiwygContainerBlock = documentCalloutBlock; static const wysiwygTableBlock = EdgeInsets.symmetric( - vertical: BusyMarkSpacing.smPlus, + vertical: BusyMarkSpacing.md, ); static const wysiwygDefaultBlock = EdgeInsets.symmetric( vertical: BusyMarkSpacing.xs, diff --git a/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart b/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart index a16e9ee0..27eb5b15 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_block_widgets.dart @@ -1449,7 +1449,7 @@ String _directionalText(BusyBlock block) { ].join(' '); } -class _TableBlockEditor extends StatelessWidget { +class _TableBlockEditor extends StatefulWidget { const _TableBlockEditor({ required this.block, required this.onFocused, @@ -1474,8 +1474,6 @@ class _TableBlockEditor extends StatelessWidget { this.onCopyPlainText, }); - static const double _controlSize = BusyMarkSizes.tableControl; - final BusyBlock block; final VoidCallback onFocused; final void Function(String cellId, String text) onCellChanged; @@ -1499,101 +1497,303 @@ class _TableBlockEditor extends StatelessWidget { final VoidCallback? onCopy; final VoidCallback? onCopyPlainText; + @override + State<_TableBlockEditor> createState() => _TableBlockEditorState(); +} + +class _TableBlockEditorState extends State<_TableBlockEditor> { + final _overlayController = OverlayPortalController(); + BuildContext? _tableRenderContext; + final _rowAnchorContexts = <BuildContext?>[]; + final _columnAnchorContexts = <BuildContext?>[]; + ({int row, int column})? _activeCell; + + @override + void initState() { + super.initState(); + _syncControlAnchors(); + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) { + _overlayController.show(); + } + }); + } + + @override + void didUpdateWidget(covariant _TableBlockEditor oldWidget) { + super.didUpdateWidget(oldWidget); + _syncControlAnchors(); + final active = _activeCell; + final rows = widget.block.children; + if (active != null && + (active.row >= rows.length || active.column >= _columnCount(rows))) { + _activeCell = rows.isEmpty + ? null + : ( + row: active.row.clamp(0, rows.length - 1), + column: active.column.clamp(0, _columnCount(rows) - 1), + ); + } + } + + void _syncControlAnchors() { + final rowCount = widget.block.children.length; + final columnCount = _columnCount(widget.block.children); + while (_rowAnchorContexts.length < rowCount) { + _rowAnchorContexts.add(null); + } + while (_rowAnchorContexts.length > rowCount) { + _rowAnchorContexts.removeLast(); + } + while (_columnAnchorContexts.length < columnCount) { + _columnAnchorContexts.add(null); + } + while (_columnAnchorContexts.length > columnCount) { + _columnAnchorContexts.removeLast(); + } + } + @override Widget build(BuildContext context) { - final colors = BusyMarkSurfaceColors.of(context); - final rows = block.children; + final scheme = Theme.of(context).colorScheme; + final rows = widget.block.children; final columnCount = _columnCount(rows); - final dataWidth = (columnCount * BusyMarkSizes.tableColumnBaseWidth) - .clamp(BusyMarkSizes.tableMinWidth, BusyMarkSizes.tableMaxWidth) - .toDouble(); - return SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: ConstrainedBox( - constraints: BoxConstraints(minWidth: dataWidth + _controlSize), - child: Table( - border: TableBorder( - horizontalInside: BorderSide(color: colors.subtleBorder), - verticalInside: BorderSide(color: colors.subtleBorder), - top: BorderSide(color: colors.subtleBorder), - right: BorderSide(color: colors.subtleBorder), - bottom: BorderSide(color: colors.subtleBorder), - left: BorderSide(color: colors.subtleBorder), - borderRadius: BorderRadius.circular(BusyMarkRadius.sm), - ), - defaultVerticalAlignment: TableCellVerticalAlignment.middle, - columnWidths: { - 0: const FixedColumnWidth(_controlSize), - for (var index = 0; index < columnCount; index++) - index + 1: const FlexColumnWidth(), - }, - children: [ - TableRow( - decoration: BoxDecoration(color: colors.controlHover), - children: [ - _TableCornerCell(onTableDeleted: onTableDeleted), - for (var column = 0; column < columnCount; column++) - _TableColumnControlCell( - columnIndex: column, - alignment: _alignmentForColumn(rows, column), - onInserted: onColumnInserted, - onDeleted: onColumnDeleted, - onAlignmentChanged: onColumnAlignmentChanged, + return OverlayPortal.overlayChildLayoutBuilder( + controller: _overlayController, + overlayChildBuilder: _buildContextControls, + child: SizedBox( + width: double.infinity, + child: KeyedSubtree( + key: ValueKey('wysiwyg-table-grid-${widget.block.id}'), + child: Builder( + builder: (tableContext) { + _tableRenderContext = tableContext; + return Table( + border: TableBorder( + horizontalInside: BorderSide( + color: scheme.outlineVariant, + width: BusyMarkStroke.tableGrid, ), - ], - ), - for (final (rowIndex, row) in rows.indexed) - TableRow( - decoration: BoxDecoration( - color: _isHeaderRow(row, rowIndex) - ? colors.control - : BusyMarkLinuxPalette.transparent, - ), - children: [ - _TableRowControlCell( - rowIndex: rowIndex, - onInserted: onRowInserted, - onDeleted: onRowDeleted, + verticalInside: BorderSide( + color: scheme.outlineVariant, + width: BusyMarkStroke.tableGrid, + ), + top: BorderSide( + color: scheme.outlineVariant, + width: BusyMarkStroke.tableGrid, + ), + right: BorderSide( + color: scheme.outlineVariant, + width: BusyMarkStroke.tableGrid, ), + bottom: BorderSide( + color: scheme.outlineVariant, + width: BusyMarkStroke.tableGrid, + ), + left: BorderSide( + color: scheme.outlineVariant, + width: BusyMarkStroke.tableGrid, + ), + borderRadius: BorderRadius.circular(BusyMarkRadius.sm), + ), + defaultVerticalAlignment: TableCellVerticalAlignment.middle, + columnWidths: { for (var column = 0; column < columnCount; column++) - _TableCellEditor( - cell: column < row.children.length - ? row.children[column] - : null, - header: _isHeaderRow(row, rowIndex), - style: busyMarkDocumentBodyTextStyle(context), - onFocused: onFocused, - onChanged: onCellChanged, - onSourceChanged: onCellSourceChanged, - editRevision: editRevision, - sourceSpan: block.sourceSpan, - onMathDiagnostic: onMathDiagnostic, - controller: column < row.children.length - ? cellController?.call(row.children[column]) - : null, - undoController: column < row.children.length - ? cellUndoController?.call(row.children[column]) - : null, - focusNode: column < row.children.length - ? cellFocusNode?.call(row.children[column]) - : null, - cellKey: column < row.children.length - ? cellKey?.call(row.children[column].id) - : null, - onCellFocused: onCellFocused, - suppressContextMenu: suppressContextMenu, - onCut: onCut, - onCopy: onCopy, - onCopyPlainText: onCopyPlainText, + column: const FlexColumnWidth(), + }, + children: [ + for (final (rowIndex, row) in rows.indexed) + TableRow( + decoration: BoxDecoration( + color: _isHeaderRow(row, rowIndex) + ? scheme.surfaceContainerHighest + : scheme.surface, + ), + children: [ + for (var column = 0; column < columnCount; column++) + _cell( + context, + row: row, + rowIndex: rowIndex, + column: column, + ), + ], ), ], - ), - ], + ); + }, + ), ), ), ); } + Widget _cell( + BuildContext context, { + required BusyBlock row, + required int rowIndex, + required int column, + }) { + final cell = column < row.children.length ? row.children[column] : null; + Widget editor = MouseRegion( + onEnter: (_) => _activateCell(rowIndex, column), + child: _TableCellEditor( + cell: cell, + header: _isHeaderRow(row, rowIndex), + style: busyMarkDocumentBodyTextStyle(context), + onFocused: widget.onFocused, + onChanged: widget.onCellChanged, + onSourceChanged: widget.onCellSourceChanged, + editRevision: widget.editRevision, + sourceSpan: widget.block.sourceSpan, + onMathDiagnostic: widget.onMathDiagnostic, + controller: cell == null ? null : widget.cellController?.call(cell), + undoController: cell == null + ? null + : widget.cellUndoController?.call(cell), + focusNode: cell == null ? null : widget.cellFocusNode?.call(cell), + cellKey: cell == null ? null : widget.cellKey?.call(cell.id), + onCellFocused: cell == null + ? null + : (cellId) { + _activateCell(rowIndex, column); + final onCellFocused = widget.onCellFocused; + if (onCellFocused == null) { + widget.onFocused(); + } else { + onCellFocused(cellId); + } + }, + suppressContextMenu: widget.suppressContextMenu, + onCut: widget.onCut, + onCopy: widget.onCopy, + onCopyPlainText: widget.onCopyPlainText, + ), + ); + if (rowIndex == 0) { + final child = editor; + editor = Builder( + builder: (anchorContext) { + _columnAnchorContexts[column] = anchorContext; + return child; + }, + ); + } + if (column == 0) { + final child = editor; + editor = Builder( + builder: (anchorContext) { + _rowAnchorContexts[rowIndex] = anchorContext; + return child; + }, + ); + } + return editor; + } + + Widget _buildContextControls( + BuildContext context, + OverlayChildLayoutInfo layoutInfo, + ) { + final active = _activeCell; + final textDirection = Directionality.of(context); + final tableRect = MatrixUtils.transformRect( + layoutInfo.childPaintTransform, + Offset.zero & layoutInfo.childSize, + ); + final controlSize = BusyMarkSizes.iconButton; + final rowRect = active == null || active.row >= _rowAnchorContexts.length + ? null + : _anchorRectInOverlay(_rowAnchorContexts[active.row], layoutInfo); + final columnRect = + active == null || active.column >= _columnAnchorContexts.length + ? null + : _anchorRectInOverlay( + _columnAnchorContexts[active.column], + layoutInfo, + ); + return Stack( + clipBehavior: Clip.none, + children: [ + Positioned( + left: textDirection == TextDirection.ltr + ? tableRect.right + BusyMarkSpacing.xs + : tableRect.left - controlSize - BusyMarkSpacing.xs, + top: tableRect.top - controlSize - BusyMarkSpacing.xs, + width: controlSize, + height: controlSize, + child: _TableDeleteControl( + key: ValueKey('wysiwyg-table-delete-${widget.block.id}'), + onTableDeleted: widget.onTableDeleted, + ), + ), + if (active != null && rowRect != null) + Positioned( + left: textDirection == TextDirection.ltr + ? tableRect.left - controlSize - BusyMarkSpacing.xs + : tableRect.right + BusyMarkSpacing.xs, + top: rowRect.center.dy - controlSize / 2, + width: controlSize, + height: controlSize, + child: _TableRowControl( + rowIndex: active.row, + onInserted: widget.onRowInserted, + onDeleted: widget.onRowDeleted, + ), + ), + if (active != null && columnRect != null) + Positioned( + left: columnRect.center.dx - controlSize / 2, + top: tableRect.top - controlSize - BusyMarkSpacing.xs, + width: controlSize, + height: controlSize, + child: _TableColumnControl( + columnIndex: active.column, + alignment: _alignmentForColumn( + widget.block.children, + active.column, + ), + onInserted: widget.onColumnInserted, + onDeleted: widget.onColumnDeleted, + onAlignmentChanged: widget.onColumnAlignmentChanged, + ), + ), + ], + ); + } + + Rect? _anchorRectInOverlay( + BuildContext? anchorContext, + OverlayChildLayoutInfo layoutInfo, + ) { + final anchor = anchorContext?.findRenderObject(); + final table = _tableRenderContext?.findRenderObject(); + if (anchor is! RenderBox || + table is! RenderBox || + !anchor.hasSize || + !table.hasSize || + !anchor.attached || + !table.attached) { + return null; + } + final rectInTable = MatrixUtils.transformRect( + anchor.getTransformTo(table), + Offset.zero & anchor.size, + ); + return MatrixUtils.transformRect( + layoutInfo.childPaintTransform, + rectInTable, + ); + } + + void _activateCell(int row, int column) { + final next = (row: row, column: column); + if (_activeCell == next) { + return; + } + setState(() => _activeCell = next); + } + int _columnCount(List<BusyBlock> rows) { var count = 1; for (final row in rows) { @@ -1633,29 +1833,25 @@ enum _TableControlAction { delete, } -class _TableCornerCell extends StatelessWidget { - const _TableCornerCell({required this.onTableDeleted}); +class _TableDeleteControl extends StatelessWidget { + const _TableDeleteControl({super.key, required this.onTableDeleted}); final VoidCallback onTableDeleted; @override Widget build(BuildContext context) { final colors = BusyMarkSurfaceColors.of(context); - return SizedBox.square( - dimension: _TableBlockEditor._controlSize, - child: BusyMarkHeaderIconButton( - tooltip: context.l10n.deleteTable, - icon: BusyMarkGlyphs.delete, - foregroundColor: colors.mutedForeground, - borderRadius: BusyMarkRadius.sm, - onPressed: onTableDeleted, - ), + return BusyMarkHeaderIconButton( + tooltip: context.l10n.deleteTable, + icon: BusyMarkGlyphs.delete, + foregroundColor: colors.mutedForeground, + onPressed: onTableDeleted, ); } } -class _TableColumnControlCell extends StatelessWidget { - const _TableColumnControlCell({ +class _TableColumnControl extends StatelessWidget { + const _TableColumnControl({ required this.columnIndex, required this.alignment, required this.onInserted, @@ -1707,8 +1903,8 @@ class _TableColumnControlCell extends StatelessWidget { } } -class _TableRowControlCell extends StatelessWidget { - const _TableRowControlCell({ +class _TableRowControl extends StatelessWidget { + const _TableRowControl({ required this.rowIndex, required this.onInserted, required this.onDeleted, @@ -1769,45 +1965,46 @@ class _TableControlMenuButton extends StatelessWidget { @override Widget build(BuildContext context) { - return BusyMarkHeaderPopupMenuButton<_TableControlAction>( - tooltip: tooltip, - icon: icon, - itemBuilder: (context) => [ + final items = <PopupMenuEntry<_TableControlAction>>[ + BusyMarkPopupMenuItem( + value: _TableControlAction.insertBefore, + label: beforeLabel, + ), + BusyMarkPopupMenuItem( + value: _TableControlAction.insertAfter, + label: afterLabel, + ), + if (alignmentLabels case final labels?) ...[ BusyMarkPopupMenuItem( - value: _TableControlAction.insertBefore, - label: beforeLabel, + value: _TableControlAction.alignUnspecified, + label: labels.unspecified, + checked: alignment == BusyTableAlignment.unspecified, ), BusyMarkPopupMenuItem( - value: _TableControlAction.insertAfter, - label: afterLabel, + value: _TableControlAction.alignLeft, + label: labels.left, + checked: alignment == BusyTableAlignment.left, ), - if (alignmentLabels case final labels?) ...[ - BusyMarkPopupMenuItem( - value: _TableControlAction.alignUnspecified, - label: labels.unspecified, - checked: alignment == BusyTableAlignment.unspecified, - ), - BusyMarkPopupMenuItem( - value: _TableControlAction.alignLeft, - label: labels.left, - checked: alignment == BusyTableAlignment.left, - ), - BusyMarkPopupMenuItem( - value: _TableControlAction.alignCenter, - label: labels.center, - checked: alignment == BusyTableAlignment.center, - ), - BusyMarkPopupMenuItem( - value: _TableControlAction.alignRight, - label: labels.right, - checked: alignment == BusyTableAlignment.right, - ), - ], BusyMarkPopupMenuItem( - value: _TableControlAction.delete, - label: deleteLabel, + value: _TableControlAction.alignCenter, + label: labels.center, + checked: alignment == BusyTableAlignment.center, + ), + BusyMarkPopupMenuItem( + value: _TableControlAction.alignRight, + label: labels.right, + checked: alignment == BusyTableAlignment.right, ), ], + BusyMarkPopupMenuItem( + value: _TableControlAction.delete, + label: deleteLabel, + ), + ]; + return BusyMarkHeaderPopupMenuButton<_TableControlAction>( + tooltip: tooltip, + icon: icon, + itemBuilder: (_) => items, onSelected: onSelected, ); } @@ -1859,8 +2056,8 @@ class _TableCellEditor extends StatefulWidget { } class _TableCellEditorState extends State<_TableCellEditor> { - late final TextEditingController _controller; - late final FocusNode _focusNode; + late TextEditingController _controller; + late FocusNode _focusNode; late bool _ownsController; late bool _ownsFocusNode; bool _sourceEditing = false; diff --git a/lib/src/writerside/writerside_table_view.dart b/lib/src/writerside/writerside_table_view.dart index 404fffb2..cf72bcc1 100644 --- a/lib/src/writerside/writerside_table_view.dart +++ b/lib/src/writerside/writerside_table_view.dart @@ -4,6 +4,7 @@ import 'package:flutter/rendering.dart'; import '../markdown/preview_model.dart'; import '../app/localization.dart'; +import '../app/busymark_design.dart'; import '../app/busymark_glyphs.dart'; import '../markdown/table_grid.dart'; @@ -73,7 +74,9 @@ class _WritersideTableViewState extends State<WritersideTableView> { padding: const EdgeInsets.symmetric(vertical: 12), child: _TableLayout( grid: grid, - fixed: widget.block.attributes['column-width'] == 'fixed', + fixed: + widget.block.attributes['element'] != 'table' || + widget.block.attributes['column-width'] == 'fixed', sticky: widget.block.attributes['sticky-header'] == 'true' && rows.first.attributes['header'] == 'true', @@ -97,10 +100,13 @@ class _WritersideTableViewState extends State<WritersideTableView> { color: header ? scheme.surfaceContainerHighest : scheme.surface, - border: Border.all(color: scheme.outlineVariant, width: 0.5), + border: Border.all( + color: scheme.outlineVariant, + width: BusyMarkStroke.tableGrid, + ), ), child: Padding( - padding: const EdgeInsets.all(10), + padding: BusyMarkInsets.documentTableCell, child: sortable ? InkWell( onTap: () => setState(() { diff --git a/test/src/busymark_document_test.dart b/test/src/busymark_document_test.dart index dbdea9d6..bd0b4b0a 100644 --- a/test/src/busymark_document_test.dart +++ b/test/src/busymark_document_test.dart @@ -5998,6 +5998,7 @@ void main() {} final widgetTable = parsed.busyDocument.blocks.singleWhere( (block) => block.kind == BusyBlockKind.table, ); + final introBlockId = parsed.busyDocument.blocks.first.id; final headerCellId = widgetTable.children.first.children.first.id; final bodyCellId = widgetTable.children[1].children.first.id; @@ -6027,8 +6028,31 @@ void main() {} expect(deleteTableFinder, findsOneWidget); expect( find.descendant(of: tableFinder, matching: deleteTableFinder), - findsOneWidget, + findsNothing, + ); + final tableWidget = tester.widget<Table>(tableFinder); + final tableSizeBeforeControls = tester.getSize(tableFinder); + expect(tableWidget.children, hasLength(2)); + for (final row in tableWidget.children) { + expect(row.children, hasLength(2)); + } + expect( + tester.getSize(tableFinder).width, + tester + .getSize(find.byKey(ValueKey('wysiwyg-field-topic.md-$introBlockId'))) + .width, + ); + final tableScheme = Theme.of(tester.element(tableFinder)).colorScheme; + expect( + (tableWidget.children.first.decoration! as BoxDecoration).color, + tableScheme.surfaceContainerHighest, + ); + expect( + (tableWidget.children.last.decoration! as BoxDecoration).color, + tableScheme.surface, ); + expect(tableWidget.border!.top.color, tableScheme.outlineVariant); + expect(tableWidget.border!.top.width, BusyMarkStroke.tableGrid); final framedTableAncestors = <DecoratedBox>[]; tester.element(tableFinder).visitAncestorElements((element) { if (element.widget is BusyMarkWysiwygBlockField) { @@ -6041,10 +6065,10 @@ void main() {} }); expect(framedTableAncestors, isEmpty); expect(busyMarkWysiwygContentPadding(widgetTable), EdgeInsets.zero); - expect(find.byTooltip('Column 1'), findsOneWidget); - expect(find.byTooltip('Column 2'), findsOneWidget); - expect(find.byTooltip('Row 1'), findsOneWidget); - expect(find.byTooltip('Row 2'), findsOneWidget); + expect(find.byTooltip('Column 1'), findsNothing); + expect(find.byTooltip('Column 2'), findsNothing); + expect(find.byTooltip('Row 1'), findsNothing); + expect(find.byTooltip('Row 2'), findsNothing); final headerField = tester.widget<TextField>( find.byKey(ValueKey(headerCellId)), @@ -6063,8 +6087,51 @@ void main() {} BusyMarkDocumentTextGeometry.selectionHeightStyle, ); + final mouse = await tester.createGesture(kind: PointerDeviceKind.mouse); + await mouse.addPointer( + location: tester.getCenter(find.byKey(ValueKey(headerCellId))), + ); + await tester.pump(); + expect(find.byTooltip('Column 1'), findsOneWidget); + expect(find.byTooltip('Row 1'), findsOneWidget); + expect(find.byTooltip('Column 2'), findsNothing); + expect(find.byTooltip('Row 2'), findsNothing); + expect(tester.getSize(tableFinder), tableSizeBeforeControls); + for (final tooltip in ['Delete table', 'Column 1', 'Row 1']) { + expect( + tester.getSize(find.byTooltip(tooltip)), + const Size.square(BusyMarkSizes.iconButton), + ); + } + final tableRect = tester.getRect(tableFinder); + final deleteRect = tester.getRect(find.byTooltip('Delete table')); + final columnRect = tester.getRect(find.byTooltip('Column 1')); + final rowRect = tester.getRect(find.byTooltip('Row 1')); + expect( + deleteRect.left, + greaterThanOrEqualTo(tableRect.right + BusyMarkSpacing.xs), + ); + expect( + deleteRect.bottom, + lessThanOrEqualTo(tableRect.top - BusyMarkSpacing.xs), + ); + expect( + columnRect.bottom, + lessThanOrEqualTo(tableRect.top - BusyMarkSpacing.xs), + ); + expect( + rowRect.right, + lessThanOrEqualTo(tableRect.left - BusyMarkSpacing.xs), + ); + + await mouse.moveTo(tester.getCenter(find.byTooltip('Column 1'))); + await tester.pump(const Duration(seconds: 1)); + expect(find.text('Column 1'), findsOneWidget); + expect(tester.takeException(), isNull); + headerField.onChanged!('Name'); await tester.pump(); + expect(tester.takeException(), isNull); bodyField.onChanged!('Alice'); await tester.pump(); @@ -6101,6 +6168,66 @@ void main() {} expect(markdown, 'Intro\n'); }); + testWidgets('WYSIWYG table overlay menus survive structural rebuilds', ( + tester, + ) async { + final parsed = parser.parse( + filePath: 'topic.md', + source: '| A | B |\n| --- | --- |\n| a | b |\n', + ); + final headerCellId = + parsed.busyDocument.blocks.single.children.first.children.first.id; + var markdown = ''; + + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: SizedBox( + width: 900, + height: 640, + child: BusyMarkWysiwygEditor( + document: parsed.busyDocument, + onSourceChanged: (_, value) => markdown = value, + ), + ), + ), + ), + ); + await tester.pump(); + + final mouse = await tester.createGesture(kind: PointerDeviceKind.mouse); + await mouse.addPointer( + location: tester.getCenter(find.byKey(ValueKey(headerCellId))), + ); + await tester.pump(); + + await tester.tap(find.byTooltip('Row 1')); + await tester.pumpAndSettle(); + await tester.tap(find.text('Insert row below')); + await tester.pumpAndSettle(); + expect(tester.takeException(), isNull); + expect(find.byType(TextField), findsNWidgets(6)); + + await mouse.moveTo(const Offset(1, 1)); + await mouse.moveTo(tester.getCenter(find.byKey(ValueKey(headerCellId)))); + await tester.pump(); + await tester.tap(find.byTooltip('Column 1')); + await tester.pumpAndSettle(); + await tester.tap(find.text('Insert column right')); + await tester.pumpAndSettle(); + expect(tester.takeException(), isNull); + expect(find.byType(TextField), findsNWidgets(9)); + expect(markdown, contains('| A | | B |')); + final columnWidths = tester.widget<Table>(find.byType(Table)).columnWidths!; + expect(columnWidths, hasLength(3)); + for (final width in columnWidths.values) { + expect(width, isA<FlexColumnWidth>()); + expect((width as FlexColumnWidth).value, 1); + } + }); + test('WYSIWYG list indent outdent and task toggle commands serialize', () { final parsed = parser.parse( filePath: 'topic.md', diff --git a/test/src/editor_ui_primitives_audit_test.dart b/test/src/editor_ui_primitives_audit_test.dart index 78b89903..88f1fced 100644 --- a/test/src/editor_ui_primitives_audit_test.dart +++ b/test/src/editor_ui_primitives_audit_test.dart @@ -44,7 +44,7 @@ void main() { r'class _RenderedHtmlBlock[\s\S]*?class _RenderedHtmlBlocks', ).firstMatch(widgets)!.group(0)!; final tableEditor = RegExp( - r'class _TableBlockEditor[\s\S]*?class _TableColumnControlCell', + r'class _TableBlockEditor[\s\S]*?enum _TableControlAction', ).firstMatch(widgets)!.group(0)!; final tableMenu = RegExp( r'class _TableControlMenuButton[\s\S]*?class _TableCellEditor', @@ -52,8 +52,17 @@ void main() { expect(htmlBlock, contains('BusyMarkHeaderIconButton(')); expect(htmlBlock, isNot(matches(RegExp(r'(?<![A-Za-z])IconButton\(')))); - expect(tableEditor, contains('BusyMarkHeaderIconButton(')); - expect(tableMenu, contains('BusyMarkHeaderPopupMenuButton')); + expect(tableEditor, contains('OverlayPortal.overlayChildLayoutBuilder(')); + expect(tableEditor, isNot(contains('CompositedTransformFollower('))); + expect(tableEditor, isNot(contains('GlobalKey()'))); + expect(tableEditor, contains('_TableDeleteControl(')); + expect(tableEditor, isNot(contains('SingleChildScrollView('))); + expect(tableEditor, isNot(contains('FixedColumnWidth('))); + expect( + tableMenu, + contains('BusyMarkHeaderPopupMenuButton<_TableControlAction>'), + ); + expect(tableMenu, isNot(contains('BusyMarkCompactIconButton('))); expect(RegExp(r'BusyMarkPopupMenuItem\(').allMatches(tableMenu).length, 7); expect(tableMenu, contains('_TableControlAction.alignUnspecified')); expect(tableMenu, contains('_TableControlAction.alignLeft')); diff --git a/test/src/localization_audit_test.dart b/test/src/localization_audit_test.dart index 0da992ca..008f9d14 100644 --- a/test/src/localization_audit_test.dart +++ b/test/src/localization_audit_test.dart @@ -447,6 +447,10 @@ void main() { expect(portuguese.file, 'Ficheiro'); expect(portuguese.link, 'Ligação'); expect(portuguese.exportReset, 'Restaurar predefinições'); + expect( + portuguese.aiCloudConsentRequired('Acme AI'), + 'Primeiro, confirme a partilha de dados com Acme AI em Definições → IA.', + ); final brazilian = lookupAppLocalizations(const Locale('pt', 'BR')); expect(brazilian.file, 'Arquivo'); expect(brazilian.link, 'Link'); @@ -481,17 +485,23 @@ void main() { expect(chinese.workspaceRecoveryRestored(3), '已恢复 3 个未保存的文档。请在保存或放弃前逐一检查。'); }); - test('Russian and Ukrainian count messages preserve the supplied count', () { - const counts = <int>[1, 2, 5, 11, 21, 22, 31]; - final localizations = <String, AppLocalizations>{ - 'ru': lookupAppLocalizations(const Locale('ru')), - 'uk': lookupAppLocalizations(const Locale('uk')), + test('Russian and Ukrainian count messages render every reviewed form', () { + const counts = <int>[1, 2, 5, 11, 21, 22, 31, 101]; + final localizations = <String, (AppLocalizations, _ExpectedMessages)>{ + 'ru': ( + lookupAppLocalizations(const Locale('ru')), + _expectedRussianMessages, + ), + 'uk': ( + lookupAppLocalizations(const Locale('uk')), + _expectedUkrainianMessages, + ), }; for (final localeEntry in localizations.entries) { - final l10n = localeEntry.value; + final (l10n, expectedMessages) = localeEntry.value; for (final count in counts) { - final messages = <String, String>{ + final actual = <String, String>{ 'unsavedChangesMultipleMessage': l10n.unsavedChangesMultipleMessage( count, ), @@ -508,39 +518,13 @@ void main() { 'gitConfirmDiscardUntracked': l10n.gitConfirmDiscardUntracked(count), 'gitConfirmDiscardMixed': l10n.gitConfirmDiscardMixed(count), }; - for (final messageEntry in messages.entries) { - expect( - messageEntry.value, - contains('$count'), - reason: - '${localeEntry.key}.${messageEntry.key} must display $count', - ); - } expect( - l10n.unsavedChangesMultipleMessage(count), - endsWith('?'), - reason: '${localeEntry.key} must preserve the save question', + actual, + expectedMessages(count), + reason: '${localeEntry.key} messages for count $count', ); } } - - final russian = localizations['ru']!; - expect(russian.usageCount(1), '1 использование'); - expect(russian.usageCount(2), '2 использования'); - expect(russian.usageCount(5), '5 использований'); - expect(russian.usageCount(11), '11 использований'); - expect(russian.usageCount(21), '21 использование'); - expect(russian.usageCount(22), '22 использования'); - expect(russian.usageCount(31), '31 использование'); - - final ukrainian = localizations['uk']!; - expect(ukrainian.usageCount(1), '1 використання'); - expect(ukrainian.usageCount(2), '2 використання'); - expect(ukrainian.usageCount(5), '5 використань'); - expect(ukrainian.usageCount(11), '11 використань'); - expect(ukrainian.usageCount(21), '21 використання'); - expect(ukrainian.usageCount(22), '22 використання'); - expect(ukrainian.usageCount(31), '31 використання'); }); test('Portuguese count messages distinguish singular and plural', () { @@ -569,6 +553,10 @@ void main() { } final portuguese = locales['pt']!; + expect( + portuguese.aiContextDisclosure(0), + 'O fornecedor selecionado receberá 0 carateres do contexto apresentado.', + ); expect( portuguese.aiContextDisclosure(1), 'O fornecedor selecionado receberá 1 caráter do contexto apresentado.', @@ -579,6 +567,10 @@ void main() { ); final brazilian = locales['pt-BR']!; + expect( + brazilian.aiContextDisclosure(0), + 'O provedor selecionado receberá 0 caracteres do contexto exibido.', + ); expect( brazilian.aiContextDisclosure(1), 'O provedor selecionado receberá 1 caractere do contexto exibido.', @@ -591,12 +583,18 @@ void main() { test('Hindi unsaved-document prompt uses saved-state terminology', () { final hindi = lookupAppLocalizations(const Locale('hi')); - for (final count in <int>[1, 2]) { - final message = hindi.unsavedChangesMultipleMessage(count); - expect(message, contains('न सहेजे गए बदलाव')); - expect(message, isNot(contains('असुरक्षित बदलाव'))); - expect(message, endsWith('?')); - } + expect( + hindi.unsavedChangesMultipleMessage(0), + '0 दस्तावेज़ों में न सहेजे गए बदलाव हैं। जारी रखने से पहले उन्हें सहेजें?', + ); + expect( + hindi.unsavedChangesMultipleMessage(1), + '1 दस्तावेज़ में न सहेजे गए बदलाव हैं। जारी रखने से पहले इसे सहेजें?', + ); + expect( + hindi.unsavedChangesMultipleMessage(2), + '2 दस्तावेज़ों में न सहेजे गए बदलाव हैं। जारी रखने से पहले उन्हें सहेजें?', + ); }); test('RTL translations isolate technical interpolations', () { @@ -762,6 +760,159 @@ void main() { }); } +typedef _ExpectedMessages = Map<String, String> Function(int count); + +enum _SlavicPluralForm { one, few, many } + +_SlavicPluralForm _reviewedSlavicForm(int count) { + if (const <int>{1, 21, 31, 101}.contains(count)) { + return _SlavicPluralForm.one; + } + if (const <int>{2, 22}.contains(count)) { + return _SlavicPluralForm.few; + } + if (const <int>{5, 11}.contains(count)) { + return _SlavicPluralForm.many; + } + throw ArgumentError.value(count, 'count', 'No reviewed expected form'); +} + +Map<String, String> _expectedRussianMessages(int count) { + switch (_reviewedSlavicForm(count)) { + case _SlavicPluralForm.one: + return <String, String>{ + 'unsavedChangesMultipleMessage': + '$count документ содержит несохранённые изменения. Сохранить каждый перед продолжением?', + 'childTopicsPromoted': + '$count дочерняя тема будет перемещена на уровень выше.', + 'usageCount': '$count использование', + 'workspaceRecoveryRestored': + 'Восстановлен $count несохранённый документ. Проверьте каждый документ, прежде чем сохранить или отбросить его.', + 'workspaceRecoveryDamaged': + 'Не удалось восстановить $count повреждённую запись восстановления. Исходный файл восстановления сохранён для проверки; корректные записи остаются доступны.', + 'gitStagedFileCount': '$count файл в индексе', + 'pdfExportedWithWarnings': + 'document.pdf экспортирован с $count предупреждением.', + 'gitConfirmDiscardTracked': + 'Все проиндексированные и непроиндексированные изменения в $count выбранном отслеживаемом файле будут отменены, а содержимое будет восстановлено до состояния HEAD.', + 'gitConfirmDiscardUntracked': + 'Будет удалён $count выбранный неотслеживаемый файл.', + 'gitConfirmDiscardMixed': + '$count выбранный файл будет восстановлен или удалён в зависимости от статуса Git.', + }; + case _SlavicPluralForm.few: + return <String, String>{ + 'unsavedChangesMultipleMessage': + '$count документа содержат несохранённые изменения. Сохранить каждый перед продолжением?', + 'childTopicsPromoted': + '$count дочерние темы будут перемещены на уровень выше.', + 'usageCount': '$count использования', + 'workspaceRecoveryRestored': + 'Восстановлено $count несохранённых документа. Проверьте каждый документ, прежде чем сохранить или отбросить его.', + 'workspaceRecoveryDamaged': + 'Не удалось восстановить $count повреждённые записи восстановления. Исходный файл восстановления сохранён для проверки; корректные записи остаются доступны.', + 'gitStagedFileCount': '$count файла в индексе', + 'pdfExportedWithWarnings': + 'document.pdf экспортирован с $count предупреждениями.', + 'gitConfirmDiscardTracked': + 'Все проиндексированные и непроиндексированные изменения в $count выбранных отслеживаемых файлах будут отменены, а файлы будут восстановлены до состояния HEAD.', + 'gitConfirmDiscardUntracked': + 'Будут удалены $count выбранных неотслеживаемых файла.', + 'gitConfirmDiscardMixed': + '$count выбранных файла будут восстановлены или удалены в зависимости от их статуса Git.', + }; + case _SlavicPluralForm.many: + return <String, String>{ + 'unsavedChangesMultipleMessage': + '$count документов содержат несохранённые изменения. Сохранить каждый перед продолжением?', + 'childTopicsPromoted': + '$count дочерних тем будут перемещены на уровень выше.', + 'usageCount': '$count использований', + 'workspaceRecoveryRestored': + 'Восстановлено $count несохранённых документов. Проверьте каждый документ, прежде чем сохранить или отбросить его.', + 'workspaceRecoveryDamaged': + 'Не удалось восстановить $count повреждённых записей восстановления. Исходный файл восстановления сохранён для проверки; корректные записи остаются доступны.', + 'gitStagedFileCount': '$count файлов в индексе', + 'pdfExportedWithWarnings': + 'document.pdf экспортирован с $count предупреждениями.', + 'gitConfirmDiscardTracked': + 'Все проиндексированные и непроиндексированные изменения в $count выбранных отслеживаемых файлах будут отменены, а файлы будут восстановлены до состояния HEAD.', + 'gitConfirmDiscardUntracked': + 'Будут удалены $count выбранных неотслеживаемых файлов.', + 'gitConfirmDiscardMixed': + '$count выбранных файлов будут восстановлены или удалены в зависимости от их статуса Git.', + }; + } +} + +Map<String, String> _expectedUkrainianMessages(int count) { + switch (_reviewedSlavicForm(count)) { + case _SlavicPluralForm.one: + return <String, String>{ + 'unsavedChangesMultipleMessage': + '$count документ має незбережені зміни. Зберегти кожен перед продовженням?', + 'childTopicsPromoted': + '$count дочірню тему буде переміщено на рівень вище.', + 'usageCount': '$count використання', + 'workspaceRecoveryRestored': + 'Відновлено $count незбережений документ. Перегляньте кожен документ, перш ніж зберегти або відхилити його.', + 'workspaceRecoveryDamaged': + 'Не вдалося відновити $count пошкоджений запис відновлення. Оригінальний файл відновлення збережено для перевірки; дійсні записи залишаються доступними.', + 'gitStagedFileCount': '$count проіндексований файл', + 'pdfExportedWithWarnings': + 'document.pdf експортовано з $count попередженням.', + 'gitConfirmDiscardTracked': + 'Усі індексовані та неіндексовані зміни в $count вибраному файлі з відстеженням буде скасовано, а вміст буде відновлено до стану HEAD.', + 'gitConfirmDiscardUntracked': + '$count вибраний невідстежуваний файл буде видалено.', + 'gitConfirmDiscardMixed': + '$count вибраний файл буде відновлено або видалено залежно від статусу Git.', + }; + case _SlavicPluralForm.few: + return <String, String>{ + 'unsavedChangesMultipleMessage': + '$count документи мають незбережені зміни. Зберегти кожен перед продовженням?', + 'childTopicsPromoted': + '$count дочірні теми буде переміщено на рівень вище.', + 'usageCount': '$count використання', + 'workspaceRecoveryRestored': + 'Відновлено $count незбережені документи. Перегляньте кожен документ, перш ніж зберегти або відхилити його.', + 'workspaceRecoveryDamaged': + 'Не вдалося відновити $count пошкоджені записи відновлення. Оригінальний файл відновлення збережено для перевірки; дійсні записи залишаються доступними.', + 'gitStagedFileCount': '$count проіндексовані файли', + 'pdfExportedWithWarnings': + 'document.pdf експортовано з $count попередженнями.', + 'gitConfirmDiscardTracked': + 'Усі індексовані та неіндексовані зміни у $count вибраних файлах з відстеженням буде скасовано, а файли буде відновлено до стану HEAD.', + 'gitConfirmDiscardUntracked': + '$count вибрані невідстежувані файли буде видалено.', + 'gitConfirmDiscardMixed': + '$count вибрані файли буде відновлено або видалено залежно від їхнього статусу Git.', + }; + case _SlavicPluralForm.many: + return <String, String>{ + 'unsavedChangesMultipleMessage': + '$count документів мають незбережені зміни. Зберегти кожен перед продовженням?', + 'childTopicsPromoted': + '$count дочірніх тем буде переміщено на рівень вище.', + 'usageCount': '$count використань', + 'workspaceRecoveryRestored': + 'Відновлено $count незбережених документів. Перегляньте кожен документ, перш ніж зберегти або відхилити його.', + 'workspaceRecoveryDamaged': + 'Не вдалося відновити $count пошкоджених записів відновлення. Оригінальний файл відновлення збережено для перевірки; дійсні записи залишаються доступними.', + 'gitStagedFileCount': '$count проіндексованих файлів', + 'pdfExportedWithWarnings': + 'document.pdf експортовано з $count попередженнями.', + 'gitConfirmDiscardTracked': + 'Усі індексовані та неіндексовані зміни у $count вибраних файлах з відстеженням буде скасовано, а файли буде відновлено до стану HEAD.', + 'gitConfirmDiscardUntracked': + '$count вибраних невідстежуваних файлів буде видалено.', + 'gitConfirmDiscardMixed': + '$count вибраних файлів буде відновлено або видалено залежно від їхнього статусу Git.', + }; + } +} + class _LiteralPattern { const _LiteralPattern(this.name, this.source, {this.dotAll = false}); diff --git a/test/src/source_audit_test.dart b/test/src/source_audit_test.dart index 52426439..81c4b64f 100644 --- a/test/src/source_audit_test.dart +++ b/test/src/source_audit_test.dart @@ -1782,7 +1782,11 @@ void main() { final tableControlMenu = RegExp( r'class _TableControlMenuButton[\s\S]*?class _TableCellEditor', ).firstMatch(blockWidgets)!.group(0)!; - expect(tableControlMenu, contains('BusyMarkHeaderPopupMenuButton')); + expect( + tableControlMenu, + contains('BusyMarkHeaderPopupMenuButton<_TableControlAction>'), + ); + expect(tableControlMenu, isNot(contains('BusyMarkCompactIconButton('))); expect(tableControlMenu, isNot(contains('theme.copyWith'))); expect(tableControlMenu, isNot(contains('color: colors.popover'))); expect(tableControlMenu, isNot(contains('elevation: BusyMarkElevation'))); diff --git a/test/src/writerside_semantic_widgets_test.dart b/test/src/writerside_semantic_widgets_test.dart index 404c6c45..8d8a6c22 100644 --- a/test/src/writerside_semantic_widgets_test.dart +++ b/test/src/writerside_semantic_widgets_test.dart @@ -145,6 +145,118 @@ void main() { expect(tester.takeException(), isNull); }); + testWidgets('Markdown table keeps empty columns equal width', (tester) async { + final block = PreviewBlock( + kind: PreviewBlockKind.table, + text: '', + children: [ + const PreviewBlock( + kind: PreviewBlockKind.table, + text: '', + attributes: {'header': 'true'}, + children: [ + PreviewBlock( + kind: PreviewBlockKind.paragraph, + text: 'Short', + attributes: {'test-id': 'first'}, + ), + PreviewBlock( + kind: PreviewBlockKind.paragraph, + text: '', + attributes: {'test-id': 'empty'}, + ), + PreviewBlock( + kind: PreviewBlockKind.paragraph, + text: 'A much longer heading', + attributes: {'test-id': 'last'}, + ), + ], + ), + ], + ); + + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: SizedBox( + width: 600, + child: WritersideTableView( + block: block, + cellBuilder: (cell, _) => SizedBox( + key: ValueKey<String>(cell.attributes['test-id']!), + width: double.infinity, + child: Text(cell.text), + ), + ), + ), + ), + ), + ); + + final widths = [ + for (final id in ['first', 'empty', 'last']) + tester.getSize(find.byKey(ValueKey(id))).width, + ]; + expect(widths[1], closeTo(widths[0], 0.01)); + expect(widths[2], closeTo(widths[0], 0.01)); + }); + + testWidgets('Writerside table preserves declared column width', ( + tester, + ) async { + const block = PreviewBlock( + kind: PreviewBlockKind.table, + text: '', + attributes: {'element': 'table', 'column-width': 'fixed'}, + children: [ + PreviewBlock( + kind: PreviewBlockKind.table, + text: '', + attributes: {'header': 'true'}, + children: [ + PreviewBlock( + kind: PreviewBlockKind.paragraph, + text: 'Fixed', + attributes: {'width': '120', 'test-id': 'fixed'}, + ), + PreviewBlock( + kind: PreviewBlockKind.paragraph, + text: 'Remaining', + attributes: {'test-id': 'remaining'}, + ), + ], + ), + ], + ); + + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: SizedBox( + width: 600, + child: WritersideTableView( + block: block, + cellBuilder: (cell, _) => SizedBox( + key: ValueKey<String>(cell.attributes['test-id']!), + width: double.infinity, + child: Text(cell.text), + ), + ), + ), + ), + ), + ); + + expect( + tester.getSize(find.byKey(const ValueKey('fixed'))).width, + lessThan(tester.getSize(find.byKey(const ValueKey('remaining'))).width), + ); + }); + testWidgets('table spans preserve geometry and sticky header position', ( tester, ) async { From e18dee142c02e3f2435014eb9ca87b00908684f9 Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Tue, 8 Sep 2026 14:46:15 -0700 Subject: [PATCH 29/37] Implement traversal through a table in Editor view --- lib/src/editor/wysiwyg/wysiwyg_editor.dart | 65 +++++++++++++++++++ test/src/busymark_document_test.dart | 72 ++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/lib/src/editor/wysiwyg/wysiwyg_editor.dart b/lib/src/editor/wysiwyg/wysiwyg_editor.dart index 2a2eedbe..78497775 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_editor.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_editor.dart @@ -2720,6 +2720,15 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { } _setActiveTableCell(tableBlockId, cellId); final keyboard = HardwareKeyboard.instance; + if (event is KeyDownEvent && + event.logicalKey == LogicalKeyboardKey.tab && + !_hasCommandModifierPressed()) { + return _moveTableCellFocus( + tableBlockId, + cellId, + backwards: keyboard.isShiftPressed, + ); + } final commands = BusyMarkCommandRegistryScope.read(context) ?? BusyMarkCommandCatalog.metadata; @@ -2794,6 +2803,62 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { return KeyEventResult.ignored; } + KeyEventResult _moveTableCellFocus( + String tableBlockId, + String cellId, { + required bool backwards, + }) { + final table = _documentController.blockById(tableBlockId); + if (table == null || table.kind != BusyBlockKind.table) { + return KeyEventResult.ignored; + } + final cells = [ + for (final row in table.children) + for (final cell in row.children) cell, + ]; + final currentIndex = cells.indexWhere((cell) => cell.id == cellId); + if (currentIndex < 0) { + return KeyEventResult.ignored; + } + + final targetIndex = currentIndex + (backwards ? -1 : 1); + if (targetIndex >= 0 && targetIndex < cells.length) { + final target = cells[targetIndex]; + final controller = _tableCellControllers[target.id]; + final focusNode = _tableCellFocusNodes[target.id]; + if (controller == null || focusNode == null) { + return KeyEventResult.ignored; + } + _setActiveTableCell(tableBlockId, target.id); + controller.selection = TextSelection.collapsed( + offset: backwards ? controller.text.length : 0, + ); + focusNode.requestFocus(); + return KeyEventResult.handled; + } + if (backwards || table.children.isEmpty) { + return KeyEventResult.ignored; + } + + _clearBlockSelection(); + _recordUndoSnapshot(); + _documentController.insertTableRow( + tableBlockId, + table.children.length - 1, + after: true, + ); + final updatedTable = _documentController.blockById(tableBlockId); + final newRow = updatedTable?.children.lastOrNull; + final firstNewCell = newRow?.children.firstOrNull; + if (firstNewCell == null) { + return KeyEventResult.ignored; + } + _setActiveTableCell(tableBlockId, firstNewCell.id); + _emitMarkdown(); + _focusTextTargetAfterFrame(firstNewCell.id, offset: 0); + return KeyEventResult.handled; + } + bool _hasCommandModifierPressed() { final keyboard = HardwareKeyboard.instance; return keyboard.isControlPressed || diff --git a/test/src/busymark_document_test.dart b/test/src/busymark_document_test.dart index bd0b4b0a..8fae2b0d 100644 --- a/test/src/busymark_document_test.dart +++ b/test/src/busymark_document_test.dart @@ -6228,6 +6228,78 @@ void main() {} } }); + testWidgets('Tab travels through WYSIWYG table cells and extends the table', ( + tester, + ) async { + final parsed = parser.parse( + filePath: 'topic.md', + source: '| A | B |\n| --- | --- |\n| a | b |\n', + ); + final table = parsed.busyDocument.blocks.single; + final cellIds = [ + for (final row in table.children) + for (final cell in row.children) cell.id, + ]; + var markdown = ''; + + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: SizedBox( + width: 900, + height: 640, + child: BusyMarkWysiwygEditor( + document: parsed.busyDocument, + onSourceChanged: (_, value) => markdown = value, + ), + ), + ), + ), + ); + await tester.pump(); + + TextField cellField(String cellId) => + tester.widget<TextField>(find.byKey(ValueKey(cellId))); + + cellField(cellIds[0]).focusNode!.requestFocus(); + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + expect(cellField(cellIds[1]).focusNode!.hasFocus, isTrue); + await tester.pump(); + + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + expect(cellField(cellIds[2]).focusNode!.hasFocus, isTrue); + await tester.pump(); + + await tester.sendKeyDownEvent(LogicalKeyboardKey.shiftLeft); + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.sendKeyUpEvent(LogicalKeyboardKey.shiftLeft); + expect(cellField(cellIds[1]).focusNode!.hasFocus, isTrue); + await tester.pump(); + + cellField(cellIds.last).focusNode!.requestFocus(); + await tester.pump(); + await tester.sendKeyEvent(LogicalKeyboardKey.tab); + await tester.pump(); + await tester.pump(); + + final tableFields = tester + .widgetList<TextField>( + find.descendant( + of: find.byType(Table), + matching: find.byType(TextField), + ), + ) + .toList(); + expect(tableFields, hasLength(6)); + expect(tableFields[4].focusNode!.hasFocus, isTrue); + expect(tableFields[5].focusNode!.hasFocus, isFalse); + expect(markdown, contains('| | |')); + expect(tester.takeException(), isNull); + }); + test('WYSIWYG list indent outdent and task toggle commands serialize', () { final parsed = parser.parse( filePath: 'topic.md', From 9b211136d9e16fcff7681ae4a99fff28b0227b8f Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Tue, 8 Sep 2026 15:13:25 -0700 Subject: [PATCH 30/37] Implemented table-size picker --- lib/src/app/busymark_design.dart | 4 + lib/src/editor/wysiwyg/wysiwyg_editor.dart | 332 +++++++++++++++++++-- test/src/busymark_document_test.dart | 135 +++++++++ 3 files changed, 448 insertions(+), 23 deletions(-) diff --git a/lib/src/app/busymark_design.dart b/lib/src/app/busymark_design.dart index 61e244a2..6ca84c9b 100644 --- a/lib/src/app/busymark_design.dart +++ b/lib/src/app/busymark_design.dart @@ -109,6 +109,7 @@ abstract final class BusyMarkSizes { BusyMarkSpacing.sm + wysiwygToolbarReserve + BusyMarkSpacing.sm; static const double wysiwygPrefixWidth = 30; static const double tableDialogWidth = 360; + static const double tablePickerHeight = 224; static const double tableMinWidth = 360; static const double markerDot = 6; static const double listMarkerTopInset = 7; @@ -2036,6 +2037,7 @@ class BusyMarkGroupedTextEntry extends StatefulWidget { this.autofocus = false, this.focusNode, this.keyboardType, + this.inputFormatters, this.minLines = 1, this.maxLines = 1, this.textInputAction, @@ -2061,6 +2063,7 @@ class BusyMarkGroupedTextEntry extends StatefulWidget { final bool autofocus; final FocusNode? focusNode; final TextInputType? keyboardType; + final List<TextInputFormatter>? inputFormatters; final int minLines; final int maxLines; final TextInputAction? textInputAction; @@ -2110,6 +2113,7 @@ class _BusyMarkGroupedTextEntryState extends State<BusyMarkGroupedTextEntry> { autofocus: widget.autofocus, focusNode: widget.focusNode, keyboardType: widget.keyboardType, + inputFormatters: widget.inputFormatters, minLines: widget.minLines, maxLines: widget.maxLines, textInputAction: widget.textInputAction, diff --git a/lib/src/editor/wysiwyg/wysiwyg_editor.dart b/lib/src/editor/wysiwyg/wysiwyg_editor.dart index 78497775..48683671 100644 --- a/lib/src/editor/wysiwyg/wysiwyg_editor.dart +++ b/lib/src/editor/wysiwyg/wysiwyg_editor.dart @@ -4792,6 +4792,7 @@ class _BusyMarkWysiwygEditorState extends State<BusyMarkWysiwygEditor> { }) { return _showEditorDialog<_TableDialogResult>( context, + maxWidth: BusyMarkSizes.tableDialogWidth, builder: (context) => _TableDialog( initialColumns: initialColumns, initialRows: initialRows, @@ -7045,6 +7046,16 @@ class _TableDialogResult { final int rows; } +abstract final class BusyMarkTableDialogKeys { + static const grid = ValueKey<String>('wysiwyg-table-size-grid'); + static const columns = ValueKey<String>('wysiwyg-table-columns-field'); + static const rows = ValueKey<String>('wysiwyg-table-rows-field'); + static const submit = ValueKey<String>('wysiwyg-table-submit'); + + static ValueKey<String> gridCell({required int columns, required int rows}) => + ValueKey<String>('wysiwyg-table-size-$columns-$rows'); +} + class _TableDialog extends StatefulWidget { const _TableDialog({required this.initialColumns, required this.initialRows}); @@ -7058,53 +7069,105 @@ class _TableDialog extends StatefulWidget { class _TableDialogState extends State<_TableDialog> { late final TextEditingController _columnsController; late final TextEditingController _rowsController; + late final FocusNode _rowsFocusNode; + late final FocusNode _gridFocusNode; + late final ScrollController _gridScrollController; + late int _selectedColumns; + late int _selectedRows; + int? _hoveredColumns; + int? _hoveredRows; + bool _gridFocused = false; @override void initState() { super.initState(); - _columnsController = TextEditingController( - text: - '${widget.initialColumns.clamp(BusyMarkSizes.tableMinColumns, BusyMarkSizes.tableMaxColumns)}', - ); - _rowsController = TextEditingController( - text: - '${widget.initialRows.clamp(BusyMarkSizes.tableMinRows, BusyMarkSizes.tableMaxRows)}', - ); + _selectedColumns = widget.initialColumns + .clamp(BusyMarkSizes.tableMinColumns, BusyMarkSizes.tableMaxColumns) + .toInt(); + _selectedRows = widget.initialRows + .clamp(BusyMarkSizes.tableMinRows, BusyMarkSizes.tableMaxRows) + .toInt(); + _columnsController = TextEditingController(text: '$_selectedColumns'); + _rowsController = TextEditingController(text: '$_selectedRows'); + _rowsFocusNode = FocusNode(debugLabel: 'BusyMark table rows'); + _gridFocusNode = FocusNode(debugLabel: 'BusyMark table size grid'); + _gridScrollController = ScrollController(); } @override void dispose() { _columnsController.dispose(); _rowsController.dispose(); + _rowsFocusNode.dispose(); + _gridFocusNode.dispose(); + _gridScrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { + final columns = _validDimension( + _columnsController, + min: BusyMarkSizes.tableMinColumns, + max: BusyMarkSizes.tableMaxColumns, + ); + final rows = _validDimension( + _rowsController, + min: BusyMarkSizes.tableMinRows, + max: BusyMarkSizes.tableMaxRows, + ); + final previewColumns = _hoveredColumns ?? _selectedColumns; + final previewRows = _hoveredRows ?? _selectedRows; return BusyMarkModalEditorScaffold( title: context.l10n.table, cancelLabel: context.l10n.cancel, saveLabel: context.l10n.insert, onCancel: () => Navigator.pop(context), - onSave: _submit, + saveKey: BusyMarkTableDialogKeys.submit, + onSave: columns != null && rows != null ? _submit : null, children: [ + _buildSizeGrid( + context, + previewColumns: previewColumns, + previewRows: previewRows, + ), + const SizedBox(height: BusyMarkSpacing.lg), BusyMarkGroupedList( filled: true, children: [ BusyMarkGroupedTextEntry( + key: BusyMarkTableDialogKeys.columns, label: context.l10n.columns, controller: _columnsController, autofocus: true, keyboardType: TextInputType.number, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], hintText: '2', - onSubmitted: (_) => _submit(), + errorText: columns == null + ? '${BusyMarkSizes.tableMinColumns}–${BusyMarkSizes.tableMaxColumns}' + : null, + textInputAction: TextInputAction.next, + onChanged: _handleColumnsChanged, + onSubmitted: (_) => _rowsFocusNode.requestFocus(), ), BusyMarkGroupedTextEntry( + key: BusyMarkTableDialogKeys.rows, label: context.l10n.rows, controller: _rowsController, + focusNode: _rowsFocusNode, keyboardType: TextInputType.number, + inputFormatters: [FilteringTextInputFormatter.digitsOnly], hintText: '2', - onSubmitted: (_) => _submit(), + errorText: rows == null + ? '${BusyMarkSizes.tableMinRows}–${BusyMarkSizes.tableMaxRows}' + : null, + textInputAction: TextInputAction.done, + onChanged: _handleRowsChanged, + onSubmitted: (_) { + if (_canSubmit) { + _submit(); + } + }, ), ], ), @@ -7113,19 +7176,242 @@ class _TableDialogState extends State<_TableDialog> { ); } - void _submit() { - final columns = int.tryParse(_columnsController.text.trim()) ?? 2; - final rows = int.tryParse(_rowsController.text.trim()) ?? 2; - Navigator.pop( - context, - _TableDialogResult( - columns: columns - .clamp(BusyMarkSizes.tableMinColumns, BusyMarkSizes.tableMaxColumns) - .toInt(), - rows: rows - .clamp(BusyMarkSizes.tableMinRows, BusyMarkSizes.tableMaxRows) - .toInt(), + Widget _buildSizeGrid( + BuildContext context, { + required int previewColumns, + required int previewRows, + }) { + final theme = Theme.of(context); + final colors = BusyMarkSurfaceColors.of(context); + return Semantics( + label: context.l10n.table, + value: + '${context.l10n.columns}: $_selectedColumns, ' + '${context.l10n.rows}: $_selectedRows', + child: Focus( + focusNode: _gridFocusNode, + onFocusChange: (focused) => setState(() => _gridFocused = focused), + onKeyEvent: _handleGridKeyEvent, + child: MouseRegion( + onExit: (_) => _clearGridPreview(), + child: DecoratedBox( + key: BusyMarkTableDialogKeys.grid, + decoration: BoxDecoration( + color: busyMarkGroupedSurfaceColor(context), + border: Border.all( + color: _gridFocused ? theme.colorScheme.primary : colors.border, + width: _gridFocused + ? BusyMarkStroke.focus + : BusyMarkStroke.hairline, + ), + borderRadius: BorderRadius.circular(BusyMarkRadius.lg), + ), + child: Padding( + padding: const EdgeInsets.all(BusyMarkSpacing.sm), + child: SizedBox( + height: BusyMarkSizes.tablePickerHeight, + child: Scrollbar( + controller: _gridScrollController, + thumbVisibility: true, + child: GridView.builder( + controller: _gridScrollController, + primary: false, + padding: const EdgeInsetsDirectional.only( + end: BusyMarkSpacing.sm, + ), + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: BusyMarkSizes.tableMaxColumns, + mainAxisSpacing: BusyMarkSpacing.xs, + crossAxisSpacing: BusyMarkSpacing.xs, + ), + itemCount: + BusyMarkSizes.tableMaxColumns * + BusyMarkSizes.tableMaxRows, + itemBuilder: (context, index) { + final row = index ~/ BusyMarkSizes.tableMaxColumns + 1; + final column = index % BusyMarkSizes.tableMaxColumns + 1; + final highlighted = + column <= previewColumns && row <= previewRows; + final selected = + column == _selectedColumns && row == _selectedRows; + final label = + '${context.l10n.columns}: $column, ' + '${context.l10n.rows}: $row'; + return Semantics( + button: true, + selected: selected, + label: label, + onTap: () => _selectGridSize(column, row), + child: ExcludeSemantics( + child: MouseRegion( + cursor: SystemMouseCursors.click, + onEnter: (_) => _previewGridSize(column, row), + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + _gridFocusNode.requestFocus(); + _selectGridSize(column, row); + }, + child: DecoratedBox( + key: BusyMarkTableDialogKeys.gridCell( + columns: column, + rows: row, + ), + decoration: BoxDecoration( + color: highlighted + ? theme.colorScheme.primary + : colors.dialog, + border: Border.all( + color: highlighted + ? theme.colorScheme.primary + : colors.border, + width: BusyMarkStroke.hairline, + ), + borderRadius: BorderRadius.circular( + BusyMarkRadius.sm, + ), + ), + ), + ), + ), + ), + ); + }, + ), + ), + ), + ), + ), + ), ), ); } + + int? _validDimension( + TextEditingController controller, { + required int min, + required int max, + }) { + final value = int.tryParse(controller.text.trim()); + return value != null && value >= min && value <= max ? value : null; + } + + bool get _canSubmit => + _validDimension( + _columnsController, + min: BusyMarkSizes.tableMinColumns, + max: BusyMarkSizes.tableMaxColumns, + ) != + null && + _validDimension( + _rowsController, + min: BusyMarkSizes.tableMinRows, + max: BusyMarkSizes.tableMaxRows, + ) != + null; + + void _handleColumnsChanged(String _) { + final columns = _validDimension( + _columnsController, + min: BusyMarkSizes.tableMinColumns, + max: BusyMarkSizes.tableMaxColumns, + ); + setState(() { + _hoveredColumns = null; + _hoveredRows = null; + if (columns != null) { + _selectedColumns = columns; + } + }); + } + + void _handleRowsChanged(String _) { + final rows = _validDimension( + _rowsController, + min: BusyMarkSizes.tableMinRows, + max: BusyMarkSizes.tableMaxRows, + ); + setState(() { + _hoveredColumns = null; + _hoveredRows = null; + if (rows != null) { + _selectedRows = rows; + } + }); + } + + void _previewGridSize(int columns, int rows) { + if (_hoveredColumns == columns && _hoveredRows == rows) { + return; + } + setState(() { + _hoveredColumns = columns; + _hoveredRows = rows; + }); + } + + void _clearGridPreview() { + if (_hoveredColumns == null && _hoveredRows == null) { + return; + } + setState(() { + _hoveredColumns = null; + _hoveredRows = null; + }); + } + + void _selectGridSize(int columns, int rows) { + _columnsController.text = '$columns'; + _rowsController.text = '$rows'; + setState(() { + _selectedColumns = columns; + _selectedRows = rows; + _hoveredColumns = null; + _hoveredRows = null; + }); + } + + KeyEventResult _handleGridKeyEvent(FocusNode _, KeyEvent event) { + if (event is! KeyDownEvent) { + return KeyEventResult.ignored; + } + final key = event.logicalKey; + var columns = _selectedColumns; + var rows = _selectedRows; + if (key == LogicalKeyboardKey.arrowLeft) { + columns = math.max(BusyMarkSizes.tableMinColumns, columns - 1); + } else if (key == LogicalKeyboardKey.arrowRight) { + columns = math.min(BusyMarkSizes.tableMaxColumns, columns + 1); + } else if (key == LogicalKeyboardKey.arrowUp) { + rows = math.max(BusyMarkSizes.tableMinRows, rows - 1); + } else if (key == LogicalKeyboardKey.arrowDown) { + rows = math.min(BusyMarkSizes.tableMaxRows, rows + 1); + } else if (key == LogicalKeyboardKey.enter || + key == LogicalKeyboardKey.numpadEnter || + key == LogicalKeyboardKey.space) { + return KeyEventResult.handled; + } else { + return KeyEventResult.ignored; + } + _selectGridSize(columns, rows); + return KeyEventResult.handled; + } + + void _submit() { + final columns = _validDimension( + _columnsController, + min: BusyMarkSizes.tableMinColumns, + max: BusyMarkSizes.tableMaxColumns, + ); + final rows = _validDimension( + _rowsController, + min: BusyMarkSizes.tableMinRows, + max: BusyMarkSizes.tableMaxRows, + ); + if (columns == null || rows == null) { + return; + } + Navigator.pop(context, _TableDialogResult(columns: columns, rows: rows)); + } } diff --git a/test/src/busymark_document_test.dart b/test/src/busymark_document_test.dart index 8fae2b0d..7e906a94 100644 --- a/test/src/busymark_document_test.dart +++ b/test/src/busymark_document_test.dart @@ -5864,6 +5864,141 @@ void main() {} expect(controller.markdown, ''); }); + testWidgets('WYSIWYG table dialog validates and synchronizes its size grid', ( + tester, + ) async { + await tester.binding.setSurfaceSize(const Size(1200, 800)); + addTearDown(() => tester.binding.setSurfaceSize(null)); + final parsed = parser.parse(filePath: 'topic.md', source: 'Intro\n'); + var markdown = parsed.source; + + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold( + body: SizedBox( + width: 900, + height: 700, + child: BusyMarkWysiwygEditor( + document: parsed.busyDocument, + toolbarPlacement: EditorToolbarPlacement.bottomLeft, + onSourceChanged: (_, value) => markdown = value, + ), + ), + ), + ), + ); + await tester.pumpAndSettle(); + + tester + .widget<IconButton>( + find.ancestor( + of: find.byIcon(BusyMarkGlyphs.table), + matching: find.byType(IconButton), + ), + ) + .onPressed!(); + await tester.pumpAndSettle(); + + final columnsField = find.descendant( + of: find.byKey(BusyMarkTableDialogKeys.columns), + matching: find.byType(EditableText), + ); + final rowsField = find.descendant( + of: find.byKey(BusyMarkTableDialogKeys.rows), + matching: find.byType(EditableText), + ); + ElevatedButton submitButton() => tester.widget<ElevatedButton>( + find.byKey(BusyMarkTableDialogKeys.submit), + ); + String fieldText(Finder finder) => + tester.widget<EditableText>(finder).controller.text; + + expect(find.byKey(BusyMarkTableDialogKeys.grid), findsOneWidget); + expect(fieldText(columnsField), '2'); + expect(fieldText(rowsField), '2'); + + final mouse = await tester.createGesture(kind: PointerDeviceKind.mouse); + await mouse.addPointer( + location: tester.getCenter( + find.byKey(BusyMarkTableDialogKeys.gridCell(columns: 4, rows: 3)), + ), + ); + await tester.pump(); + expect(find.text('Columns: 4 · Rows: 3'), findsNothing); + expect(fieldText(columnsField), '2'); + expect(fieldText(rowsField), '2'); + await mouse.moveTo(const Offset(1, 1)); + await tester.pump(); + + await tester.enterText(columnsField, 'letters'); + await tester.pump(); + expect(fieldText(columnsField), isEmpty); + expect(find.text('1–12'), findsOneWidget); + expect(submitButton().onPressed, isNull); + + await tester.enterText(columnsField, '13'); + await tester.pump(); + expect(fieldText(columnsField), '13'); + expect(find.text('1–12'), findsOneWidget); + expect(submitButton().onPressed, isNull); + + await tester.tap( + find.byKey(BusyMarkTableDialogKeys.gridCell(columns: 4, rows: 3)), + ); + await tester.pump(); + expect(fieldText(columnsField), '4'); + expect(fieldText(rowsField), '3'); + expect(find.text('1–12'), findsNothing); + expect(submitButton().onPressed, isNotNull); + + await tester.sendKeyEvent(LogicalKeyboardKey.arrowRight); + await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); + await tester.pump(); + expect(fieldText(columnsField), '5'); + expect(fieldText(rowsField), '4'); + + await tester.enterText(columnsField, '6'); + await tester.enterText(rowsField, '4'); + await tester.pump(); + final selectedCell = tester.widget<DecoratedBox>( + find.byKey(BusyMarkTableDialogKeys.gridCell(columns: 6, rows: 4)), + ); + final unselectedCell = tester.widget<DecoratedBox>( + find.byKey(BusyMarkTableDialogKeys.gridCell(columns: 7, rows: 4)), + ); + final dialogScheme = Theme.of( + tester.element(find.byKey(BusyMarkTableDialogKeys.grid)), + ).colorScheme; + expect( + (selectedCell.decoration as BoxDecoration).color, + dialogScheme.primary, + ); + expect( + (unselectedCell.decoration as BoxDecoration).color, + isNot(dialogScheme.primary), + ); + + await tester.tap( + find.byKey(BusyMarkTableDialogKeys.gridCell(columns: 4, rows: 3)), + ); + await tester.pump(); + await tester.tap(find.byKey(BusyMarkTableDialogKeys.submit)); + await tester.pumpAndSettle(); + + final inserted = parser + .parse(filePath: 'topic.md', source: markdown) + .busyDocument + .blocks + .singleWhere((block) => block.kind == BusyBlockKind.table); + expect(inserted.children, hasLength(4)); + for (final row in inserted.children) { + expect(row.children, hasLength(4)); + } + expect(tester.takeException(), isNull); + }); + test('table alignment survives parsing, edits, and structural changes', () { const source = '| Left | Center | Right | Default |\n' From 8b64e0500ab6f98b2546517a3d8c306bc85290d3 Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Tue, 8 Sep 2026 15:53:46 -0700 Subject: [PATCH 31/37] Pinned the current stable Flutter 3.47.2 --- pubspec.lock | 2 +- pubspec.yaml | 2 +- snap/snapcraft.yaml | 2 +- test/src/wysiwyg_ai_test.dart | 25 +++++++++++++++++-------- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index dbed2c87..ee4391ac 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1140,4 +1140,4 @@ packages: version: "0.0.4" sdks: dart: ">=3.12.1 <4.0.0" - flutter: ">=3.47.0 <3.48.0" + flutter: "3.47.2" diff --git a/pubspec.yaml b/pubspec.yaml index 6be12592..db68b71c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ version: 0.3.5 environment: sdk: ">=3.12.1 <4.0.0" - flutter: ">=3.47.0 <3.48.0" + flutter: 3.47.2 dependencies: flutter: diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 43be85f1..337033cd 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -64,7 +64,7 @@ parts: flutter-target: lib/main.dart flutter-channel: stable build-environment: - - BUSYMARK_FLUTTER_VERSION: "3.47.0" + - BUSYMARK_FLUTTER_VERSION: "3.47.2" build-snaps: - node/24/stable build-packages: diff --git a/test/src/wysiwyg_ai_test.dart b/test/src/wysiwyg_ai_test.dart index fc99f554..758fdc5a 100644 --- a/test/src/wysiwyg_ai_test.dart +++ b/test/src/wysiwyg_ai_test.dart @@ -265,14 +265,18 @@ void main() { ); final editableState = tester.state<EditableTextState>(editableFinder); editableState.clipboardStatus.value = ClipboardStatus.pasteable; - final expectedSelectionActions = editableState.contextMenuButtonItems - .map( - (item) => AdaptiveTextSelectionToolbar.getButtonLabel( - tester.element(editableFinder), - item, - ), - ) - .toList(); + final expectedSelectionActions = <String>[]; + for (final item in editableState.contextMenuButtonItems) { + expectedSelectionActions.add( + AdaptiveTextSelectionToolbar.getButtonLabel( + tester.element(editableFinder), + item, + ), + ); + if (item.type == ContextMenuButtonType.copy) { + expectedSelectionActions.add('Copy Plain Text'); + } + } expect(paragraph.controller!.selection.isCollapsed, isFalse); expect(paragraph.contextMenuBuilder, isNotNull); @@ -295,11 +299,16 @@ void main() { ); expect(_nativeShortcut(nativeEntries!, 'Cut'), 'Ctrl+X'); expect(_nativeShortcut(nativeEntries!, 'Copy'), 'Ctrl+C'); + expect(_nativeShortcut(nativeEntries!, 'Copy Plain Text'), 'Ctrl+Shift+C'); expect(_nativeShortcut(nativeEntries!, 'Paste'), 'Ctrl+V'); expect(_nativeShortcut(nativeEntries!, 'Select all'), 'Ctrl+A'); expect(_nativeShortcut(nativeEntries!, 'Refine with AI'), 'Ctrl+G'); expect(_nativeIcon(nativeEntries!, 'Cut'), 'edit-cut-symbolic'); expect(_nativeIcon(nativeEntries!, 'Copy'), 'edit-copy-symbolic'); + expect( + _nativeIcon(nativeEntries!, 'Copy Plain Text'), + 'edit-copy-symbolic', + ); expect(_nativeIcon(nativeEntries!, 'Paste'), 'edit-paste-symbolic'); expect( _nativeIcon(nativeEntries!, 'Select all'), From cd897904efd4061d75b21e7e1f006cab780209ce Mon Sep 17 00:00:00 2001 From: albert <albert.gee.ca@gmail.com> Date: Tue, 8 Sep 2026 16:30:04 -0700 Subject: [PATCH 32/37] Refactor readme, add new screenshots, remove demo. --- README.md | 373 +++++------------- demo/ai-editing.md | 194 --------- demo/openapi-local-reference.md | 27 -- demo/openapi/components.yaml | 10 - demo/plantuml-conformance.md | 169 -------- demo/visualizations.md | 114 ------ demo/writerside-instances/admin.tree | 8 - demo/writerside-instances/cfg/PDF.xml | 11 - .../cfg/buildprofiles.xml | 14 - demo/writerside-instances/guide.tree | 14 - .../images/busymark-mark.svg | 7 - demo/writerside-instances/instance-groups.xml | 4 - demo/writerside-instances/shared.tree | 9 - .../topics/desktop-settings.md | 3 - demo/writerside-instances/topics/install.md | 3 - demo/writerside-instances/topics/legal.md | 4 - .../writerside-instances/topics/operations.md | 4 - .../topics/server-settings.md | 3 - demo/writerside-instances/topics/welcome.md | 3 - demo/writerside-instances/writerside.cfg | 11 - docs/screenshots/busymark-d2.png | Bin 0 -> 75229 bytes .../screenshots/busymark-mermaid-plantuml.png | Bin 0 -> 89143 bytes docs/screenshots/busymark-openapi.png | Bin 0 -> 55465 bytes docs/screenshots/busymark-split-view.png | Bin 123323 -> 348643 bytes docs/screenshots/busymark-writerside-toc.png | Bin 0 -> 128650 bytes 25 files changed, 106 insertions(+), 879 deletions(-) delete mode 100644 demo/ai-editing.md delete mode 100644 demo/openapi-local-reference.md delete mode 100644 demo/openapi/components.yaml delete mode 100644 demo/plantuml-conformance.md delete mode 100644 demo/visualizations.md delete mode 100644 demo/writerside-instances/admin.tree delete mode 100644 demo/writerside-instances/cfg/PDF.xml delete mode 100644 demo/writerside-instances/cfg/buildprofiles.xml delete mode 100644 demo/writerside-instances/guide.tree delete mode 100644 demo/writerside-instances/images/busymark-mark.svg delete mode 100644 demo/writerside-instances/instance-groups.xml delete mode 100644 demo/writerside-instances/shared.tree delete mode 100644 demo/writerside-instances/topics/desktop-settings.md delete mode 100644 demo/writerside-instances/topics/install.md delete mode 100644 demo/writerside-instances/topics/legal.md delete mode 100644 demo/writerside-instances/topics/operations.md delete mode 100644 demo/writerside-instances/topics/server-settings.md delete mode 100644 demo/writerside-instances/topics/welcome.md delete mode 100644 demo/writerside-instances/writerside.cfg create mode 100644 docs/screenshots/busymark-d2.png create mode 100644 docs/screenshots/busymark-mermaid-plantuml.png create mode 100644 docs/screenshots/busymark-openapi.png create mode 100644 docs/screenshots/busymark-writerside-toc.png diff --git a/README.md b/README.md index 5d0b4b82..2326f36b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # BusyMark -BusyMark is a Markdown editor for Linux with support for Writerside-compatible documentation -projects. +Markdown and Writerside editor for Linux. [![busymark](https://snapcraft.io/busymark/badge.svg)](https://snapcraft.io/busymark) @@ -11,339 +10,179 @@ projects. <img src="docs/screenshots/busymark-split-view.png" alt="BusyMark split source and reading view" width="900"> </p> -<p align="center"> - <sub>Split view with Markdown source, outline navigation, and locally rendered diagrams.</sub> -</p> - ## Features -- Open individual Markdown files. -- Open Markdown documentation folders. -- Open Writerside-compatible project folders. -- Create Writerside-compatible starter projects. -- Create Writerside Markdown and XML topics from the TOC. -- Create, select, import, edit, and reuse Writerside instances and TOC libraries. -- Edit and save local files. -- Read rendered Markdown without editing it. -- Render Mermaid, PlantUML, D2, and fenced OpenAPI content locally and offline. -- Typeset inline and display mathematics locally and offline with bundled - MathJax, including Writerside math forms and vector PDF output. -- Edit Markdown with free-form AI instructions, an explicit change target, and - explicitly selected context through Ollama, OpenAI, or Gemini, with - diff-before-apply review. -- Export Markdown documents as accessible, tagged PDF files. -- Export the current Markdown document or a Writerside instance as portable, offline HTML. See [HTML export](docs/html-export.md). -- Navigate project files, table of contents, and document outline. -- Review, stage, commit, branch, synchronize, and inspect history in Git-backed - documentation workspaces using the user's normal Git configuration and tools. -- Run basic diagnostics. -- Reopen recent workspaces. -- Use native Linux desktop chrome with a GTK headerbar. +* **Markdown editing** — Source, Editor, Reading, and Split views with formatting tools, syntax highlighting, code folding, tables, images, links, code blocks, callouts, collapsible content, and document diagnostics. +* **Writerside projects** — Open and create Writerside-compatible projects; edit Markdown and XML topics; manage instances, tables of contents, reusable TOC libraries, and project structure. +* **Project navigation and search** — Files, TOC, and Outline views, tabbed documents, command palette, keyboard shortcuts, document search and replace, reviewed workspace-wide replacement, and Markdown TOC generation. +* **Technical documentation** — Local rendering of Mermaid, PlantUML, D2, fenced OpenAPI specifications, and MathJax mathematical expressions. +* **PDF and HTML publishing** — Export Markdown documents and Writerside instances to configurable PDF or portable offline HTML, with controls for layout, typography, tables of contents, heading numbering, and HTML styling. +* **Git integration** — Review changes and diffs, stage and unstage files, commit, create and switch branches, fetch, pull, push, inspect file and project history, compare historical versions, and restore earlier file versions. +* **AI-assisted editing** — Optional Ollama, OpenAI, and Gemini integration with explicit edit scope and shared context, proposal review before changes are applied, and AI-assisted Git commit-message drafting. +* **Workspace reliability** — Detect files changed outside BusyMark, recover unsaved documents, restore previous workspace sessions, manage remote-image permissions, and protect Git operations behind workspace trust. ## Screenshots <table> <tr> <td width="50%"> - <img src="docs/screenshots/busymark-welcome.png" alt="BusyMark welcome screen"> + <img src="docs/screenshots/busymark-split-view.png" alt="BusyMark split source and reading view"> <br> - <sub><b>Welcome screen</b> for creating or opening Markdown and Writerside workspaces.</sub> + <sub><b>Split view</b> with Markdown source and rendered document.</sub> </td> <td width="50%"> <img src="docs/screenshots/busymark-editor-view.png" alt="BusyMark editor view"> <br> - <sub><b>Editor view</b> with formatting tools, outline navigation, and offline diagrams.</sub> + <sub><b>Editor view</b> with formatting tools and document navigation.</sub> </td> </tr> <tr> <td width="50%"> <img src="docs/screenshots/busymark-preview-view.png" alt="BusyMark reading view"> <br> - <sub><b>Reading view</b> with locally rendered Mermaid and PlantUML content.</sub> + <sub><b>Reading view</b> for rendered documentation.</sub> </td> <td width="50%"> <img src="docs/screenshots/busymark-keyboard-shortcuts.png" alt="BusyMark keyboard shortcuts dialog"> <br> - <sub><b>Keyboard shortcuts</b> shown in the built-in shortcut reference.</sub> + <sub><b>Keyboard shortcuts</b> reference.</sub> + </td> + </tr> + <tr> + <td width="50%"> + <img src="docs/screenshots/busymark-mermaid-plantuml.png" alt="Mermaid and PlantUML diagrams rendered in BusyMark"> + <br> + <sub><b>Mermaid and PlantUML</b> diagrams rendered directly in the document.</sub> + </td> + <td width="50%"> + <img src="docs/screenshots/busymark-d2.png" alt="D2 diagram rendered in BusyMark"> + <br> + <sub><b>D2</b> diagram rendering.</sub> + </td> + </tr> + <tr> + <td width="50%"> + <img src="docs/screenshots/busymark-openapi.png" alt="OpenAPI documentation rendered in BusyMark"> + <br> + <sub><b>OpenAPI</b> documentation rendering.</sub> + </td> + <td width="50%"> + <img src="docs/screenshots/busymark-writerside-toc.png" alt="Writerside table of contents in BusyMark"> + <br> + <sub><b>Writerside</b> project and table-of-contents editing.</sub> </td> </tr> </table> -## Supported platforms - -BusyMark is currently developed and tested for Linux desktop, especially GNOME -and Ubuntu-style GTK environments. - -## Supported files and projects - -BusyMark can open Markdown files such as `.md` and `.markdown`. - -BusyMark opens Writerside help modules whose root contains `writerside.cfg` or -the equivalent older `project.ihp` file. Writerside support includes documented -configuration locations for topics, images, variables, categories, instances, -snippets, build configuration, API specifications, instance groups, and selected -settings metadata. Topic support includes Markdown topics, XML `.topic` files, -TOC registration, instance-specific topic titles, and custom web file names. -Instance support includes local selection and icon colors, version/web-path and -build settings, Markdown import, status, ID refactoring, instance groups, -conditional and reusable TOC sections, and cross-instance topic references. -See [Writerside instances](docs/writerside-instances.md) for behavior, safety -rules, an openable example, and the authoritative JetBrains references. -Writerside `<video>` elements are recognized in Markdown and XML topics, with -local preview images plus HTTPS YouTube and Vimeo sources. See -[Writerside videos](docs/videos.md) for syntax and preview/export behavior. -Writerside tip, note, warning, and quote blocks render as native document -callouts and can be inserted from the WYSIWYG toolbar. See -[Writerside admonitions](docs/admonitions.md) for supported syntax. -Writerside chapters, procedures, code blocks, and definition lists support -documented collapsed and expanded states in Preview and WYSIWYG views. See -[Writerside collapsible elements](docs/collapsible-elements.md) for syntax and -the ordinary-Markdown boundary. - -Folder workspaces show all files and directories, including hidden project -files such as `.gitignore`. Unsupported and binary files remain visible but are -disabled in the text editor. Version-control metadata directories such as -`.git` are excluded, and traversal remains bounded for safety. - -## PDF export - -Use **Main menu → Export as PDF** or <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>E</kbd> -to export either the active Markdown document or the opened Writerside module. -Markdown export uses the current editor contents, including unsaved changes, -and offers A4, Letter, Legal or custom paper, orientation and independent margins, -Noto typography, accent colors, title headers/footers, positioned page numbers, -and optional TOC and heading numbering. Settings are remembered separately for -PDF and HTML; **Reset to defaults** restores each format’s defaults. See -[PDF export settings](docs/pdf-export.md). - -Markdown PDF generation is local and offline. BusyMark bundles the pinned Typst -compiler; users do not install or configure a separate program. Local PNG, -JPEG, GIF, and safe SVG images are included. Remote images are deliberately not -downloaded during export and are represented by their alternative text. - -Inline and display equations use the same bundled MathJax semantics in preview -and PDF export. Safe generated equations remain self-contained vector SVG, with -inline baseline metrics carried into Typst. See [mathematical expressions](docs/math.md) -for supported Markdown and Writerside forms, the scientific TeX package profile, -editing behavior, and offline security boundaries. - -Mermaid and PlantUML fences are exported as vector diagrams. D2 uses normalized -SVG where possible and a local high-resolution raster fallback for browser-only -labels. OpenAPI fences become static, selectable API reference content. Failed -visualizations fall back to their original source and produce an export warning. - -See [offline visualizations](docs/visualizations.md) for supported fences, -security policy, pinned engines, architecture, and verification. Working -examples are in [demo/visualizations.md](demo/visualizations.md), -[demo/openapi-local-reference.md](demo/openapi-local-reference.md), and -[demo/plantuml-conformance.md](demo/plantuml-conformance.md). - -Writerside PDF export builds one selected output instance with BusyMark's -bundled native Typst, MathJax, and diagram pipeline. It follows the resolved -instance TOC and supports Writerside Markdown and `.topic` XML without Docker, -a Writerside installation, a daemon, or a network connection. See -[Writerside PDF export](docs/writerside-pdf-export.md) for supported layout -options, security boundaries, and native-export scope. An exportable example is -included in [demo/writerside-instances](demo/writerside-instances). +## Markdown and Writerside -## AI editing +BusyMark opens Markdown files using `.md` and `.markdown` extensions and can work with ordinary documentation folders. -BusyMark's optional AI editing is disabled by default and supports loopback -Ollama, OpenAI, and Google Gemini. In Source and Editor views, select text and -choose **Refine with AI** from its context menu, or press **Ctrl+G**. The user -then writes the instruction and independently chooses what may change and what -document context may be shared. Staged-diff commit-message drafting is -available separately in Git Changes. BusyMark discloses the exact context, -streams into a temporary proposal, reparses and validates the complete -candidate Markdown document, shows a unified diff, and never applies a proposal -without confirmation. Cloud -keys are stored in the operating-system credential service and cloud use -requires explicit consent; provider routing never crosses provider boundaries. +Writerside-compatible projects are recognized through `writerside.cfg` and the older `project.ihp` format. BusyMark supports Markdown and XML topics, Writerside instances, tables of contents, reusable content, project configuration, and other commonly used Writerside documentation features. -See [AI editing](docs/local-ai.md) for configuration, privacy and security -boundaries, model routing, release qualification, and authoritative protocol -references. An interactive exercise is available in -[demo/ai-editing.md](demo/ai-editing.md). +More information: -## Run From Source +* [Writerside instances](docs/writerside-instances.md) +* [Writerside videos](docs/videos.md) +* [Admonitions](docs/admonitions.md) +* [Collapsible elements](docs/collapsible-elements.md) -1. [Install Flutter 3.47.0](https://docs.flutter.dev/install). The exact - project version is declared in `pubspec.yaml` and shared with CI. +## Diagrams and mathematics -2. Run the application: +BusyMark renders Mermaid, PlantUML, D2, and fenced OpenAPI content locally. Mathematical expressions are rendered with the bundled MathJax environment. -```bash -flutter doctor -flutter pub get -flutter run -d linux -``` +See: -Open a file or folder from the command line: +* [Offline visualizations](docs/visualizations.md) +* [Mathematical expressions](docs/math.md) -```bash -flutter run -d linux -- /path/to/README.md -flutter run -d linux -- /path/to/docs -``` +## Export -## Feedback API - -The **Main menu → Report an issue** form -submits JSON to `https://busystack.org/api/feedback`. BusyMark sends no private -credentials or other API secrets; storage is handled by BusyStack.org. - -Every request contains a newly generated submission UUID, `app: "busymark"`, -the application version and build number read from the current package's -generated build metadata (including Flutter build overrides), -`platform: "linux"`, the selected category, subject, detailed message, and the -optional reply email. The optional `technicalDetails` object is included after -user explicitly selects the checkbox. It contains exactly the Linux -operating-system version and the BusyMark application locale; logs, files, -document content, paths, account data, tokens, screenshots, and attachments are -never added. - -```json -{ - "submissionId": "b3f44f5f-dae4-4c6e-bf56-657f35f3450a", - "app": "busymark", - "appVersion": "0.2.2", - "buildNumber": "0", - "platform": "linux", - "category": "problem", - "subject": "Example subject", - "message": "Detailed feedback message", - "replyEmail": null, - "technicalDetails": { - "osVersion": "Linux version string", - "locale": "en" - } -} -``` +BusyMark can export the current Markdown document or a Writerside instance to PDF and portable offline HTML. -The endpoint returns HTTP 201 and `{"id":"<server reference ID>"}` after it -accepts a report. Validation failures, connection failures, timeouts, rate -limits, and server failures are shown without clearing the entered form. +PDF export supports configurable paper size, orientation, margins, typography, headers and footers, page numbering, table of contents, and heading numbering. -For local development, override only the endpoint at build time. For example, -when the BusyStack.org backend is listening on port 8090: +See: -```bash -flutter run -d linux \ - --dart-define=BUSYSTACK_FEEDBACK_ENDPOINT=http://127.0.0.1:8090/api/feedback -``` +* [PDF export settings](docs/pdf-export.md) +* [Writerside PDF export](docs/writerside-pdf-export.md) +* [HTML export](docs/html-export.md) + +## AI editing -Production builds use the HTTPS endpoint by default. No credential belongs in -the Dart define or in the desktop application. +AI-assisted editing is optional and disabled by default. -## Test +BusyMark supports Ollama, OpenAI, and Google Gemini. Proposed edits are presented for review before changes are applied. + +See [AI editing](docs/local-ai.md) for configuration, privacy, provider behavior, and security information. + +## Installation + +Install BusyMark from the Snap Store: ```bash -flutter analyze -flutter test +sudo snap install busymark --beta ``` -## Localization - -BusyMark has ARB localization files for: - -- Arabic (ar) -- Dutch (nl) -- English (en) -- Estonian (et) -- French (fr) -- German (de) -- Hindi (hi) -- Indonesian (id) -- Italian (it) -- Japanese (ja) -- Korean (ko) -- Norwegian Bokmål (nb) -- Persian (fa) -- Polish (pl) -- Portuguese (pt) -- Russian (ru) -- Simplified Chinese (zh-CN) -- Spanish (es) -- Turkish (tr) -- Ukrainian (uk) -- Vietnamese (vi) - -English in `lib/l10n/app_en.arb` is the source of truth for app strings. - -Every base and regional ARB catalog must contain the complete current English -message-key set. Language-only catalogs such as `app_pt.arb` and `app_zh.arb` -are required alongside their regional catalogs; they are not partial fallback -stubs. Catalogs are audited for structure, parity, placeholders, plurals, and -reviewed terminology. - -When changing user-facing text, update `app_en.arb`, keep every target ARB in -sync, then run: +The Snap uses strict confinement. See [Snap confinement notes](docs/snap-confinement.md) for details about filesystem and Git integration. + +## Run from source + +BusyMark currently uses Flutter 3.47.0. + +Install the required Linux development packages: ```bash -flutter gen-l10n -flutter test test/src/localization_audit_test.dart -flutter analyze -flutter test +sudo apt-get install \ + curl \ + libhandy-1-dev \ + xz-utils \ + libwebkit2gtk-4.1-dev \ + fonts-noto-core \ + fonts-noto-mono ``` -Linux `.desktop` and AppStream metadata are localized in the repository. Snap -Store listing translations are managed outside `snap/snapcraft.yaml`. +Node.js 22 or newer with npm is also required when building the bundled web components. -The Snap uses strict confinement and bundles Git and OpenSSH. If Git cannot -find an author identity while committing, BusyMark opens a native form, saves -the chosen repository or BusyMark-wide identity, and retries the commit. Install -it with: +Prepare and run the application: ```bash -sudo snap install busymark +flutter doctor +flutter pub get +flutter run -d linux ``` -The [Snap confinement notes](docs/snap-confinement.md) document supported -interfaces and the limits of host Git integration. +A Markdown file or documentation folder can be opened directly from the command line: -## Build Linux Locally +```bash +flutter run -d linux +``` + +## Build -Source builds require the libhandy and WebKitGTK 4.1 development headers, -`curl`, `xz-utils`, and Node.js 22 or newer with npm. Node.js is used only to -assemble the checksum-pinned web bundle. Packaged users receive every runtime -component with BusyMark and do not install development packages, Node.js, Java, -or Chromium. +Build the Linux desktop application with: ```bash -sudo apt-get install curl libhandy-1-dev xz-utils libwebkit2gtk-4.1-dev fonts-noto-core fonts-noto-mono -# Install Node.js 22 or newer from https://nodejs.org/en/download -node --version -npm --version flutter build linux ``` -The Linux build downloads the matching x86_64 or ARM64 Typst 0.15.1 binary, the -Linux amd64 D2 0.7.1 release, and exact JavaScript packages, then verifies the -pinned artifacts before bundling them. D2 visualization is currently packaged -only for amd64. To reuse already downloaded official Typst and D2 archives, -point the build at them: +The build assembles the runtime components required by BusyMark. Packaged users do not need separate Typst, Java, Node.js, or Chromium installations. + +## Test ```bash -BUSYMARK_TYPST_ARCHIVE=/path/to/typst-x86_64-unknown-linux-musl.tar.xz \ -BUSYMARK_D2_ARCHIVE=/path/to/d2-v0.7.1-linux-amd64.tar.gz \ - flutter build linux +flutter analyze +flutter test ``` -A clean source build still assembles the checksum-pinned JavaScript packages. -The resulting BusyMark application is self-contained and performs no runtime -downloads for visualization. - -The Linux desktop file uses the application id `io.busystack.busymark` and -installs the app icon from `assets/branding/busymark_logo.svg`. - ## Contributing -Issues and small focused pull requests are welcome. Please keep changes aligned -with the current beta scope: local editing, Linux desktop quality, safe file -handling, and clear user-facing behavior. +Issues and focused pull requests are welcome. + +Changes should remain consistent with BusyMark's current scope as a desktop Markdown and Writerside documentation editor. ## License -Apache-2.0. See [LICENSE](LICENSE). Bundled Typst and D2 licenses and notices are -installed under `share/licenses`; visualization JavaScript licenses, package -metadata, the exact lock file, and consolidated notices are installed with the -offline web bundle. +BusyMark is licensed under the Apache License 2.0. See [LICENSE](LICENSE). + +Licenses and notices for bundled third-party components are distributed with the application. diff --git a/demo/ai-editing.md b/demo/ai-editing.md deleted file mode 100644 index 73078267..00000000 --- a/demo/ai-editing.md +++ /dev/null @@ -1,194 +0,0 @@ ---- -title: BusyMark AI editing release qualification -audience: documentation-engineering ---- - -# BusyMark AI editing release qualification - -Use this non-sensitive document to qualify an exact provider and model before a -release. In **Settings → AI**, configure Local Ollama, OpenAI, or Google Gemini, -run **Test connection**, and record the provider/model shown in each proposal. -For a cloud provider, confirm the disclosure before sending this content. Work -in **Source** view and review every diff before applying it. - -## Rewrite for clarity - -Select the following paragraph and choose **Rewrite**: - -The release process is something that has a number of steps which need to be -performed by the documentation owner, and those steps should be carried out in -the order in which they are described because doing them in another order can -cause the published documentation to become inconsistent with the application. - -Expected quality: concise professional prose, unchanged meaning, and no added -facts. - -## Shorten without losing requirements - -Select the following paragraph and choose **Shorten**: - -Before publishing the operator guide, the release engineer must validate all -internal links, build the English and German editions, retain the generated -reports for ninety days, and obtain approval from both the documentation lead -and the security reviewer. Publication must not begin until both approvals are -recorded in the release ticket. - -Expected quality: every language, retention period, approval, and ordering -constraint remains present. - -## Proofread - -Select the following paragraph and choose **Proofread**: - -Each administrator configure the service before users signs in. The settings -is stored locally, and they must be reviewed when the server are upgraded. - -Expected quality: grammar and agreement are corrected without changing the -operational requirement. - -## Change tone - -Select the following paragraph, choose **Change tone**, and enter -`neutral technical documentation`: - -Just flip this switch and you are good to go. If the network is acting weird, -give the service a minute and smash Retry again. - -Expected quality: the instructions become professional without inventing a -different control, wait time, or recovery procedure. - -## Translate - -Select the following paragraph, choose **Translate**, and enter a target -language such as `German`: - -The maintenance window begins at 22:00 UTC. Save active work before the window -starts because the documentation service will be unavailable for approximately -fifteen minutes. - -Expected quality: `22:00 UTC` and the fifteen-minute duration remain exact. - -## Summarize - -Select the following three paragraphs and choose **Summarize**: - -The migration begins with a read-only inventory of every published space. The -inventory records the owning team, current release, custom domain, and number -of active readers. It does not copy document content. - -After the owners approve the inventory, the migration tool creates the target -spaces and copies one release at a time. Each copied release is validated -before its target space becomes visible. - -The old service remains available for seven days after validation. During that -period it is read-only, and all new changes must be made in the target service. -The operations team removes the old service only after the rollback period. - -Expected quality: inventory, approval, per-release validation, and the -seven-day rollback period all survive in a concise summary. Also run Summarize -with no selection to qualify whole-document context disclosure and insertion. - -## Draft from notes - -Place the cursor after these notes, choose **Draft**, and enter -`Write a concise deployment prerequisites section`: - -- Ubuntu 24.04 hosts -- outbound HTTPS to the approved package mirror -- 8 GB RAM minimum; 16 GB recommended -- a non-interactive service account -- 20 GB free disk space before upgrade - -Expected quality: valid Markdown using only the supplied requirements. - -## Fenced-code assistance - -Place the cursor inside this fence and choose **Explain code block**. The -proposal should insert a concise explanation after the fence without changing -the code. - -```dart -Iterable<String> releaseTags(Iterable<String> tags) sync* { - for (final tag in tags) { - if (tag.startsWith('release/')) yield tag.substring(8); - } -} -``` - -Next choose **Improve code block**. BusyMark must accept only a proposal that -replaces exactly this complete fence while preserving the `dart` language -identifier. Review behavior changes rather than assuming generated code is -correct. - -## Protected Markdown regression fixture {#protected-fixture} - -Select only the prose in the next paragraph and choose **Rewrite**. BusyMark may -change the prose but must reject a result that swaps or alters either link: - -Read the [operator guide][operations] before opening the -[release checklist](https://docs.example.test/releases/checklist). - -Select the rest of this section and choose **Rewrite**. BusyMark must reject a -proposal that changes the reference/footnote identifiers, URL associations, -autolink, table structure, heading ID, Writerside element, or code: - -Use ``code ` value`` and retain incident evidence for seven days.[^retention] -Report status through <https://status.example.test>. - -| Environment | Approval | -| --- | --- | -| Production | Security reviewer | - -<note title="Do not remove">This is Writerside markup.</note> - -```bash -curl --fail --silent http://127.0.0.1:8080/health -``` - -[operations]: https://docs.example.test/operations -[^retention]: The seven-day period begins after validation. - -## Stale, cancellation, and request isolation - -Start an action, edit the document before generation finishes, and verify that -**Apply proposal** remains disabled. Start a second action on the same target -and verify that the older request is cancelled. Cancel a streaming proposal and -verify that no partial text reaches the editor. - -## Git commit-message draft - -In a disposable Git repository, stage a small documentation edit while leaving -a different edit unstaged. In **Git → Changes**, choose **Draft with AI**. -Verify that: - -- the disclosure identifies a staged Git diff; -- the proposal describes only staged changes; -- accepting it fills, but does not submit, the commit-message field; -- the subject is at most 72 characters; -- a body, when present, follows a blank line; -- no file is staged, unstaged, or committed by the AI action. - -## Deterministic checks - -Choose **Generate/update table of contents** twice. Verify that one -marker-delimited TOC is generated and the second run updates it rather than -duplicating it. Then introduce a skipped heading level, an empty link, and an -empty table header to verify that BusyMark reports deterministic accessibility -diagnostics without making an AI request. - -## Qualification record - -Record the release result outside this demo document: - -| Field | Result | -| --- | --- | -| BusyMark version | | -| Provider | | -| Exact model | | -| Connection test | Pass / Fail | -| Editing actions | Pass / Fail | -| Markdown protection | Pass / Fail | -| Code assistance | Pass / Fail | -| Git draft | Pass / Fail | -| Cancellation/staleness | Pass / Fail | -| Reviewer and date | | diff --git a/demo/openapi-local-reference.md b/demo/openapi-local-reference.md deleted file mode 100644 index 29070782..00000000 --- a/demo/openapi-local-reference.md +++ /dev/null @@ -1,27 +0,0 @@ -# OpenAPI local-reference demo - -The parser resolves this relative file inside the canonical workspace root. - -```oas -openapi: 3.1.0 -info: - title: Local Reference Demo - version: 1.0.0 -paths: - /nodes/{id}: - get: - operationId: getNode - parameters: - - name: id - in: path - required: true - schema: - type: string - responses: - "200": - description: A recursive node - content: - application/json: - schema: - $ref: "./openapi/components.yaml#/components/schemas/Node" -``` diff --git a/demo/openapi/components.yaml b/demo/openapi/components.yaml deleted file mode 100644 index 48134c9d..00000000 --- a/demo/openapi/components.yaml +++ /dev/null @@ -1,10 +0,0 @@ -components: - schemas: - Node: - type: object - required: [id] - properties: - id: - type: string - parent: - $ref: "#/components/schemas/Node" diff --git a/demo/plantuml-conformance.md b/demo/plantuml-conformance.md deleted file mode 100644 index 8a531b1c..00000000 --- a/demo/plantuml-conformance.md +++ /dev/null @@ -1,169 +0,0 @@ -# PlantUML browser-build conformance corpus - -These diagrams cover the PlantUML families supported for BusyMark's first release. - -## Sequence - -```plantuml -@startuml -Alice -> Bob: Hello -Bob --> Alice: Ready -@enduml -``` - -## Class - -```puml -@startuml -class Document { - +title: String - +render(): Svg -} -interface Renderer -Renderer <|.. Document -@enduml -``` - -## Component - -```plantuml -@startuml -component BusyMark -component Renderer -BusyMark --> Renderer -@enduml -``` - -## Deployment - -```plantuml -@startuml -node "Linux desktop" { - artifact BusyMark - node WebKitGTK -} -BusyMark --> WebKitGTK -@enduml -``` - -## State - -```plantuml -@startuml -[*] --> Editing -Editing --> Rendering -Rendering --> Ready -Rendering --> Editing : invalid source -Ready --> [*] -@enduml -``` - -## Activity - -```plantuml -@startuml -start -:Parse source; -if (Valid?) then (yes) - :Render SVG; -else (no) - :Keep last valid render; -endif -stop -@enduml -``` - -## Use case - -```plantuml -@startuml -left to right direction -actor Author -rectangle BusyMark { - usecase "Preview diagram" as Preview - usecase "Export PDF" as Export -} -Author --> Preview -Author --> Export -@enduml -``` - -## Entity relationship - -```plantuml -@startuml -entity Document { - * id : UUID - -- - title : text -} -entity Diagram { - * id : UUID - document_id : UUID -} -Document ||--o{ Diagram -@enduml -``` - -## Mind map - -```plantuml -@startmindmap -* BusyMark -** Preview -*** Mermaid -*** PlantUML -*** D2 -** API Reference -*** OpenAPI -@endmindmap -``` - -## Work breakdown structure - -```plantuml -@startwbs -* Release -** Renderers -*** Mermaid -*** PlantUML -*** D2 -** OpenAPI -** PDF tests -@endwbs -``` - -## Gantt - -```plantuml -@startgantt -Project starts 2026-08-18 -[Renderer contracts] lasts 2 days -[Preview integration] starts at [Renderer contracts]'s end and lasts 2 days -[PDF verification] starts at [Preview integration]'s end and lasts 1 day -@endgantt -``` - -## JSON - -```plantuml -@startjson -{ - "offline": true, - "engines": ["Mermaid", "PlantUML", "D2", "OpenAPI"] -} -@endjson -``` - -## YAML - -```plantuml -@startyaml -application: BusyMark -offline: true -renderers: - - Mermaid - - PlantUML - - D2 -@endyaml -``` diff --git a/demo/visualizations.md b/demo/visualizations.md deleted file mode 100644 index 3a5bb94f..00000000 --- a/demo/visualizations.md +++ /dev/null @@ -1,114 +0,0 @@ -# BusyMark offline visualizations - -This document exercises every renderer without a network connection. - -## Mermaid - -```mermaid -flowchart LR - Source[Markdown fence] --> Render[Local WebKitGTK renderer] - Render --> Preview[Sanitized SVG preview] - Render --> PDF[Typst PDF asset] -``` - -## PlantUML - -```plantuml -@startuml -actor Author -participant BusyMark -participant "Bundled @plantuml/core" as PlantUML -Author -> BusyMark: Edit fenced diagram -BusyMark -> PlantUML: Render locally -PlantUML --> BusyMark: SVG -BusyMark --> Author: Sanitized preview -@enduml -``` - -## D2 vector output - -```d2 -direction: right -markdown: Markdown source -renderer: Bundled D2 CLI -preview: Sanitized SVG -pdf: Typst PDF -markdown -> renderer -> preview -renderer -> pdf -``` - -## D2 Markdown-label raster fallback - -```d2 -source: |md - # BusyMark - **Offline** diagram rendering -| -source -> output: browser-dependent label -``` - -## OpenAPI - -```openapi -openapi: 3.1.0 -info: - title: BusyMark Demo API - version: 1.0.0 - description: An offline API Reference demonstration. -servers: - - url: https://api.example.test/v1 - description: Demonstration server (requests are disabled) -paths: - /notes: - get: - operationId: listNotes - summary: List Markdown notes - tags: [Notes] - responses: - "200": - description: Notes returned successfully - content: - application/json: - schema: - type: array - items: - $ref: "#/components/schemas/Note" - post: - operationId: createNote - summary: Create a Markdown note - tags: [Notes] - requestBody: - required: true - content: - application/json: - schema: - $ref: "#/components/schemas/NoteInput" - responses: - "201": - description: Note created -components: - securitySchemes: - demoToken: - type: http - scheme: bearer - schemas: - Note: - type: object - required: [id, title] - properties: - id: - type: string - format: uuid - title: - type: string - body: - type: string - NoteInput: - type: object - required: [title] - properties: - title: - type: string - body: - type: string -``` diff --git a/demo/writerside-instances/admin.tree b/demo/writerside-instances/admin.tree deleted file mode 100644 index dcb64ad1..00000000 --- a/demo/writerside-instances/admin.tree +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE instance-profile SYSTEM "https://resources.jetbrains.com/writerside/1.0/product-profile.dtd"> -<instance-profile id="admin" name="Administration Guide" - start-page="operations.md" status="eap"> - <toc-element topic="operations.md"/> - <include from="shared.tree" element-id="setup" instance="@published" - use-filter="empty,server"/> -</instance-profile> diff --git a/demo/writerside-instances/cfg/PDF.xml b/demo/writerside-instances/cfg/PDF.xml deleted file mode 100644 index 45290aaa..00000000 --- a/demo/writerside-instances/cfg/PDF.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<pdf landscape="false"> - <cover-page> - <title>BusyMark Product Guide - Writerside instances, reusable navigation, and project workflows - BusyStack © 2026 - -
BusyMark Product Guide
-
BusyStack documentation
- Guide contents - diff --git a/demo/writerside-instances/cfg/buildprofiles.xml b/demo/writerside-instances/cfg/buildprofiles.xml deleted file mode 100644 index ba1c006c..00000000 --- a/demo/writerside-instances/cfg/buildprofiles.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - false - - - - - true - - - diff --git a/demo/writerside-instances/guide.tree b/demo/writerside-instances/guide.tree deleted file mode 100644 index e22e528b..00000000 --- a/demo/writerside-instances/guide.tree +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - diff --git a/demo/writerside-instances/images/busymark-mark.svg b/demo/writerside-instances/images/busymark-mark.svg deleted file mode 100644 index d6bff905..00000000 --- a/demo/writerside-instances/images/busymark-mark.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - BusyMark demo mark - - - - diff --git a/demo/writerside-instances/instance-groups.xml b/demo/writerside-instances/instance-groups.xml deleted file mode 100644 index 0a1d22a5..00000000 --- a/demo/writerside-instances/instance-groups.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/demo/writerside-instances/shared.tree b/demo/writerside-instances/shared.tree deleted file mode 100644 index 5f9ccf03..00000000 --- a/demo/writerside-instances/shared.tree +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/demo/writerside-instances/topics/desktop-settings.md b/demo/writerside-instances/topics/desktop-settings.md deleted file mode 100644 index 9c782c85..00000000 --- a/demo/writerside-instances/topics/desktop-settings.md +++ /dev/null @@ -1,3 +0,0 @@ -# Desktop settings - -This topic is selected by the `desktop` custom TOC filter. diff --git a/demo/writerside-instances/topics/install.md b/demo/writerside-instances/topics/install.md deleted file mode 100644 index 1b5cf76f..00000000 --- a/demo/writerside-instances/topics/install.md +++ /dev/null @@ -1,3 +0,0 @@ -# Install - -This topic is reused from the shared TOC library in both output instances. diff --git a/demo/writerside-instances/topics/legal.md b/demo/writerside-instances/topics/legal.md deleted file mode 100644 index b58d35fd..00000000 --- a/demo/writerside-instances/topics/legal.md +++ /dev/null @@ -1,4 +0,0 @@ -# Legal information - -This topic remains part of the Product Guide output but is hidden from its -published table of contents. diff --git a/demo/writerside-instances/topics/operations.md b/demo/writerside-instances/topics/operations.md deleted file mode 100644 index 49fa3401..00000000 --- a/demo/writerside-instances/topics/operations.md +++ /dev/null @@ -1,4 +0,0 @@ -# Operations - -This topic belongs to the Administration Guide and is referenced from the -Product Guide with `ref` and `in`. diff --git a/demo/writerside-instances/topics/server-settings.md b/demo/writerside-instances/topics/server-settings.md deleted file mode 100644 index 211fcfa7..00000000 --- a/demo/writerside-instances/topics/server-settings.md +++ /dev/null @@ -1,3 +0,0 @@ -# Server settings - -This topic is selected by the `server` custom TOC filter. diff --git a/demo/writerside-instances/topics/welcome.md b/demo/writerside-instances/topics/welcome.md deleted file mode 100644 index 6a70cd29..00000000 --- a/demo/writerside-instances/topics/welcome.md +++ /dev/null @@ -1,3 +0,0 @@ -# Welcome - -This topic is the start page of the Product Guide instance. diff --git a/demo/writerside-instances/writerside.cfg b/demo/writerside-instances/writerside.cfg deleted file mode 100644 index 14bfe09a..00000000 --- a/demo/writerside-instances/writerside.cfg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/docs/screenshots/busymark-d2.png b/docs/screenshots/busymark-d2.png new file mode 100644 index 0000000000000000000000000000000000000000..cd1c623ca1a53095f56b85f924a8762b1be4b723 GIT binary patch literal 75229 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%0D6*~G-&d9?1wsY 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 F{{d7AG7$g( literal 0 HcmV?d00001 diff --git a/docs/screenshots/busymark-openapi.png b/docs/screenshots/busymark-openapi.png new file mode 100644 index 0000000000000000000000000000000000000000..0956c4af7e8d88fc142aca75438ae07f84643cc0 GIT binary patch literal 55465 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

+cA|pqpF?UQ<>NBd&KEUJH9bsL05L9} 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 WW-7&@;&Uj{_Q~V=$1;Aj4*54EGfH3p literal 0 HcmV?d00001 diff --git a/docs/screenshots/busymark-split-view.png b/docs/screenshots/busymark-split-view.png index 95029305ee572b527b92dfde50489c9a25f60180..70d0e95a2f424efddf12f14a8a3fcf8e7d2c3c32 100644 GIT binary patch literal 348643 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 JTXQfV>z_}cpjQ9@ literal 123323 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

h)1UoFGZX$GAg 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�J)@ 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%0Dqn?sqbxzP#Zs?Chx4K{XmP8kGh7{Hw>l2S; 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 literal 0 HcmV?d00001 From 88b360e05f0f1533f62f4af8b590b21a55d52227 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 8 Sep 2026 17:00:58 -0700 Subject: [PATCH 33/37] Unify PDF and HTML export --- lib/src/app/busymark_app.dart | 44 +++------ lib/src/app/busymark_dialogs.dart | 5 +- lib/src/app/busymark_main_menu.dart | 21 ++-- lib/src/app/busymark_shortcuts.dart | 21 ++-- lib/src/app/command_registry.dart | 16 +-- lib/src/export/export_options_editor.dart | 98 ++++++++++++++----- lib/src/export/html_export_ui.dart | 39 +++++--- lib/src/export/markdown_pdf_export_ui.dart | 31 ++++-- lib/src/export/workspace_export_ui.dart | 44 +++++++++ lib/src/export/writerside_pdf_export_ui.dart | 34 ++++--- .../platform/header_bar_configuration.dart | 21 ++-- .../platform/linux_header_bar_service.dart | 6 +- .../presentation/settings_screen.dart | 6 +- .../presentation/welcome_screen.dart | 6 +- .../presentation/workspace_screen.dart | 15 +-- linux/runner/my_application.cc | 36 +++---- test/src/app_smoke_test.dart | 22 ++++- test/src/export_options_editor_test.dart | 60 +++++++++++- test/src/header_bar_configuration_test.dart | 12 ++- test/src/html_export_ui_test.dart | 68 +++++++------ test/src/native_headerbar_audit_test.dart | 13 ++- 21 files changed, 392 insertions(+), 226 deletions(-) create mode 100644 lib/src/export/workspace_export_ui.dart diff --git a/lib/src/app/busymark_app.dart b/lib/src/app/busymark_app.dart index e13fab3f..3a8bcaa5 100644 --- a/lib/src/app/busymark_app.dart +++ b/lib/src/app/busymark_app.dart @@ -10,8 +10,7 @@ import 'package:path/path.dart' as p; import 'package:ubuntu_localizations/ubuntu_localizations.dart'; import '../../l10n/generated/app_localizations.dart'; -import '../export/markdown_pdf_export_ui.dart'; -import '../export/html_export_ui.dart'; +import '../export/workspace_export_ui.dart'; import '../git/application/git_controller.dart'; import '../platform/linux_header_bar_service.dart'; import '../workspace/workspace_controller.dart'; @@ -40,8 +39,7 @@ final busyMarkCommandRegistryProvider = Provider(( BusyMarkCommandIds.newDocument: const _NewWorkspaceIntent(), BusyMarkCommandIds.open: const _OpenWorkspaceIntent(), BusyMarkCommandIds.save: const _SaveActiveIntent(), - BusyMarkCommandIds.exportPdf: const _ExportPdfIntent(), - BusyMarkCommandIds.exportHtml: const _ExportHtmlIntent(), + BusyMarkCommandIds.export: const _ExportIntent(), BusyMarkCommandIds.fullScreen: const _ToggleFullScreenIntent(), BusyMarkCommandIds.back: const _BackIntent(), BusyMarkCommandIds.search: const _OpenSearchIntent(), @@ -80,10 +78,8 @@ final busyMarkCommandRegistryProvider = Provider(( enabled: { BusyMarkCommandIds.save: () => ref.read(workspaceControllerProvider).workspace != null, - BusyMarkCommandIds.exportHtml: () => - canExportWorkspaceHtml(ref.read(workspaceControllerProvider)), - BusyMarkCommandIds.exportPdf: () => - canExportWorkspacePdf(ref.read(workspaceControllerProvider)), + BusyMarkCommandIds.export: () => + canExportWorkspace(ref.read(workspaceControllerProvider)), BusyMarkCommandIds.search: () => ref.read(workspaceControllerProvider).workspace != null, }, @@ -205,24 +201,13 @@ class BusyMarkApp extends ConsumerWidget { return null; }, ), - _ExportPdfIntent: CallbackAction<_ExportPdfIntent>( + _ExportIntent: CallbackAction<_ExportIntent>( onInvoke: (intent) { final state = ref.read(workspaceControllerProvider); final navigatorContext = rootNavigatorKey.currentContext; if (navigatorContext != null && - canExportWorkspacePdf(state)) { - unawaited(exportWorkspaceToPdf(navigatorContext, ref)); - } - return null; - }, - ), - _ExportHtmlIntent: CallbackAction<_ExportHtmlIntent>( - onInvoke: (intent) { - final state = ref.read(workspaceControllerProvider); - final navigatorContext = rootNavigatorKey.currentContext; - if (navigatorContext != null && - canExportWorkspaceHtml(state)) { - unawaited(exportWorkspaceToHtml(navigatorContext, ref)); + canExportWorkspace(state)) { + unawaited(exportWorkspace(navigatorContext, ref)); } return null; }, @@ -832,10 +817,9 @@ class BusyMarkApp extends ConsumerWidget { back: material.backButtonTooltip, backShortcut: shortcut(BusyMarkCommandIds.back), save: label(BusyMarkCommandIds.save), - exportPdf: label(BusyMarkCommandIds.exportPdf), - exportHtml: label(BusyMarkCommandIds.exportHtml), - exportPdfShortcut: shortcut(BusyMarkCommandIds.exportPdf), - exportPdfGtkAccelerator: accelerator(BusyMarkCommandIds.exportPdf), + export: label(BusyMarkCommandIds.export), + exportShortcut: shortcut(BusyMarkCommandIds.export), + exportGtkAccelerator: accelerator(BusyMarkCommandIds.export), fullScreen: label(BusyMarkCommandIds.fullScreen), fullScreenShortcut: shortcut(BusyMarkCommandIds.fullScreen), fullScreenGtkAccelerator: accelerator(BusyMarkCommandIds.fullScreen), @@ -1116,12 +1100,8 @@ class _SaveActiveIntent extends Intent { const _SaveActiveIntent(); } -class _ExportHtmlIntent extends Intent { - const _ExportHtmlIntent(); -} - -class _ExportPdfIntent extends Intent { - const _ExportPdfIntent(); +class _ExportIntent extends Intent { + const _ExportIntent(); } class _ToggleFullScreenIntent extends Intent { diff --git a/lib/src/app/busymark_dialogs.dart b/lib/src/app/busymark_dialogs.dart index 2924d003..50e548d6 100644 --- a/lib/src/app/busymark_dialogs.dart +++ b/lib/src/app/busymark_dialogs.dart @@ -495,11 +495,10 @@ void showLegacyBusyMarkKeyboardShortcutsDialog(BuildContext context) { ), ), BusyMarkActionRow( - title: context.l10n.exportAsPdf, - subtitle: context.l10n.shortcutExportPdfDescription, + title: context.l10n.export, leading: const Icon(BusyMarkGlyphs.exportPdf), trailing: const _KeyboardShortcutBadge( - BusyMarkAppShortcutLabels.exportPdf, + BusyMarkAppShortcutLabels.export, ), ), BusyMarkActionRow( diff --git a/lib/src/app/busymark_main_menu.dart b/lib/src/app/busymark_main_menu.dart index 177b5df1..1e6a842e 100644 --- a/lib/src/app/busymark_main_menu.dart +++ b/lib/src/app/busymark_main_menu.dart @@ -10,8 +10,7 @@ import 'localization.dart'; import 'window_control_service.dart'; enum BusyMarkMainMenuAction { - exportPdf, - exportHtml, + export, generateMarkdownToc, fullScreen, settings, @@ -51,18 +50,11 @@ class BusyMarkMainMenuButton extends ConsumerWidget { icon: BusyMarkGlyphs.menuVertical, itemBuilder: (context) => [ BusyMarkPopupMenuItem( - value: BusyMarkMainMenuAction.exportPdf, - label: command(BusyMarkCommandIds.exportPdf).label(context), + value: BusyMarkMainMenuAction.export, + label: command(BusyMarkCommandIds.export).label(context), icon: BusyMarkGlyphs.exportPdf, - shortcut: command(BusyMarkCommandIds.exportPdf).shortcut?.label, - enabled: canExportPdf, - ), - BusyMarkPopupMenuItem( - value: BusyMarkMainMenuAction.exportHtml, - label: command(BusyMarkCommandIds.exportHtml).label(context), - icon: BusyMarkGlyphs.exportPdf, - shortcut: command(BusyMarkCommandIds.exportHtml).shortcut?.label, - enabled: canExportHtml, + shortcut: command(BusyMarkCommandIds.export).shortcut?.label, + enabled: canExportPdf || canExportHtml, ), BusyMarkPopupMenuItem( value: BusyMarkMainMenuAction.generateMarkdownToc, @@ -118,8 +110,7 @@ class BusyMarkMainMenuButton extends ConsumerWidget { ], onSelected: (action) { final commandId = switch (action) { - BusyMarkMainMenuAction.exportPdf => BusyMarkCommandIds.exportPdf, - BusyMarkMainMenuAction.exportHtml => BusyMarkCommandIds.exportHtml, + BusyMarkMainMenuAction.export => BusyMarkCommandIds.export, BusyMarkMainMenuAction.fullScreen => BusyMarkCommandIds.fullScreen, BusyMarkMainMenuAction.settings => BusyMarkCommandIds.settings, BusyMarkMainMenuAction.keyboardShortcuts => diff --git a/lib/src/app/busymark_shortcuts.dart b/lib/src/app/busymark_shortcuts.dart index 1d1f67eb..94e814f4 100644 --- a/lib/src/app/busymark_shortcuts.dart +++ b/lib/src/app/busymark_shortcuts.dart @@ -22,7 +22,7 @@ enum BusyMarkAppShortcutAction { newDocument, open, save, - exportPdf, + export, fullScreen, back, search, @@ -43,7 +43,7 @@ abstract final class BusyMarkAppShortcuts { static const newDocumentLabel = 'Ctrl+N'; static const openLabel = 'Ctrl+O'; static const saveLabel = 'Ctrl+S'; - static const exportPdfLabel = 'Ctrl+Shift+E'; + static const exportLabel = 'Ctrl+Shift+E'; static const fullScreenLabel = 'F11'; static const backLabel = 'Alt+Left'; static const searchLabel = 'Ctrl+F'; @@ -60,7 +60,7 @@ abstract final class BusyMarkAppShortcuts { static const newDocumentGtkAccelerator = 'n'; static const openGtkAccelerator = 'o'; static const saveGtkAccelerator = 's'; - static const exportPdfGtkAccelerator = 'e'; + static const exportGtkAccelerator = 'e'; static const fullScreenGtkAccelerator = 'F11'; static const backGtkAccelerator = 'Left'; static const searchGtkAccelerator = 'f'; @@ -89,14 +89,14 @@ abstract final class BusyMarkAppShortcuts { activator: SingleActivator(LogicalKeyboardKey.keyS, control: true), gtkAccelerator: saveGtkAccelerator, ); - static const exportPdf = BusyMarkShortcutDefinition( - label: exportPdfLabel, + static const export = BusyMarkShortcutDefinition( + label: exportLabel, activator: SingleActivator( LogicalKeyboardKey.keyE, control: true, shift: true, ), - gtkAccelerator: exportPdfGtkAccelerator, + gtkAccelerator: exportGtkAccelerator, ); static const fullScreen = BusyMarkShortcutDefinition( label: fullScreenLabel, @@ -192,7 +192,7 @@ abstract final class BusyMarkAppShortcuts { BusyMarkAppShortcutAction.newDocument: newDocument, BusyMarkAppShortcutAction.open: open, BusyMarkAppShortcutAction.save: save, - BusyMarkAppShortcutAction.exportPdf: exportPdf, + BusyMarkAppShortcutAction.export: export, BusyMarkAppShortcutAction.fullScreen: fullScreen, BusyMarkAppShortcutAction.back: back, BusyMarkAppShortcutAction.search: search, @@ -214,7 +214,7 @@ abstract final class BusyMarkAppShortcutLabels { static const newDocument = BusyMarkAppShortcuts.newDocumentLabel; static const open = BusyMarkAppShortcuts.openLabel; static const save = BusyMarkAppShortcuts.saveLabel; - static const exportPdf = BusyMarkAppShortcuts.exportPdfLabel; + static const export = BusyMarkAppShortcuts.exportLabel; static const fullScreen = BusyMarkAppShortcuts.fullScreenLabel; static const back = BusyMarkAppShortcuts.backLabel; static const search = BusyMarkAppShortcuts.searchLabel; @@ -235,8 +235,7 @@ abstract final class BusyMarkAppShortcutActivators { BusyMarkAppShortcuts.newDocument.activator; static ShortcutActivator get open => BusyMarkAppShortcuts.open.activator; static ShortcutActivator get save => BusyMarkAppShortcuts.save.activator; - static ShortcutActivator get exportPdf => - BusyMarkAppShortcuts.exportPdf.activator; + static ShortcutActivator get export => BusyMarkAppShortcuts.export.activator; static ShortcutActivator get fullScreen => BusyMarkAppShortcuts.fullScreen.activator; static ShortcutActivator get back => BusyMarkAppShortcuts.back.activator; @@ -265,7 +264,7 @@ abstract final class BusyMarkAppShortcutGtkAccelerators { const BusyMarkAppShortcutGtkAccelerators._(); static const search = BusyMarkAppShortcuts.searchGtkAccelerator; - static const exportPdf = BusyMarkAppShortcuts.exportPdfGtkAccelerator; + static const export = BusyMarkAppShortcuts.exportGtkAccelerator; static const fullScreen = BusyMarkAppShortcuts.fullScreenGtkAccelerator; static const back = BusyMarkAppShortcuts.backGtkAccelerator; static const keyboardShortcuts = diff --git a/lib/src/app/command_registry.dart b/lib/src/app/command_registry.dart index 618ae37f..3813b741 100644 --- a/lib/src/app/command_registry.dart +++ b/lib/src/app/command_registry.dart @@ -244,8 +244,7 @@ abstract final class BusyMarkCommandIds { static const newDocument = 'file.newDocument'; static const open = 'file.open'; static const save = 'file.save'; - static const exportPdf = 'file.exportPdf'; - static const exportHtml = 'file.exportHtml'; + static const export = 'file.export'; static const fullScreen = 'view.fullScreen'; static const back = 'navigation.back'; static const search = 'search.find'; @@ -320,12 +319,6 @@ abstract final class BusyMarkCommandCatalog { } final commands = [ - command( - id: BusyMarkCommandIds.exportHtml, - label: (context) => context.l10n.exportAsHtml, - category: (context) => context.l10n.export, - scope: BusyMarkCommandScope.application, - ), for (final action in BusyMarkAppShortcutAction.values) command( id: _appId(action), @@ -396,7 +389,7 @@ abstract final class BusyMarkCommandCatalog { BusyMarkAppShortcutAction.newDocument => BusyMarkCommandIds.newDocument, BusyMarkAppShortcutAction.open => BusyMarkCommandIds.open, BusyMarkAppShortcutAction.save => BusyMarkCommandIds.save, - BusyMarkAppShortcutAction.exportPdf => BusyMarkCommandIds.exportPdf, + BusyMarkAppShortcutAction.export => BusyMarkCommandIds.export, BusyMarkAppShortcutAction.fullScreen => BusyMarkCommandIds.fullScreen, BusyMarkAppShortcutAction.back => BusyMarkCommandIds.back, BusyMarkAppShortcutAction.search => BusyMarkCommandIds.search, @@ -421,7 +414,7 @@ abstract final class BusyMarkCommandCatalog { BusyMarkAppShortcutAction.newDocument => context.l10n.shortcutNewDocument, BusyMarkAppShortcutAction.open => context.l10n.open, BusyMarkAppShortcutAction.save => context.l10n.save, - BusyMarkAppShortcutAction.exportPdf => context.l10n.exportAsPdf, + BusyMarkAppShortcutAction.export => context.l10n.export, BusyMarkAppShortcutAction.fullScreen => context.l10n.fullScreen, BusyMarkAppShortcutAction.back => context.l10n.back, BusyMarkAppShortcutAction.search => context.l10n.search, @@ -468,8 +461,7 @@ abstract final class BusyMarkCommandCatalog { context.l10n.shortcutNewDocumentDescription, BusyMarkAppShortcutAction.open => context.l10n.shortcutOpenDescription, BusyMarkAppShortcutAction.save => context.l10n.shortcutSaveDescription, - BusyMarkAppShortcutAction.exportPdf => - context.l10n.shortcutExportPdfDescription, + BusyMarkAppShortcutAction.export => null, BusyMarkAppShortcutAction.search => context.l10n.shortcutSearchDescription, BusyMarkAppShortcutAction.keyboardShortcuts => context.l10n.shortcutKeyboardShortcutsDescription, diff --git a/lib/src/export/export_options_editor.dart b/lib/src/export/export_options_editor.dart index 2acb3183..f5b3965a 100644 --- a/lib/src/export/export_options_editor.dart +++ b/lib/src/export/export_options_editor.dart @@ -10,6 +10,8 @@ import '../writerside/writerside_model.dart'; import 'export_options.dart'; import 'html_export_styles.dart'; +enum ExportFormat { pdf, html } + class ExportOptionsSelection { const ExportOptionsSelection({this.pdf, this.html, this.instance}); final PdfExportOptions? pdf; @@ -20,10 +22,13 @@ class ExportOptionsSelection { Future showExportOptions( BuildContext context, WidgetRef ref, { - required bool pdf, + ExportFormat initialFormat = ExportFormat.pdf, + bool canExportPdf = true, + bool canExportHtml = true, List instances = const [], String? workspaceRoot, }) async { + assert(canExportPdf || canExportHtml); final controller = ref.read(appSettingsControllerProvider.notifier); await controller.waitUntilLoaded(); if (!context.mounted) return null; @@ -34,8 +39,11 @@ Future showExportOptions( headerBarService: bar.isAvailable ? bar : null, maxWidth: 720, builder: (context) => ExportOptionsDialog( - pdf: pdf ? settings.pdfExportOptions : null, - html: pdf ? null : settings.htmlExportOptions, + pdf: settings.pdfExportOptions, + html: settings.htmlExportOptions, + initialFormat: initialFormat, + canExportPdf: canExportPdf, + canExportHtml: canExportHtml, instances: instances, instanceId: workspaceRoot == null ? null @@ -61,13 +69,19 @@ Future showExportOptions( class ExportOptionsDialog extends StatefulWidget { const ExportOptionsDialog({ super.key, - this.pdf, - this.html, + required this.pdf, + required this.html, + required this.initialFormat, + this.canExportPdf = true, + this.canExportHtml = true, this.instances = const [], this.instanceId, - }) : assert((pdf == null) != (html == null)); - final PdfExportOptions? pdf; - final HtmlExportOptions? html; + }) : assert(canExportPdf || canExportHtml); + final PdfExportOptions pdf; + final HtmlExportOptions html; + final ExportFormat initialFormat; + final bool canExportPdf; + final bool canExportHtml; final List instances; final String? instanceId; @override @@ -75,8 +89,9 @@ class ExportOptionsDialog extends StatefulWidget { } class _ExportOptionsDialogState extends State { - late PdfExportOptions? _pdf = widget.pdf; - late HtmlExportOptions? _html = widget.html; + late PdfExportOptions _pdf = widget.pdf; + late HtmlExportOptions _html = widget.html; + late ExportFormat _format = _availableInitialFormat(); late WritersideInstance? _instance = widget.instances.where((i) => i.id == widget.instanceId).firstOrNull ?? widget.instances.firstOrNull; @@ -84,16 +99,28 @@ class _ExportOptionsDialogState extends State { var _saving = false; List _fileErrors = []; List get _issues => [ - ...?_pdf?.validate(), - ...?_html?.validate(), + ...switch (_format) { + ExportFormat.pdf => _pdf.validate(), + ExportFormat.html => _html.validate(), + }, ..._fileErrors, ]; + ExportFormat _availableInitialFormat() { + if (widget.initialFormat == ExportFormat.pdf && widget.canExportPdf) { + return ExportFormat.pdf; + } + if (widget.initialFormat == ExportFormat.html && widget.canExportHtml) { + return ExportFormat.html; + } + return widget.canExportPdf ? ExportFormat.pdf : ExportFormat.html; + } + Future _submit() async { if (_issues.isNotEmpty) return; final selection = ExportOptionsSelection( - pdf: _pdf, - html: _html, + pdf: _format == ExportFormat.pdf ? _pdf : null, + html: _format == ExportFormat.html ? _html : null, instance: _instance, ); setState(() => _saving = true); @@ -116,20 +143,47 @@ class _ExportOptionsDialogState extends State { @override Widget build(BuildContext context) => BusyMarkModalEditorScaffold( - title: _pdf == null ? context.l10n.exportAsHtml : context.l10n.exportAsPdf, + title: context.l10n.export, cancelLabel: context.l10n.cancel, saveLabel: context.l10n.export, onCancel: () => Navigator.pop(context), onSave: _issues.isEmpty && !_saving ? _submit : null, + saveKey: const ValueKey('export-options-submit'), saving: _saving, children: [ + SegmentedButton( + showSelectedIcon: false, + segments: [ + ButtonSegment( + value: ExportFormat.pdf, + label: const Text('PDF'), + enabled: widget.canExportPdf, + ), + ButtonSegment( + value: ExportFormat.html, + label: const Text('HTML'), + enabled: widget.canExportHtml, + ), + ], + selected: {_format}, + onSelectionChanged: _saving + ? null + : (selection) => setState(() { + _format = selection.single; + _fileErrors = []; + }), + ), + const SizedBox(height: BusyMarkSpacing.md), BusyMarkDialogButton( label: context.l10n.exportReset, onPressed: _saving ? null : () => setState(() { - if (_pdf != null) _pdf = const PdfExportOptions(); - if (_html != null) _html = const HtmlExportOptions(); + if (_format == ExportFormat.pdf) { + _pdf = const PdfExportOptions(); + } else { + _html = const HtmlExportOptions(); + } _revision++; _fileErrors = []; }), @@ -143,17 +197,17 @@ class _ExportOptionsDialogState extends State { style: TextStyle(color: Theme.of(context).colorScheme.error), ), ), - if (_pdf != null) + if (_format == ExportFormat.pdf) PdfExportOptionsEditor( - key: ValueKey(_revision), - value: _pdf!, + key: ValueKey((_format, _revision)), + value: _pdf, instance: _instanceRow(context), onChanged: (value) => setState(() => _pdf = value), ) else HtmlExportOptionsEditor( - key: ValueKey(_revision), - value: _html!, + key: ValueKey((_format, _revision)), + value: _html, instance: _instanceRow(context), onChanged: (value) => setState(() { _html = value; diff --git a/lib/src/export/html_export_ui.dart b/lib/src/export/html_export_ui.dart index bda62501..caee626e 100644 --- a/lib/src/export/html_export_ui.dart +++ b/lib/src/export/html_export_ui.dart @@ -31,7 +31,11 @@ final htmlExportServiceProvider = Provider( bool canExportWorkspaceHtml(WorkspaceState state) => canExportActiveMarkdown(state) || canExportWritersidePdf(state); -Future exportWorkspaceToHtml(BuildContext context, WidgetRef ref) async { +Future exportWorkspaceToHtml( + BuildContext context, + WidgetRef ref, { + ExportOptionsSelection? configuredSelection, +}) async { var snapshot = ref.read(workspaceControllerProvider); if (!canExportWorkspaceHtml(snapshot)) return; final site = snapshot.workspace?.kind == WorkspaceKind.writersideModule; @@ -41,20 +45,25 @@ Future exportWorkspaceToHtml(BuildContext context, WidgetRef ref) async { } final workspace = snapshot.workspace!; final headerBar = ref.read(linuxHeaderBarServiceProvider); - final selection = await showExportOptions( - context, - ref, - pdf: false, - instances: site - ? workspace.writersideModule!.instances - .where((i) => !i.isLibrary) - .toList() - : const [], - workspaceRoot: site ? workspace.rootPath : null, - ); - if (selection == null || !context.mounted) return; - final instance = selection.instance; - final options = selection.html!; + final configuration = + configuredSelection ?? + await showExportOptions( + context, + ref, + initialFormat: ExportFormat.html, + canExportPdf: false, + instances: site + ? workspace.writersideModule!.instances + .where((i) => !i.isLibrary) + .toList() + : const [], + workspaceRoot: site ? workspace.rootPath : null, + ); + if (configuration == null || configuration.html == null || !context.mounted) { + return; + } + final instance = configuration.instance; + final options = configuration.html!; final path = workspace.activeFilePath ?? workspace.markdown?.filePath ?? ''; final name = path.isEmpty ? context.l10n.untitledMarkdownFileName diff --git a/lib/src/export/markdown_pdf_export_ui.dart b/lib/src/export/markdown_pdf_export_ui.dart index e7de3fb5..665dd933 100644 --- a/lib/src/export/markdown_pdf_export_ui.dart +++ b/lib/src/export/markdown_pdf_export_ui.dart @@ -58,27 +58,42 @@ bool canExportWorkspacePdf(WorkspaceState state) { return canExportActiveMarkdown(state) || canExportWritersidePdf(state); } -Future exportWorkspaceToPdf(BuildContext context, WidgetRef ref) { +Future exportWorkspaceToPdf( + BuildContext context, + WidgetRef ref, { + ExportOptionsSelection? configuredSelection, +}) { final workspace = ref.read(workspaceControllerProvider).workspace; if (workspace?.kind == WorkspaceKind.writersideModule) { - return exportWritersideModuleToPdf(context, ref); + return exportWritersideModuleToPdf( + context, + ref, + configuredSelection: configuredSelection, + ); } - return exportActiveMarkdownToPdf(context, ref); + return exportActiveMarkdownToPdf( + context, + ref, + configuredSelection: configuredSelection, + ); } Future exportActiveMarkdownToPdf( BuildContext context, - WidgetRef ref, -) async { + WidgetRef ref, { + ExportOptionsSelection? configuredSelection, +}) async { final snapshot = ref.read(workspaceControllerProvider); if (!canExportActiveMarkdown(snapshot)) { return; } final workspace = snapshot.workspace!; final headerBar = ref.read(linuxHeaderBarServiceProvider); - final selection = await showExportOptions(context, ref, pdf: true); - if (selection == null || !context.mounted) return; - final options = selection.pdf!; + final selected = + configuredSelection ?? + await showExportOptions(context, ref, canExportHtml: false); + if (selected == null || selected.pdf == null || !context.mounted) return; + final options = selected.pdf!; final activePath = workspace.activeFilePath ?? workspace.markdown?.filePath; final baseName = activePath == null || activePath.isEmpty diff --git a/lib/src/export/workspace_export_ui.dart b/lib/src/export/workspace_export_ui.dart new file mode 100644 index 00000000..de76071a --- /dev/null +++ b/lib/src/export/workspace_export_ui.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../workspace/workspace_controller.dart'; +import '../workspace/workspace_model.dart'; +import 'export_options_editor.dart'; +import 'html_export_ui.dart'; +import 'markdown_pdf_export_ui.dart'; + +export 'html_export_ui.dart' show canExportWorkspaceHtml; +export 'markdown_pdf_export_ui.dart' show canExportWorkspacePdf; + +bool canExportWorkspace(WorkspaceState state) => + canExportWorkspacePdf(state) || canExportWorkspaceHtml(state); + +Future exportWorkspace(BuildContext context, WidgetRef ref) async { + final state = ref.read(workspaceControllerProvider); + final canExportPdf = canExportWorkspacePdf(state); + final canExportHtml = canExportWorkspaceHtml(state); + if (!canExportPdf && !canExportHtml) return; + + final workspace = state.workspace!; + final writerside = workspace.kind == WorkspaceKind.writersideModule; + final selection = await showExportOptions( + context, + ref, + initialFormat: canExportPdf ? ExportFormat.pdf : ExportFormat.html, + canExportPdf: canExportPdf, + canExportHtml: canExportHtml, + instances: writerside + ? workspace.writersideModule!.instances + .where((instance) => !instance.isLibrary) + .toList(growable: false) + : const [], + workspaceRoot: writerside ? workspace.rootPath : null, + ); + if (selection == null || !context.mounted) return; + + if (selection.pdf != null) { + await exportWorkspaceToPdf(context, ref, configuredSelection: selection); + } else if (selection.html != null) { + await exportWorkspaceToHtml(context, ref, configuredSelection: selection); + } +} diff --git a/lib/src/export/writerside_pdf_export_ui.dart b/lib/src/export/writerside_pdf_export_ui.dart index cc118280..8c74a947 100644 --- a/lib/src/export/writerside_pdf_export_ui.dart +++ b/lib/src/export/writerside_pdf_export_ui.dart @@ -55,8 +55,9 @@ String defaultWritersideModuleName(WritersideModule module) { Future exportWritersideModuleToPdf( BuildContext context, - WidgetRef ref, -) async { + WidgetRef ref, { + ExportOptionsSelection? configuredSelection, +}) async { if (!canExportWritersidePdf(ref.read(workspaceControllerProvider))) { return; } @@ -73,14 +74,21 @@ Future exportWritersideModuleToPdf( .where((instance) => !instance.isLibrary) .toList(growable: false); final headerBar = ref.read(linuxHeaderBarServiceProvider); - final selection = await showExportOptions( - context, - ref, - pdf: true, - instances: instances, - workspaceRoot: workspace.rootPath, - ); - if (selection == null || !context.mounted) return; + final selected = + configuredSelection ?? + await showExportOptions( + context, + ref, + canExportHtml: false, + instances: instances, + workspaceRoot: workspace.rootPath, + ); + if (selected == null || + selected.pdf == null || + selected.instance == null || + !context.mounted) { + return; + } final location = await getSaveLocation( acceptedTypeGroups: [ XTypeGroup( @@ -89,7 +97,7 @@ Future exportWritersideModuleToPdf( mimeTypes: const ['application/pdf'], ), ], - suggestedName: '${selection.instance!.id}.pdf', + suggestedName: '${selected.instance!.id}.pdf', initialDirectory: module.rootPath, confirmButtonText: context.l10n.export, ); @@ -113,10 +121,10 @@ Future exportWritersideModuleToPdf( final request = WritersidePdfExportRequest( moduleRoot: module.rootPath, projectRoot: workspace.rootPath, - instanceId: selection.instance!.id, + instanceId: selected.instance!.id, destinationPath: destination, overwrite: overwrite, - options: selection.pdf!, + options: selected.pdf!, ); final outcome = await showBusyMarkModalDialog<_WritersidePdfOutcome>( context, diff --git a/lib/src/platform/header_bar_configuration.dart b/lib/src/platform/header_bar_configuration.dart index 7a527af0..0ad1759a 100644 --- a/lib/src/platform/header_bar_configuration.dart +++ b/lib/src/platform/header_bar_configuration.dart @@ -32,10 +32,9 @@ class HeaderBarLabels { required this.back, required this.backShortcut, required this.save, - required this.exportPdf, - this.exportHtml = '', - required this.exportPdfShortcut, - required this.exportPdfGtkAccelerator, + required this.export, + required this.exportShortcut, + required this.exportGtkAccelerator, required this.fullScreen, required this.fullScreenShortcut, required this.fullScreenGtkAccelerator, @@ -74,10 +73,9 @@ class HeaderBarLabels { final String back; final String backShortcut; final String save; - final String exportPdf; - final String exportHtml; - final String exportPdfShortcut; - final String exportPdfGtkAccelerator; + final String export; + final String exportShortcut; + final String exportGtkAccelerator; final String fullScreen; final String fullScreenShortcut; final String fullScreenGtkAccelerator; @@ -116,10 +114,9 @@ class HeaderBarLabels { 'back': back, 'backShortcut': backShortcut, 'save': save, - 'exportPdf': exportPdf, - 'exportHtml': exportHtml, - 'exportPdfShortcut': exportPdfShortcut, - 'exportPdfGtkAccelerator': exportPdfGtkAccelerator, + 'export': export, + 'exportShortcut': exportShortcut, + 'exportGtkAccelerator': exportGtkAccelerator, 'fullScreen': fullScreen, 'fullScreenShortcut': fullScreenShortcut, 'fullScreenGtkAccelerator': fullScreenGtkAccelerator, diff --git a/lib/src/platform/linux_header_bar_service.dart b/lib/src/platform/linux_header_bar_service.dart index 1ae96164..0e22370d 100644 --- a/lib/src/platform/linux_header_bar_service.dart +++ b/lib/src/platform/linux_header_bar_service.dart @@ -16,8 +16,7 @@ enum HeaderBarAction { search, refresh, save, - exportPdf, - exportHtml, + export, fullScreen, menu, settings, @@ -392,8 +391,7 @@ class LinuxHeaderBarService extends ChangeNotifier { 'search' => HeaderBarAction.search, 'refresh' => HeaderBarAction.refresh, 'save' => HeaderBarAction.save, - 'exportPdf' => HeaderBarAction.exportPdf, - 'exportHtml' => HeaderBarAction.exportHtml, + 'export' => HeaderBarAction.export, 'fullScreen' => HeaderBarAction.fullScreen, 'menu' => HeaderBarAction.menu, 'settings' => HeaderBarAction.settings, diff --git a/lib/src/workspace/presentation/settings_screen.dart b/lib/src/workspace/presentation/settings_screen.dart index 6e373bc1..04fe49e9 100644 --- a/lib/src/workspace/presentation/settings_screen.dart +++ b/lib/src/workspace/presentation/settings_screen.dart @@ -318,8 +318,7 @@ class _SettingsScreenState extends ConsumerState { case HeaderBarAction.search: case HeaderBarAction.refresh: case HeaderBarAction.save: - case HeaderBarAction.exportHtml: - case HeaderBarAction.exportPdf: + case HeaderBarAction.export: case HeaderBarAction.fullScreen: case HeaderBarAction.menu: case HeaderBarAction.viewModeEditor: @@ -340,8 +339,7 @@ class _SettingsScreenState extends ConsumerState { BusyMarkMainMenuAction action, ) { switch (action) { - case BusyMarkMainMenuAction.exportHtml: - case BusyMarkMainMenuAction.exportPdf: + case BusyMarkMainMenuAction.export: case BusyMarkMainMenuAction.generateMarkdownToc: break; case BusyMarkMainMenuAction.fullScreen: diff --git a/lib/src/workspace/presentation/welcome_screen.dart b/lib/src/workspace/presentation/welcome_screen.dart index 063b0276..e7a0dee9 100644 --- a/lib/src/workspace/presentation/welcome_screen.dart +++ b/lib/src/workspace/presentation/welcome_screen.dart @@ -255,8 +255,7 @@ class _WelcomeScreenState extends ConsumerState { case HeaderBarAction.search: case HeaderBarAction.refresh: case HeaderBarAction.save: - case HeaderBarAction.exportHtml: - case HeaderBarAction.exportPdf: + case HeaderBarAction.export: case HeaderBarAction.fullScreen: case HeaderBarAction.menu: case HeaderBarAction.viewModeEditor: @@ -286,8 +285,7 @@ class _WelcomeScreenState extends ConsumerState { BusyMarkMainMenuAction action, ) { switch (action) { - case BusyMarkMainMenuAction.exportHtml: - case BusyMarkMainMenuAction.exportPdf: + case BusyMarkMainMenuAction.export: case BusyMarkMainMenuAction.generateMarkdownToc: break; case BusyMarkMainMenuAction.fullScreen: diff --git a/lib/src/workspace/presentation/workspace_screen.dart b/lib/src/workspace/presentation/workspace_screen.dart index bbbfa17d..df59d13e 100644 --- a/lib/src/workspace/presentation/workspace_screen.dart +++ b/lib/src/workspace/presentation/workspace_screen.dart @@ -57,8 +57,7 @@ import '../../editor/wysiwyg/wysiwyg_editor.dart'; import '../../editor/wysiwyg/wysiwyg_session_state.dart'; import '../../editor/writerside_video_view.dart'; import '../../feedback/presentation/feedback_dialog.dart'; -import '../../export/markdown_pdf_export_ui.dart'; -import '../../export/html_export_ui.dart'; +import '../../export/workspace_export_ui.dart'; import '../../git/application/git_controller.dart'; import '../../git/domain/git_models.dart'; import '../../git/presentation/git_diff_viewer.dart'; @@ -978,10 +977,8 @@ class WorkspaceScreen extends ConsumerWidget { unawaited(_validateActiveAndShowProblems(context, ref)); case HeaderBarAction.save: execute(BusyMarkCommandIds.save); - case HeaderBarAction.exportHtml: - execute(BusyMarkCommandIds.exportHtml); - case HeaderBarAction.exportPdf: - execute(BusyMarkCommandIds.exportPdf); + case HeaderBarAction.export: + execute(BusyMarkCommandIds.export); case HeaderBarAction.fullScreen: execute(BusyMarkCommandIds.fullScreen); case HeaderBarAction.settings: @@ -1027,10 +1024,8 @@ class WorkspaceScreen extends ConsumerWidget { BusyMarkMainMenuAction action, ) { switch (action) { - case BusyMarkMainMenuAction.exportHtml: - unawaited(exportWorkspaceToHtml(context, ref)); - case BusyMarkMainMenuAction.exportPdf: - unawaited(exportWorkspaceToPdf(context, ref)); + case BusyMarkMainMenuAction.export: + unawaited(exportWorkspace(context, ref)); case BusyMarkMainMenuAction.generateMarkdownToc: _generateOrUpdateMarkdownToc(context, ref); case BusyMarkMainMenuAction.fullScreen: diff --git a/linux/runner/my_application.cc b/linux/runner/my_application.cc index f20cac9c..20b6d289 100644 --- a/linux/runner/my_application.cc +++ b/linux/runner/my_application.cc @@ -109,6 +109,8 @@ struct _MyApplication { GtkWidget* search_entry; gboolean document_controls_visible; gboolean search_visible; + gboolean can_export_pdf; + gboolean can_export_html; GtkWidget* view_mode_box; GtkWidget* view_mode_button; GtkWidget* view_mode_icon; @@ -1325,7 +1327,7 @@ static GtkWidget* create_header_toggle_button(const gchar* icon_name) { } static const gchar* main_menu_icon_name(const gchar* action) { - if (g_strcmp0(action, "exportPdf") == 0 || g_strcmp0(action, "exportHtml") == 0) { + if (g_strcmp0(action, "export") == 0) { return "document-save-as-symbolic"; } if (g_strcmp0(action, "settings") == 0) { @@ -1381,14 +1383,9 @@ static void rebuild_main_menu_model(MyApplication* self, FlValue* labels) { g_menu_remove_all(self->main_menu_model); append_action_menu_item( self->main_menu_model, - localized_label_or(labels, "exportPdf", ""), "header.export-pdf", - main_menu_icon_name("exportPdf"), - fl_lookup_string_arg(labels, "exportPdfGtkAccelerator")); - append_action_menu_item( - self->main_menu_model, - localized_label_or(labels, "exportHtml", ""), "header.export-html", - main_menu_icon_name("exportHtml"), - nullptr); + localized_label_or(labels, "export", ""), "header.export", + main_menu_icon_name("export"), + fl_lookup_string_arg(labels, "exportGtkAccelerator")); append_action_menu_item( self->main_menu_model, localized_label_or(labels, "fullScreen", ""), "header.full-screen", @@ -1560,10 +1557,8 @@ static void set_header_action_enabled(MyApplication* self, static void setup_header_actions(MyApplication* self) { self->header_action_group = g_simple_action_group_new(); - add_header_gaction(self, "export-pdf", "exportPdf"); - add_header_gaction(self, "export-html", "exportHtml"); - set_header_action_enabled(self, "export-html", FALSE); - set_header_action_enabled(self, "export-pdf", FALSE); + add_header_gaction(self, "export", "export"); + set_header_action_enabled(self, "export", FALSE); add_header_gaction(self, "settings", "settings"); add_header_gaction(self, "keyboard-shortcuts", "keyboardShortcuts"); add_header_gaction(self, "syntax-reference", "syntaxReference"); @@ -1927,9 +1922,10 @@ static void apply_header_bar_configuration( gtk_label_set_text(GTK_LABEL(self->title_label), configuration.title); } set_widget_sensitive(self->refresh_button, configuration.can_refresh); - set_header_action_enabled(self, "export-pdf", - configuration.can_export_pdf); - set_header_action_enabled(self, "export-html", configuration.can_export_html); + self->can_export_pdf = configuration.can_export_pdf; + self->can_export_html = configuration.can_export_html; + set_header_action_enabled( + self, "export", self->can_export_pdf || self->can_export_html); set_sidebar_width(self, configuration.sidebar_width); set_text_direction(self, configuration.text_direction); set_sidebar_visible(self, configuration.sidebar_visible); @@ -2170,10 +2166,14 @@ static void header_bar_method_call_cb(FlMethodChannel* channel, set_widget_sensitive(self->refresh_button, fl_method_bool_arg(args)); respond_success(method_call); } else if (strcmp(method, "setCanExportHtml") == 0) { - set_header_action_enabled(self, "export-html", fl_method_bool_arg(args)); + self->can_export_html = fl_method_bool_arg(args); + set_header_action_enabled( + self, "export", self->can_export_pdf || self->can_export_html); respond_success(method_call); } else if (strcmp(method, "setCanExportPdf") == 0) { - set_header_action_enabled(self, "export-pdf", fl_method_bool_arg(args)); + self->can_export_pdf = fl_method_bool_arg(args); + set_header_action_enabled( + self, "export", self->can_export_pdf || self->can_export_html); respond_success(method_call); } else if (strcmp(method, "setDocumentControlsVisible") == 0) { set_document_controls_visible(self, fl_method_bool_arg(args)); diff --git a/test/src/app_smoke_test.dart b/test/src/app_smoke_test.dart index 91096407..39bd407a 100644 --- a/test/src/app_smoke_test.dart +++ b/test/src/app_smoke_test.dart @@ -31,6 +31,7 @@ import 'package:busymark/src/editor/markdown_image_view.dart'; import 'package:busymark/src/editor/source/source_editor.dart'; import 'package:busymark/src/editor/source/source_read_only_view.dart'; import 'package:busymark/src/feedback/presentation/feedback_dialog.dart'; +import 'package:busymark/src/export/export_options_editor.dart'; import 'package:busymark/src/git/application/git_controller.dart'; import 'package:busymark/src/git/domain/git_models.dart'; import 'package:busymark/src/git/presentation/git_diff_viewer.dart'; @@ -2427,7 +2428,7 @@ void main() { final exportItem = find.byWidgetPredicate( (widget) => widget is BusyMarkPopupMenuItem && - widget.label == l10n.exportAsPdf, + widget.label == l10n.export, ); expect(exportItem, findsOneWidget); expect( @@ -2443,10 +2444,29 @@ void main() { } expect(find.byType(BusyMarkModalEditorSurface), findsOneWidget); expect(find.byType(BusyMarkModalEditorScaffold), findsOneWidget); + expect(find.byType(SegmentedButton), findsOneWidget); expect(find.text(l10n.pdfPageSize), findsOneWidget); expect(find.text(l10n.pdfIncludePageNumbers), findsOneWidget); await tester.tap(find.text(l10n.cancel)); await tester.pumpAndSettle(); + + await tester.sendKeyDownEvent(LogicalKeyboardKey.controlLeft); + await tester.sendKeyDownEvent(LogicalKeyboardKey.shiftLeft); + await tester.sendKeyEvent(LogicalKeyboardKey.keyE); + await tester.sendKeyUpEvent(LogicalKeyboardKey.shiftLeft); + await tester.sendKeyUpEvent(LogicalKeyboardKey.controlLeft); + for (var index = 0; index < 20; index++) { + await tester.pump(const Duration(milliseconds: 100)); + if (find.byType(BusyMarkModalEditorSurface).evaluate().isNotEmpty) { + break; + } + } + expect(find.byType(BusyMarkModalEditorSurface), findsOneWidget); + expect(find.byType(SegmentedButton), findsOneWidget); + expect(find.text('PDF'), findsOneWidget); + expect(find.text('HTML'), findsOneWidget); + await tester.tap(find.text(l10n.cancel)); + await tester.pumpAndSettle(); }); testWidgets('tab keyboard shortcuts move and close editor tabs', ( diff --git a/test/src/export_options_editor_test.dart b/test/src/export_options_editor_test.dart index 8b602763..5a124c2a 100644 --- a/test/src/export_options_editor_test.dart +++ b/test/src/export_options_editor_test.dart @@ -50,7 +50,9 @@ void main() { selected = await showExportOptions( context, ref, - pdf: pdf, + initialFormat: pdf + ? ExportFormat.pdf + : ExportFormat.html, instances: writerside ? module!.instances .where((i) => !i.isLibrary) @@ -71,6 +73,7 @@ void main() { ); await tester.pumpAndSettle(); expect(find.byType(ExportContentOptionsEditor), findsOneWidget); + expect(find.byType(SegmentedButton), findsOneWidget); if (pdf) { expect( tester @@ -123,7 +126,7 @@ void main() { 17, ); } - await tester.tap(find.text('Export')); + await tester.tap(find.byKey(const ValueKey('export-options-submit'))); await tester.runAsync( () => Future.delayed(const Duration(milliseconds: 40)), ); @@ -150,6 +153,52 @@ void main() { } } + testWidgets('one Export modal switches between PDF and HTML', (tester) async { + final settings = _Settings(AppSettings.defaults().toJson()); + ExportOptionsSelection? selected; + await tester.pumpWidget( + ProviderScope( + overrides: [localSettingsStoreProvider.overrideWithValue(settings)], + child: MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: buildBusyMarkTheme( + brightness: Brightness.light, + accentColor: Colors.blue, + ), + home: Scaffold( + body: Consumer( + builder: (context, ref, _) => TextButton( + child: const Text('Configure'), + onPressed: () async { + selected = await showExportOptions(context, ref); + }, + ), + ), + ), + ), + ), + ); + + await tester.tap(find.text('Configure')); + await tester.runAsync( + () => Future.delayed(const Duration(milliseconds: 40)), + ); + await tester.pumpAndSettle(); + expect(find.byType(PdfExportOptionsEditor), findsOneWidget); + expect(find.byType(HtmlExportOptionsEditor), findsNothing); + + await tester.tap(find.text('HTML')); + await tester.pumpAndSettle(); + expect(find.byType(PdfExportOptionsEditor), findsNothing); + expect(find.byType(HtmlExportOptionsEditor), findsOneWidget); + + await tester.tap(find.byKey(const ValueKey('export-options-submit'))); + await tester.pumpAndSettle(); + expect(selected?.pdf, isNull); + expect(selected?.html, isNotNull); + }); + testWidgets( 'custom geometry controls, TOC enablement and invalid input at minimum size', (tester) async { @@ -233,7 +282,12 @@ void main() { child: const Text('Configure'), onPressed: () async { confirmed = - await showExportOptions(context, ref, pdf: false) != null; + await showExportOptions( + context, + ref, + initialFormat: ExportFormat.html, + ) != + null; }, ), ), diff --git a/test/src/header_bar_configuration_test.dart b/test/src/header_bar_configuration_test.dart index 7b997ebe..3842c10a 100644 --- a/test/src/header_bar_configuration_test.dart +++ b/test/src/header_bar_configuration_test.dart @@ -430,6 +430,12 @@ void main() { }); test('native header labels expose the Syntax Reference command', () { + expect(_labels.toMap(), containsPair('export', 'Export')); + expect(_labels.toMap(), containsPair('exportShortcut', 'Ctrl+Shift+E')); + expect( + _labels.toMap(), + containsPair('exportGtkAccelerator', 'e'), + ); expect( _labels.toMap(), containsPair('syntaxReference', 'Syntax Reference'), @@ -495,9 +501,9 @@ const _labels = HeaderBarLabels( back: 'Back', backShortcut: 'Alt+Left', save: 'Save', - exportPdf: 'Export as PDF', - exportPdfShortcut: 'Ctrl+Shift+E', - exportPdfGtkAccelerator: 'e', + export: 'Export', + exportShortcut: 'Ctrl+Shift+E', + exportGtkAccelerator: 'e', fullScreen: 'Full Screen', fullScreenShortcut: 'F11', fullScreenGtkAccelerator: 'F11', diff --git a/test/src/html_export_ui_test.dart b/test/src/html_export_ui_test.dart index 3d93a123..09345a33 100644 --- a/test/src/html_export_ui_test.dart +++ b/test/src/html_export_ui_test.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:busymark/l10n/generated/app_localizations.dart'; import 'package:busymark/src/app/app_settings.dart'; import 'package:busymark/src/app/app_theme.dart'; +import 'package:busymark/src/app/busymark_design.dart'; import 'package:busymark/src/app/busymark_main_menu.dart'; import 'package:busymark/src/app/command_registry.dart'; import 'package:busymark/src/export/html_export_models.dart'; @@ -18,30 +19,28 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:path/path.dart' as p; void main() { - test( - 'HTML command has no default shortcut and PDF retains Ctrl+Shift+E', - () async { - var calls = 0; - var enabled = false; - final registry = BusyMarkCommandCatalog.create( - executions: {BusyMarkCommandIds.exportHtml: () => calls++}, - enabled: {BusyMarkCommandIds.exportHtml: () => enabled}, - ); - expect(registry[BusyMarkCommandIds.exportHtml]!.shortcut, isNull); - expect( - registry[BusyMarkCommandIds.exportPdf]!.shortcut!.label, - 'Ctrl+Shift+E', - ); - expect(await registry.execute(BusyMarkCommandIds.exportHtml), isFalse); - enabled = true; - expect(await registry.execute(BusyMarkCommandIds.exportHtml), isTrue); - expect(calls, 1); - final native = File('linux/runner/my_application.cc').readAsStringSync(); - expect(native, contains('"header.export-html"')); - expect(native, contains('configuration.can_export_html')); - expect(native, contains('"setCanExportHtml"')); - }, - ); + test('one Export command retains Ctrl+Shift+E', () async { + var calls = 0; + var enabled = false; + final registry = BusyMarkCommandCatalog.create( + executions: {BusyMarkCommandIds.export: () => calls++}, + enabled: {BusyMarkCommandIds.export: () => enabled}, + ); + expect( + registry[BusyMarkCommandIds.export]!.shortcut!.label, + 'Ctrl+Shift+E', + ); + expect(await registry.execute(BusyMarkCommandIds.export), isFalse); + enabled = true; + expect(await registry.execute(BusyMarkCommandIds.export), isTrue); + expect(calls, 1); + final native = File('linux/runner/my_application.cc').readAsStringSync(); + expect(native, contains('"header.export"')); + expect(native, isNot(contains('"header.export-html"'))); + expect(native, isNot(contains('"header.export-pdf"'))); + expect(native, contains('configuration.can_export_html')); + expect(native, contains('"setCanExportHtml"')); + }); testWidgets('Flutter HTML menu preserves enablement and dispatch', ( tester, @@ -56,7 +55,7 @@ void main() { body: BusyMarkMainMenuButton( canExportHtml: enabled, onSelected: (action) => - selected = action == BusyMarkMainMenuAction.exportHtml, + selected = action == BusyMarkMainMenuAction.export, ), ), ), @@ -65,13 +64,15 @@ void main() { await menu(false); await tester.tap(find.byType(BusyMarkMainMenuButton)); await tester.pumpAndSettle(); - final item = find.byWidgetPredicate( + final exportItem = find.byWidgetPredicate( (widget) => - widget is PopupMenuItem && - widget.value == BusyMarkMainMenuAction.exportHtml, + widget is BusyMarkPopupMenuItem && + widget.value == BusyMarkMainMenuAction.export, ); expect( - tester.widget>(item).enabled, + tester + .widget>(exportItem) + .enabled, isFalse, ); await tester.sendKeyEvent(LogicalKeyboardKey.escape); @@ -80,10 +81,13 @@ void main() { await tester.tap(find.byType(BusyMarkMainMenuButton)); await tester.pumpAndSettle(); expect( - tester.widget>(item).enabled, + tester + .widget>(exportItem) + .enabled, isTrue, ); - await tester.tap(find.text('Export as HTML…')); + expect(find.text('Ctrl+Shift+E'), findsOneWidget); + await tester.tap(exportItem); await tester.pumpAndSettle(); expect(selected, isTrue); }); @@ -123,7 +127,7 @@ void main() { () => Future.delayed(const Duration(milliseconds: 80)), ); await tester.pumpAndSettle(); - await tester.tap(find.text('Export')); + await tester.tap(find.byKey(const ValueKey('export-options-submit'))); await tester.pumpAndSettle(); expect(suggestion, endsWith('.html')); ref diff --git a/test/src/native_headerbar_audit_test.dart b/test/src/native_headerbar_audit_test.dart index 1af22882..8425fae5 100644 --- a/test/src/native_headerbar_audit_test.dart +++ b/test/src/native_headerbar_audit_test.dart @@ -253,23 +253,28 @@ void main() { expect(welcome, contains('case HeaderBarAction.reportIssue:')); expect(welcome, contains('BusyMarkMainMenuButton(')); expect(mainMenu, contains('BusyMarkHeaderPopupMenuButton')); + expect(mainMenu, isNot(contains('BusyMarkPopupSubmenu'))); expect(mainMenu, contains('tooltip: l10n.mainMenu')); - expect(mainMenu, contains('label: l10n.reportIssue')); expect( mainMenu, - contains('label: command(BusyMarkCommandIds.exportPdf).label(context)'), + contains('label: command(BusyMarkCommandIds.export).label(context)'), ); + expect(mainMenu, contains('label: l10n.reportIssue')); expect( mainMenu, contains('label: command(BusyMarkCommandIds.fullScreen).label(context)'), ); - expect(mainMenu, contains('enabled: canExportPdf')); + expect(mainMenu, contains('enabled: canExportPdf || canExportHtml')); expect(native, contains('GtkWidget* main_menu_button;')); expect(native, contains('GMenu* main_menu_model;')); expect(native, contains('GSimpleActionGroup* header_action_group;')); expect(native, contains('rebuild_main_menu_model')); + expect(native, isNot(contains('g_menu_item_new_submenu'))); + expect(native, contains('localized_label_or(labels, "export", "")')); expect(native, contains('"header.keyboard-shortcuts"')); - expect(native, contains('"header.export-pdf"')); + expect(native, contains('"header.export"')); + expect(native, isNot(contains('"header.export-pdf"'))); + expect(native, isNot(contains('"header.export-html"'))); expect(native, contains('"header.full-screen"')); expect(native, contains('full_screen_gaction_activated_cb')); expect(native, contains('configuration.full_screen')); From a324df22aab6b8646391a55b2d7c5924a0a348c7 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 8 Sep 2026 17:11:43 -0700 Subject: [PATCH 34/37] Refactor tests and localization: update messages, improve fixture paths, and revise export options. --- lib/src/export/export_options_editor.dart | 4 ++-- test/src/app_smoke_test.dart | 4 ++-- test/src/export_options_editor_test.dart | 2 +- test/src/native_headerbar_audit_test.dart | 7 +++---- .../visualization_packaging_audit_test.dart | 2 +- test/src/writerside_pdf_export_test.dart | 10 +++++---- test/src/writerside_test.dart | 21 +++++++++---------- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/lib/src/export/export_options_editor.dart b/lib/src/export/export_options_editor.dart index f5b3965a..c3155827 100644 --- a/lib/src/export/export_options_editor.dart +++ b/lib/src/export/export_options_editor.dart @@ -156,12 +156,12 @@ class _ExportOptionsDialogState extends State { segments: [ ButtonSegment( value: ExportFormat.pdf, - label: const Text('PDF'), + label: Text(context.l10n.fileTypePdf), enabled: widget.canExportPdf, ), ButtonSegment( value: ExportFormat.html, - label: const Text('HTML'), + label: Text(context.l10n.fileTypeHtml), enabled: widget.canExportHtml, ), ], diff --git a/test/src/app_smoke_test.dart b/test/src/app_smoke_test.dart index 39bd407a..aa25bf24 100644 --- a/test/src/app_smoke_test.dart +++ b/test/src/app_smoke_test.dart @@ -2463,8 +2463,8 @@ void main() { } expect(find.byType(BusyMarkModalEditorSurface), findsOneWidget); expect(find.byType(SegmentedButton), findsOneWidget); - expect(find.text('PDF'), findsOneWidget); - expect(find.text('HTML'), findsOneWidget); + expect(find.text(l10n.fileTypePdf), findsOneWidget); + expect(find.text(l10n.fileTypeHtml), findsOneWidget); await tester.tap(find.text(l10n.cancel)); await tester.pumpAndSettle(); }); diff --git a/test/src/export_options_editor_test.dart b/test/src/export_options_editor_test.dart index 5a124c2a..395a87c7 100644 --- a/test/src/export_options_editor_test.dart +++ b/test/src/export_options_editor_test.dart @@ -188,7 +188,7 @@ void main() { expect(find.byType(PdfExportOptionsEditor), findsOneWidget); expect(find.byType(HtmlExportOptionsEditor), findsNothing); - await tester.tap(find.text('HTML')); + await tester.tap(find.text('HTML document')); await tester.pumpAndSettle(); expect(find.byType(PdfExportOptionsEditor), findsNothing); expect(find.byType(HtmlExportOptionsEditor), findsOneWidget); diff --git a/test/src/native_headerbar_audit_test.dart b/test/src/native_headerbar_audit_test.dart index 8425fae5..40f3ac74 100644 --- a/test/src/native_headerbar_audit_test.dart +++ b/test/src/native_headerbar_audit_test.dart @@ -1085,10 +1085,9 @@ void main() { ); expect(snapcraft, contains('- libhandy-1-dev')); expect(snapcraft, contains('- libhandy-1-0')); - expect( - readme, - contains('sudo apt-get install curl libhandy-1-dev xz-utils'), - ); + expect(readme, contains('sudo apt-get install')); + expect(readme, contains('libhandy-1-dev')); + expect(readme, contains('xz-utils')); expect(native, isNot(contains('kHeaderWindowRadius'))); expect(native, isNot(contains('create_rounded_window_region'))); expect(native, isNot(contains('gdk_window_shape_combine_region'))); diff --git a/test/src/visualization_packaging_audit_test.dart b/test/src/visualization_packaging_audit_test.dart index 07206460..ba8b96ab 100644 --- a/test/src/visualization_packaging_audit_test.dart +++ b/test/src/visualization_packaging_audit_test.dart @@ -10,7 +10,7 @@ void main() { r' match.group(1)!).toSet(); - expect(screenshotPaths, hasLength(5)); + expect(screenshotPaths, isNotEmpty); for (final path in screenshotPaths) { final screenshot = File(path); expect(screenshot.existsSync(), isTrue, reason: '$path is missing'); diff --git a/test/src/writerside_pdf_export_test.dart b/test/src/writerside_pdf_export_test.dart index 9864a79e..42b1b3cb 100644 --- a/test/src/writerside_pdf_export_test.dart +++ b/test/src/writerside_pdf_export_test.dart @@ -592,14 +592,16 @@ void main() { }); test( - 'native Writerside demo compiles end to end with bundled Typst', + 'native Writerside fixture compiles end to end with bundled Typst', () async { final output = await Directory.systemTemp.createTemp( 'busymark-writerside-native-pdf-', ); addTearDown(() => output.delete(recursive: true)); - final module = Directory('demo/writerside-instances').absolute; - final destination = p.join(output.path, 'writerside-demo.pdf'); + final module = Directory( + 'test/fixtures/writerside/conformance_project', + ).absolute; + final destination = p.join(output.path, 'writerside-conformance.pdf'); final service = WritersidePdfExportService( markdownExporter: MarkdownPdfExportService( compilerLocator: TypstCompilerLocator( @@ -611,7 +613,7 @@ void main() { final result = await service.export( WritersidePdfExportRequest( moduleRoot: module.path, - instanceId: 'guide', + instanceId: 'conformance', destinationPath: destination, overwrite: false, ), diff --git a/test/src/writerside_test.dart b/test/src/writerside_test.dart index 9f49ddcd..9950b62f 100644 --- a/test/src/writerside_test.dart +++ b/test/src/writerside_test.dart @@ -993,17 +993,16 @@ void main() { expect(profiles.valuesFor('guide').offlineDocs, isFalse); }); - test('instance demo is a valid openable Writerside module', () async { - final module = await moduleService.load('demo/writerside-instances'); - - expect(module.instances.map((instance) => instance.id), [ - 'guide', - 'admin', - 'shared', - ]); - expect(module.instances.last.isLibrary, isTrue); - expect(module.instances.first.allowSearchEngineIndexing, isTrue); - expect(module.instances[1].offlineArtifact, isTrue); + test('conformance fixture is a valid openable Writerside module', () async { + final module = await moduleService.load( + 'test/fixtures/writerside/conformance_project', + ); + + expect(module.instances.map((instance) => instance.id), ['conformance']); + expect( + module.topicsByFileName.keys, + containsAll(['features.topic', 'semantic.md']), + ); expect(module.diagnostics.where(isError), isEmpty); }); } From bb250b8896dbfd0b874833b5e07d1b5a1240f826 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 8 Sep 2026 17:44:08 -0700 Subject: [PATCH 35/37] Fix PDF export image bug --- assets/export/markdown.typ | 27 +++++++------ lib/l10n/app_ar.arb | 4 ++ lib/l10n/app_de.arb | 4 ++ lib/l10n/app_en.arb | 2 + lib/l10n/app_es.arb | 4 ++ lib/l10n/app_et.arb | 4 ++ lib/l10n/app_fa.arb | 4 ++ lib/l10n/app_fr.arb | 4 ++ lib/l10n/app_hi.arb | 4 ++ lib/l10n/app_id.arb | 4 ++ lib/l10n/app_it.arb | 4 ++ lib/l10n/app_ja.arb | 4 ++ lib/l10n/app_ko.arb | 4 ++ lib/l10n/app_nb.arb | 4 ++ lib/l10n/app_nl.arb | 4 ++ lib/l10n/app_pl.arb | 4 ++ lib/l10n/app_pt.arb | 4 ++ lib/l10n/app_pt_BR.arb | 4 ++ lib/l10n/app_ru.arb | 4 ++ lib/l10n/app_tr.arb | 4 ++ lib/l10n/app_uk.arb | 4 ++ lib/l10n/app_vi.arb | 4 ++ lib/l10n/app_zh.arb | 4 ++ lib/l10n/app_zh_CN.arb | 4 ++ lib/l10n/generated/app_localizations.dart | 6 +++ lib/l10n/generated/app_localizations_ar.dart | 3 ++ lib/l10n/generated/app_localizations_de.dart | 3 ++ lib/l10n/generated/app_localizations_en.dart | 3 ++ lib/l10n/generated/app_localizations_es.dart | 3 ++ lib/l10n/generated/app_localizations_et.dart | 3 ++ lib/l10n/generated/app_localizations_fa.dart | 3 ++ lib/l10n/generated/app_localizations_fr.dart | 3 ++ lib/l10n/generated/app_localizations_hi.dart | 3 ++ lib/l10n/generated/app_localizations_id.dart | 3 ++ lib/l10n/generated/app_localizations_it.dart | 3 ++ lib/l10n/generated/app_localizations_ja.dart | 3 ++ lib/l10n/generated/app_localizations_ko.dart | 3 ++ lib/l10n/generated/app_localizations_nb.dart | 3 ++ lib/l10n/generated/app_localizations_nl.dart | 3 ++ lib/l10n/generated/app_localizations_pl.dart | 3 ++ lib/l10n/generated/app_localizations_pt.dart | 6 +++ lib/l10n/generated/app_localizations_ru.dart | 3 ++ lib/l10n/generated/app_localizations_tr.dart | 3 ++ lib/l10n/generated/app_localizations_uk.dart | 3 ++ lib/l10n/generated/app_localizations_vi.dart | 3 ++ lib/l10n/generated/app_localizations_zh.dart | 6 +++ lib/src/export/export_options_editor.dart | 38 +++++++++---------- test/src/app_smoke_test.dart | 12 ++++-- test/src/export_options_editor_test.dart | 5 ++- .../src/markdown_pdf_export_service_test.dart | 20 ++++++++++ 50 files changed, 231 insertions(+), 36 deletions(-) diff --git a/assets/export/markdown.typ b/assets/export/markdown.typ index 226eaeda..e319ff68 100644 --- a/assets/export/markdown.typ +++ b/assets/export/markdown.typ @@ -14,6 +14,7 @@ #let typography = options.typography #let geometry = options.page #let margins = geometry.marginsPt +#let content-height = (geometry.heightPt - margins.top - margins.bottom) * 1pt #let running-visible() = options.showHeaderFooterOnFirstPage or counter(page).get().first() > 1 #let number-position = if options.pageNumbers == "bottomLeft" { left } else if options.pageNumbers == "bottomRight" { right } else { center } #set page( @@ -152,19 +153,23 @@ } } +#let render-fitted-image(asset, alt: "", maximum-height: 72% * content-height) = layout(size => { + let natural-size = measure(image(asset)) + let scaled-height = natural-size.height * (size.width / natural-size.width) + if scaled-height > maximum-height { + image(asset, height: maximum-height, fit: "contain", alt: alt) + } else { + image(asset, width: 100%, fit: "contain", alt: alt) + } +}) + #let render-display-image(item) = { let asset = value-or(item, "asset", "") let alt = value-or(item, "alt", "") if asset == "" { emph(text(if alt == "" { "[Image unavailable]" } else { "[Image: " + alt + "]" })) } else { - layout(size => image( - asset, - width: 100%, - height: 72% * size.height, - fit: "contain", - alt: alt, - )) + render-fitted-image(asset, alt: alt) } } @@ -361,13 +366,11 @@ above: 0.8em, below: 0.8em, breakable: false, - align(center, layout(size => image( + align(center, render-fitted-image( asset, - width: 100%, - height: 70% * size.height, - fit: "contain", alt: alt, - ))), + maximum-height: 70% * content-height, + )), ) } } else if kind == "openApiReference" { diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index 12c419af..6353995b 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -2769,6 +2769,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "تنسيق الإخراج", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "جارٍ تصدير PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index d43c95c5..27fdcb4a 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -2769,6 +2769,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Ausgabeformat", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "PDF wird exportiert…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 81d4048a..f4ba2a59 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1959,6 +1959,8 @@ "@pdfIncludePageNumbers": {"description": "Toggle for page numbers in an exported PDF."}, "export": "Export", "@export": {"description": "Button label that starts an export."}, + "exportFormat": "Output format", + "@exportFormat": {"description": "Output format selector in the export dialog."}, "exportingPdf": "Exporting PDF…", "@exportingPdf": {"description": "Progress dialog title while a PDF is being exported."}, "fileTypePdf": "PDF document", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 338a2169..dd6fd8bf 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -2769,6 +2769,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Formato de salida", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "Exportando PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_et.arb b/lib/l10n/app_et.arb index ce330ee8..775a56b5 100644 --- a/lib/l10n/app_et.arb +++ b/lib/l10n/app_et.arb @@ -3229,6 +3229,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Väljundvorming", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "PDF-i eksportimine…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index 40db2f8f..3bff95fe 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -2811,6 +2811,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "قالب خروجی", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "در حال تهیه PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 23797d5e..fa1c4bdf 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -2769,6 +2769,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Format de sortie", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "Exportation du PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index 10b8c704..397b515c 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -2769,6 +2769,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "आउटपुट फ़ॉर्मैट", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "PDF निर्यात हो रहा है…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_id.arb b/lib/l10n/app_id.arb index 37b88e65..9ee3a64a 100644 --- a/lib/l10n/app_id.arb +++ b/lib/l10n/app_id.arb @@ -3693,6 +3693,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Format keluaran", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "Mengekspor PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 0e4f5e2f..2cbee3d7 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -2769,6 +2769,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Formato di output", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "Esportazione PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 8dd5bfe1..9ec4fc04 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -3693,6 +3693,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "出力形式", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "PDF をエクスポート中…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index d3fa7fbd..7fabd224 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -3693,6 +3693,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "출력 형식", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "PDF 내보내기 중…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_nb.arb b/lib/l10n/app_nb.arb index c7feaecf..b7153c3d 100644 --- a/lib/l10n/app_nb.arb +++ b/lib/l10n/app_nb.arb @@ -2769,6 +2769,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Utdataformat", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "Eksporterer PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 98e0b735..4b04b23c 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -3693,6 +3693,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Uitvoerformaat", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "PDF exporteren…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 2af1e31c..d6d3ae63 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -2795,6 +2795,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Format wyjściowy", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "Eksportowanie PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 6fa058f1..ce9a07e6 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -2769,6 +2769,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Formato de saída", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "A exportar PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_pt_BR.arb b/lib/l10n/app_pt_BR.arb index 17c75eca..c36c96da 100644 --- a/lib/l10n/app_pt_BR.arb +++ b/lib/l10n/app_pt_BR.arb @@ -2769,6 +2769,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Formato de saída", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "Exportando PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 622fe46b..c175e7db 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -2795,6 +2795,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Формат вывода", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "Экспорт PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index e52f096a..069d6c18 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -3693,6 +3693,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Çıktı biçimi", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "PDF dışa aktarılıyor…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index c4e4437a..52313fec 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -2795,6 +2795,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Формат виведення", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "Експорт PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index 5e827cd4..275741df 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -3693,6 +3693,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "Định dạng đầu ra", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "Đang xuất PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 98c567c8..80ad14f8 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -3693,6 +3693,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "输出格式", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "正在导出 PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/app_zh_CN.arb b/lib/l10n/app_zh_CN.arb index b5198c57..54c4eba7 100644 --- a/lib/l10n/app_zh_CN.arb +++ b/lib/l10n/app_zh_CN.arb @@ -3693,6 +3693,10 @@ "@export": { "description": "Button label that starts an export." }, + "exportFormat": "输出格式", + "@exportFormat": { + "description": "Output format selector in the export dialog." + }, "exportingPdf": "正在导出 PDF…", "@exportingPdf": { "description": "Progress dialog title while a PDF is being exported." diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index c6d1403c..1c883050 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -4992,6 +4992,12 @@ abstract class AppLocalizations { /// **'Export'** String get export; + /// Output format selector in the export dialog. + /// + /// In en, this message translates to: + /// **'Output format'** + String get exportFormat; + /// Progress dialog title while a PDF is being exported. /// /// In en, this message translates to: diff --git a/lib/l10n/generated/app_localizations_ar.dart b/lib/l10n/generated/app_localizations_ar.dart index fd291a1e..de018b1b 100644 --- a/lib/l10n/generated/app_localizations_ar.dart +++ b/lib/l10n/generated/app_localizations_ar.dart @@ -2995,6 +2995,9 @@ class AppLocalizationsAr extends AppLocalizations { @override String get export => 'تصدير'; + @override + String get exportFormat => 'تنسيق الإخراج'; + @override String get exportingPdf => 'جارٍ تصدير PDF…'; diff --git a/lib/l10n/generated/app_localizations_de.dart b/lib/l10n/generated/app_localizations_de.dart index 37f310dc..77dcf063 100644 --- a/lib/l10n/generated/app_localizations_de.dart +++ b/lib/l10n/generated/app_localizations_de.dart @@ -2991,6 +2991,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get export => 'Exportieren'; + @override + String get exportFormat => 'Ausgabeformat'; + @override String get exportingPdf => 'PDF wird exportiert…'; diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 7513dbaf..73313181 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -2963,6 +2963,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get export => 'Export'; + @override + String get exportFormat => 'Output format'; + @override String get exportingPdf => 'Exporting PDF…'; diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart index 4529a74b..ac44a06e 100644 --- a/lib/l10n/generated/app_localizations_es.dart +++ b/lib/l10n/generated/app_localizations_es.dart @@ -2996,6 +2996,9 @@ class AppLocalizationsEs extends AppLocalizations { @override String get export => 'Exportar'; + @override + String get exportFormat => 'Formato de salida'; + @override String get exportingPdf => 'Exportando PDF…'; diff --git a/lib/l10n/generated/app_localizations_et.dart b/lib/l10n/generated/app_localizations_et.dart index e5bb4ad4..d1109651 100644 --- a/lib/l10n/generated/app_localizations_et.dart +++ b/lib/l10n/generated/app_localizations_et.dart @@ -2963,6 +2963,9 @@ class AppLocalizationsEt extends AppLocalizations { @override String get export => 'Ekspordi'; + @override + String get exportFormat => 'Väljundvorming'; + @override String get exportingPdf => 'PDF-i eksportimine…'; diff --git a/lib/l10n/generated/app_localizations_fa.dart b/lib/l10n/generated/app_localizations_fa.dart index d5f38f1e..afb09527 100644 --- a/lib/l10n/generated/app_localizations_fa.dart +++ b/lib/l10n/generated/app_localizations_fa.dart @@ -3013,6 +3013,9 @@ class AppLocalizationsFa extends AppLocalizations { @override String get export => 'خروجی'; + @override + String get exportFormat => 'قالب خروجی'; + @override String get exportingPdf => 'در حال تهیه PDF…'; diff --git a/lib/l10n/generated/app_localizations_fr.dart b/lib/l10n/generated/app_localizations_fr.dart index 86f26d31..2b210940 100644 --- a/lib/l10n/generated/app_localizations_fr.dart +++ b/lib/l10n/generated/app_localizations_fr.dart @@ -2991,6 +2991,9 @@ class AppLocalizationsFr extends AppLocalizations { @override String get export => 'Exporter'; + @override + String get exportFormat => 'Format de sortie'; + @override String get exportingPdf => 'Exportation du PDF…'; diff --git a/lib/l10n/generated/app_localizations_hi.dart b/lib/l10n/generated/app_localizations_hi.dart index 94566127..8c532cfc 100644 --- a/lib/l10n/generated/app_localizations_hi.dart +++ b/lib/l10n/generated/app_localizations_hi.dart @@ -2956,6 +2956,9 @@ class AppLocalizationsHi extends AppLocalizations { @override String get export => 'निर्यात करें'; + @override + String get exportFormat => 'आउटपुट फ़ॉर्मैट'; + @override String get exportingPdf => 'PDF निर्यात हो रहा है…'; diff --git a/lib/l10n/generated/app_localizations_id.dart b/lib/l10n/generated/app_localizations_id.dart index b7e7c9ce..95ac534c 100644 --- a/lib/l10n/generated/app_localizations_id.dart +++ b/lib/l10n/generated/app_localizations_id.dart @@ -2971,6 +2971,9 @@ class AppLocalizationsId extends AppLocalizations { @override String get export => 'Ekspor'; + @override + String get exportFormat => 'Format keluaran'; + @override String get exportingPdf => 'Mengekspor PDF…'; diff --git a/lib/l10n/generated/app_localizations_it.dart b/lib/l10n/generated/app_localizations_it.dart index e9c4395b..dad2fc9e 100644 --- a/lib/l10n/generated/app_localizations_it.dart +++ b/lib/l10n/generated/app_localizations_it.dart @@ -2989,6 +2989,9 @@ class AppLocalizationsIt extends AppLocalizations { @override String get export => 'Esporta'; + @override + String get exportFormat => 'Formato di output'; + @override String get exportingPdf => 'Esportazione PDF…'; diff --git a/lib/l10n/generated/app_localizations_ja.dart b/lib/l10n/generated/app_localizations_ja.dart index 1b814f56..ec9de0d9 100644 --- a/lib/l10n/generated/app_localizations_ja.dart +++ b/lib/l10n/generated/app_localizations_ja.dart @@ -2878,6 +2878,9 @@ class AppLocalizationsJa extends AppLocalizations { @override String get export => 'エクスポート'; + @override + String get exportFormat => '出力形式'; + @override String get exportingPdf => 'PDF をエクスポート中…'; diff --git a/lib/l10n/generated/app_localizations_ko.dart b/lib/l10n/generated/app_localizations_ko.dart index 2a207ac6..89a028a0 100644 --- a/lib/l10n/generated/app_localizations_ko.dart +++ b/lib/l10n/generated/app_localizations_ko.dart @@ -2873,6 +2873,9 @@ class AppLocalizationsKo extends AppLocalizations { @override String get export => '내보내기'; + @override + String get exportFormat => '출력 형식'; + @override String get exportingPdf => 'PDF 내보내기 중…'; diff --git a/lib/l10n/generated/app_localizations_nb.dart b/lib/l10n/generated/app_localizations_nb.dart index e3e19a05..406d4c42 100644 --- a/lib/l10n/generated/app_localizations_nb.dart +++ b/lib/l10n/generated/app_localizations_nb.dart @@ -2962,6 +2962,9 @@ class AppLocalizationsNb extends AppLocalizations { @override String get export => 'Eksporter'; + @override + String get exportFormat => 'Utdataformat'; + @override String get exportingPdf => 'Eksporterer PDF…'; diff --git a/lib/l10n/generated/app_localizations_nl.dart b/lib/l10n/generated/app_localizations_nl.dart index 544a47a0..3c8f86f2 100644 --- a/lib/l10n/generated/app_localizations_nl.dart +++ b/lib/l10n/generated/app_localizations_nl.dart @@ -2975,6 +2975,9 @@ class AppLocalizationsNl extends AppLocalizations { @override String get export => 'Exporteren'; + @override + String get exportFormat => 'Uitvoerformaat'; + @override String get exportingPdf => 'PDF exporteren…'; diff --git a/lib/l10n/generated/app_localizations_pl.dart b/lib/l10n/generated/app_localizations_pl.dart index 5a7aaa07..9d4290c7 100644 --- a/lib/l10n/generated/app_localizations_pl.dart +++ b/lib/l10n/generated/app_localizations_pl.dart @@ -3015,6 +3015,9 @@ class AppLocalizationsPl extends AppLocalizations { @override String get export => 'Eksportuj'; + @override + String get exportFormat => 'Format wyjściowy'; + @override String get exportingPdf => 'Eksportowanie PDF…'; diff --git a/lib/l10n/generated/app_localizations_pt.dart b/lib/l10n/generated/app_localizations_pt.dart index 487f921a..01ee508b 100644 --- a/lib/l10n/generated/app_localizations_pt.dart +++ b/lib/l10n/generated/app_localizations_pt.dart @@ -2984,6 +2984,9 @@ class AppLocalizationsPt extends AppLocalizations { @override String get export => 'Exportar'; + @override + String get exportFormat => 'Formato de saída'; + @override String get exportingPdf => 'A exportar PDF…'; @@ -6924,6 +6927,9 @@ class AppLocalizationsPtBr extends AppLocalizationsPt { @override String get export => 'Exportar'; + @override + String get exportFormat => 'Formato de saída'; + @override String get exportingPdf => 'Exportando PDF…'; diff --git a/lib/l10n/generated/app_localizations_ru.dart b/lib/l10n/generated/app_localizations_ru.dart index 7195407e..1bae9acf 100644 --- a/lib/l10n/generated/app_localizations_ru.dart +++ b/lib/l10n/generated/app_localizations_ru.dart @@ -3013,6 +3013,9 @@ class AppLocalizationsRu extends AppLocalizations { @override String get export => 'Экспортировать'; + @override + String get exportFormat => 'Формат вывода'; + @override String get exportingPdf => 'Экспорт PDF…'; diff --git a/lib/l10n/generated/app_localizations_tr.dart b/lib/l10n/generated/app_localizations_tr.dart index 8fe377f8..d6a9c6da 100644 --- a/lib/l10n/generated/app_localizations_tr.dart +++ b/lib/l10n/generated/app_localizations_tr.dart @@ -2963,6 +2963,9 @@ class AppLocalizationsTr extends AppLocalizations { @override String get export => 'Dışa aktar'; + @override + String get exportFormat => 'Çıktı biçimi'; + @override String get exportingPdf => 'PDF dışa aktarılıyor…'; diff --git a/lib/l10n/generated/app_localizations_uk.dart b/lib/l10n/generated/app_localizations_uk.dart index 4b18a58f..76494aa2 100644 --- a/lib/l10n/generated/app_localizations_uk.dart +++ b/lib/l10n/generated/app_localizations_uk.dart @@ -3020,6 +3020,9 @@ class AppLocalizationsUk extends AppLocalizations { @override String get export => 'Експортувати'; + @override + String get exportFormat => 'Формат виведення'; + @override String get exportingPdf => 'Експорт PDF…'; diff --git a/lib/l10n/generated/app_localizations_vi.dart b/lib/l10n/generated/app_localizations_vi.dart index 2251752b..79d2c2ce 100644 --- a/lib/l10n/generated/app_localizations_vi.dart +++ b/lib/l10n/generated/app_localizations_vi.dart @@ -2959,6 +2959,9 @@ class AppLocalizationsVi extends AppLocalizations { @override String get export => 'Xuất'; + @override + String get exportFormat => 'Định dạng đầu ra'; + @override String get exportingPdf => 'Đang xuất PDF…'; diff --git a/lib/l10n/generated/app_localizations_zh.dart b/lib/l10n/generated/app_localizations_zh.dart index 8a0500b1..60422903 100644 --- a/lib/l10n/generated/app_localizations_zh.dart +++ b/lib/l10n/generated/app_localizations_zh.dart @@ -2829,6 +2829,9 @@ class AppLocalizationsZh extends AppLocalizations { @override String get export => '导出'; + @override + String get exportFormat => '输出格式'; + @override String get exportingPdf => '正在导出 PDF…'; @@ -6547,6 +6550,9 @@ class AppLocalizationsZhCn extends AppLocalizationsZh { @override String get export => '导出'; + @override + String get exportFormat => '输出格式'; + @override String get exportingPdf => '正在导出 PDF…'; diff --git a/lib/src/export/export_options_editor.dart b/lib/src/export/export_options_editor.dart index c3155827..c0d22373 100644 --- a/lib/src/export/export_options_editor.dart +++ b/lib/src/export/export_options_editor.dart @@ -151,27 +151,27 @@ class _ExportOptionsDialogState extends State { saveKey: const ValueKey('export-options-submit'), saving: _saving, children: [ - SegmentedButton( - showSelectedIcon: false, - segments: [ - ButtonSegment( - value: ExportFormat.pdf, - label: Text(context.l10n.fileTypePdf), - enabled: widget.canExportPdf, - ), - ButtonSegment( - value: ExportFormat.html, - label: Text(context.l10n.fileTypeHtml), - enabled: widget.canExportHtml, + BusyMarkGroupedList( + filled: true, + children: [ + BusyMarkComboRow( + title: context.l10n.exportFormat, + values: [ + if (widget.canExportPdf) ExportFormat.pdf, + if (widget.canExportHtml) ExportFormat.html, + ], + selected: _format, + labelFor: (format) => switch (format) { + ExportFormat.pdf => context.l10n.fileTypePdf, + ExportFormat.html => context.l10n.fileTypeHtml, + }, + enabled: !_saving, + onSelected: (format) => setState(() { + _format = format; + _fileErrors = []; + }), ), ], - selected: {_format}, - onSelectionChanged: _saving - ? null - : (selection) => setState(() { - _format = selection.single; - _fileErrors = []; - }), ), const SizedBox(height: BusyMarkSpacing.md), BusyMarkDialogButton( diff --git a/test/src/app_smoke_test.dart b/test/src/app_smoke_test.dart index aa25bf24..956e96cb 100644 --- a/test/src/app_smoke_test.dart +++ b/test/src/app_smoke_test.dart @@ -2444,7 +2444,8 @@ void main() { } expect(find.byType(BusyMarkModalEditorSurface), findsOneWidget); expect(find.byType(BusyMarkModalEditorScaffold), findsOneWidget); - expect(find.byType(SegmentedButton), findsOneWidget); + expect(find.byType(BusyMarkComboRow), findsOneWidget); + expect(find.byType(SegmentedButton), findsNothing); expect(find.text(l10n.pdfPageSize), findsOneWidget); expect(find.text(l10n.pdfIncludePageNumbers), findsOneWidget); await tester.tap(find.text(l10n.cancel)); @@ -2462,9 +2463,12 @@ void main() { } } expect(find.byType(BusyMarkModalEditorSurface), findsOneWidget); - expect(find.byType(SegmentedButton), findsOneWidget); - expect(find.text(l10n.fileTypePdf), findsOneWidget); - expect(find.text(l10n.fileTypeHtml), findsOneWidget); + final formatRow = tester.widget>( + find.byType(BusyMarkComboRow), + ); + expect(formatRow.title, l10n.exportFormat); + expect(formatRow.values, ExportFormat.values); + expect(formatRow.selected, ExportFormat.pdf); await tester.tap(find.text(l10n.cancel)); await tester.pumpAndSettle(); }); diff --git a/test/src/export_options_editor_test.dart b/test/src/export_options_editor_test.dart index 395a87c7..54c619ce 100644 --- a/test/src/export_options_editor_test.dart +++ b/test/src/export_options_editor_test.dart @@ -73,7 +73,8 @@ void main() { ); await tester.pumpAndSettle(); expect(find.byType(ExportContentOptionsEditor), findsOneWidget); - expect(find.byType(SegmentedButton), findsOneWidget); + expect(find.byType(BusyMarkComboRow), findsOneWidget); + expect(find.byType(SegmentedButton), findsNothing); if (pdf) { expect( tester @@ -188,6 +189,8 @@ void main() { expect(find.byType(PdfExportOptionsEditor), findsOneWidget); expect(find.byType(HtmlExportOptionsEditor), findsNothing); + await tester.tap(find.byType(BusyMarkComboRow)); + await tester.pumpAndSettle(); await tester.tap(find.text('HTML document')); await tester.pumpAndSettle(); expect(find.byType(PdfExportOptionsEditor), findsNothing); diff --git a/test/src/markdown_pdf_export_service_test.dart b/test/src/markdown_pdf_export_service_test.dart index f678a2cc..e630bdec 100644 --- a/test/src/markdown_pdf_export_service_test.dart +++ b/test/src/markdown_pdf_export_service_test.dart @@ -11,6 +11,26 @@ void main() { final typstPath = Platform.environment['BUSYMARK_TYPST_PATH']; final canRunTypst = typstPath != null && File(typstPath).existsSync(); + test('display images do not reserve a fixed-height letterbox', () { + final template = File('assets/export/markdown.typ').readAsStringSync(); + final renderer = RegExp( + r'#let render-fitted-image[\s\S]*?#let render-table', + ).firstMatch(template)?.group(0); + + expect(renderer, isNotNull); + expect(renderer, contains('let natural-size = measure(image(asset))')); + expect( + renderer, + contains( + 'let scaled-height = natural-size.height * ' + '(size.width / natural-size.width)', + ), + ); + expect(renderer, contains('image(asset, width: 100%')); + expect(renderer, contains('image(asset, height: maximum-height')); + expect(renderer, isNot(contains('height: 72% * size.height'))); + }); + test( 'bundled template exports representative Markdown to a valid PDF', () async { From a0c2e3f866a2feee2c2f5c5176e6a36b086df3bf Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 8 Sep 2026 18:51:57 -0700 Subject: [PATCH 36/37] fix export - missing image in html, missing quote in pdf --- assets/export/markdown.typ | 74 ++++++++++++---- lib/src/app/busymark_dialogs.dart | 53 ++++++++++- lib/src/core/local_image_resolver.dart | 7 ++ lib/src/export/html_export_assets.dart | 4 +- lib/src/export/markdown_export_mapper.dart | 12 ++- test/src/busymark_dialogs_test.dart | 87 ++++++++++++------- test/src/export_options_editor_test.dart | 41 +++++++++ test/src/html_export_test.dart | 30 +++++++ .../src/markdown_pdf_export_service_test.dart | 17 ++++ test/src/writerside_admonition_test.dart | 5 ++ 10 files changed, 276 insertions(+), 54 deletions(-) diff --git a/assets/export/markdown.typ b/assets/export/markdown.typ index e319ff68..8921201d 100644 --- a/assets/export/markdown.typ +++ b/assets/export/markdown.typ @@ -250,6 +250,26 @@ } } +#let render-callout(body, fill: none, accent: black, title: "") = { + let content = { + if title != "" { + strong(title) + linebreak() + } + body + } + block( + width: 100%, + above: 0.7em, + below: 0.7em, + fill: fill, + stroke: (left: 2pt + accent), + inset: 9pt, + radius: 4pt, + content, + ) +} + #let render-block(block-data) = { let kind = block-data.kind let inlines = value-or(block-data, "inlines", ()) @@ -286,31 +306,47 @@ } else if kind == "admonition" { let style = value-or(block-data, "style", "note") let fill = if style == "warning" { - rgb("fff4d6") + rgb("fff6e9") } else if style == "tip" { - rgb("e8f7ed") + rgb("f0faf4") } else { - rgb("eaf2fb") + rgb("f1f7fd") } - block( - width: 100%, + let accent = if style == "warning" { + rgb("a34200") + } else if style == "tip" { + rgb("247550") + } else { + rgb("2366aa") + } + let body = if children.len() > 0 { + for child in children { render-block(child) } + } else { + render-inlines(inlines) + } + let default-title = if style == "warning" { + "Warning" + } else if style == "tip" { + "Tip" + } else { + "Note" + } + render-callout( + body, fill: fill, - inset: 9pt, - radius: 4pt, - if children.len() > 0 { - for child in children { render-block(child) } - } else { - render-inlines(inlines) - }, + accent: accent, + title: value-or(block-data, "title", default-title), ) } else if kind == "blockquote" { - quote( - block: true, - if children.len() > 0 { - for child in children { render-block(child) } - } else { - render-inlines(inlines) - }, + let body = if children.len() > 0 { + for child in children { render-block(child) } + } else { + render-inlines(inlines) + } + render-callout( + body, + fill: rgb("f5f7fa"), + accent: rgb("4b5563"), ) } else if kind == "thematicBreak" { block(above: 0.8em, below: 0.8em, line(length: 100%, stroke: 0.6pt + rgb("aeb4bc"))) diff --git a/lib/src/app/busymark_dialogs.dart b/lib/src/app/busymark_dialogs.dart index 50e548d6..1266c196 100644 --- a/lib/src/app/busymark_dialogs.dart +++ b/lib/src/app/busymark_dialogs.dart @@ -94,11 +94,55 @@ final _busyMarkModalShortcuts = { /// /// Use this around modal UI that is not presented by /// [showBusyMarkModalDialog], such as an in-page editor overlay. -class BusyMarkModalShortcutBoundary extends StatelessWidget { +class BusyMarkModalShortcutBoundary extends StatefulWidget { const BusyMarkModalShortcutBoundary({super.key, required this.child}); final Widget child; + @override + State createState() => + _BusyMarkModalShortcutBoundaryState(); +} + +class _BusyMarkModalShortcutBoundaryState + extends State { + final _fallbackFocusNode = FocusNode( + debugLabel: 'BusyMark modal shortcut fallback', + ); + FocusScopeNode? _enclosingScope; + + @override + void initState() { + super.initState(); + // DialogRoute initially parks focus on its own scope. Wait for that focus + // transition, then move it below Shortcuts only when no child requested + // focus, so Escape works without overriding a field's autofocus. + FocusManager.instance.addListener(_focusFallbackIfNeeded); + WidgetsBinding.instance.addPostFrameCallback((_) { + _focusFallbackIfNeeded(); + }); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + _enclosingScope = FocusScope.of(context); + } + + @override + void dispose() { + FocusManager.instance.removeListener(_focusFallbackIfNeeded); + _fallbackFocusNode.dispose(); + super.dispose(); + } + + void _focusFallbackIfNeeded() { + if (!mounted || _fallbackFocusNode.context == null) return; + if (FocusManager.instance.primaryFocus == _enclosingScope) { + _fallbackFocusNode.requestFocus(); + } + } + @override Widget build(BuildContext context) { return Shortcuts( @@ -113,7 +157,12 @@ class BusyMarkModalShortcutBoundary extends StatelessWidget { }, ), }, - child: child, + child: Focus( + focusNode: _fallbackFocusNode, + skipTraversal: true, + includeSemantics: false, + child: widget.child, + ), ), ); } diff --git a/lib/src/core/local_image_resolver.dart b/lib/src/core/local_image_resolver.dart index a6c884b0..c9f3d5ae 100644 --- a/lib/src/core/local_image_resolver.dart +++ b/lib/src/core/local_image_resolver.dart @@ -23,6 +23,13 @@ String? resolveLocalImagePath({ maxRecursiveEntries: maxRecursiveEntries, ); +/// Expands the home-directory syntax accepted by BusyMark's local-media +/// resolver while leaving all other paths unchanged. +/// +/// Callers must still validate the resulting path against their own allowed +/// roots before reading it. +String expandLocalMediaHomePath(String value) => _expandHomeDirectory(value); + /// Resolves an authored local media reference inside the same roots used for /// Writerside images and videos. String? resolveLocalMediaPath({ diff --git a/lib/src/export/html_export_assets.dart b/lib/src/export/html_export_assets.dart index 344da910..2236f68c 100644 --- a/lib/src/export/html_export_assets.dart +++ b/lib/src/export/html_export_assets.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:crypto/crypto.dart'; import 'package:path/path.dart' as p; import 'package:xml/xml.dart'; +import '../core/local_image_resolver.dart'; import '../visualization/generated_svg_normalizer.dart'; import 'markdown_export_assets.dart'; import 'html_export_models.dart'; @@ -55,9 +56,10 @@ class HtmlExportAssets { 'Remote or unsupported resource was not packaged.', ); } - final path = uri.scheme == 'file' + final decodedPath = uri.scheme == 'file' ? uri.toFilePath() : Uri.decodeComponent(uri.path); + final path = expandLocalMediaHomePath(decodedPath); final candidates = p.isAbsolute(path) ? [path] : [ diff --git a/lib/src/export/markdown_export_mapper.dart b/lib/src/export/markdown_export_mapper.dart index 1a9ba3e9..184bec3a 100644 --- a/lib/src/export/markdown_export_mapper.dart +++ b/lib/src/export/markdown_export_mapper.dart @@ -206,6 +206,7 @@ class MarkdownExportMapper { Map blockOverrides, ) { final style = busyAdmonitionStyleFromName(block.attributes['style']); + final title = block.attributes['title']; final admonition = block.attributes[busyMarkWritersideAdmonitionAttribute] == 'true' && style != BusyAdmonitionStyle.quote; @@ -215,7 +216,10 @@ class MarkdownExportMapper { : MarkdownExportBlockKind.blockquote, inlines: _mapInlines(block.inlines), children: _mapBlocks(block.children, blockOverrides), - attributes: {if (admonition) 'style': style?.name ?? 'tip'}, + attributes: { + if (admonition) 'style': style?.name ?? 'tip', + if (admonition && title != null) 'title': title, + }, ); } @@ -223,6 +227,7 @@ class MarkdownExportMapper { BusyBlock block, Map blockOverrides, ) { + final title = block.attributes['title']; final style = busyAdmonitionStyleFromName( block.attributes['style'] ?? block.attributes['element'], @@ -234,7 +239,10 @@ class MarkdownExportMapper { : MarkdownExportBlockKind.admonition, inlines: _mapInlines(block.inlines), children: _mapBlocks(block.children, blockOverrides), - attributes: {if (style != BusyAdmonitionStyle.quote) 'style': style.name}, + attributes: { + if (style != BusyAdmonitionStyle.quote) 'style': style.name, + if (style != BusyAdmonitionStyle.quote && title != null) 'title': title, + }, ); } diff --git a/test/src/busymark_dialogs_test.dart b/test/src/busymark_dialogs_test.dart index e8bfe360..0f40e993 100644 --- a/test/src/busymark_dialogs_test.dart +++ b/test/src/busymark_dialogs_test.dart @@ -95,41 +95,68 @@ void main() { expect(find.text('Dismiss'), findsOneWidget); }); - testWidgets( - 'Escape closes a modal even when its barrier is not dismissible', - (tester) async { - late BuildContext hostContext; - await tester.pumpWidget( - MaterialApp( - home: Builder( - builder: (context) { - hostContext = context; - return const Scaffold(body: SizedBox.expand()); - }, - ), + testWidgets('Escape closes a modal without an initially focused control', ( + tester, + ) async { + late BuildContext hostContext; + await tester.pumpWidget( + MaterialApp( + home: Builder( + builder: (context) { + hostContext = context; + return const Scaffold(body: SizedBox.expand()); + }, ), - ); + ), + ); - final result = showBusyMarkModalDialog( - hostContext, - barrierDismissible: false, - builder: (_) => const Dialog( - child: TextField( - autofocus: true, - decoration: InputDecoration(labelText: 'Modal input'), - ), + final result = showBusyMarkModalDialog( + hostContext, + barrierDismissible: false, + builder: (_) => const Dialog(child: Text('Modal content')), + ); + await tester.pumpAndSettle(); + expect(find.text('Modal content'), findsOneWidget); + + await tester.sendKeyEvent(LogicalKeyboardKey.escape); + await tester.pumpAndSettle(); + expect(find.text('Modal content'), findsNothing); + await result; + }); + + testWidgets('modal fallback does not steal a child autofocus request', ( + tester, + ) async { + late BuildContext hostContext; + await tester.pumpWidget( + MaterialApp( + home: Builder( + builder: (context) { + hostContext = context; + return const Scaffold(body: SizedBox.expand()); + }, ), - ); - await tester.pumpAndSettle(); - expect(find.text('Modal input'), findsOneWidget); + ), + ); - await tester.sendKeyEvent(LogicalKeyboardKey.escape); - await tester.pumpAndSettle(); - await result; + final result = showBusyMarkModalDialog( + hostContext, + builder: (_) => const Dialog( + child: TextField( + autofocus: true, + decoration: InputDecoration(labelText: 'Modal input'), + ), + ), + ); + await tester.pumpAndSettle(); + + final input = tester.widget(find.byType(EditableText)); + expect(input.focusNode.hasPrimaryFocus, isTrue); - expect(find.text('Modal input'), findsNothing); - }, - ); + Navigator.of(tester.element(find.byType(Dialog))).pop(); + await tester.pumpAndSettle(); + await result; + }); testWidgets('overlapping dialogs synchronize native modal depth', ( tester, diff --git a/test/src/export_options_editor_test.dart b/test/src/export_options_editor_test.dart index 54c619ce..246ca8da 100644 --- a/test/src/export_options_editor_test.dart +++ b/test/src/export_options_editor_test.dart @@ -2,15 +2,56 @@ import 'dart:io'; import 'package:busymark/l10n/generated/app_localizations.dart'; import 'package:busymark/src/app/app_settings.dart'; import 'package:busymark/src/app/busymark_design.dart'; +import 'package:busymark/src/app/busymark_dialogs.dart'; import 'package:busymark/src/app/app_theme.dart'; import 'package:busymark/src/export/export_options.dart'; import 'package:busymark/src/export/export_options_editor.dart'; import 'package:busymark/src/writerside/writerside_module_service.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { + testWidgets('Escape closes Export before a control receives focus', ( + tester, + ) async { + late BuildContext hostContext; + await tester.pumpWidget( + MaterialApp( + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + theme: buildBusyMarkTheme( + brightness: Brightness.light, + accentColor: Colors.blue, + ), + home: Builder( + builder: (context) { + hostContext = context; + return const Scaffold(body: SizedBox.expand()); + }, + ), + ), + ); + + final result = showBusyMarkModalEditorDialog( + hostContext, + builder: (_) => const ExportOptionsDialog( + pdf: PdfExportOptions(), + html: HtmlExportOptions(), + initialFormat: ExportFormat.pdf, + ), + ); + await tester.pumpAndSettle(); + expect(find.byType(ExportOptionsDialog), findsOneWidget); + + await tester.sendKeyEvent(LogicalKeyboardKey.escape); + await tester.pumpAndSettle(); + + expect(find.byType(ExportOptionsDialog), findsNothing); + expect(await result, isNull); + }); + for (final pdf in [true, false]) { for (final writerside in [false, true]) { testWidgets( diff --git a/test/src/html_export_test.dart b/test/src/html_export_test.dart index a405b846..68181283 100644 --- a/test/src/html_export_test.dart +++ b/test/src/html_export_test.dart @@ -1,4 +1,5 @@ import 'dart:io'; +import 'package:busymark/src/core/local_image_resolver.dart'; import 'package:busymark/src/export/html_export_models.dart'; import 'package:busymark/src/export/html_export_service.dart'; import 'package:busymark/src/export/html_export_assets.dart'; @@ -208,6 +209,35 @@ Footnote[^note] and again[^note]. }, ); + test('home-relative images use the shared local-media path rules', () async { + final downloads = await Directory(p.join(root.path, 'Downloads')).create(); + const svg = + ''; + await File(p.join(downloads.path, 'example.svg')).writeAsString(svg); + debugLocalImageHomeDirectoryOverride = root.path; + addTearDown(() => debugLocalImageHomeDirectoryOverride = null); + + final result = await service.exportMarkdown( + MarkdownHtmlExportRequest( + source: '# Image\n\n![Example](~/Downloads/example.svg)', + filePath: p.join(downloads.path, 'source.md'), + workspaceRoot: downloads.path, + destinationPath: p.join(downloads.path, 'document.html'), + mode: MarkdownMode.gfm, + ), + ); + + final doc = html.parse(await File(result.entryPointPath).readAsString()); + final source = doc.querySelector('img')?.attributes['src']; + expect(source, startsWith('document.assets/')); + expect(result.warnings, isEmpty); + expect(result.assetsPath, isNotNull); + expect( + await File(p.join(downloads.path, Uri.decodeComponent(source!))).exists(), + isTrue, + ); + }); + test('untrusted metadata and data URLs cannot create active HTML', () async { final result = await export('''--- title: diff --git a/test/src/markdown_pdf_export_service_test.dart b/test/src/markdown_pdf_export_service_test.dart index e630bdec..ff8c3f6a 100644 --- a/test/src/markdown_pdf_export_service_test.dart +++ b/test/src/markdown_pdf_export_service_test.dart @@ -31,6 +31,23 @@ void main() { expect(renderer, isNot(contains('height: 72% * size.height'))); }); + test('quotes and admonitions use the existing callout presentation', () { + final template = File('assets/export/markdown.typ').readAsStringSync(); + final callouts = RegExp( + r'#let render-callout[\s\S]*?else if kind == "thematicBreak"', + ).firstMatch(template)?.group(0); + + expect(callouts, isNotNull); + expect(callouts, contains('stroke: (left: 2pt + accent)')); + expect( + callouts, + contains('title: value-or(block-data, "title", default-title)'), + ); + expect(callouts, contains('fill: rgb("f5f7fa")')); + expect(callouts, contains('accent: rgb("4b5563")')); + expect(callouts, isNot(contains('quote(\n block: true'))); + }); + test( 'bundled template exports representative Markdown to a valid PDF', () async { diff --git a/test/src/writerside_admonition_test.dart b/test/src/writerside_admonition_test.dart index 912c4699..e1310692 100644 --- a/test/src/writerside_admonition_test.dart +++ b/test/src/writerside_admonition_test.dart @@ -353,6 +353,8 @@ Helpful advice. > Quoted. {style="quote"} + +Named. ''', mode: MarkdownMode.writersideMarkdown, validateLocalReferences: false, @@ -363,8 +365,11 @@ Helpful advice. MarkdownExportBlockKind.admonition, MarkdownExportBlockKind.admonition, MarkdownExportBlockKind.blockquote, + MarkdownExportBlockKind.admonition, ]); expect(exported.blocks[0].attributes['style'], 'tip'); expect(exported.blocks[1].attributes['style'], 'note'); + expect(exported.blocks[3].attributes['style'], 'note'); + expect(exported.blocks[3].attributes['title'], 'Known issue'); }); } From c51432aba61abf284a4ed81ced8f313fe9d2e6c1 Mon Sep 17 00:00:00 2001 From: albert Date: Tue, 8 Sep 2026 19:19:54 -0700 Subject: [PATCH 37/37] Refactor fixture paths in visualization script and documentation; update workflow accordingly. --- .github/workflows/flutter-linux.yml | 8 +- docs/visualizations.md | 10 +- .../visualization/openapi-local-reference.md | 27 +++ .../visualization/openapi/components.yaml | 10 ++ .../visualization/plantuml-conformance.md | 170 ++++++++++++++++++ .../visualization_packaging_audit_test.dart | 17 ++ tools/visualization_smoke.py | 28 +-- 7 files changed, 251 insertions(+), 19 deletions(-) create mode 100644 test/fixtures/visualization/openapi-local-reference.md create mode 100644 test/fixtures/visualization/openapi/components.yaml create mode 100644 test/fixtures/visualization/plantuml-conformance.md diff --git a/.github/workflows/flutter-linux.yml b/.github/workflows/flutter-linux.yml index 0c0e72eb..a712d7eb 100644 --- a/.github/workflows/flutter-linux.yml +++ b/.github/workflows/flutter-linux.yml @@ -114,7 +114,9 @@ jobs: env WEBKIT_DISABLE_COMPOSITING_MODE=1 LIBGL_ALWAYS_SOFTWARE=1 \ /usr/bin/python3 -u tools/visualization_smoke.py \ --assets build/linux/x64/release/bundle/share/busymark/visualization \ - --d2 build/linux/x64/release/bundle/libexec/busymark/d2 + --d2 build/linux/x64/release/bundle/libexec/busymark/d2 \ + --demo test/fixtures/markdown/basic.md \ + --plantuml-corpus test/fixtures/visualization/plantuml-conformance.md - name: Exercise the release binary visualization and PDF paths under X11 run: | @@ -153,7 +155,9 @@ jobs: LIBGL_ALWAYS_SOFTWARE=1 \ /usr/bin/python3 -u tools/visualization_smoke.py \ --assets build/linux/x64/release/bundle/share/busymark/visualization \ - --d2 build/linux/x64/release/bundle/libexec/busymark/d2 + --d2 build/linux/x64/release/bundle/libexec/busymark/d2 \ + --demo test/fixtures/markdown/basic.md \ + --plantuml-corpus test/fixtures/visualization/plantuml-conformance.md report="${RUNNER_TEMP}/visualization-release-wayland.json" XDG_RUNTIME_DIR="$runtime_dir" WAYLAND_DISPLAY=wayland-99 \ GDK_BACKEND=wayland BUSYMARK_RELEASE_SMOKE=1 \ diff --git a/docs/visualizations.md b/docs/visualizations.md index a062e9e1..f083618b 100644 --- a/docs/visualizations.md +++ b/docs/visualizations.md @@ -58,11 +58,11 @@ documentation for [D2](https://www.jetbrains.com/help/writerside/d2-diagrams.htm [PlantUML](https://www.jetbrains.com/help/writerside/plantuml-diagrams.html), and [Mermaid](https://www.jetbrains.com/help/writerside/mermaid-diagrams.html). -Demonstrations are available in: +The automated conformance corpus is stored in: -- [`demo/visualizations.md`](../demo/visualizations.md) -- [`demo/openapi-local-reference.md`](../demo/openapi-local-reference.md) -- [`demo/plantuml-conformance.md`](../demo/plantuml-conformance.md) +- [`test/fixtures/markdown/basic.md`](../test/fixtures/markdown/basic.md) +- [`test/fixtures/visualization/openapi-local-reference.md`](../test/fixtures/visualization/openapi-local-reference.md) +- [`test/fixtures/visualization/plantuml-conformance.md`](../test/fixtures/visualization/plantuml-conformance.md) ## Runtime design @@ -221,7 +221,7 @@ cancellation, stale-result rejection, timeout wiring, sanitization and external resources, traversal and symlink escapes, circular OpenAPI references, input limits, both themes, cache-version invalidation, D2 raster snapshots, and a rasterized visual assertion of generated SVG content in the PDF. Human release -review should still inspect the demo documents and PDF for visual quality; it +review should still inspect the fixture documents and PDF for visual quality; it is not a substitute for these automated product-path checks. ## Authoritative references diff --git a/test/fixtures/visualization/openapi-local-reference.md b/test/fixtures/visualization/openapi-local-reference.md new file mode 100644 index 00000000..eeb8a5f7 --- /dev/null +++ b/test/fixtures/visualization/openapi-local-reference.md @@ -0,0 +1,27 @@ +# OpenAPI local-reference conformance fixture + +The parser resolves this relative file inside the canonical workspace root. + +```oas +openapi: 3.1.0 +info: + title: Local Reference Fixture + version: 1.0.0 +paths: + /nodes/{id}: + get: + operationId: getNode + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + "200": + description: A recursive node + content: + application/json: + schema: + $ref: "./openapi/components.yaml#/components/schemas/Node" +``` diff --git a/test/fixtures/visualization/openapi/components.yaml b/test/fixtures/visualization/openapi/components.yaml new file mode 100644 index 00000000..48134c9d --- /dev/null +++ b/test/fixtures/visualization/openapi/components.yaml @@ -0,0 +1,10 @@ +components: + schemas: + Node: + type: object + required: [id] + properties: + id: + type: string + parent: + $ref: "#/components/schemas/Node" diff --git a/test/fixtures/visualization/plantuml-conformance.md b/test/fixtures/visualization/plantuml-conformance.md new file mode 100644 index 00000000..81627a25 --- /dev/null +++ b/test/fixtures/visualization/plantuml-conformance.md @@ -0,0 +1,170 @@ +# PlantUML browser-build conformance corpus + +These diagrams cover the PlantUML families supported by BusyMark. + +## Sequence + +```plantuml +@startuml +Alice -> Bob: Hello +Bob --> Alice: Ready +@enduml +``` + +## Class + +```puml +@startuml +class Document { + +title: String + +render(): Svg +} +interface Renderer +Renderer <|.. Document +@enduml +``` + +## Component + +```plantuml +@startuml +component BusyMark +component Renderer +BusyMark --> Renderer +@enduml +``` + +## Deployment + +```plantuml +@startuml +node "Linux desktop" { + artifact BusyMark + node WebKitGTK +} +BusyMark --> WebKitGTK +@enduml +``` + +## State + +```plantuml +@startuml +[*] --> Editing +Editing --> Rendering +Rendering --> Ready +Rendering --> Editing : invalid source +Ready --> [*] +@enduml +``` + +## Activity + +```plantuml +@startuml +start +:Parse source; +if (Valid?) then (yes) + :Render SVG; +else (no) + :Keep last valid render; +endif +stop +@enduml +``` + +## Use case + +```plantuml +@startuml +left to right direction +actor Author +rectangle BusyMark { + usecase "Preview diagram" as Preview + usecase "Export PDF" as Export +} +Author --> Preview +Author --> Export +@enduml +``` + +## Entity relationship + +```plantuml +@startuml +entity Document { + * id : UUID + -- + title : text +} +entity Diagram { + * id : UUID + document_id : UUID +} +Document ||--o{ Diagram +@enduml +``` + +## Mind map + +```plantuml +@startmindmap +* BusyMark +** Preview +*** Mermaid +*** PlantUML +*** D2 +** API Reference +*** OpenAPI +@endmindmap +``` + +## Work breakdown structure + +```plantuml +@startwbs +* Release +** Renderers +*** Mermaid +*** PlantUML +*** D2 +** OpenAPI +** PDF tests +@endwbs +``` + +## Gantt + +```plantuml +@startgantt +Project starts 2026-08-18 +[Renderer contracts] lasts 2 days +[Preview integration] starts at [Renderer contracts]'s end and lasts 2 days +[PDF verification] starts at [Preview integration]'s end and lasts 1 day +@endgantt +``` + +## JSON + +```plantuml +@startjson +{ + "offline": true, + "engines": ["Mermaid", "PlantUML", "D2", "OpenAPI"] +} +@endjson +``` + +## YAML + +```plantuml +@startyaml +application: BusyMark +offline: true +renderers: + - Mermaid + - PlantUML + - D2 + - OpenAPI +@endyaml +``` diff --git a/test/src/visualization_packaging_audit_test.dart b/test/src/visualization_packaging_audit_test.dart index ba8b96ab..12e7ae0c 100644 --- a/test/src/visualization_packaging_audit_test.dart +++ b/test/src/visualization_packaging_audit_test.dart @@ -175,6 +175,14 @@ void main() { expect(workflow, contains('BUSYMARK_D2_PATH:')); expect(workflow, contains('BUSYMARK_TYPST_PATH:')); expect(workflow, contains('tools/visualization_smoke.py')); + expect(workflow, contains('--demo test/fixtures/markdown/basic.md')); + expect( + workflow, + contains( + '--plantuml-corpus ' + 'test/fixtures/visualization/plantuml-conformance.md', + ), + ); expect(workflow, contains('GDK_BACKEND=wayland')); expect(workflow, contains('snapcore/action-build@v1')); expect(workflow, contains("if: steps.snapcraft.outcome == 'failure'")); @@ -187,6 +195,15 @@ void main() { expect(workflow, contains('BUSYMARK_RELEASE_SMOKE=1')); expect(workflow, contains('visualization-smoke.pdf')); final smoke = File('tools/visualization_smoke.py').readAsStringSync(); + expect(smoke, isNot(contains('demo/'))); + for (final fixture in [ + 'test/fixtures/markdown/basic.md', + 'test/fixtures/visualization/openapi-local-reference.md', + 'test/fixtures/visualization/openapi/components.yaml', + 'test/fixtures/visualization/plantuml-conformance.md', + ]) { + expect(File(fixture).existsSync(), isTrue, reason: '$fixture must exist'); + } expect(smoke, contains('terminate_web_process')); expect(smoke, contains('WebKit process termination and recovery')); expect(smoke, contains('smoke-responsive-gradient')); diff --git a/tools/visualization_smoke.py b/tools/visualization_smoke.py index 7fec234e..c489b114 100755 --- a/tools/visualization_smoke.py +++ b/tools/visualization_smoke.py @@ -18,6 +18,14 @@ from gi.repository import Gio, GLib, Gtk, WebKit2 # noqa: E402 +REPOSITORY_ROOT = Path(__file__).resolve().parents[1] +MARKDOWN_FIXTURE = REPOSITORY_ROOT / "test/fixtures/markdown/basic.md" +VISUALIZATION_FIXTURES = REPOSITORY_ROOT / "test/fixtures/visualization" +PLANTUML_FIXTURE = VISUALIZATION_FIXTURES / "plantuml-conformance.md" +LOCAL_OPENAPI_FIXTURE = VISUALIZATION_FIXTURES / "openapi-local-reference.md" +LOCAL_OPENAPI_DEPENDENCY = VISUALIZATION_FIXTURES / "openapi/components.yaml" + + def fenced_sources(path: Path, languages: tuple[str, ...]) -> list[str]: language_pattern = "|".join(re.escape(language) for language in languages) pattern = re.compile( @@ -438,12 +446,10 @@ def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--assets", required=True, type=Path) parser.add_argument("--d2", required=True, type=Path) - parser.add_argument( - "--demo", default=Path("demo/visualizations.md"), type=Path - ) + parser.add_argument("--demo", default=MARKDOWN_FIXTURE, type=Path) parser.add_argument( "--plantuml-corpus", - default=Path("demo/plantuml-conformance.md"), + default=PLANTUML_FIXTURE, type=Path, ) args = parser.parse_args() @@ -451,11 +457,9 @@ def main() -> int: mermaid = fenced_sources(args.demo, ("mermaid",))[0] openapi = fenced_sources(args.demo, ("openapi", "oas", "swagger"))[0] local_openapi = fenced_sources( - Path("demo/openapi-local-reference.md"), ("openapi", "oas", "swagger") + LOCAL_OPENAPI_FIXTURE, ("openapi", "oas", "swagger") )[0] - local_dependency = Path("demo/openapi/components.yaml").read_text( - encoding="utf-8" - ) + local_dependency = LOCAL_OPENAPI_DEPENDENCY.read_text(encoding="utf-8") plantuml = fenced_sources(args.plantuml_corpus, ("plantuml", "puml")) d2_failures, d2_outputs = d2_smoke(args.d2.resolve()) cases: list[dict[str, object]] = [ @@ -766,11 +770,11 @@ def main() -> int: "uri": "busymark-render://app/harness.html", "request": { "operation": "parseOpenApi", - "entryId": "demo/openapi-local-reference.md", + "entryId": "fixtures/openapi-local-reference.md", "source": local_openapi, "dependencies": [ { - "id": "demo/openapi/components.yaml", + "id": "fixtures/openapi/components.yaml", "source": local_dependency, } ], @@ -858,11 +862,11 @@ def main() -> int: "name": "Scalar local circular reference", "uri": "busymark-render://app/reference.html", "request": { - "entryId": "demo/openapi-local-reference.md", + "entryId": "fixtures/openapi-local-reference.md", "source": local_openapi, "dependencies": [ { - "id": "demo/openapi/components.yaml", + "id": "fixtures/openapi/components.yaml", "source": local_dependency, } ],

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�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%0A={yo$a7ywdcxaGmoH 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