typst_library/routines.rs
1use std::fmt::{self, Debug, Formatter};
2use std::hash::{Hash, Hasher};
3
4use comemo::{Tracked, TrackedMut};
5use typst_syntax::{Span, SyntaxMode};
6use typst_utils::LazyHash;
7
8use crate::World;
9use crate::diag::SourceResult;
10use crate::engine::{Engine, Route, Sink, Traced};
11use crate::foundations::{
12 Args, Closure, Content, Context, Func, Module, NativeRuleMap, Scope, StyleChain,
13 Styles, Value,
14};
15use crate::introspection::{Introspector, Locator, SplitLocator};
16use crate::layout::{Frame, Region};
17use crate::model::DocumentInfo;
18use crate::visualize::Color;
19
20/// Defines the `Routines` struct.
21macro_rules! routines {
22 ($(
23 $(#[$attr:meta])*
24 fn $name:ident $(<$($time:lifetime),*>)? ($($args:tt)*) -> $ret:ty
25 )*) => {
26 /// Defines implementation of various Typst compiler routines as a table
27 /// of function pointers.
28 ///
29 /// This is essentially dynamic linking and done to allow for crate
30 /// splitting.
31 pub struct Routines {
32 /// Native show rules.
33 pub rules: NativeRuleMap,
34 $(
35 $(#[$attr])*
36 pub $name: $(for<$($time),*>)? fn ($($args)*) -> $ret
37 ),*
38 }
39
40 impl Hash for Routines {
41 fn hash<H: Hasher>(&self, _: &mut H) {}
42 }
43
44 impl Debug for Routines {
45 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
46 f.pad("Routines(..)")
47 }
48 }
49 };
50}
51
52routines! {
53 /// Evaluates a string as code and return the resulting value.
54 fn eval_string(
55 routines: &Routines,
56 world: Tracked<dyn World + '_>,
57 sink: TrackedMut<Sink>,
58 string: &str,
59 span: Span,
60 mode: SyntaxMode,
61 scope: Scope,
62 ) -> SourceResult<Value>
63
64 /// Call the closure in the context with the arguments.
65 fn eval_closure(
66 func: &Func,
67 closure: &LazyHash<Closure>,
68 routines: &Routines,
69 world: Tracked<dyn World + '_>,
70 introspector: Tracked<Introspector>,
71 traced: Tracked<Traced>,
72 sink: TrackedMut<Sink>,
73 route: Tracked<Route>,
74 context: Tracked<Context>,
75 args: Args,
76 ) -> SourceResult<Value>
77
78 /// Realizes content into a flat list of well-known, styled items.
79 fn realize<'a>(
80 kind: RealizationKind,
81 engine: &mut Engine,
82 locator: &mut SplitLocator,
83 arenas: &'a Arenas,
84 content: &'a Content,
85 styles: StyleChain<'a>,
86 ) -> SourceResult<Vec<Pair<'a>>>
87
88 /// Lays out content into a single region, producing a single frame.
89 fn layout_frame(
90 engine: &mut Engine,
91 content: &Content,
92 locator: Locator,
93 styles: StyleChain,
94 region: Region,
95 ) -> SourceResult<Frame>
96
97 /// Constructs the `html` module.
98 fn html_module() -> Module
99
100 /// Wraps content in a span with a color.
101 ///
102 /// This is a temporary workaround until `TextElem::fill` is supported in
103 /// HTML export.
104 fn html_span_filled(content: Content, color: Color) -> Content
105}
106
107/// Defines what kind of realization we are performing.
108pub enum RealizationKind<'a> {
109 /// This the root realization for layout. Requires a mutable reference
110 /// to document metadata that will be filled from `set document` rules.
111 LayoutDocument { info: &'a mut DocumentInfo },
112 /// A nested realization in a container (e.g. a `block`). Requires a mutable
113 /// reference to an enum that will be set to `FragmentKind::Inline` if the
114 /// fragment's content was fully inline.
115 LayoutFragment { kind: &'a mut FragmentKind },
116 /// A nested realization in a paragraph (i.e. a `par`)
117 LayoutPar,
118 /// This the root realization for HTML. Requires a mutable reference to
119 /// document metadata that will be filled from `set document` rules.
120 ///
121 /// The `is_inline` function checks whether content consists of an inline
122 /// HTML element. It's used by the `PAR` grouping rules. This is slightly
123 /// hacky and might be replaced by a mechanism to supply the grouping rules
124 /// as a realization user.
125 HtmlDocument { info: &'a mut DocumentInfo, is_inline: fn(&Content) -> bool },
126 /// A nested realization in a container (e.g. a `block`). Requires a mutable
127 /// reference to an enum that will be set to `FragmentKind::Inline` if the
128 /// fragment's content was fully inline.
129 HtmlFragment { kind: &'a mut FragmentKind, is_inline: fn(&Content) -> bool },
130 /// A realization within math.
131 Math,
132}
133
134impl RealizationKind<'_> {
135 /// It this a realization for HTML export?
136 pub fn is_html(&self) -> bool {
137 matches!(self, Self::HtmlDocument { .. } | Self::HtmlFragment { .. })
138 }
139
140 /// It this a realization for a container?
141 pub fn is_fragment(&self) -> bool {
142 matches!(self, Self::LayoutFragment { .. } | Self::HtmlFragment { .. })
143 }
144
145 /// It this a realization for the whole document?
146 pub fn is_document(&self) -> bool {
147 matches!(self, Self::LayoutDocument { .. } | Self::HtmlDocument { .. })
148 }
149
150 /// If this is a document-level realization, accesses the document info.
151 pub fn as_document_mut(&mut self) -> Option<&mut DocumentInfo> {
152 match self {
153 Self::LayoutDocument { info } | Self::HtmlDocument { info, .. } => {
154 Some(*info)
155 }
156 _ => None,
157 }
158 }
159
160 /// If this is a container-level realization, accesses the fragment kind.
161 pub fn as_fragment_mut(&mut self) -> Option<&mut FragmentKind> {
162 match self {
163 Self::LayoutFragment { kind } | Self::HtmlFragment { kind, .. } => {
164 Some(*kind)
165 }
166 _ => None,
167 }
168 }
169}
170
171/// The kind of fragment output that realization produced.
172#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
173pub enum FragmentKind {
174 /// The fragment's contents were fully inline, and as a result, the output
175 /// elements are too.
176 Inline,
177 /// The fragment contained non-inline content, so inline content was forced
178 /// into paragraphs, and as a result, the output elements are not inline.
179 Block,
180}
181
182/// Temporary storage arenas for lifetime extension during realization.
183///
184/// Must be kept live while the content returned from realization is processed.
185#[derive(Default)]
186pub struct Arenas {
187 /// A typed arena for owned content.
188 pub content: typed_arena::Arena<Content>,
189 /// A typed arena for owned styles.
190 pub styles: typed_arena::Arena<Styles>,
191 /// An untyped arena for everything that is `Copy`.
192 pub bump: bumpalo::Bump,
193}
194
195/// A pair of content and a style chain that applies to it.
196pub type Pair<'a> = (&'a Content, StyleChain<'a>);