1extern crate self as typst_library;
14
15pub mod diag;
16pub mod engine;
17pub mod foundations;
18pub mod html;
19pub mod introspection;
20pub mod layout;
21pub mod loading;
22pub mod math;
23pub mod model;
24pub mod pdf;
25pub mod routines;
26pub mod symbols;
27pub mod text;
28pub mod visualize;
29
30use std::ops::{Deref, Range};
31
32use serde::{Deserialize, Serialize};
33use typst_syntax::{FileId, Source, Span};
34use typst_utils::{LazyHash, SmallBitSet};
35
36use crate::diag::FileResult;
37use crate::foundations::{Array, Binding, Bytes, Datetime, Dict, Module, Scope, Styles};
38use crate::layout::{Alignment, Dir};
39use crate::text::{Font, FontBook};
40use crate::visualize::Color;
41
42#[comemo::track]
58pub trait World: Send + Sync {
59 fn library(&self) -> &LazyHash<Library>;
63
64 fn book(&self) -> &LazyHash<FontBook>;
66
67 fn main(&self) -> FileId;
69
70 fn source(&self, id: FileId) -> FileResult<Source>;
72
73 fn file(&self, id: FileId) -> FileResult<Bytes>;
75
76 fn font(&self, index: usize) -> Option<Font>;
78
79 fn today(&self, offset: Option<i64>) -> Option<Datetime>;
87}
88
89macro_rules! world_impl {
90 ($W:ident for $ptr:ty) => {
91 impl<$W: World> World for $ptr {
92 fn library(&self) -> &LazyHash<Library> {
93 self.deref().library()
94 }
95
96 fn book(&self) -> &LazyHash<FontBook> {
97 self.deref().book()
98 }
99
100 fn main(&self) -> FileId {
101 self.deref().main()
102 }
103
104 fn source(&self, id: FileId) -> FileResult<Source> {
105 self.deref().source(id)
106 }
107
108 fn file(&self, id: FileId) -> FileResult<Bytes> {
109 self.deref().file(id)
110 }
111
112 fn font(&self, index: usize) -> Option<Font> {
113 self.deref().font(index)
114 }
115
116 fn today(&self, offset: Option<i64>) -> Option<Datetime> {
117 self.deref().today(offset)
118 }
119 }
120 };
121}
122
123world_impl!(W for std::boxed::Box<W>);
124world_impl!(W for std::sync::Arc<W>);
125world_impl!(W for &W);
126
127pub trait WorldExt {
129 fn range(&self, span: Span) -> Option<Range<usize>>;
133}
134
135impl<T: World + ?Sized> WorldExt for T {
136 fn range(&self, span: Span) -> Option<Range<usize>> {
137 span.range().or_else(|| self.source(span.id()?).ok()?.range(span))
138 }
139}
140
141#[derive(Debug, Clone, Hash)]
143pub struct Library {
144 pub global: Module,
146 pub math: Module,
148 pub styles: Styles,
151 pub std: Binding,
153 pub features: Features,
155}
156
157impl Library {
158 pub fn builder() -> LibraryBuilder {
160 LibraryBuilder::default()
161 }
162}
163
164impl Default for Library {
165 fn default() -> Self {
167 Self::builder().build()
168 }
169}
170
171#[derive(Debug, Clone, Default)]
175pub struct LibraryBuilder {
176 inputs: Option<Dict>,
177 features: Features,
178}
179
180impl LibraryBuilder {
181 pub fn with_inputs(mut self, inputs: Dict) -> Self {
183 self.inputs = Some(inputs);
184 self
185 }
186
187 pub fn with_features(mut self, features: Features) -> Self {
191 self.features = features;
192 self
193 }
194
195 pub fn build(self) -> Library {
197 let math = math::module();
198 let inputs = self.inputs.unwrap_or_default();
199 let global = global(math.clone(), inputs, &self.features);
200 Library {
201 global: global.clone(),
202 math,
203 styles: Styles::new(),
204 std: Binding::detached(global),
205 features: self.features,
206 }
207 }
208}
209
210#[derive(Debug, Default, Clone, Hash)]
214pub struct Features(SmallBitSet);
215
216impl Features {
217 pub fn is_enabled(&self, feature: Feature) -> bool {
219 self.0.contains(feature as usize)
220 }
221}
222
223impl FromIterator<Feature> for Features {
224 fn from_iter<T: IntoIterator<Item = Feature>>(iter: T) -> Self {
225 let mut set = SmallBitSet::default();
226 for feature in iter {
227 set.insert(feature as usize);
228 }
229 Self(set)
230 }
231}
232
233#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
235#[non_exhaustive]
236pub enum Feature {
237 Html,
238}
239
240#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
242#[serde(rename_all = "kebab-case")]
243pub enum Category {
244 Foundations,
245 Introspection,
246 Layout,
247 DataLoading,
248 Math,
249 Model,
250 Symbols,
251 Text,
252 Visualize,
253 Pdf,
254 Html,
255 Svg,
256 Png,
257}
258
259impl Category {
260 pub fn name(&self) -> &'static str {
262 match self {
263 Self::Foundations => "foundations",
264 Self::Introspection => "introspection",
265 Self::Layout => "layout",
266 Self::DataLoading => "data-loading",
267 Self::Math => "math",
268 Self::Model => "model",
269 Self::Symbols => "symbols",
270 Self::Text => "text",
271 Self::Visualize => "visualize",
272 Self::Pdf => "pdf",
273 Self::Html => "html",
274 Self::Svg => "svg",
275 Self::Png => "png",
276 }
277 }
278}
279
280fn global(math: Module, inputs: Dict, features: &Features) -> Module {
282 let mut global = Scope::deduplicating();
283
284 self::foundations::define(&mut global, inputs, features);
285 self::model::define(&mut global);
286 self::text::define(&mut global);
287 self::layout::define(&mut global);
288 self::visualize::define(&mut global);
289 self::introspection::define(&mut global);
290 self::loading::define(&mut global);
291 self::symbols::define(&mut global);
292
293 global.define("math", math);
294 global.define("pdf", self::pdf::module());
295 if features.is_enabled(Feature::Html) {
296 global.define("html", self::html::module());
297 }
298
299 prelude(&mut global);
300
301 Module::new("global", global)
302}
303
304fn prelude(global: &mut Scope) {
306 global.define("black", Color::BLACK);
307 global.define("gray", Color::GRAY);
308 global.define("silver", Color::SILVER);
309 global.define("white", Color::WHITE);
310 global.define("navy", Color::NAVY);
311 global.define("blue", Color::BLUE);
312 global.define("aqua", Color::AQUA);
313 global.define("teal", Color::TEAL);
314 global.define("eastern", Color::EASTERN);
315 global.define("purple", Color::PURPLE);
316 global.define("fuchsia", Color::FUCHSIA);
317 global.define("maroon", Color::MAROON);
318 global.define("red", Color::RED);
319 global.define("orange", Color::ORANGE);
320 global.define("yellow", Color::YELLOW);
321 global.define("olive", Color::OLIVE);
322 global.define("green", Color::GREEN);
323 global.define("lime", Color::LIME);
324 global.define("luma", Color::luma_data());
325 global.define("oklab", Color::oklab_data());
326 global.define("oklch", Color::oklch_data());
327 global.define("rgb", Color::rgb_data());
328 global.define("cmyk", Color::cmyk_data());
329 global.define("range", Array::range_data());
330 global.define("ltr", Dir::LTR);
331 global.define("rtl", Dir::RTL);
332 global.define("ttb", Dir::TTB);
333 global.define("btt", Dir::BTT);
334 global.define("start", Alignment::START);
335 global.define("left", Alignment::LEFT);
336 global.define("center", Alignment::CENTER);
337 global.define("right", Alignment::RIGHT);
338 global.define("end", Alignment::END);
339 global.define("top", Alignment::TOP);
340 global.define("horizon", Alignment::HORIZON);
341 global.define("bottom", Alignment::BOTTOM);
342}