1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::num::NonZeroUsize;
use comemo::Tracked;
use ecow::EcoString;
use once_cell::sync::OnceCell;
use super::{Args, Dynamic, Module, Value, Vm};
use crate::diag::SourceResult;
use crate::doc::Document;
use crate::geom::{Abs, Dir};
use crate::model::{Content, ElemFunc, Introspector, Label, StyleChain, Styles, Vt};
use crate::syntax::Span;
use crate::util::hash128;
use crate::World;
/// Definition of Typst's standard library.
#[derive(Debug, Clone, Hash)]
pub struct Library {
/// The scope containing definitions that are available everywhere.
pub global: Module,
/// The scope containing definitions available in math mode.
pub math: Module,
/// The default properties for page size, font selection and so on.
pub styles: Styles,
/// Defines which standard library items fulfill which syntactical roles.
pub items: LangItems,
}
/// Definition of library items the language is aware of.
#[derive(Clone)]
pub struct LangItems {
/// The root layout function.
pub layout:
fn(vt: &mut Vt, content: &Content, styles: StyleChain) -> SourceResult<Document>,
/// Access the em size.
pub em: fn(StyleChain) -> Abs,
/// Access the text direction.
pub dir: fn(StyleChain) -> Dir,
/// Whitespace.
pub space: fn() -> Content,
/// A forced line break: `\`.
pub linebreak: fn() -> Content,
/// Plain text without markup.
pub text: fn(text: EcoString) -> Content,
/// The text function.
pub text_func: ElemFunc,
/// Get the string if this is a text element.
pub text_str: fn(&Content) -> Option<EcoString>,
/// A smart quote: `'` or `"`.
pub smart_quote: fn(double: bool) -> Content,
/// A paragraph break.
pub parbreak: fn() -> Content,
/// Strong content: `*Strong*`.
pub strong: fn(body: Content) -> Content,
/// Emphasized content: `_Emphasized_`.
pub emph: fn(body: Content) -> Content,
/// Raw text with optional syntax highlighting: `` `...` ``.
pub raw: fn(text: EcoString, tag: Option<EcoString>, block: bool) -> Content,
/// The language names and tags supported by raw text.
pub raw_languages: fn() -> Vec<(&'static str, Vec<&'static str>)>,
/// A hyperlink: `https://typst.org`.
pub link: fn(url: EcoString) -> Content,
/// A reference: `@target`, `@target[..]`.
pub reference: fn(target: Label, supplement: Option<Content>) -> Content,
/// The keys contained in the bibliography and short descriptions of them.
#[allow(clippy::type_complexity)]
pub bibliography_keys: fn(
world: Tracked<dyn World>,
introspector: Tracked<Introspector>,
) -> Vec<(EcoString, Option<EcoString>)>,
/// A section heading: `= Introduction`.
pub heading: fn(level: NonZeroUsize, body: Content) -> Content,
/// An item in a bullet list: `- ...`.
pub list_item: fn(body: Content) -> Content,
/// An item in an enumeration (numbered list): `+ ...` or `1. ...`.
pub enum_item: fn(number: Option<usize>, body: Content) -> Content,
/// An item in a term list: `/ Term: Details`.
pub term_item: fn(term: Content, description: Content) -> Content,
/// A mathematical equation: `$x$`, `$ x^2 $`.
pub equation: fn(body: Content, block: bool) -> Content,
/// An alignment point in math: `&`.
pub math_align_point: fn() -> Content,
/// Matched delimiters in math: `[x + y]`.
pub math_delimited: fn(open: Content, body: Content, close: Content) -> Content,
/// A base with optional attachments in math: `a_1^2`.
pub math_attach:
fn(base: Content, bottom: Option<Content>, top: Option<Content>) -> Content,
/// A base with an accent: `arrow(x)`.
pub math_accent: fn(base: Content, accent: char) -> Content,
/// A fraction in math: `x/2`.
pub math_frac: fn(num: Content, denom: Content) -> Content,
/// Dispatch a method on a library value.
pub library_method: fn(
vm: &mut Vm,
dynamic: &Dynamic,
method: &str,
args: Args,
span: Span,
) -> SourceResult<Value>,
}
impl Debug for LangItems {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad("LangItems { .. }")
}
}
impl Hash for LangItems {
fn hash<H: Hasher>(&self, state: &mut H) {
(self.layout as usize).hash(state);
(self.em as usize).hash(state);
(self.dir as usize).hash(state);
self.space.hash(state);
self.linebreak.hash(state);
self.text.hash(state);
self.text_func.hash(state);
(self.text_str as usize).hash(state);
self.smart_quote.hash(state);
self.parbreak.hash(state);
self.strong.hash(state);
self.emph.hash(state);
self.raw.hash(state);
self.link.hash(state);
self.reference.hash(state);
self.heading.hash(state);
self.list_item.hash(state);
self.enum_item.hash(state);
self.term_item.hash(state);
self.equation.hash(state);
self.math_align_point.hash(state);
self.math_delimited.hash(state);
self.math_attach.hash(state);
self.math_accent.hash(state);
self.math_frac.hash(state);
}
}
/// Global storage for lang items.
#[doc(hidden)]
pub static LANG_ITEMS: OnceCell<LangItems> = OnceCell::new();
/// Set the lang items.
///
/// This is a hack :(
///
/// Passing the lang items everywhere they are needed (especially text related
/// things) is very painful. By storing them globally, in theory, we break
/// incremental, but only when different sets of lang items are used in the same
/// program. For this reason, if this function is called multiple times, the
/// items must be the same (and this is enforced).
pub fn set_lang_items(items: LangItems) {
if let Err(items) = LANG_ITEMS.set(items) {
let first = hash128(LANG_ITEMS.get().unwrap());
let second = hash128(&items);
assert_eq!(first, second, "set differing lang items");
}
}
/// Access a lang item.
macro_rules! item {
($name:ident) => {
$crate::eval::LANG_ITEMS.get().unwrap().$name
};
}
|