From ce169026b329a35e57f45b0c57b32e706fa4b9e2 Mon Sep 17 00:00:00 2001 From: Alice Carroll Date: Mon, 7 Jul 2025 10:59:50 +0300 Subject: [PATCH] feat: non-breaking hyphen shorthand Closes #6355 --- crates/typst-syntax/src/ast.rs | 1 + crates/typst-syntax/src/lexer.rs | 3 ++- tests/ref/shorthand-nbsp-and-shy-hyphen.png | Bin 1356 -> 2047 bytes tests/suite/layout/inline/linebreak.typ | 2 +- tests/suite/syntax/shorthand.typ | 2 +- tools/support/typst.tmLanguage.json | 4 ++++ 6 files changed, 9 insertions(+), 3 deletions(-) diff --git a/crates/typst-syntax/src/ast.rs b/crates/typst-syntax/src/ast.rs index 547d53cd8..c51eaeec8 100644 --- a/crates/typst-syntax/src/ast.rs +++ b/crates/typst-syntax/src/ast.rs @@ -595,6 +595,7 @@ impl Shorthand<'_> { ("--", '\u{2013}'), ("---", '\u{2014}'), ("-?", '\u{00AD}'), + ("-!", '\u{2011}'), ]; /// Get the shorthanded character. diff --git a/crates/typst-syntax/src/lexer.rs b/crates/typst-syntax/src/lexer.rs index 82f65cd36..59a89d138 100644 --- a/crates/typst-syntax/src/lexer.rs +++ b/crates/typst-syntax/src/lexer.rs @@ -191,6 +191,7 @@ impl Lexer<'_> { '-' if self.s.eat_if("--") => SyntaxKind::Shorthand, '-' if self.s.eat_if('-') => SyntaxKind::Shorthand, '-' if self.s.eat_if('?') => SyntaxKind::Shorthand, + '-' if self.s.eat_if('!') => SyntaxKind::Shorthand, '-' if self.s.at(char::is_numeric) => SyntaxKind::Shorthand, '*' if !self.in_word() => SyntaxKind::Star, '_' if !self.in_word() => SyntaxKind::Underscore, @@ -528,7 +529,7 @@ impl Lexer<'_> { match s.eat() { Some(' ') if s.at(char::is_alphanumeric) => {} Some('/') if !s.at(['/', '*']) => {} - Some('-') if !s.at(['-', '?']) => {} + Some('-') if !s.at(['-', '?', '!']) => {} Some('.') if !s.at("..") => {} Some('h') if !s.at("ttp://") && !s.at("ttps://") => {} Some('@') if !s.at(is_valid_in_label_literal) => {} diff --git a/tests/ref/shorthand-nbsp-and-shy-hyphen.png b/tests/ref/shorthand-nbsp-and-shy-hyphen.png index e6984bb79d8bdca473675cca0edc62fb3569de2b..ad5a92a132ae4bca883e0d2c73d7774bdfeddedd 100644 GIT binary patch delta 2046 zcmV?)Kh?}{)f9@u6 zbTo;MeIo&kiY+P;)U|M{5ygUXDt1H^!3GK_g1CU9v<0PiL5k7@RGJ6U%q~&{frVYl z*7rGcb8~K(aRVyOCA^=&Yv%XI=llDD&(s&=@HjjU|Nh{r0)O6@B2|uI(zFkStK}+su0t)q!CG03D-;A<`AB1}-hHEkzgNax z)|lq3j|438Fn`0YmL=60)@t|kzPvn@s7fcpk$2VLS8Ko7~VXAOXM(o_utj`Iwy~j5eDIk<- zOex=qFmuoAk;CFcP$4AsfNElw`Ze%F87MS;Q0VyB@n+n<`kRN_PVV{n$mbXk>0xkFeg;@85=Rt{Z}tBp ztSV7pq<@Yl3`l^5<@ zyga0j@hYRw*Q*9eXgKB#Hb8H{krS7u$-f9Gc6n_;t10r8&NZ_xl0R z7wF!k_6bhM+dO#vt|H@b#_6^fG3#{~{9fdBSby_#i!?L#bot+apg64SBz_!@D7UMc z+-=#J3p6ig)1&@i!0K%>{zB-eIRY{c{UeUBYml}Zw?N)RqyHjGL z5=VWGJ0U0IY2|vNcLkCWNoBea^tt@2UVmzGOO(IQy`)Ts~O|w?au)-Jd z{wn`Ga#$+FAn{Fx)w={E2}Taf)=LgImme(acFA!pJ@bq}|I4RzJd)%MoGx+m0e|QW zIlY9QYvN{9;kUbq_AdgUEzwh3f2iirebixBzZ?ZTy(a21Kb3KXmErv}`U1Ch+g8`_ zZkzt*)PCh61+YdXTf!=N&rI#1!h5#$I~BPA+!*jk!X&zHAxHkjlu^J!3LSa4EmMY2 zhJ8k0FfJKB2ea<0F2*6M1Nl69mw)Id!J?)qS(%l3yOpm1XbC*vgM|_SQ?;Xc>P9Q_ z9Khr}2pd`5>URUD7}=Ok?q5 z{Y34E;ed5*mqeYoKLnx6sl=f@`}=L3HT#_+<#x{P>-~V(UBOnBwfp@Z@PB0E)ryC1 zSEP@30$$#}yNfO3iYOZMJ6lN|Mmgx*2#h}w^7&MO&!P$~L z_jbAhBl^2Mf4PtZz>N4i>VF#V!YI-u?K}%BBFp*p`K$sz#3jMLPPV1mw}lm&xf_C5$`SNoKK`2~1e6wIvRsMV3hopG0Dm-zdLix0mtz6b`3wJR z0FX6wj30^L3TrV;Gd8etK@0{J{C#X-+!HWt&KSUjK?=?#P!d`}!>y+Pq}`eZDUn_9 zD7KICu#!&!KTLb%^cL>f(ibY*qCOf9oUG`Y%!Q<0v+jgY>2l2)b>OFf$qZig7RG9K zm!B_X*1$9nFn4{39qB(^4++I~bL*#o{UzN$;vUzaxU=`}9`g18U$-)q#TD38Y)^*P zj?@k4KRzt6zcZ&~m0kXUt2w%Z=Z>`k_tssRomuk_|BF;C^hmAQDUOqF82{dm!{hKc c{D+1A4QE8ItBFBzG5`Po07*qoM6N<$f|CCM00000 delta 1350 zcmV-M1-bhF56lXX7k@Pf00000ugP${000FONkl=ne=0EtG!_wDoI^X~V2#5?Mv1$Y5ofImFA`3`SNUw^D)dg_w-!n^$rZ1u6t za^OvktZid@s-*y-hPlIkk>WwM>JV>Cq+&(_05fxkA^i%d_6LdDs8xiTplesfNjbw( zSswmTz79G7QHc93!-*sZb9Sbj`h3?Z1W5ceLQTGFdVJAf%_Y9&T0V1w zMO3-n-|<{C0oV>BVAT+=*;Q^tq;;ofPKi|5=%t0oJf3ST)$(J1vUF1s2)ie3XgZ0o z;!OYSVcB_jB&7J9aq*z3AK1{#r#L2H*Ijgupf~_g>wn+@+_QLWGc`E&6&@LuCAt-D zY;V_p$=$;Qc9@totnqYxLY&LM4Y#36=cFlUb;@fzQ)dc~xpkCg`Q z!_4$|Er0WbU#@DyN~PoJ*7(8Lg4pA}^ z5z8`$7GFx} zx_JAOe_MykynEZT?acv^?KJ~-9C@y;$nkFa7=MV%#ZHwGiHo91-2Bm%jQ0Do$e zw+8=~n?0OLyi+f?2 z14gqnivulSu;pZb&4(qEY6pGoF)|Bfj?TpPsQo| z6GOTD&m0FN4%nxD`^$B@8Z=9S-#%;sjJn~4C$Ru8!0!+IF9u>)utd`_^#A|>07*qo IM6N<$f~udI>Hq)$ diff --git a/tests/suite/layout/inline/linebreak.typ b/tests/suite/layout/inline/linebreak.typ index 86a900252..7de01490a 100644 --- a/tests/suite/layout/inline/linebreak.typ +++ b/tests/suite/layout/inline/linebreak.typ @@ -10,7 +10,7 @@ Supercalifragilisticexpialidocious Expialigoricmetrioxidation. --- linebreak-hyphen-nbsp --- // Test for non-breaking space and hyphen. -There are non\u{2011}breaking~characters. +There are non-!breaking~characters. --- linebreak-narrow-nbsp --- // Test for narrow non-breaking space. diff --git a/tests/suite/syntax/shorthand.typ b/tests/suite/syntax/shorthand.typ index 7d1782b9f..696a794e0 100644 --- a/tests/suite/syntax/shorthand.typ +++ b/tests/suite/syntax/shorthand.typ @@ -1,7 +1,7 @@ // Test shorthands for unicode codepoints. --- shorthand-nbsp-and-shy-hyphen --- -The non-breaking space~does work, soft-?hyphen also does. +The non-breaking space~does work, soft-?hyphen does, and non-!breaking hyphen also does. --- shorthand-nbsp-width --- // Make sure non-breaking and normal space always diff --git a/tools/support/typst.tmLanguage.json b/tools/support/typst.tmLanguage.json index 104df060e..a8e85bc91 100644 --- a/tools/support/typst.tmLanguage.json +++ b/tools/support/typst.tmLanguage.json @@ -42,6 +42,10 @@ "name": "punctuation.definition.nonbreaking-space.typst", "match": "~" }, + { + "name": "punctuation.definition.nonbreaking-hyphen.typst", + "match": "-!" + }, { "name": "punctuation.definition.shy.typst", "match": "-\\?"