mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Split shorthands into math and markup, add tilde shorthand (#4706)
This commit is contained in:
parent
a6a8cdaa28
commit
b07607d35e
@ -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
|
||||
|
@ -172,6 +172,7 @@ pub fn highlight(node: &LinkedNode) -> Option<Tag> {
|
||||
|
||||
SyntaxKind::Math => None,
|
||||
SyntaxKind::MathIdent => highlight_ident(node),
|
||||
SyntaxKind::MathShorthand => Some(Tag::Escape),
|
||||
SyntaxKind::MathAlignPoint => Some(Tag::MathOperator),
|
||||
SyntaxKind::MathDelimited => None,
|
||||
SyntaxKind::MathAttach => None,
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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),
|
||||
|
@ -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<Self::Output> {
|
||||
Ok(Value::Symbol(Symbol::single(self.get().into())))
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for ast::MathAlignPoint<'_> {
|
||||
type Output = Content;
|
||||
|
||||
|
@ -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
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
BIN
tests/ref/shorthand-minus.png
Normal file
BIN
tests/ref/shorthand-minus.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 175 B |
Binary file not shown.
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.9 KiB |
@ -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 $
|
||||
|
||||
|
@ -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.
|
||||
$...$\
|
||||
$-$\
|
||||
$'$\
|
||||
$*$\
|
||||
$~$\
|
||||
$!=$\
|
||||
$:=$\
|
||||
$::=$\
|
||||
|
Loading…
x
Reference in New Issue
Block a user