From b07607d35e697be3dd5e56945b16afa8103a491e Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 9 Aug 2024 07:41:01 +0000 Subject: [PATCH] Split shorthands into math and markup, add tilde shorthand (#4706) --- crates/typst-syntax/src/ast.rs | 110 ++++++++++++++++----------- crates/typst-syntax/src/highlight.rs | 1 + crates/typst-syntax/src/kind.rs | 3 + crates/typst-syntax/src/lexer.rs | 72 +++++++++--------- crates/typst-syntax/src/parser.rs | 2 +- crates/typst-syntax/src/set.rs | 2 +- crates/typst/src/eval/code.rs | 1 + crates/typst/src/eval/math.rs | 9 +++ docs/src/lib.rs | 4 +- tests/ref/math-class-chars.png | Bin 1331 -> 1346 bytes tests/ref/shorthand-minus.png | Bin 0 -> 175 bytes tests/ref/shorthands-math.png | Bin 1832 -> 1921 bytes tests/suite/math/class.typ | 2 +- tests/suite/syntax/shorthand.typ | 7 +- 14 files changed, 127 insertions(+), 86 deletions(-) create mode 100644 tests/ref/shorthand-minus.png diff --git a/crates/typst-syntax/src/ast.rs b/crates/typst-syntax/src/ast.rs index 1cd9cd429..3d3a85ad4 100644 --- a/crates/typst-syntax/src/ast.rs +++ b/crates/typst-syntax/src/ast.rs @@ -125,6 +125,8 @@ pub enum Expr<'a> { Math(Math<'a>), /// An identifier in math: `pi`. MathIdent(MathIdent<'a>), + /// A shorthand for a unicode codepoint in math: `a <= b`. + MathShorthand(MathShorthand<'a>), /// An alignment point in math: `&`. MathAlignPoint(MathAlignPoint<'a>), /// Matched delimiters in math: `[x + y]`. @@ -232,6 +234,7 @@ impl<'a> AstNode<'a> for Expr<'a> { SyntaxKind::Equation => node.cast().map(Self::Equation), SyntaxKind::Math => node.cast().map(Self::Math), SyntaxKind::MathIdent => node.cast().map(Self::MathIdent), + SyntaxKind::MathShorthand => node.cast().map(Self::MathShorthand), SyntaxKind::MathAlignPoint => node.cast().map(Self::MathAlignPoint), SyntaxKind::MathDelimited => node.cast().map(Self::MathDelimited), SyntaxKind::MathAttach => node.cast().map(Self::MathAttach), @@ -295,6 +298,7 @@ impl<'a> AstNode<'a> for Expr<'a> { Self::Equation(v) => v.to_untyped(), Self::Math(v) => v.to_untyped(), Self::MathIdent(v) => v.to_untyped(), + Self::MathShorthand(v) => v.to_untyped(), Self::MathAlignPoint(v) => v.to_untyped(), Self::MathDelimited(v) => v.to_untyped(), Self::MathAttach(v) => v.to_untyped(), @@ -450,7 +454,7 @@ node! { impl Shorthand<'_> { /// A list of all shorthands in markup mode. - pub const MARKUP_LIST: &'static [(&'static str, char)] = &[ + pub const LIST: &'static [(&'static str, char)] = &[ ("...", '…'), ("~", '\u{00A0}'), ("-", '\u{2212}'), // Only before a digit @@ -459,52 +463,11 @@ impl Shorthand<'_> { ("-?", '\u{00AD}'), ]; - /// A list of all shorthands in math mode. - pub const MATH_LIST: &'static [(&'static str, char)] = &[ - ("...", '…'), - ("-", '\u{2212}'), - ("'", '′'), - ("*", '∗'), - ("!=", '≠'), - (":=", '≔'), - ("::=", '⩴'), - ("=:", '≕'), - ("<<", '≪'), - ("<<<", '⋘'), - (">>", '≫'), - (">>>", '⋙'), - ("<=", '≤'), - (">=", '≥'), - ("->", '→'), - ("-->", '⟶'), - ("|->", '↦'), - (">->", '↣'), - ("->>", '↠'), - ("<-", '←'), - ("<--", '⟵'), - ("<-<", '↢'), - ("<<-", '↞'), - ("<->", '↔'), - ("<-->", '⟷'), - ("~>", '⇝'), - ("~~>", '⟿'), - ("<~", '⇜'), - ("<~~", '⬳'), - ("=>", '⇒'), - ("|=>", '⤇'), - ("==>", '⟹'), - ("<==", '⟸'), - ("<=>", '⇔'), - ("<==>", '⟺'), - ("[|", '⟦'), - ("|]", '⟧'), - ("||", '‖'), - ]; - /// Get the shorthanded character. pub fn get(self) -> char { let text = self.0.text(); - (Self::MARKUP_LIST.iter().chain(Self::MATH_LIST)) + Self::LIST + .iter() .find(|&&(s, _)| s == text) .map_or_else(char::default, |&(_, c)| c) } @@ -770,6 +733,65 @@ impl Deref for MathIdent<'_> { } } +node! { + /// A shorthand for a unicode codepoint in math: `a <= b`. + MathShorthand +} + +impl MathShorthand<'_> { + /// A list of all shorthands in math mode. + pub const LIST: &'static [(&'static str, char)] = &[ + ("...", '…'), + ("-", '−'), + ("'", '′'), + ("*", '∗'), + ("~", '∼'), + ("!=", '≠'), + (":=", '≔'), + ("::=", '⩴'), + ("=:", '≕'), + ("<<", '≪'), + ("<<<", '⋘'), + (">>", '≫'), + (">>>", '⋙'), + ("<=", '≤'), + (">=", '≥'), + ("->", '→'), + ("-->", '⟶'), + ("|->", '↦'), + (">->", '↣'), + ("->>", '↠'), + ("<-", '←'), + ("<--", '⟵'), + ("<-<", '↢'), + ("<<-", '↞'), + ("<->", '↔'), + ("<-->", '⟷'), + ("~>", '⇝'), + ("~~>", '⟿'), + ("<~", '⇜'), + ("<~~", '⬳'), + ("=>", '⇒'), + ("|=>", '⤇'), + ("==>", '⟹'), + ("<==", '⟸'), + ("<=>", '⇔'), + ("<==>", '⟺'), + ("[|", '⟦'), + ("|]", '⟧'), + ("||", '‖'), + ]; + + /// Get the shorthanded character. + pub fn get(self) -> char { + let text = self.0.text(); + Self::LIST + .iter() + .find(|&&(s, _)| s == text) + .map_or_else(char::default, |&(_, c)| c) + } +} + node! { /// An alignment point in math: `&`. MathAlignPoint diff --git a/crates/typst-syntax/src/highlight.rs b/crates/typst-syntax/src/highlight.rs index 0c1f3d5fd..ddd293260 100644 --- a/crates/typst-syntax/src/highlight.rs +++ b/crates/typst-syntax/src/highlight.rs @@ -172,6 +172,7 @@ pub fn highlight(node: &LinkedNode) -> Option { SyntaxKind::Math => None, SyntaxKind::MathIdent => highlight_ident(node), + SyntaxKind::MathShorthand => Some(Tag::Escape), SyntaxKind::MathAlignPoint => Some(Tag::MathOperator), SyntaxKind::MathDelimited => None, SyntaxKind::MathAttach => None, diff --git a/crates/typst-syntax/src/kind.rs b/crates/typst-syntax/src/kind.rs index 7505dbc61..a4456b9f4 100644 --- a/crates/typst-syntax/src/kind.rs +++ b/crates/typst-syntax/src/kind.rs @@ -75,6 +75,8 @@ pub enum SyntaxKind { Math, /// An identifier in math: `pi`. MathIdent, + /// A shorthand for a unicode codepoint in math: `a <= b`. + MathShorthand, /// An alignment point in math: `&`. MathAlignPoint, /// Matched delimiters in math: `[x + y]`. @@ -400,6 +402,7 @@ impl SyntaxKind { Self::Equation => "equation", Self::Math => "math", Self::MathIdent => "math identifier", + Self::MathShorthand => "math shorthand", Self::MathAlignPoint => "math alignment point", Self::MathDelimited => "delimited math", Self::MathAttach => "math attachments", diff --git a/crates/typst-syntax/src/lexer.rs b/crates/typst-syntax/src/lexer.rs index 993af0806..92e78b2d0 100644 --- a/crates/typst-syntax/src/lexer.rs +++ b/crates/typst-syntax/src/lexer.rs @@ -514,42 +514,42 @@ impl Lexer<'_> { '\\' => self.backslash(), '"' => self.string(), - '-' 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.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.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.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.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.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.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.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.eat_if('|') => SyntaxKind::Shorthand, - '~' if self.s.eat_if("~>") => SyntaxKind::Shorthand, - '~' if self.s.eat_if('>') => SyntaxKind::Shorthand, - '*' | '-' => SyntaxKind::Shorthand, + '-' if self.s.eat_if(">>") => SyntaxKind::MathShorthand, + '-' if self.s.eat_if('>') => SyntaxKind::MathShorthand, + '-' if self.s.eat_if("->") => SyntaxKind::MathShorthand, + ':' if self.s.eat_if('=') => SyntaxKind::MathShorthand, + ':' if self.s.eat_if(":=") => SyntaxKind::MathShorthand, + '!' if self.s.eat_if('=') => SyntaxKind::MathShorthand, + '.' if self.s.eat_if("..") => SyntaxKind::MathShorthand, + '[' if self.s.eat_if('|') => SyntaxKind::MathShorthand, + '<' if self.s.eat_if("==>") => SyntaxKind::MathShorthand, + '<' if self.s.eat_if("-->") => SyntaxKind::MathShorthand, + '<' if self.s.eat_if("--") => SyntaxKind::MathShorthand, + '<' if self.s.eat_if("-<") => SyntaxKind::MathShorthand, + '<' if self.s.eat_if("->") => SyntaxKind::MathShorthand, + '<' if self.s.eat_if("<-") => SyntaxKind::MathShorthand, + '<' if self.s.eat_if("<<") => SyntaxKind::MathShorthand, + '<' if self.s.eat_if("=>") => SyntaxKind::MathShorthand, + '<' if self.s.eat_if("==") => SyntaxKind::MathShorthand, + '<' if self.s.eat_if("~~") => SyntaxKind::MathShorthand, + '<' if self.s.eat_if('=') => SyntaxKind::MathShorthand, + '<' if self.s.eat_if('<') => SyntaxKind::MathShorthand, + '<' if self.s.eat_if('-') => SyntaxKind::MathShorthand, + '<' if self.s.eat_if('~') => SyntaxKind::MathShorthand, + '>' if self.s.eat_if("->") => SyntaxKind::MathShorthand, + '>' if self.s.eat_if(">>") => SyntaxKind::MathShorthand, + '=' if self.s.eat_if("=>") => SyntaxKind::MathShorthand, + '=' if self.s.eat_if('>') => SyntaxKind::MathShorthand, + '=' if self.s.eat_if(':') => SyntaxKind::MathShorthand, + '>' if self.s.eat_if('=') => SyntaxKind::MathShorthand, + '>' if self.s.eat_if('>') => SyntaxKind::MathShorthand, + '|' if self.s.eat_if("->") => SyntaxKind::MathShorthand, + '|' if self.s.eat_if("=>") => SyntaxKind::MathShorthand, + '|' if self.s.eat_if(']') => SyntaxKind::MathShorthand, + '|' if self.s.eat_if('|') => SyntaxKind::MathShorthand, + '~' if self.s.eat_if("~>") => SyntaxKind::MathShorthand, + '~' if self.s.eat_if('>') => SyntaxKind::MathShorthand, + '*' | '-' | '~' => SyntaxKind::MathShorthand, '#' => SyntaxKind::Hash, '_' => SyntaxKind::Underscore, diff --git a/crates/typst-syntax/src/parser.rs b/crates/typst-syntax/src/parser.rs index 2cbce1d70..4ce3917e0 100644 --- a/crates/typst-syntax/src/parser.rs +++ b/crates/typst-syntax/src/parser.rs @@ -319,7 +319,7 @@ fn math_expr_prec(p: &mut Parser, min_prec: usize, stop: SyntaxKind) { } } - SyntaxKind::Text | SyntaxKind::Shorthand => { + SyntaxKind::Text | SyntaxKind::MathShorthand => { continuable = matches!( math_class(p.current_text()), None | Some(MathClass::Alphabetic) diff --git a/crates/typst-syntax/src/set.rs b/crates/typst-syntax/src/set.rs index 39e64651b..2297cacb1 100644 --- a/crates/typst-syntax/src/set.rs +++ b/crates/typst-syntax/src/set.rs @@ -80,7 +80,7 @@ pub const MATH_EXPR: SyntaxSet = SyntaxSet::new() .add(SyntaxKind::Hash) .add(SyntaxKind::MathIdent) .add(SyntaxKind::Text) - .add(SyntaxKind::Shorthand) + .add(SyntaxKind::MathShorthand) .add(SyntaxKind::Linebreak) .add(SyntaxKind::MathAlignPoint) .add(SyntaxKind::Escape) diff --git a/crates/typst/src/eval/code.rs b/crates/typst/src/eval/code.rs index dcbc5b69d..7cfb7f593 100644 --- a/crates/typst/src/eval/code.rs +++ b/crates/typst/src/eval/code.rs @@ -95,6 +95,7 @@ impl Eval for ast::Expr<'_> { Self::Equation(v) => v.eval(vm).map(Value::Content), Self::Math(v) => v.eval(vm).map(Value::Content), Self::MathIdent(v) => v.eval(vm), + Self::MathShorthand(v) => v.eval(vm), Self::MathAlignPoint(v) => v.eval(vm).map(Value::Content), Self::MathDelimited(v) => v.eval(vm).map(Value::Content), Self::MathAttach(v) => v.eval(vm).map(Value::Content), diff --git a/crates/typst/src/eval/math.rs b/crates/typst/src/eval/math.rs index 548c935dc..42528d618 100644 --- a/crates/typst/src/eval/math.rs +++ b/crates/typst/src/eval/math.rs @@ -4,6 +4,7 @@ use crate::diag::{At, SourceResult}; use crate::eval::{Eval, Vm}; use crate::foundations::{Content, NativeElement, Value}; use crate::math::{AlignPointElem, AttachElem, FracElem, LrElem, PrimesElem, RootElem}; +use crate::symbols::Symbol; use crate::syntax::ast::{self, AstNode}; use crate::text::TextElem; @@ -26,6 +27,14 @@ impl Eval for ast::MathIdent<'_> { } } +impl Eval for ast::MathShorthand<'_> { + type Output = Value; + + fn eval(self, _: &mut Vm) -> SourceResult { + Ok(Value::Symbol(Symbol::single(self.get().into()))) + } +} + impl Eval for ast::MathAlignPoint<'_> { type Output = Content; diff --git a/docs/src/lib.rs b/docs/src/lib.rs index 335d01108..b28111e4e 100644 --- a/docs/src/lib.rs +++ b/docs/src/lib.rs @@ -664,8 +664,8 @@ fn symbols_model(resolver: &dyn Resolver, group: &GroupData) -> SymbolsModel { list.push(SymbolModel { name: complete(variant), - markup_shorthand: shorthand(typst::syntax::ast::Shorthand::MARKUP_LIST), - math_shorthand: shorthand(typst::syntax::ast::Shorthand::MATH_LIST), + markup_shorthand: shorthand(typst::syntax::ast::Shorthand::LIST), + math_shorthand: shorthand(typst::syntax::ast::MathShorthand::LIST), codepoint: c.char() as _, accent: typst::math::Accent::combine(c.char()).is_some(), alternates: symbol diff --git a/tests/ref/math-class-chars.png b/tests/ref/math-class-chars.png index a4f7d29b114b68ecd0f9b6032c99d3e67e0cbda1..6bcaaf40804a3335275bbc00cf2bd5206a9d0b4e 100644 GIT binary patch delta 1340 zcmV-C1;hHY3c?DI7k{P*00000G&>Yg000FENklOyY)vR?ayDcR{_sxb1tD1PLs}jub-Lv`UFqbPB%}$!6?^%rbyPWHeKg+p zgkV!lfp4l)fzhQDi0|qWZE|U_2D=k>MxIj#Ci1!fxFh1C7fPl#ZihOh z;E#qU)}U0mpMN!dLa==arN53Ti{C08Z`p-l0u6pgE`e<=aH%+<7%A9%#d;fH7@%`d zn_L?Fa=n2I~(H6kl&>0MDc_av@)#V@^NhdY_yBOWqCYNUYQ6SXa<0pdJ_O(4wQh6VF1A7yW=Q@ z83o{@H7G5^Rn1WW*dL|#kIz@n9rQdrxErNIC-@Yl-Gd&7;Poe1B||1y-x(*QiB%&gaGizA(mPs;Mbj9VP=5g9|72P)AA+~upc|p3ITr618}%E zIbQ@GDH|%V0c-{Ud&O1RUEP+9D_Ji2rGT7*&q&2yaI6l9dVe&01wv7!A%(_+J6An z0%V7t?hu0St!BqXfM|f=8xPkD!7-=su>w>BcvH7Q2##ttcvk|H00a=yC{9uCj>|0RS6dgUNGHc)~W;-CriO!J2{!P z_XZHx0))q>cFVx+)Q1wJ2l~yxGJ9=|3=EsA=U*CISCMd72HwXW{dM0$AT{R>I3lc{ ynPlKxCQ6$#dV$(e;CjxmHn}udgEjbn0sjRcmXnfIblu4S0000%)7GLjK_VzpBo#<$E2UC&bkwLtD`45wLKPW@y+uHFalxXXh^&f5WtlOI z0}Qj@Z;g{1ia}%AnR8QfzE8h%=i!r^dva#x;VwX<7D!ma5`UJkc5qI(csL)REJGk% z)no$D1H_+h6b8q4{1Jl+e|Wo~RuJ4DLQWCC>h(+Y`ijZVIhZ2|uHMPou5myQ^rsMf zPY`TNHHKy>_+a!IM&Y}+g*Ub+ zqTr84AFWpBx_`Z_z9R^BFQVeG312_gdERmhf{8MRWw(H94bW0{unbYK{gU$rz$ie^ zuspdW{BpoE>R=ZOyEdy+v`Z*lTB1%Rr9$D2PB8D!J_gQ>BH@XxK(M(d8rV7^5YB3a zfe>;Ffz~X6@Ot3ESIW}XPTxWld?y8Xdnc73!Qk9B_C~H|kxEKU#!(_j>{k zhoKfl`hT(6%YlZkrlHnl{0-F7t_B$XW{i0oOAIhP^2`t9KM4u{&tQ*<7tG}GC)^%0 z!VA>X4kIz`euNLy^US7ED`@J|LHz-L!VSQbYN(*y3)uJUe~7OjSmvd{pK$6$D63kP zwGAMy1)#BFU2Zr4j}Gm=2f&-K>Mt&)`VT%8<9~r$Q_GkJZ~}0P_nE?%{g*g^*I?xU zo|sd9gRP+^pn5MBW*gk3F1>}@+W;29Vkf3ht6!gS&(U~e`S_DX7hv60NmA=#qR2x>8Oc?w||?pft4+212-Bpf)gAX!5#89mxNzdSkVaX zebu84>BrIXS!N*%Qg3}8%g2Nw(flaA7sr<8rwYwA%@PCT? z<~0E2yPE93149wSUlRaNyhm}S2L{JnRe4sxn8ybr0$}F`<3qa)2+!isg zm!chnjR9VOAZn7uz!2F+kOg11wImzFz@I6HIxD^?1awz{ukWu{#K42lIwpE~3b^M4 j%yn*ga!FXi5*FFtWN986X}PMK00000NkvXXu0mjfu4Qtr diff --git a/tests/ref/shorthand-minus.png b/tests/ref/shorthand-minus.png new file mode 100644 index 0000000000000000000000000000000000000000..e42498651cec439c30da7857c7665b3be2d9ba7d GIT binary patch literal 175 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 U07*qoM6N<$f(qb$jsO4v diff --git a/tests/suite/math/class.typ b/tests/suite/math/class.typ index 7aad04465..d25071dbd 100644 --- a/tests/suite/math/class.typ +++ b/tests/suite/math/class.typ @@ -8,7 +8,7 @@ $ a class("normal", +) b \ { x class("fence", \;) x > 0} \ a class("large", \/) b \ a class("punctuation", :) b \ - a class("relation", ~) b \ + a class("relation", !) b \ a + class("unary", times) b \ class("vary", :) a class("vary", :) b $ diff --git a/tests/suite/syntax/shorthand.typ b/tests/suite/syntax/shorthand.typ index 81aa6b7bd..7d1782b9f 100644 --- a/tests/suite/syntax/shorthand.typ +++ b/tests/suite/syntax/shorthand.typ @@ -19,12 +19,17 @@ a~b #set text(font: "Roboto") A... vs #"A..." +--- shorthand-minus --- +// Make sure shorthand is applied only before a digit. +-a -1 + --- shorthands-math --- -// Check all math shorthands +// Check all math shorthands. $...$\ $-$\ $'$\ $*$\ +$~$\ $!=$\ $:=$\ $::=$\