diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-03-01 16:30:58 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-03-01 16:33:28 +0100 |
| commit | 6ab7760822ccd24b4ef126d4737d41f1be15fe19 (patch) | |
| tree | 49905f91d292ceefe4f9878ead43f117c4b1fec0 /src/eval/library.rs | |
| parent | ab841188e3d2687ee8f436336e6fde337985a83e (diff) | |
Split up `model` module
Diffstat (limited to 'src/eval/library.rs')
| -rw-r--r-- | src/eval/library.rs | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/src/eval/library.rs b/src/eval/library.rs new file mode 100644 index 00000000..adfcc6e7 --- /dev/null +++ b/src/eval/library.rs @@ -0,0 +1,145 @@ +use std::fmt::{self, Debug, Formatter}; +use std::hash::{Hash, Hasher}; +use std::num::NonZeroUsize; + +use ecow::EcoString; +use once_cell::sync::OnceCell; + +use super::Module; +use crate::diag::SourceResult; +use crate::doc::Document; +use crate::geom::{Abs, Dir}; +use crate::model::{Content, NodeId, StyleChain, StyleMap, Vt}; +use crate::util::hash128; + +/// 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: StyleMap, + /// 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 id of the text node. + pub text_id: NodeId, + /// Get the string if this is a text node. + pub text_str: fn(&Content) -> Option<&str>, + /// 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, + /// A hyperlink: `https://typst.org`. + pub link: fn(url: EcoString) -> Content, + /// A reference: `@target`. + pub ref_: fn(target: EcoString) -> Content, + /// 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<NonZeroUsize>, body: Content) -> Content, + /// An item in a term list: `/ Term: Details`. + pub term_item: fn(term: Content, description: Content) -> Content, + /// A mathematical formula: `$x$`, `$ x^2 $`. + pub formula: fn(body: Content, block: bool) -> Content, + /// An alignment point in a formula: `&`. + pub math_align_point: fn() -> Content, + /// Matched delimiters surrounding math in a formula: `[x + y]`. + pub math_delimited: fn(open: Content, body: Content, close: Content) -> Content, + /// A base with optional attachments in a formula: `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 a formula: `x/2`. + pub math_frac: fn(num: Content, denom: Content) -> Content, +} + +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_id.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.ref_.hash(state); + self.heading.hash(state); + self.list_item.hash(state); + self.enum_item.hash(state); + self.term_item.hash(state); + self.formula.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 the text node +/// 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. +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 + }; +} |
