mirror of
https://github.com/typst/typst
synced 2025-06-28 00:03:17 +08:00
Symbol values and modules
This commit is contained in:
parent
13efa128c8
commit
1de53730bc
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -974,11 +974,6 @@ dependencies = [
|
|||||||
"siphasher",
|
"siphasher",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "symmie"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = "git+https://github.com/typst/symmie#75755e62895fcd822b3a1038462f4548b18b8119"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.107"
|
version = "1.0.107"
|
||||||
@ -1107,7 +1102,6 @@ dependencies = [
|
|||||||
"siphasher",
|
"siphasher",
|
||||||
"subsetter",
|
"subsetter",
|
||||||
"svg2pdf",
|
"svg2pdf",
|
||||||
"symmie",
|
|
||||||
"thin-vec",
|
"thin-vec",
|
||||||
"tiny-skia",
|
"tiny-skia",
|
||||||
"ttf-parser 0.18.1",
|
"ttf-parser 0.18.1",
|
||||||
@ -1152,7 +1146,6 @@ dependencies = [
|
|||||||
"roxmltree",
|
"roxmltree",
|
||||||
"rustybuzz",
|
"rustybuzz",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"symmie",
|
|
||||||
"syntect",
|
"syntect",
|
||||||
"ttf-parser 0.18.1",
|
"ttf-parser 0.18.1",
|
||||||
"typed-arena",
|
"typed-arena",
|
||||||
|
@ -32,7 +32,6 @@ serde = { version = "1", features = ["derive"] }
|
|||||||
siphasher = "0.3"
|
siphasher = "0.3"
|
||||||
subsetter = "0.1"
|
subsetter = "0.1"
|
||||||
svg2pdf = "0.4"
|
svg2pdf = "0.4"
|
||||||
symmie = { git = "https://github.com/typst/symmie" }
|
|
||||||
thin-vec = "0.2"
|
thin-vec = "0.2"
|
||||||
tiny-skia = "0.6.2"
|
tiny-skia = "0.6.2"
|
||||||
ttf-parser = "0.18.1"
|
ttf-parser = "0.18.1"
|
||||||
|
@ -20,7 +20,6 @@ once_cell = "1"
|
|||||||
roxmltree = "0.14"
|
roxmltree = "0.14"
|
||||||
rustybuzz = "0.5"
|
rustybuzz = "0.5"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
symmie = { git = "https://github.com/typst/symmie" }
|
|
||||||
syntect = { version = "5", default-features = false, features = ["default-syntaxes", "regex-fancy"] }
|
syntect = { version = "5", default-features = false, features = ["default-syntaxes", "regex-fancy"] }
|
||||||
ttf-parser = "0.18.1"
|
ttf-parser = "0.18.1"
|
||||||
typed-arena = "2"
|
typed-arena = "2"
|
||||||
|
@ -17,13 +17,14 @@ use self::layout::LayoutRoot;
|
|||||||
|
|
||||||
/// Construct the standard library.
|
/// Construct the standard library.
|
||||||
pub fn build() -> Library {
|
pub fn build() -> Library {
|
||||||
let math = math::module();
|
let sym = text::sym();
|
||||||
let global = global(math.clone());
|
let math = math::module(&sym);
|
||||||
|
let global = global(sym, math.clone());
|
||||||
Library { global, math, styles: styles(), items: items() }
|
Library { global, math, styles: styles(), items: items() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct the module with global definitions.
|
/// Construct the module with global definitions.
|
||||||
fn global(math: Module) -> Module {
|
fn global(sym: Module, math: Module) -> Module {
|
||||||
let mut global = Scope::deduplicating();
|
let mut global = Scope::deduplicating();
|
||||||
|
|
||||||
// Basics.
|
// Basics.
|
||||||
@ -36,7 +37,6 @@ fn global(math: Module) -> Module {
|
|||||||
// Text.
|
// Text.
|
||||||
global.def_func::<text::TextNode>("text");
|
global.def_func::<text::TextNode>("text");
|
||||||
global.def_func::<text::LinebreakNode>("linebreak");
|
global.def_func::<text::LinebreakNode>("linebreak");
|
||||||
global.def_func::<text::SymbolNode>("symbol");
|
|
||||||
global.def_func::<text::SmartQuoteNode>("smartquote");
|
global.def_func::<text::SmartQuoteNode>("smartquote");
|
||||||
global.def_func::<text::StrongNode>("strong");
|
global.def_func::<text::StrongNode>("strong");
|
||||||
global.def_func::<text::EmphNode>("emph");
|
global.def_func::<text::EmphNode>("emph");
|
||||||
@ -49,6 +49,8 @@ fn global(math: Module) -> Module {
|
|||||||
global.def_func::<text::StrikeNode>("strike");
|
global.def_func::<text::StrikeNode>("strike");
|
||||||
global.def_func::<text::OverlineNode>("overline");
|
global.def_func::<text::OverlineNode>("overline");
|
||||||
global.def_func::<text::RawNode>("raw");
|
global.def_func::<text::RawNode>("raw");
|
||||||
|
global.define("sym", sym);
|
||||||
|
global.define("emoji", text::emoji());
|
||||||
|
|
||||||
// Math.
|
// Math.
|
||||||
global.define("math", math);
|
global.define("math", math);
|
||||||
@ -169,7 +171,6 @@ fn items() -> LangItems {
|
|||||||
text: |text| text::TextNode(text).pack(),
|
text: |text| text::TextNode(text).pack(),
|
||||||
text_id: NodeId::of::<text::TextNode>(),
|
text_id: NodeId::of::<text::TextNode>(),
|
||||||
text_str: |content| Some(&content.to::<text::TextNode>()?.0),
|
text_str: |content| Some(&content.to::<text::TextNode>()?.0),
|
||||||
symbol: |notation| text::SymbolNode(notation).pack(),
|
|
||||||
smart_quote: |double| text::SmartQuoteNode { double }.pack(),
|
smart_quote: |double| text::SmartQuoteNode { double }.pack(),
|
||||||
parbreak: || layout::ParbreakNode.pack(),
|
parbreak: || layout::ParbreakNode.pack(),
|
||||||
strong: |body| text::StrongNode(body).pack(),
|
strong: |body| text::StrongNode(body).pack(),
|
||||||
|
@ -17,6 +17,7 @@ mod script;
|
|||||||
mod spacing;
|
mod spacing;
|
||||||
mod stretch;
|
mod stretch;
|
||||||
mod style;
|
mod style;
|
||||||
|
mod symbols;
|
||||||
|
|
||||||
pub use self::accent::*;
|
pub use self::accent::*;
|
||||||
pub use self::align::*;
|
pub use self::align::*;
|
||||||
@ -46,10 +47,10 @@ use crate::prelude::*;
|
|||||||
use crate::text::LinebreakNode;
|
use crate::text::LinebreakNode;
|
||||||
use crate::text::TextNode;
|
use crate::text::TextNode;
|
||||||
use crate::text::TextSize;
|
use crate::text::TextSize;
|
||||||
use crate::text::{families, variant, FallbackList, FontFamily, SpaceNode, SymbolNode};
|
use crate::text::{families, variant, FallbackList, FontFamily, SpaceNode};
|
||||||
|
|
||||||
/// Create a module with all math definitions.
|
/// Create a module with all math definitions.
|
||||||
pub fn module() -> Module {
|
pub fn module(sym: &Module) -> Module {
|
||||||
let mut math = Scope::deduplicating();
|
let mut math = Scope::deduplicating();
|
||||||
math.def_func::<FormulaNode>("formula");
|
math.def_func::<FormulaNode>("formula");
|
||||||
math.def_func::<LrNode>("lr");
|
math.def_func::<LrNode>("lr");
|
||||||
@ -77,7 +78,9 @@ pub fn module() -> Module {
|
|||||||
math.def_func::<MonoNode>("mono");
|
math.def_func::<MonoNode>("mono");
|
||||||
math.def_func::<BbNode>("bb");
|
math.def_func::<BbNode>("bb");
|
||||||
spacing::define(&mut math);
|
spacing::define(&mut math);
|
||||||
|
symbols::define(&mut math);
|
||||||
op::define(&mut math);
|
op::define(&mut math);
|
||||||
|
math.copy_from(sym.scope());
|
||||||
Module::new("math").with_scope(math)
|
Module::new("math").with_scope(math)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,14 +230,6 @@ impl LayoutMath for Content {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(node) = self.to::<SymbolNode>() {
|
|
||||||
if let Some(c) = symmie::get(&node.0) {
|
|
||||||
return AtomNode(c.into()).layout_math(ctx);
|
|
||||||
} else if let Some(span) = self.span() {
|
|
||||||
bail!(span, "unknown symbol");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(node) = self.to::<SequenceNode>() {
|
if let Some(node) = self.to::<SequenceNode>() {
|
||||||
for child in &node.0 {
|
for child in &node.0 {
|
||||||
child.layout_math(ctx)?;
|
child.layout_math(ctx)?;
|
||||||
|
425
library/src/math/symbols.rs
Normal file
425
library/src/math/symbols.rs
Normal file
@ -0,0 +1,425 @@
|
|||||||
|
use typst::model::symbols;
|
||||||
|
|
||||||
|
symbols! {
|
||||||
|
define,
|
||||||
|
|
||||||
|
// Lowercase Greek.
|
||||||
|
alpha: 'α',
|
||||||
|
beta: ['β', "alt": 'ϐ'],
|
||||||
|
chi: 'χ',
|
||||||
|
delta: 'δ',
|
||||||
|
epsilon: ['ε', "alt": 'ϵ'],
|
||||||
|
eta: 'η',
|
||||||
|
gamma: 'γ',
|
||||||
|
iota: 'ι',
|
||||||
|
kai: 'ϗ',
|
||||||
|
kappa: ['κ', "alt": 'ϰ'],
|
||||||
|
lambda: 'λ',
|
||||||
|
mu: 'μ',
|
||||||
|
nu: 'ν',
|
||||||
|
ohm: ['Ω', "inv": '℧'],
|
||||||
|
omega: 'ω',
|
||||||
|
omicron: 'ο',
|
||||||
|
phi: ['φ', "alt": 'ϕ'],
|
||||||
|
pi: ['π', "alt": 'ϖ'],
|
||||||
|
psi: 'ψ',
|
||||||
|
rho: ['ρ', "alt": 'ϱ'],
|
||||||
|
sigma: 'σ',
|
||||||
|
tau: 'τ',
|
||||||
|
theta: ['θ', "alt": 'ϑ'],
|
||||||
|
upsilon: 'υ',
|
||||||
|
xi: 'ξ',
|
||||||
|
zeta: 'ζ',
|
||||||
|
|
||||||
|
// Uppercase Greek.
|
||||||
|
Alpha: 'Α',
|
||||||
|
Beta: 'Β',
|
||||||
|
Chi: 'Χ',
|
||||||
|
Delta: 'Δ',
|
||||||
|
Epsilon: 'Ε',
|
||||||
|
Eta: 'Η',
|
||||||
|
Gamma: 'Γ',
|
||||||
|
Iota: 'Ι',
|
||||||
|
Kai: 'Ϗ',
|
||||||
|
Kappa: 'Κ',
|
||||||
|
Lambda: 'Λ',
|
||||||
|
Mu: 'Μ',
|
||||||
|
Nu: 'Ν',
|
||||||
|
Omega: 'Ω',
|
||||||
|
Omicron: 'Ο',
|
||||||
|
Phi: 'Φ',
|
||||||
|
Pi: 'Π',
|
||||||
|
Psi: 'Ψ',
|
||||||
|
Rho: 'Ρ',
|
||||||
|
Sigma: 'Σ',
|
||||||
|
Tau: 'Τ',
|
||||||
|
Theta: 'Θ',
|
||||||
|
Upsilon: 'Υ',
|
||||||
|
Xi: 'Ξ',
|
||||||
|
Zeta: 'Ζ',
|
||||||
|
|
||||||
|
// Hebrew.
|
||||||
|
alef: 'א',
|
||||||
|
bet: 'ב',
|
||||||
|
gimel: 'ג',
|
||||||
|
shin: 'ש',
|
||||||
|
|
||||||
|
// Double-struck.
|
||||||
|
AA: '𝔸',
|
||||||
|
BB: '𝔹',
|
||||||
|
CC: 'ℂ',
|
||||||
|
DD: '𝔻',
|
||||||
|
EE: '𝔼',
|
||||||
|
FF: '𝔽',
|
||||||
|
GG: '𝔾',
|
||||||
|
HH: 'ℍ',
|
||||||
|
II: '𝕀',
|
||||||
|
JJ: '𝕁',
|
||||||
|
KK: '𝕂',
|
||||||
|
LL: '𝕃',
|
||||||
|
MM: '𝕄',
|
||||||
|
NN: 'ℕ',
|
||||||
|
OO: '𝕆',
|
||||||
|
PP: 'ℙ',
|
||||||
|
QQ: 'ℚ',
|
||||||
|
RR: 'ℝ',
|
||||||
|
SS: '𝕊',
|
||||||
|
TT: '𝕋',
|
||||||
|
UU: '𝕌',
|
||||||
|
VV: '𝕍',
|
||||||
|
WW: '𝕎',
|
||||||
|
XX: '𝕏',
|
||||||
|
YY: '𝕐',
|
||||||
|
ZZ: 'ℤ',
|
||||||
|
|
||||||
|
// Override.
|
||||||
|
angled: [
|
||||||
|
"l": '⟨',
|
||||||
|
"l.double": '⟪',
|
||||||
|
"r": '⟩',
|
||||||
|
"r.double": '⟫',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Operators.
|
||||||
|
plus: [
|
||||||
|
'+',
|
||||||
|
"circle": '⊕',
|
||||||
|
"circle.arrow": '⟴',
|
||||||
|
"circle.big": '⨁',
|
||||||
|
"dot": '∔',
|
||||||
|
"minus": '±',
|
||||||
|
"small": '﹢',
|
||||||
|
"square": '⊞',
|
||||||
|
"triangle": '⨹',
|
||||||
|
],
|
||||||
|
minus: [
|
||||||
|
'−',
|
||||||
|
"circle": '⊖',
|
||||||
|
"dot": '∸',
|
||||||
|
"plus": '∓',
|
||||||
|
"square": '⊟',
|
||||||
|
"tilde": '≂',
|
||||||
|
"triangle": '⨺',
|
||||||
|
],
|
||||||
|
dot: [
|
||||||
|
'⋅',
|
||||||
|
"circle": '⊙',
|
||||||
|
"circle.big": '⨀',
|
||||||
|
"square": '⊡',
|
||||||
|
],
|
||||||
|
div: [
|
||||||
|
'∕',
|
||||||
|
"circle": '⊘',
|
||||||
|
"sign": '÷',
|
||||||
|
"sign.circle": '⨸',
|
||||||
|
],
|
||||||
|
times: [
|
||||||
|
'×',
|
||||||
|
"big": '⨉',
|
||||||
|
"circle": '⊗',
|
||||||
|
"circle.big": '⨂',
|
||||||
|
"div": '⋇',
|
||||||
|
"l": '⋋',
|
||||||
|
"r": '⋌',
|
||||||
|
"square": '⊠',
|
||||||
|
"triangle": '⨻',
|
||||||
|
],
|
||||||
|
ast: [
|
||||||
|
'∗',
|
||||||
|
"circle": '⊛',
|
||||||
|
"small": '﹡',
|
||||||
|
"sq": '⧆',
|
||||||
|
],
|
||||||
|
star: '⋆',
|
||||||
|
smash: '⨳',
|
||||||
|
wreath: '≀',
|
||||||
|
|
||||||
|
// Relations.
|
||||||
|
eq: [
|
||||||
|
'=',
|
||||||
|
"ast": '≛',
|
||||||
|
"circle": '⊜',
|
||||||
|
"colon": '≕',
|
||||||
|
"def": '≝',
|
||||||
|
"delta": '≜',
|
||||||
|
"equi": '≚',
|
||||||
|
"est": '≙',
|
||||||
|
"gt": '⋝',
|
||||||
|
"lt": '⋜',
|
||||||
|
"m": '≞',
|
||||||
|
"not": '≠',
|
||||||
|
"prec": '⋞',
|
||||||
|
"quest": '≟',
|
||||||
|
"small": '﹦',
|
||||||
|
"succ": '⋟',
|
||||||
|
],
|
||||||
|
gt: [
|
||||||
|
'>',
|
||||||
|
"circle": '⧁',
|
||||||
|
"dot": '⋗',
|
||||||
|
"double": '≫',
|
||||||
|
"eq": '≥',
|
||||||
|
"eq.lt": '⋛',
|
||||||
|
"eq.not": '≱',
|
||||||
|
"eqq": '≧',
|
||||||
|
"lt": '≷',
|
||||||
|
"lt.not": '≹',
|
||||||
|
"neqq": '≩',
|
||||||
|
"not": '≯',
|
||||||
|
"ntilde": '⋧',
|
||||||
|
"small": '﹥',
|
||||||
|
"tilde": '≳',
|
||||||
|
"tilde.not": '≵',
|
||||||
|
"triple": '⋙',
|
||||||
|
"triple.nested": '⫸',
|
||||||
|
],
|
||||||
|
lt: [
|
||||||
|
'<',
|
||||||
|
"circle": '⧀',
|
||||||
|
"dot": '⋖',
|
||||||
|
"double": '≪',
|
||||||
|
"eq": '≤',
|
||||||
|
"eq.gt": '⋚',
|
||||||
|
"eq.not": '≰',
|
||||||
|
"eqq": '≦',
|
||||||
|
"gt": '≶',
|
||||||
|
"gt.not": '≸',
|
||||||
|
"neqq": '≨',
|
||||||
|
"not": '≮',
|
||||||
|
"ntilde": '⋦',
|
||||||
|
"small": '﹤',
|
||||||
|
"tilde": '≲',
|
||||||
|
"tilde.not": '≴',
|
||||||
|
"triple": '⋘',
|
||||||
|
"triple.nested": '⫷',
|
||||||
|
],
|
||||||
|
prec: [
|
||||||
|
'≺',
|
||||||
|
"approx": '⪷',
|
||||||
|
"double": '⪻',
|
||||||
|
"eq": '≼',
|
||||||
|
"eq.not": '⋠',
|
||||||
|
"eqq": '⪳',
|
||||||
|
"napprox": '⪹',
|
||||||
|
"neqq": '⪵',
|
||||||
|
"not": '⊀',
|
||||||
|
"ntilde": '⋨',
|
||||||
|
"tilde": '≾',
|
||||||
|
],
|
||||||
|
succ: [
|
||||||
|
'≻',
|
||||||
|
"approx": '⪸',
|
||||||
|
"double": '⪼',
|
||||||
|
"eq": '≽',
|
||||||
|
"eq.not": '⋡',
|
||||||
|
"eqq": '⪴',
|
||||||
|
"napprox": '⪺',
|
||||||
|
"neqq": '⪶',
|
||||||
|
"not": '⊁',
|
||||||
|
"ntilde": '⋩',
|
||||||
|
"tilde": '≿',
|
||||||
|
],
|
||||||
|
ident: ['≡', "not": '≢', "strict": '≣'],
|
||||||
|
approx: ['≈', "eq": '≊', "not": '≉'],
|
||||||
|
tilde: [
|
||||||
|
'∼',
|
||||||
|
"eq": '≃',
|
||||||
|
"eq.not": '≄',
|
||||||
|
"eq.rev": '⋍',
|
||||||
|
"eqq": '≅',
|
||||||
|
"eqq.not": '≇',
|
||||||
|
"neqq": '≆',
|
||||||
|
"not": '≁',
|
||||||
|
"rev": '∽',
|
||||||
|
"rev.eqq": '≌',
|
||||||
|
"triple": '≋',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Set theory.
|
||||||
|
nothing: ['∅', "rev": '⦰'],
|
||||||
|
in: [
|
||||||
|
'∈',
|
||||||
|
"not": '∉',
|
||||||
|
"rev": '∋',
|
||||||
|
"rev.not": '∌',
|
||||||
|
"rev.small": '∍',
|
||||||
|
"small": '∊',
|
||||||
|
],
|
||||||
|
subset: [
|
||||||
|
'⊂',
|
||||||
|
"dot": '⪽',
|
||||||
|
"double": '⋐',
|
||||||
|
"eq": '⊆',
|
||||||
|
"eq.not": '⊈',
|
||||||
|
"eq.sq": '⊑',
|
||||||
|
"eq.sq.not": '⋢',
|
||||||
|
"neq": '⊊',
|
||||||
|
"not": '⊄',
|
||||||
|
"sq": '⊏',
|
||||||
|
"sq.neq": '⋤',
|
||||||
|
],
|
||||||
|
supset: [
|
||||||
|
'⊃',
|
||||||
|
"dot": '⪾',
|
||||||
|
"double": '⋑',
|
||||||
|
"eq": '⊇',
|
||||||
|
"eq.not": '⊉',
|
||||||
|
"eq.sq": '⊒',
|
||||||
|
"eq.sq.not": '⋣',
|
||||||
|
"neq": '⊋',
|
||||||
|
"not": '⊅',
|
||||||
|
"sq": '⊐',
|
||||||
|
"sq.neq": '⋥',
|
||||||
|
],
|
||||||
|
union: [
|
||||||
|
'∪',
|
||||||
|
"arrow": '⊌',
|
||||||
|
"big": '⋃',
|
||||||
|
"dot": '⊍',
|
||||||
|
"dot.big": '⨃',
|
||||||
|
"double": '⋓',
|
||||||
|
"minus": '⩁',
|
||||||
|
"or": '⩅',
|
||||||
|
"plus": '⊎',
|
||||||
|
"plus.big": '⨄',
|
||||||
|
"sq": '⊔',
|
||||||
|
"sq.big": '⨆',
|
||||||
|
"sq.double": '⩏',
|
||||||
|
],
|
||||||
|
sect: [
|
||||||
|
'∩',
|
||||||
|
"and": '⩄',
|
||||||
|
"big": '⋂',
|
||||||
|
"dot": '⩀',
|
||||||
|
"double": '⋒',
|
||||||
|
"sq": '⊓',
|
||||||
|
"sq.big": '⨅',
|
||||||
|
"sq.double": '⩎',
|
||||||
|
],
|
||||||
|
without: '∖',
|
||||||
|
complement: '∁',
|
||||||
|
|
||||||
|
// Relational algebra.
|
||||||
|
join: [
|
||||||
|
'⨝',
|
||||||
|
"r": '⟖',
|
||||||
|
"l": '⟕',
|
||||||
|
"l.r": '⟗',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Logic.
|
||||||
|
forall: '∀',
|
||||||
|
exists: ['∃', "not": '∄'],
|
||||||
|
top: '⟙',
|
||||||
|
bot: '⊥',
|
||||||
|
not: '¬',
|
||||||
|
and: [
|
||||||
|
'∧',
|
||||||
|
"big": '⋀',
|
||||||
|
"curly": '⋏',
|
||||||
|
"dot": '⟑',
|
||||||
|
"double": '⩓',
|
||||||
|
],
|
||||||
|
or: [
|
||||||
|
'∨',
|
||||||
|
"big": '⋁',
|
||||||
|
"curly": '⋎',
|
||||||
|
"dot": '⟇',
|
||||||
|
"double": '⩔',
|
||||||
|
],
|
||||||
|
models: '⊧',
|
||||||
|
therefore: '∴',
|
||||||
|
because: '∵',
|
||||||
|
qed: '∎',
|
||||||
|
tack: [
|
||||||
|
"r": '⊢',
|
||||||
|
"r.long": '⟝',
|
||||||
|
"l": '⊣',
|
||||||
|
"l.long": '⟞',
|
||||||
|
"l.short": '⫞',
|
||||||
|
"t": '⊥',
|
||||||
|
"t.big": '⟘',
|
||||||
|
"t.double": '⫫',
|
||||||
|
"t.short": '⫠',
|
||||||
|
"b": '⊤',
|
||||||
|
"b.big": '⟙',
|
||||||
|
"b.double": '⫪',
|
||||||
|
"b.short": '⫟',
|
||||||
|
"l.r": '⟛',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Geometry.
|
||||||
|
perp: ['⟂', "circle": '⦹'],
|
||||||
|
parallel: ['∥', "circle": '⦷', "not": '∦'],
|
||||||
|
angle: [
|
||||||
|
'∠',
|
||||||
|
"acute": '⦟',
|
||||||
|
"arc": '∡',
|
||||||
|
"arc.rev": '⦛',
|
||||||
|
"rev": '⦣',
|
||||||
|
"right": '∟',
|
||||||
|
"right.rev": '⯾',
|
||||||
|
"right.arc": '⊾',
|
||||||
|
"right.dot": '⦝',
|
||||||
|
"right.sq": '⦜',
|
||||||
|
"spatial": '⟀',
|
||||||
|
"spheric": '∢',
|
||||||
|
"spheric.rev": '⦠',
|
||||||
|
"spheric.top": '⦡',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Analysis.
|
||||||
|
infty: '∞',
|
||||||
|
sum: ['∑', "integral": '⨋'],
|
||||||
|
prod: ['∏', "co": '∐'],
|
||||||
|
integral: [
|
||||||
|
'∫',
|
||||||
|
"arrow.hook": '⨗',
|
||||||
|
"ccw": '⨑',
|
||||||
|
"cont": '∮',
|
||||||
|
"cont.ccw": '∳',
|
||||||
|
"cont.cw": '∲',
|
||||||
|
"cw": '∱',
|
||||||
|
"double": '∬',
|
||||||
|
"quad": '⨌',
|
||||||
|
"sect": '⨙',
|
||||||
|
"sq": '⨖',
|
||||||
|
"surf": '∯',
|
||||||
|
"times": '⨘',
|
||||||
|
"triple": '∭',
|
||||||
|
"union": '⨚',
|
||||||
|
"vol": '∰',
|
||||||
|
],
|
||||||
|
prop: '∝',
|
||||||
|
divides: ['∣', "not": '∤'],
|
||||||
|
|
||||||
|
// Miscellaneous.
|
||||||
|
diff: '∂',
|
||||||
|
nabla: '∇',
|
||||||
|
kelvin: 'K',
|
||||||
|
micro: 'µ',
|
||||||
|
degree: ['°', "c": '℃', "f": '℉'],
|
||||||
|
planck: ['ℎ', "reduce": 'ℏ'],
|
||||||
|
angstrom: 'Å',
|
||||||
|
diameter: '⌀',
|
||||||
|
}
|
1355
library/src/text/emoji.rs
Normal file
1355
library/src/text/emoji.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,20 +1,22 @@
|
|||||||
//! Text handling.
|
//! Text handling.
|
||||||
|
|
||||||
mod deco;
|
mod deco;
|
||||||
|
mod emoji;
|
||||||
mod misc;
|
mod misc;
|
||||||
mod quotes;
|
mod quotes;
|
||||||
mod raw;
|
mod raw;
|
||||||
mod shaping;
|
mod shaping;
|
||||||
mod shift;
|
mod shift;
|
||||||
mod symbol;
|
mod symbols;
|
||||||
|
|
||||||
pub use self::deco::*;
|
pub use self::deco::*;
|
||||||
|
pub use self::emoji::*;
|
||||||
pub use self::misc::*;
|
pub use self::misc::*;
|
||||||
pub use self::quotes::*;
|
pub use self::quotes::*;
|
||||||
pub use self::raw::*;
|
pub use self::raw::*;
|
||||||
pub use self::shaping::*;
|
pub use self::shaping::*;
|
||||||
pub use self::shift::*;
|
pub use self::shift::*;
|
||||||
pub use self::symbol::*;
|
pub use self::symbols::*;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
@ -1,111 +0,0 @@
|
|||||||
use crate::prelude::*;
|
|
||||||
use crate::text::TextNode;
|
|
||||||
|
|
||||||
/// # Symbol
|
|
||||||
/// A symbol identified by symmie notation.
|
|
||||||
///
|
|
||||||
/// Symmie is Typst's notation for Unicode symbols. It is based on the idea of
|
|
||||||
/// _modifiers._ Many symbols in Unicode are very similar. In symmie, such
|
|
||||||
/// groups of symbols share a common name. To distinguish between the symbols
|
|
||||||
/// within a group, we use one or multiple modifiers that are separated from the
|
|
||||||
/// name by colons.
|
|
||||||
///
|
|
||||||
/// There is currently no easily viewable list of all names, but in the
|
|
||||||
/// meantime you can rely on the autocompletion in Typst's web editor.
|
|
||||||
///
|
|
||||||
/// ## Syntax
|
|
||||||
/// This function also has dedicated syntax: In markup, you can enclose symmie
|
|
||||||
/// notation within colons to produce a symbol. And in math, you can just write
|
|
||||||
/// the notation directly. There, all letter sequence of length at least two are
|
|
||||||
/// automatically parsed as symbols (unless a variable of that name is defined).
|
|
||||||
///
|
|
||||||
/// Additionally, some very common but hard to type symbols can be expressed with
|
|
||||||
/// dedicated shortcuts. These are:
|
|
||||||
///
|
|
||||||
/// | Symmie | Shorthand | Result |
|
|
||||||
/// | ----------- | --------- | ------ |
|
|
||||||
/// | `dots:b` | `...` | … |
|
|
||||||
/// | `dash:en` | `---` | – |
|
|
||||||
/// | `dash:em` | `--` | — |
|
|
||||||
/// | none yet | `-?` | A soft hyphen |
|
|
||||||
/// | none yet | `~` | A non breaking space |
|
|
||||||
///
|
|
||||||
/// Within math mode, additional shorthands are available:
|
|
||||||
///
|
|
||||||
/// | Symmie | Shorthand | Result |
|
|
||||||
/// | ------------------ | --------- | ------ |
|
|
||||||
/// | `arrow:r` | `->` | `→` |
|
|
||||||
/// | `arrow:r:double` | `=>` | `⇒` |
|
|
||||||
/// | `arrow:l` | `<-` | `←` |
|
|
||||||
/// | `arrow:r:bar` | <code>|-></code> | `↦` |
|
|
||||||
/// | `arrow:l:r` | `<->` | `↔` |
|
|
||||||
/// | `arrow:l:r:double` | `<=>` | `⇔` |
|
|
||||||
/// | `eq:not` | `!=` | `≠` |
|
|
||||||
/// | `eq:gt` | `>=` | `≥` |
|
|
||||||
/// | `eq:lt` | `<=` | `≤` |
|
|
||||||
/// | `colon:eq` | `:=` | `≔` |
|
|
||||||
///
|
|
||||||
/// ## Example
|
|
||||||
/// ```
|
|
||||||
/// // In text, with colons.
|
|
||||||
/// :arrow:l: \
|
|
||||||
/// :arrow:r: \
|
|
||||||
/// :arrow:t: \
|
|
||||||
/// :turtle: \
|
|
||||||
/// :face:halo: \
|
|
||||||
/// :woman:old:
|
|
||||||
///
|
|
||||||
/// // In math, directly.
|
|
||||||
/// $f : NN -> RR$ \
|
|
||||||
/// $A sub:eq B without C$ \
|
|
||||||
/// $a times:div b eq:not c$
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ## Parameters
|
|
||||||
/// - notation: EcoString (positional, required)
|
|
||||||
/// The symbol's symmie notation.
|
|
||||||
///
|
|
||||||
/// Consists of a name, followed by a number colon-separated modifiers
|
|
||||||
/// in no particular order.
|
|
||||||
///
|
|
||||||
/// ### Example
|
|
||||||
/// ```
|
|
||||||
/// #symbol("NN") \
|
|
||||||
/// #symbol("face:grin")
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ## Category
|
|
||||||
/// text
|
|
||||||
#[func]
|
|
||||||
#[capable(Show)]
|
|
||||||
#[derive(Debug, Hash)]
|
|
||||||
pub struct SymbolNode(pub EcoString);
|
|
||||||
|
|
||||||
#[node]
|
|
||||||
impl SymbolNode {
|
|
||||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
|
||||||
Ok(Self(args.expect("notation")?).pack())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn field(&self, name: &str) -> Option<Value> {
|
|
||||||
match name {
|
|
||||||
"notation" => Some(Value::Str(self.0.clone().into())),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Show for SymbolNode {
|
|
||||||
fn show(&self, _: &mut Vt, this: &Content, _: StyleChain) -> SourceResult<Content> {
|
|
||||||
match symmie::get(&self.0) {
|
|
||||||
Some(c) => Ok(TextNode::packed(c)),
|
|
||||||
None => {
|
|
||||||
if let Some(span) = this.span() {
|
|
||||||
bail!(span, "unknown symbol");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Content::empty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
460
library/src/text/symbols.rs
Normal file
460
library/src/text/symbols.rs
Normal file
@ -0,0 +1,460 @@
|
|||||||
|
use typst::model::{symbols, Module, Scope};
|
||||||
|
|
||||||
|
/// A module with all symbols.
|
||||||
|
pub fn sym() -> Module {
|
||||||
|
let mut scope = Scope::new();
|
||||||
|
define(&mut scope);
|
||||||
|
Module::new("sym").with_scope(scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
symbols! {
|
||||||
|
define,
|
||||||
|
|
||||||
|
// Space and control.
|
||||||
|
space: [
|
||||||
|
' ',
|
||||||
|
"em": '\u{2003}',
|
||||||
|
"en": '\u{2002}',
|
||||||
|
"fig": '\u{2007}',
|
||||||
|
"hair": '\u{200A}',
|
||||||
|
"ideo": '\u{3000}',
|
||||||
|
"nobreak": '\u{A0}',
|
||||||
|
"punct": '\u{2008}',
|
||||||
|
"quarter": '\u{2005}',
|
||||||
|
"sixth": '\u{2006}',
|
||||||
|
"thin": '\u{2009}',
|
||||||
|
"third": '\u{2004}',
|
||||||
|
],
|
||||||
|
wj: '\u{2060}',
|
||||||
|
zwj: '\u{200D}',
|
||||||
|
zwnj: '\u{200C}',
|
||||||
|
zws: '\u{200B}',
|
||||||
|
|
||||||
|
// Punctuation.
|
||||||
|
dot: ['.', "c": '·'],
|
||||||
|
dots: [
|
||||||
|
"h": '…',
|
||||||
|
"h.c": '⋯',
|
||||||
|
"v": '⋮',
|
||||||
|
"down": '⋱',
|
||||||
|
"up": '⋰',
|
||||||
|
],
|
||||||
|
colon: [
|
||||||
|
':',
|
||||||
|
"eq": '≔',
|
||||||
|
"double.eq": '⩴',
|
||||||
|
],
|
||||||
|
comma: ',',
|
||||||
|
semi: [';', "rev": '⁏'],
|
||||||
|
quest: ['?', "double": '⁇', "excl": '⁈', "inv": '¿'],
|
||||||
|
excl: ['!', "double": '‼', "inv": '¡', "quest": '⁉'],
|
||||||
|
interrobang: '‽',
|
||||||
|
hash: '#',
|
||||||
|
at: '@',
|
||||||
|
section: '§',
|
||||||
|
percent: '%',
|
||||||
|
permille: '‰',
|
||||||
|
co: '℅',
|
||||||
|
pilcrow: ['¶', "rev": '⁋'],
|
||||||
|
dagger: ['†', "double": '‡'],
|
||||||
|
slash: ['/', "double": '⫽', "triple": '⫻'],
|
||||||
|
backslash: ['\\', "circle": '⦸', "not": '⧷'],
|
||||||
|
ast: ['*', "low": '⁎', "double": '⁑', "triple": '⁂'],
|
||||||
|
amp: ['&', "inv": '⅋'],
|
||||||
|
dash: [
|
||||||
|
"en": '–',
|
||||||
|
"em": '—',
|
||||||
|
"fig": '‒',
|
||||||
|
"wave": '〜',
|
||||||
|
"colon": '∹',
|
||||||
|
"circle": '⊝',
|
||||||
|
"wave.double": '〰',
|
||||||
|
],
|
||||||
|
hyph: [
|
||||||
|
'‐',
|
||||||
|
"minus": '\u{2D}',
|
||||||
|
"nobreak": '\u{2011}',
|
||||||
|
"point": '‧',
|
||||||
|
"soft": '\u{ad}',
|
||||||
|
],
|
||||||
|
prime: [
|
||||||
|
'′',
|
||||||
|
"rev": '‵',
|
||||||
|
"double": '″',
|
||||||
|
"double.rev": '‶',
|
||||||
|
"triple": '‴',
|
||||||
|
"triple.rev": '‷',
|
||||||
|
"quad": '⁗',
|
||||||
|
],
|
||||||
|
quote: [
|
||||||
|
"double": '"',
|
||||||
|
"single": '\'',
|
||||||
|
"l.double": '“',
|
||||||
|
"l.single": '‘',
|
||||||
|
"r.double": '”',
|
||||||
|
"r.single": '’',
|
||||||
|
"angle.l.double": '«',
|
||||||
|
"angle.l.single": '‹',
|
||||||
|
"angle.r.double": '»',
|
||||||
|
"angle.r.single": '›',
|
||||||
|
"high.double": '‟',
|
||||||
|
"high.single": '‛',
|
||||||
|
"low.double": '„',
|
||||||
|
"low.single": '‚',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Delimiters.
|
||||||
|
paren: [
|
||||||
|
"l": '(',
|
||||||
|
"r": ')',
|
||||||
|
"t": '⏜',
|
||||||
|
"b": '⏝',
|
||||||
|
],
|
||||||
|
bracket: [
|
||||||
|
"l": '[',
|
||||||
|
"r": ']',
|
||||||
|
"t": '⎴',
|
||||||
|
"b": '⎵',
|
||||||
|
],
|
||||||
|
brace: [
|
||||||
|
"l": '{',
|
||||||
|
"r": '}',
|
||||||
|
"t": '⏞',
|
||||||
|
"b": '⏟',
|
||||||
|
],
|
||||||
|
turtle: [
|
||||||
|
"l": '〔',
|
||||||
|
"r": '〕',
|
||||||
|
"t": '⏠',
|
||||||
|
"b": '⏡',
|
||||||
|
],
|
||||||
|
angled: ["l": '〈', "r": '〉'],
|
||||||
|
bar: [
|
||||||
|
"v": '|',
|
||||||
|
"v.double": '‖',
|
||||||
|
"v.triple": '⦀',
|
||||||
|
"v.broken": '¦',
|
||||||
|
"v.circle": '⦶',
|
||||||
|
"h": '―',
|
||||||
|
],
|
||||||
|
fence: [
|
||||||
|
"l": '⧘',
|
||||||
|
"l.double": '⧚',
|
||||||
|
"r": '⧙',
|
||||||
|
"r.double": '⧛',
|
||||||
|
"dotted": '⦙',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Accents.
|
||||||
|
acute: ['´', "double": '˝'],
|
||||||
|
breve: '˘',
|
||||||
|
caret: '‸',
|
||||||
|
caron: 'ˇ',
|
||||||
|
cedilla: '¸',
|
||||||
|
circum: '^',
|
||||||
|
diaer: '¨',
|
||||||
|
grave: '`',
|
||||||
|
macron: '¯',
|
||||||
|
tilde: '~',
|
||||||
|
overline: '‾',
|
||||||
|
|
||||||
|
// Currency.
|
||||||
|
bitcoin: '₿',
|
||||||
|
dollar: '$',
|
||||||
|
euro: '€',
|
||||||
|
franc: '₣',
|
||||||
|
lira: '₺',
|
||||||
|
peso: '₱',
|
||||||
|
pound: '£',
|
||||||
|
ruble: '₽',
|
||||||
|
rupee: '₹',
|
||||||
|
won: '₩',
|
||||||
|
yen: '¥',
|
||||||
|
|
||||||
|
// Miscellaneous.
|
||||||
|
ballot: ['☐', "x": '☒'],
|
||||||
|
checkmark: ['✓', "light": '🗸'],
|
||||||
|
copyright: ['©', "sound": '℗'],
|
||||||
|
floral: ['❦', "l": '☙', "r": '❧'],
|
||||||
|
notes: ["up": '🎜', "down": '🎝'],
|
||||||
|
refmark: '※',
|
||||||
|
servicemark: '℠',
|
||||||
|
maltese: '✠',
|
||||||
|
suit: [
|
||||||
|
"club": '♣',
|
||||||
|
"diamond": '♦',
|
||||||
|
"heart": '♥',
|
||||||
|
"spade": '♠',
|
||||||
|
],
|
||||||
|
|
||||||
|
// Shapes.
|
||||||
|
circle: [
|
||||||
|
"stroked": '○',
|
||||||
|
"stroked.tiny": '∘',
|
||||||
|
"stroked.small": '⚬',
|
||||||
|
"stroked.big": '◯',
|
||||||
|
"filled": '●',
|
||||||
|
"filled.tiny": '⦁',
|
||||||
|
"filled.small": '∙',
|
||||||
|
"filled.big": '⬤',
|
||||||
|
"dotted": '◌',
|
||||||
|
"nested": '⊚',
|
||||||
|
],
|
||||||
|
square: [
|
||||||
|
"stroked": '□',
|
||||||
|
"stroked.tiny": '▫',
|
||||||
|
"stroked.small": '◽',
|
||||||
|
"stroked.medium": '◻',
|
||||||
|
"stroked.big": '⬜',
|
||||||
|
"stroked.dotted": '⬚',
|
||||||
|
"stroked.rounded": '▢',
|
||||||
|
"filled": '■',
|
||||||
|
"filled.tiny": '▪',
|
||||||
|
"filled.small": '◾',
|
||||||
|
"filled.medium": '◼',
|
||||||
|
"filled.big": '⬛',
|
||||||
|
],
|
||||||
|
ellipse: [
|
||||||
|
"stroked.h": '⬭',
|
||||||
|
"stroked.v": '⬯',
|
||||||
|
"filled.h": '⬬',
|
||||||
|
"filled.v": '⬮',
|
||||||
|
],
|
||||||
|
rect: [
|
||||||
|
"stroked.h": '▭',
|
||||||
|
"stroked.v": '▯',
|
||||||
|
"filled.h": '▬',
|
||||||
|
"filled.v": '▮',
|
||||||
|
],
|
||||||
|
triangle: [
|
||||||
|
"stroked.r": '▷',
|
||||||
|
"stroked.l": '◁',
|
||||||
|
"stroked.t": '△',
|
||||||
|
"stroked.b": '▽',
|
||||||
|
"stroked.bl": '◺',
|
||||||
|
"stroked.br": '◿',
|
||||||
|
"stroked.tl": '◸',
|
||||||
|
"stroked.tr": '◹',
|
||||||
|
"stroked.small.r": '▹',
|
||||||
|
"stroked.small.b": '▿',
|
||||||
|
"stroked.small.l": '◃',
|
||||||
|
"stroked.small.t": '▵',
|
||||||
|
"stroked.rounded": '🛆',
|
||||||
|
"stroked.nested": '⟁',
|
||||||
|
"stroked.dot": '◬',
|
||||||
|
"filled.r": '▶',
|
||||||
|
"filled.l": '◀',
|
||||||
|
"filled.t": '▲',
|
||||||
|
"filled.b": '▼',
|
||||||
|
"filled.bl": '◣',
|
||||||
|
"filled.br": '◢',
|
||||||
|
"filled.tl": '◤',
|
||||||
|
"filled.tr": '◥',
|
||||||
|
"filled.small.r": '▸',
|
||||||
|
"filled.small.b": '▾',
|
||||||
|
"filled.small.l": '◂',
|
||||||
|
"filled.small.t": '▴',
|
||||||
|
],
|
||||||
|
diamond: [
|
||||||
|
"stroked": '◇',
|
||||||
|
"stroked.small": '⋄',
|
||||||
|
"stroked.medium": '⬦',
|
||||||
|
"stroked.dot": '⟐',
|
||||||
|
"filled": '◆',
|
||||||
|
"filled.medium": '⬥',
|
||||||
|
"filled.small": '⬩',
|
||||||
|
],
|
||||||
|
lozenge: [
|
||||||
|
"stroked": '◊',
|
||||||
|
"stroked.small": '⬫',
|
||||||
|
"stroked.medium": '⬨',
|
||||||
|
"filled": '⧫',
|
||||||
|
"filled.small": '⬪',
|
||||||
|
"filled.medium": '⬧',
|
||||||
|
],
|
||||||
|
penta: ["stroked": '⬠', "filled": '⬟'],
|
||||||
|
hexa: ["stroked": '⬡', "filled": '⬢'],
|
||||||
|
|
||||||
|
// Arrows and harpoons.
|
||||||
|
arrow: [
|
||||||
|
"r": '→',
|
||||||
|
"r.long.bar": '⟼',
|
||||||
|
"r.bar": '↦',
|
||||||
|
"r.curve": '⤷',
|
||||||
|
"r.dashed": '⇢',
|
||||||
|
"r.dotted": '⤑',
|
||||||
|
"r.double": '⇒',
|
||||||
|
"r.double.bar": '⤇',
|
||||||
|
"r.double.long": '⟹',
|
||||||
|
"r.double.long.bar": '⟾',
|
||||||
|
"r.double.not": '⇏',
|
||||||
|
"r.filled": '➡',
|
||||||
|
"r.hook": '↪',
|
||||||
|
"r.long": '⟶',
|
||||||
|
"r.long.squiggly": '⟿',
|
||||||
|
"r.loop": '↬',
|
||||||
|
"r.not": '↛',
|
||||||
|
"r.quad": '⭆',
|
||||||
|
"r.squiggly": '⇝',
|
||||||
|
"r.stop": '⇥',
|
||||||
|
"r.stroked": '⇨',
|
||||||
|
"r.tail": '↣',
|
||||||
|
"r.triple": '⇛',
|
||||||
|
"r.twohead.bar": '⤅',
|
||||||
|
"r.twohead": '↠',
|
||||||
|
"r.wave": '↝',
|
||||||
|
"l": '←',
|
||||||
|
"l.bar": '↤',
|
||||||
|
"l.curve": '⤶',
|
||||||
|
"l.dashed": '⇠',
|
||||||
|
"l.dotted": '⬸',
|
||||||
|
"l.double": '⇐',
|
||||||
|
"l.double.bar": '⤆',
|
||||||
|
"l.double.long": '⟸',
|
||||||
|
"l.double.long.bar": '⟽',
|
||||||
|
"l.double.not": '⇍',
|
||||||
|
"l.filled": '⬅',
|
||||||
|
"l.hook": '↩',
|
||||||
|
"l.long": '⟵',
|
||||||
|
"l.long.bar": '⟻',
|
||||||
|
"l.long.squiggly": '⬳',
|
||||||
|
"l.loop": '↫',
|
||||||
|
"l.not": '↚',
|
||||||
|
"l.quad": '⭅',
|
||||||
|
"l.squiggly": '⇜',
|
||||||
|
"l.stop": '⇤',
|
||||||
|
"l.stroked": '⇦',
|
||||||
|
"l.tail": '↢',
|
||||||
|
"l.triple": '⇚',
|
||||||
|
"l.twohead.bar": '⬶',
|
||||||
|
"l.twohead": '↞',
|
||||||
|
"l.wave": '↜',
|
||||||
|
"t": '↑',
|
||||||
|
"t.bar": '↥',
|
||||||
|
"t.curve": '⤴',
|
||||||
|
"t.dashed": '⇡',
|
||||||
|
"t.double": '⇑',
|
||||||
|
"t.filled": '⬆',
|
||||||
|
"t.quad": '⟰',
|
||||||
|
"t.stop": '⤒',
|
||||||
|
"t.stroked": '⇧',
|
||||||
|
"t.triple": '⤊',
|
||||||
|
"t.twohead": '↟',
|
||||||
|
"b": '↓',
|
||||||
|
"b.bar": '↧',
|
||||||
|
"b.curve": '⤵',
|
||||||
|
"b.dashed": '⇣',
|
||||||
|
"b.double": '⇓',
|
||||||
|
"b.filled": '⬇',
|
||||||
|
"b.quad": '⟱',
|
||||||
|
"b.stop": '⤓',
|
||||||
|
"b.stroked": '⇩',
|
||||||
|
"b.triple": '⤋',
|
||||||
|
"b.twohead": '↡',
|
||||||
|
"l.r": '↔',
|
||||||
|
"l.r.double": '⇔',
|
||||||
|
"l.r.double.long": '⟺',
|
||||||
|
"l.r.double.not": '⇎',
|
||||||
|
"l.r.filled": '⬌',
|
||||||
|
"l.r.long": '⟷',
|
||||||
|
"l.r.not": '↮',
|
||||||
|
"l.r.stroked": '⬄',
|
||||||
|
"l.r.wave": '↭',
|
||||||
|
"t.b": '↕',
|
||||||
|
"t.b.double": '⇕',
|
||||||
|
"t.b.filled": '⬍',
|
||||||
|
"t.b.stroked": '⇳',
|
||||||
|
"tr": '↗',
|
||||||
|
"tr.double": '⇗',
|
||||||
|
"tr.filled": '⬈',
|
||||||
|
"tr.hook": '⤤',
|
||||||
|
"tr.stroked": '⬀',
|
||||||
|
"br": '↘',
|
||||||
|
"br.double": '⇘',
|
||||||
|
"br.filled": '⬊',
|
||||||
|
"br.hook": '⤥',
|
||||||
|
"br.stroked": '⬂',
|
||||||
|
"tl": '↖',
|
||||||
|
"tl.double": '⇖',
|
||||||
|
"tl.filled": '⬉',
|
||||||
|
"tl.hook": '⤣',
|
||||||
|
"tl.stroked": '⬁',
|
||||||
|
"bl": '↙',
|
||||||
|
"bl.double": '⇙',
|
||||||
|
"bl.filled": '⬋',
|
||||||
|
"bl.hook": '⤦',
|
||||||
|
"bl.stroked": '⬃',
|
||||||
|
"tl.br": '⤡',
|
||||||
|
"tr.bl": '⤢',
|
||||||
|
"ccw": '↺',
|
||||||
|
"ccw.half": '↶',
|
||||||
|
"cw": '↻',
|
||||||
|
"cw.half": '↷',
|
||||||
|
"zigzag": '↯',
|
||||||
|
],
|
||||||
|
arrows: [
|
||||||
|
"rr": '⇉',
|
||||||
|
"ll": '⇇',
|
||||||
|
"tt": '⇈',
|
||||||
|
"bb": '⇊',
|
||||||
|
"lr": '⇆',
|
||||||
|
"lr.stop": '↹',
|
||||||
|
"rl": '⇄',
|
||||||
|
"tb": '⇅',
|
||||||
|
"bt": '⇵',
|
||||||
|
"rrr": '⇶',
|
||||||
|
"lll": '⬱',
|
||||||
|
],
|
||||||
|
arrowhead: [
|
||||||
|
"t": '⌃',
|
||||||
|
"b": '⌄',
|
||||||
|
],
|
||||||
|
harpoon: [
|
||||||
|
"rt": '⇀',
|
||||||
|
"rt.bar": '⥛',
|
||||||
|
"rt.stop": '⥓',
|
||||||
|
"rb": '⇁',
|
||||||
|
"rb.bar": '⥟',
|
||||||
|
"rb.stop": '⥗',
|
||||||
|
"lt": '↼',
|
||||||
|
"lt.bar": '⥚',
|
||||||
|
"lt.stop": '⥒',
|
||||||
|
"lb": '↽',
|
||||||
|
"lb.bar": '⥞',
|
||||||
|
"lb.stop": '⥖',
|
||||||
|
"tl": '↿',
|
||||||
|
"tl.bar": '⥠',
|
||||||
|
"tl.stop": '⥘',
|
||||||
|
"tr": '↾',
|
||||||
|
"tr.bar": '⥜',
|
||||||
|
"tr.stop": '⥔',
|
||||||
|
"bl": '⇃',
|
||||||
|
"bl.bar": '⥡',
|
||||||
|
"bl.stop": '⥙',
|
||||||
|
"br": '⇂',
|
||||||
|
"br.bar": '⥝',
|
||||||
|
"br.stop": '⥕',
|
||||||
|
"lt.rt": '⥎',
|
||||||
|
"lb.rb": '⥐',
|
||||||
|
"lb.rt": '⥋',
|
||||||
|
"lt.rb": '⥊',
|
||||||
|
"tl.bl": '⥑',
|
||||||
|
"tr.br": '⥏',
|
||||||
|
"tl.br": '⥍',
|
||||||
|
"tr.bl": '⥌',
|
||||||
|
],
|
||||||
|
harpoons: [
|
||||||
|
"rtrb": '⥤',
|
||||||
|
"blbr": '⥥',
|
||||||
|
"bltr": '⥯',
|
||||||
|
"lbrb": '⥧',
|
||||||
|
"ltlb": '⥢',
|
||||||
|
"ltrb": '⇋',
|
||||||
|
"ltrt": '⥦',
|
||||||
|
"rblb": '⥩',
|
||||||
|
"rtlb": '⇌',
|
||||||
|
"rtlt": '⥨',
|
||||||
|
"tlbr": '⥮',
|
||||||
|
"tltr": '⥣',
|
||||||
|
],
|
||||||
|
}
|
@ -43,8 +43,6 @@ pub struct LangItems {
|
|||||||
pub text_id: NodeId,
|
pub text_id: NodeId,
|
||||||
/// Get the string if this is a text node.
|
/// Get the string if this is a text node.
|
||||||
pub text_str: fn(&Content) -> Option<&str>,
|
pub text_str: fn(&Content) -> Option<&str>,
|
||||||
/// Symbol notation: `:arrow:l:`.
|
|
||||||
pub symbol: fn(notation: EcoString) -> Content,
|
|
||||||
/// A smart quote: `'` or `"`.
|
/// A smart quote: `'` or `"`.
|
||||||
pub smart_quote: fn(double: bool) -> Content,
|
pub smart_quote: fn(double: bool) -> Content,
|
||||||
/// A paragraph break.
|
/// A paragraph break.
|
||||||
|
@ -23,6 +23,7 @@ mod module;
|
|||||||
mod ops;
|
mod ops;
|
||||||
mod realize;
|
mod realize;
|
||||||
mod scope;
|
mod scope;
|
||||||
|
mod symbol;
|
||||||
mod typeset;
|
mod typeset;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -42,5 +43,6 @@ pub use self::realize::*;
|
|||||||
pub use self::scope::*;
|
pub use self::scope::*;
|
||||||
pub use self::str::*;
|
pub use self::str::*;
|
||||||
pub use self::styles::*;
|
pub use self::styles::*;
|
||||||
|
pub use self::symbol::*;
|
||||||
pub use self::typeset::*;
|
pub use self::typeset::*;
|
||||||
pub use self::value::*;
|
pub use self::value::*;
|
||||||
|
@ -108,6 +108,15 @@ impl Scope {
|
|||||||
self.0.insert(var.into(), Slot::new(value.into(), Kind::Captured));
|
self.0.insert(var.into(), Slot::new(value.into(), Kind::Captured));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Copy definitions from another scope that aren't yet defined in this one.
|
||||||
|
pub fn copy_from(&mut self, other: &Self) {
|
||||||
|
for (name, value) in other.iter() {
|
||||||
|
self.0
|
||||||
|
.entry(name.clone())
|
||||||
|
.or_insert_with(|| Slot::new(value.clone(), Kind::Normal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Try to access a variable immutably.
|
/// Try to access a variable immutably.
|
||||||
pub fn get(&self, var: &str) -> Option<&Value> {
|
pub fn get(&self, var: &str) -> Option<&Value> {
|
||||||
self.0.get(var).map(Slot::read)
|
self.0.get(var).map(Slot::read)
|
||||||
|
152
src/model/symbol.rs
Normal file
152
src/model/symbol.rs
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
use std::cmp::Reverse;
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
use std::fmt::{self, Debug, Formatter, Write};
|
||||||
|
|
||||||
|
use crate::diag::StrResult;
|
||||||
|
use crate::util::EcoString;
|
||||||
|
|
||||||
|
/// Define a list of symbols.
|
||||||
|
#[macro_export]
|
||||||
|
#[doc(hidden)]
|
||||||
|
macro_rules! __symbols {
|
||||||
|
($func:ident, $($name:ident: $value:tt),* $(,)?) => {
|
||||||
|
pub(super) fn $func(scope: &mut $crate::model::Scope) {
|
||||||
|
$(scope.define(stringify!($name), $crate::model::symbols!(@one $value));)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(@one $c:literal) => { $crate::model::Symbol::new($c) };
|
||||||
|
(@one [$($first:literal $(: $second:literal)?),* $(,)?]) => {
|
||||||
|
$crate::model::Symbol::list(&[
|
||||||
|
$($crate::model::symbols!(@pair $first $(: $second)?)),*
|
||||||
|
])
|
||||||
|
};
|
||||||
|
(@pair $first:literal) => { ("", $first) };
|
||||||
|
(@pair $first:literal: $second:literal) => { ($first, $second) };
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use crate::__symbols as symbols;
|
||||||
|
|
||||||
|
/// A symbol.
|
||||||
|
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||||
|
pub struct Symbol {
|
||||||
|
repr: Repr,
|
||||||
|
modifiers: EcoString,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A collection of symbols.
|
||||||
|
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||||
|
enum Repr {
|
||||||
|
Single(char),
|
||||||
|
List(&'static [(&'static str, char)]),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Symbol {
|
||||||
|
/// Create a new symbol from a single character.
|
||||||
|
pub fn new(c: char) -> Self {
|
||||||
|
Self { repr: Repr::Single(c), modifiers: EcoString::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a symbol with variants.
|
||||||
|
#[track_caller]
|
||||||
|
pub fn list(list: &'static [(&'static str, char)]) -> Self {
|
||||||
|
debug_assert!(!list.is_empty());
|
||||||
|
Self {
|
||||||
|
repr: Repr::List(list),
|
||||||
|
modifiers: EcoString::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the symbol's text.
|
||||||
|
pub fn get(&self) -> char {
|
||||||
|
match self.repr {
|
||||||
|
Repr::Single(c) => c,
|
||||||
|
Repr::List(list) => find(list, &self.modifiers).unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply a modifier to the symbol.
|
||||||
|
pub fn modified(mut self, modifier: &str) -> StrResult<Self> {
|
||||||
|
if !self.modifiers.is_empty() {
|
||||||
|
self.modifiers.push('.');
|
||||||
|
}
|
||||||
|
self.modifiers.push_str(modifier);
|
||||||
|
if match self.repr {
|
||||||
|
Repr::Single(_) => true,
|
||||||
|
Repr::List(list) => find(list, &self.modifiers).is_none(),
|
||||||
|
} {
|
||||||
|
Err("unknown modifier")?
|
||||||
|
}
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The characters that are covered by this symbol.
|
||||||
|
pub fn chars(&self) -> impl Iterator<Item = char> {
|
||||||
|
let (first, slice) = match self.repr {
|
||||||
|
Repr::Single(c) => (Some(c), [].as_slice()),
|
||||||
|
Repr::List(list) => (None, list),
|
||||||
|
};
|
||||||
|
first.into_iter().chain(slice.iter().map(|&(_, c)| c))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Possible modifiers.
|
||||||
|
pub fn modifiers(&self) -> impl Iterator<Item = &str> + '_ {
|
||||||
|
let mut set = BTreeSet::new();
|
||||||
|
if let Repr::List(list) = self.repr {
|
||||||
|
for modifier in list.iter().flat_map(|(name, _)| name.split('.')) {
|
||||||
|
if !modifier.is_empty() && !contained(&self.modifiers, modifier) {
|
||||||
|
set.insert(modifier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
set.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Symbol {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
f.write_char(self.get())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find the best symbol from the list.
|
||||||
|
fn find(list: &[(&str, char)], modifiers: &str) -> Option<char> {
|
||||||
|
let mut best = None;
|
||||||
|
let mut best_score = None;
|
||||||
|
|
||||||
|
// Find the best table entry with this name.
|
||||||
|
'outer: for candidate in list {
|
||||||
|
for modifier in parts(modifiers) {
|
||||||
|
if !contained(candidate.0, modifier) {
|
||||||
|
continue 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut matching = 0;
|
||||||
|
let mut total = 0;
|
||||||
|
for modifier in parts(candidate.0) {
|
||||||
|
if contained(modifiers, modifier) {
|
||||||
|
matching += 1;
|
||||||
|
}
|
||||||
|
total += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let score = (matching, Reverse(total));
|
||||||
|
if best_score.map_or(true, |b| score > b) {
|
||||||
|
best = Some(candidate.1);
|
||||||
|
best_score = Some(score);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
best
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Split a modifier list into its parts.
|
||||||
|
fn parts(modifiers: &str) -> impl Iterator<Item = &str> {
|
||||||
|
modifiers.split('.').filter(|s| !s.is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether the modifier string contains the modifier `m`.
|
||||||
|
fn contained(modifiers: &str, m: &str) -> bool {
|
||||||
|
parts(modifiers).any(|part| part == m)
|
||||||
|
}
|
@ -7,10 +7,12 @@ use std::sync::Arc;
|
|||||||
use siphasher::sip128::{Hasher128, SipHasher};
|
use siphasher::sip128::{Hasher128, SipHasher};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
format_str, ops, Args, Array, Cast, CastInfo, Content, Dict, Func, Label, Module, Str,
|
format_str, ops, Args, Array, Cast, CastInfo, Content, Dict, Func, Label, Module,
|
||||||
|
Str, Symbol,
|
||||||
};
|
};
|
||||||
use crate::diag::StrResult;
|
use crate::diag::StrResult;
|
||||||
use crate::geom::{Abs, Angle, Color, Em, Fr, Length, Ratio, Rel, RgbaColor};
|
use crate::geom::{Abs, Angle, Color, Em, Fr, Length, Ratio, Rel, RgbaColor};
|
||||||
|
use crate::syntax::Span;
|
||||||
use crate::util::{format_eco, EcoString};
|
use crate::util::{format_eco, EcoString};
|
||||||
|
|
||||||
/// A computational value.
|
/// A computational value.
|
||||||
@ -38,6 +40,8 @@ pub enum Value {
|
|||||||
Fraction(Fr),
|
Fraction(Fr),
|
||||||
/// A color value: `#f79143ff`.
|
/// A color value: `#f79143ff`.
|
||||||
Color(Color),
|
Color(Color),
|
||||||
|
/// A symbol: `arrow.l`.
|
||||||
|
Symbol(Symbol),
|
||||||
/// A string: `"string"`.
|
/// A string: `"string"`.
|
||||||
Str(Str),
|
Str(Str),
|
||||||
/// A label: `<intro>`.
|
/// A label: `<intro>`.
|
||||||
@ -81,6 +85,7 @@ impl Value {
|
|||||||
Self::Relative(_) => Rel::<Length>::TYPE_NAME,
|
Self::Relative(_) => Rel::<Length>::TYPE_NAME,
|
||||||
Self::Fraction(_) => Fr::TYPE_NAME,
|
Self::Fraction(_) => Fr::TYPE_NAME,
|
||||||
Self::Color(_) => Color::TYPE_NAME,
|
Self::Color(_) => Color::TYPE_NAME,
|
||||||
|
Self::Symbol(_) => Symbol::TYPE_NAME,
|
||||||
Self::Str(_) => Str::TYPE_NAME,
|
Self::Str(_) => Str::TYPE_NAME,
|
||||||
Self::Label(_) => Label::TYPE_NAME,
|
Self::Label(_) => Label::TYPE_NAME,
|
||||||
Self::Content(_) => Content::TYPE_NAME,
|
Self::Content(_) => Content::TYPE_NAME,
|
||||||
@ -98,11 +103,33 @@ impl Value {
|
|||||||
T::cast(self)
|
T::cast(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Try to access a field on the value.
|
||||||
|
pub fn field(&self, field: &str) -> StrResult<Value> {
|
||||||
|
match self {
|
||||||
|
Self::Symbol(symbol) => symbol.clone().modified(&field).map(Self::Symbol),
|
||||||
|
Self::Dict(dict) => dict.at(&field).cloned(),
|
||||||
|
Self::Content(content) => content
|
||||||
|
.field(&field)
|
||||||
|
.ok_or_else(|| format_eco!("unknown field `{field}`")),
|
||||||
|
Self::Module(module) => module.get(&field).cloned(),
|
||||||
|
v => Err(format_eco!("cannot access fields on type {}", v.type_name())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the debug representation of the value.
|
/// Return the debug representation of the value.
|
||||||
pub fn repr(&self) -> Str {
|
pub fn repr(&self) -> Str {
|
||||||
format_str!("{:?}", self)
|
format_str!("{:?}", self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attach a span to the value, if possibly.
|
||||||
|
pub fn spanned(self, span: Span) -> Self {
|
||||||
|
match self {
|
||||||
|
Value::Content(v) => Value::Content(v.spanned(span)),
|
||||||
|
Value::Func(v) => Value::Func(v.spanned(span)),
|
||||||
|
v => v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the display representation of the value.
|
/// Return the display representation of the value.
|
||||||
pub fn display(self) -> Content {
|
pub fn display(self) -> Content {
|
||||||
match self {
|
match self {
|
||||||
@ -110,6 +137,7 @@ impl Value {
|
|||||||
Self::Int(v) => item!(text)(format_eco!("{}", v)),
|
Self::Int(v) => item!(text)(format_eco!("{}", v)),
|
||||||
Self::Float(v) => item!(text)(format_eco!("{}", v)),
|
Self::Float(v) => item!(text)(format_eco!("{}", v)),
|
||||||
Self::Str(v) => item!(text)(v.into()),
|
Self::Str(v) => item!(text)(v.into()),
|
||||||
|
Self::Symbol(v) => item!(text)(v.get().into()),
|
||||||
Self::Content(v) => v,
|
Self::Content(v) => v,
|
||||||
Self::Func(_) => Content::empty(),
|
Self::Func(_) => Content::empty(),
|
||||||
Self::Module(module) => module.content(),
|
Self::Module(module) => module.content(),
|
||||||
@ -122,6 +150,8 @@ impl Value {
|
|||||||
match self {
|
match self {
|
||||||
Self::Int(v) => item!(math_atom)(format_eco!("{}", v)),
|
Self::Int(v) => item!(math_atom)(format_eco!("{}", v)),
|
||||||
Self::Float(v) => item!(math_atom)(format_eco!("{}", v)),
|
Self::Float(v) => item!(math_atom)(format_eco!("{}", v)),
|
||||||
|
Self::Symbol(v) => item!(math_atom)(v.get().into()),
|
||||||
|
Self::Str(v) => item!(math_atom)(v.into()),
|
||||||
_ => self.display(),
|
_ => self.display(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -147,6 +177,7 @@ impl Debug for Value {
|
|||||||
Self::Relative(v) => Debug::fmt(v, f),
|
Self::Relative(v) => Debug::fmt(v, f),
|
||||||
Self::Fraction(v) => Debug::fmt(v, f),
|
Self::Fraction(v) => Debug::fmt(v, f),
|
||||||
Self::Color(v) => Debug::fmt(v, f),
|
Self::Color(v) => Debug::fmt(v, f),
|
||||||
|
Self::Symbol(v) => Debug::fmt(v, f),
|
||||||
Self::Str(v) => Debug::fmt(v, f),
|
Self::Str(v) => Debug::fmt(v, f),
|
||||||
Self::Label(v) => Debug::fmt(v, f),
|
Self::Label(v) => Debug::fmt(v, f),
|
||||||
Self::Content(_) => f.pad("[...]"),
|
Self::Content(_) => f.pad("[...]"),
|
||||||
@ -187,6 +218,7 @@ impl Hash for Value {
|
|||||||
Self::Relative(v) => v.hash(state),
|
Self::Relative(v) => v.hash(state),
|
||||||
Self::Fraction(v) => v.hash(state),
|
Self::Fraction(v) => v.hash(state),
|
||||||
Self::Color(v) => v.hash(state),
|
Self::Color(v) => v.hash(state),
|
||||||
|
Self::Symbol(v) => v.hash(state),
|
||||||
Self::Str(v) => v.hash(state),
|
Self::Str(v) => v.hash(state),
|
||||||
Self::Label(v) => v.hash(state),
|
Self::Label(v) => v.hash(state),
|
||||||
Self::Content(v) => v.hash(state),
|
Self::Content(v) => v.hash(state),
|
||||||
@ -398,11 +430,13 @@ primitive! { Rel<Length>: "relative length",
|
|||||||
}
|
}
|
||||||
primitive! { Fr: "fraction", Fraction }
|
primitive! { Fr: "fraction", Fraction }
|
||||||
primitive! { Color: "color", Color }
|
primitive! { Color: "color", Color }
|
||||||
|
primitive! { Symbol: "symbol", Symbol }
|
||||||
primitive! { Str: "string", Str }
|
primitive! { Str: "string", Str }
|
||||||
primitive! { Label: "label", Label }
|
primitive! { Label: "label", Label }
|
||||||
primitive! { Content: "content",
|
primitive! { Content: "content",
|
||||||
Content,
|
Content,
|
||||||
None => Content::empty(),
|
None => Content::empty(),
|
||||||
|
Symbol(symbol) => item!(text)(symbol.get().into()),
|
||||||
Str(text) => item!(text)(text.into())
|
Str(text) => item!(text)(text.into())
|
||||||
}
|
}
|
||||||
primitive! { Array: "array", Array }
|
primitive! { Array: "array", Array }
|
||||||
|
@ -89,8 +89,6 @@ pub enum Expr {
|
|||||||
/// A shorthand for a unicode codepoint. For example, `~` for non-breaking
|
/// A shorthand for a unicode codepoint. For example, `~` for non-breaking
|
||||||
/// space or `-?` for a soft hyphen.
|
/// space or `-?` for a soft hyphen.
|
||||||
Shorthand(Shorthand),
|
Shorthand(Shorthand),
|
||||||
/// Symbol notation: `:arrow:l:`.
|
|
||||||
Symbol(Symbol),
|
|
||||||
/// A smart quote: `'` or `"`.
|
/// A smart quote: `'` or `"`.
|
||||||
SmartQuote(SmartQuote),
|
SmartQuote(SmartQuote),
|
||||||
/// Strong content: `*Strong*`.
|
/// Strong content: `*Strong*`.
|
||||||
@ -413,18 +411,6 @@ impl Shorthand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node! {
|
|
||||||
/// Symbol notation: `:arrow:l:`.
|
|
||||||
Symbol
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Symbol {
|
|
||||||
/// Get the symbol's notation.
|
|
||||||
pub fn get(&self) -> &str {
|
|
||||||
self.0.text().trim_matches(':')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node! {
|
node! {
|
||||||
/// A smart quote: `'` or `"`.
|
/// A smart quote: `'` or `"`.
|
||||||
SmartQuote
|
SmartQuote
|
||||||
|
@ -24,9 +24,6 @@ pub enum SyntaxKind {
|
|||||||
/// A shorthand for a unicode codepoint. For example, `~` for non-breaking
|
/// A shorthand for a unicode codepoint. For example, `~` for non-breaking
|
||||||
/// space or `-?` for a soft hyphen.
|
/// space or `-?` for a soft hyphen.
|
||||||
Shorthand,
|
Shorthand,
|
||||||
/// Symbol notation: `:arrow:l:`. The string only contains the inner part
|
|
||||||
/// without leading and trailing dot.
|
|
||||||
Symbol,
|
|
||||||
/// A smart quote: `'` or `"`.
|
/// A smart quote: `'` or `"`.
|
||||||
SmartQuote,
|
SmartQuote,
|
||||||
/// Strong content: `*Strong*`.
|
/// Strong content: `*Strong*`.
|
||||||
@ -332,7 +329,6 @@ impl SyntaxKind {
|
|||||||
Self::Parbreak => "paragraph break",
|
Self::Parbreak => "paragraph break",
|
||||||
Self::Escape => "escape sequence",
|
Self::Escape => "escape sequence",
|
||||||
Self::Shorthand => "shorthand",
|
Self::Shorthand => "shorthand",
|
||||||
Self::Symbol => "symbol notation",
|
|
||||||
Self::Strong => "strong content",
|
Self::Strong => "strong content",
|
||||||
Self::Emph => "emphasized content",
|
Self::Emph => "emphasized content",
|
||||||
Self::Raw => "raw block",
|
Self::Raw => "raw block",
|
||||||
|
@ -167,21 +167,12 @@ impl Lexer<'_> {
|
|||||||
fn markup(&mut self, start: usize, c: char) -> SyntaxKind {
|
fn markup(&mut self, start: usize, c: char) -> SyntaxKind {
|
||||||
match c {
|
match c {
|
||||||
'\\' => self.backslash(),
|
'\\' => self.backslash(),
|
||||||
':' if self.s.at(is_id_start) => self.maybe_symbol(),
|
|
||||||
'`' => self.raw(),
|
'`' => self.raw(),
|
||||||
'h' if self.s.eat_if("ttp://") => self.link(),
|
'h' if self.s.eat_if("ttp://") => self.link(),
|
||||||
'h' if self.s.eat_if("ttps://") => self.link(),
|
'h' if self.s.eat_if("ttps://") => self.link(),
|
||||||
'0'..='9' => self.numbering(start),
|
'0'..='9' => self.numbering(start),
|
||||||
'<' if self.s.at(is_id_continue) => self.label(),
|
'<' if self.s.at(is_id_continue) => self.label(),
|
||||||
'@' if self.s.at(is_id_continue) => self.reference(),
|
'@' if self.s.at(is_id_continue) => self.reference(),
|
||||||
'#' if self.s.eat_if('{') => SyntaxKind::LeftBrace,
|
|
||||||
'#' if self.s.eat_if('[') => SyntaxKind::LeftBracket,
|
|
||||||
'#' if self.s.at(is_id_start) => {
|
|
||||||
match keyword(self.s.eat_while(is_id_continue)) {
|
|
||||||
Some(keyword) => keyword,
|
|
||||||
None => SyntaxKind::Ident,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
'.' 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,
|
||||||
@ -190,8 +181,7 @@ impl Lexer<'_> {
|
|||||||
'*' if !self.in_word() => SyntaxKind::Star,
|
'*' if !self.in_word() => SyntaxKind::Star,
|
||||||
'_' if !self.in_word() => SyntaxKind::Underscore,
|
'_' if !self.in_word() => SyntaxKind::Underscore,
|
||||||
|
|
||||||
'{' => SyntaxKind::LeftBrace,
|
'#' if !self.s.at(char::is_whitespace) => SyntaxKind::Hashtag,
|
||||||
'}' => SyntaxKind::RightBrace,
|
|
||||||
'[' => SyntaxKind::LeftBracket,
|
'[' => SyntaxKind::LeftBracket,
|
||||||
']' => SyntaxKind::RightBracket,
|
']' => SyntaxKind::RightBracket,
|
||||||
'\'' => SyntaxKind::SmartQuote,
|
'\'' => SyntaxKind::SmartQuote,
|
||||||
@ -241,26 +231,6 @@ impl Lexer<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_symbol(&mut self) -> SyntaxKind {
|
|
||||||
let start = self.s.cursor();
|
|
||||||
let mut end = start;
|
|
||||||
while !self.s.eat_while(is_id_continue).is_empty() && self.s.at(':') {
|
|
||||||
end = self.s.cursor();
|
|
||||||
self.s.eat();
|
|
||||||
}
|
|
||||||
|
|
||||||
self.s.jump(end);
|
|
||||||
|
|
||||||
if start < end {
|
|
||||||
self.s.expect(':');
|
|
||||||
SyntaxKind::Symbol
|
|
||||||
} else if self.mode == LexMode::Markup {
|
|
||||||
SyntaxKind::Colon
|
|
||||||
} else {
|
|
||||||
SyntaxKind::Atom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn raw(&mut self) -> SyntaxKind {
|
fn raw(&mut self) -> SyntaxKind {
|
||||||
let mut backticks = 1;
|
let mut backticks = 1;
|
||||||
while self.s.eat_if('`') {
|
while self.s.eat_if('`') {
|
||||||
@ -408,7 +378,6 @@ impl Lexer<'_> {
|
|||||||
fn math(&mut self, start: usize, c: char) -> SyntaxKind {
|
fn math(&mut self, start: usize, c: char) -> SyntaxKind {
|
||||||
match c {
|
match c {
|
||||||
'\\' => self.backslash(),
|
'\\' => self.backslash(),
|
||||||
':' if self.s.at(is_id_start) => self.maybe_symbol(),
|
|
||||||
'"' => self.string(),
|
'"' => self.string(),
|
||||||
|
|
||||||
'.' if self.s.eat_if("..") => SyntaxKind::Shorthand,
|
'.' if self.s.eat_if("..") => SyntaxKind::Shorthand,
|
||||||
@ -434,9 +403,10 @@ impl Lexer<'_> {
|
|||||||
'^' => SyntaxKind::Hat,
|
'^' => SyntaxKind::Hat,
|
||||||
'&' => SyntaxKind::MathAlignPoint,
|
'&' => SyntaxKind::MathAlignPoint,
|
||||||
|
|
||||||
// Identifiers and symbol notation.
|
// Identifiers.
|
||||||
c if is_math_id_start(c) && self.s.at(is_math_id_continue) => {
|
c if is_math_id_start(c) && self.s.at(is_math_id_continue) => {
|
||||||
self.math_ident()
|
self.s.eat_while(is_math_id_continue);
|
||||||
|
SyntaxKind::MathIdent
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other math atoms.
|
// Other math atoms.
|
||||||
@ -444,25 +414,6 @@ impl Lexer<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn math_ident(&mut self) -> SyntaxKind {
|
|
||||||
self.s.eat_while(is_math_id_continue);
|
|
||||||
|
|
||||||
let mut symbol = false;
|
|
||||||
while self.s.eat_if(':') && !self.s.eat_while(char::is_alphanumeric).is_empty() {
|
|
||||||
symbol = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if symbol {
|
|
||||||
return SyntaxKind::Symbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.s.scout(-1) == Some(':') {
|
|
||||||
self.s.uneat();
|
|
||||||
}
|
|
||||||
|
|
||||||
SyntaxKind::Ident
|
|
||||||
}
|
|
||||||
|
|
||||||
fn atom(&mut self, start: usize, c: char) -> SyntaxKind {
|
fn atom(&mut self, start: usize, c: char) -> SyntaxKind {
|
||||||
// Keep numbers and grapheme clusters together.
|
// Keep numbers and grapheme clusters together.
|
||||||
if c.is_numeric() {
|
if c.is_numeric() {
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 4.3 KiB |
@ -23,6 +23,6 @@ $ accent(a, grave),
|
|||||||
accent(a, overline),
|
accent(a, overline),
|
||||||
accent(a, breve),
|
accent(a, breve),
|
||||||
accent(a, dot),
|
accent(a, dot),
|
||||||
accent(a, dia),
|
accent(a, diaer),
|
||||||
accent(a, caron),
|
accent(a, caron),
|
||||||
accent(a, arrow) $
|
accent(a, arrow) $
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#let kinds = (math.serif, math.sans, math.cal, math.frak, math.mono, math.bb)
|
#let kinds = (math.serif, math.sans, math.cal, math.frak, math.mono, math.bb)
|
||||||
#let modifiers = (v => v, math.italic, math.bold, v => math.italic(math.bold(v)))
|
#let modifiers = (v => v, math.italic, math.bold, v => math.italic(math.bold(v)))
|
||||||
|
|
||||||
#let cells = ([:triangle:nested:], [--], [`italic`], [`bold`], [both])
|
#let cells = (sym.triangle.nested, [--], [`italic`], [`bold`], [both])
|
||||||
#for kk in kinds {
|
#for kk in kinds {
|
||||||
cells.push(raw(repr(kk).trim("<function ").trim(">")))
|
cells.push(raw(repr(kk).trim("<function ").trim(">")))
|
||||||
for mm in modifiers {
|
for mm in modifiers {
|
||||||
|
@ -19,6 +19,6 @@ $ sqrt(x^2) = frac(x, 1) $
|
|||||||
$ "profit" = "income" - "expenses" $
|
$ "profit" = "income" - "expenses" $
|
||||||
$ x < #for i in range(5) [$ #i < $] y $
|
$ x < #for i in range(5) [$ #i < $] y $
|
||||||
$ 1 + 2 = #{1 + 2} $
|
$ 1 + 2 = #{1 + 2} $
|
||||||
$ A sub:eq:not B $
|
$ A subset.eq.not B $
|
||||||
```
|
```
|
||||||
<table>
|
<table>
|
||||||
|
@ -1,27 +1,18 @@
|
|||||||
// Test symbol notation.
|
// Test symbols.
|
||||||
|
|
||||||
---
|
---
|
||||||
:face:
|
#emoji.face
|
||||||
:face:unknown:
|
#emoji.woman.old
|
||||||
:woman:old:
|
#emoji.turtle
|
||||||
:turtle:
|
|
||||||
|
|
||||||
#set text("New Computer Modern Math")
|
#set text("New Computer Modern Math")
|
||||||
:arrow:
|
#sym.arrow
|
||||||
:arrow:l:
|
#sym.arrow.l
|
||||||
:arrow:r:squiggly:
|
#sym.arrow.r.squiggly
|
||||||
#symbol(("arrow", "tr", "hook").join(":"))
|
#sym.arrow.tr.hook
|
||||||
|
|
||||||
|
#sym.arrow.r;this and this#sym.arrow.l;
|
||||||
|
|
||||||
---
|
---
|
||||||
Just a: colon. \
|
// Error: 13-20 unknown modifier
|
||||||
Still :not a symbol. \
|
#emoji.face.garbage
|
||||||
Also not:a symbol \
|
|
||||||
:arrow:r:this and this:arrow:l: \
|
|
||||||
|
|
||||||
---
|
|
||||||
#show symbol.where(notation: "my:custom"): "MY"
|
|
||||||
This is :my:custom: notation.
|
|
||||||
|
|
||||||
---
|
|
||||||
// Error: 1-14 unknown symbol
|
|
||||||
:nonexisting:
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user