1extern crate self as typst_library;
14
15pub mod diag;
16pub mod engine;
17pub mod foundations;
18pub mod introspection;
19pub mod layout;
20pub mod loading;
21pub mod math;
22pub mod model;
23pub mod pdf;
24pub mod routines;
25pub mod symbols;
26pub mod text;
27pub mod visualize;
28
29use std::ops::{Deref, Range};
30
31use serde::{Deserialize, Serialize};
32use typst_syntax::{FileId, Source, Span};
33use typst_utils::{LazyHash, SmallBitSet};
34
35use crate::diag::FileResult;
36use crate::foundations::{Array, Binding, Bytes, Datetime, Dict, Module, Scope, Styles};
37use crate::layout::{Alignment, Dir};
38use crate::routines::Routines;
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)]
148pub struct Library {
149 pub global: Module,
151 pub math: Module,
153 pub styles: Styles,
156 pub std: Binding,
158 pub features: Features,
160}
161
162#[derive(Debug, Clone)]
166pub struct LibraryBuilder {
167 routines: &'static Routines,
168 inputs: Option<Dict>,
169 features: Features,
170}
171
172impl LibraryBuilder {
173 #[doc(hidden)]
175 pub fn from_routines(routines: &'static Routines) -> Self {
176 Self {
177 routines,
178 inputs: None,
179 features: Features::default(),
180 }
181 }
182
183 pub fn with_inputs(mut self, inputs: Dict) -> Self {
185 self.inputs = Some(inputs);
186 self
187 }
188
189 pub fn with_features(mut self, features: Features) -> Self {
193 self.features = features;
194 self
195 }
196
197 pub fn build(self) -> Library {
199 let math = math::module();
200 let inputs = self.inputs.unwrap_or_default();
201 let global = global(self.routines, math.clone(), inputs, &self.features);
202 Library {
203 global: global.clone(),
204 math,
205 styles: Styles::new(),
206 std: Binding::detached(global),
207 features: self.features,
208 }
209 }
210}
211
212#[derive(Debug, Default, Clone, Hash)]
216pub struct Features(SmallBitSet);
217
218impl Features {
219 pub fn is_enabled(&self, feature: Feature) -> bool {
221 self.0.contains(feature as usize)
222 }
223}
224
225impl FromIterator<Feature> for Features {
226 fn from_iter<T: IntoIterator<Item = Feature>>(iter: T) -> Self {
227 let mut set = SmallBitSet::default();
228 for feature in iter {
229 set.insert(feature as usize);
230 }
231 Self(set)
232 }
233}
234
235#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
237#[non_exhaustive]
238pub enum Feature {
239 Html,
240 A11yExtras,
241}
242
243#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
245#[serde(rename_all = "kebab-case")]
246pub enum Category {
247 Foundations,
248 Introspection,
249 Layout,
250 DataLoading,
251 Math,
252 Model,
253 Symbols,
254 Text,
255 Visualize,
256 Pdf,
257 Html,
258 Svg,
259 Png,
260}
261
262impl Category {
263 pub fn name(&self) -> &'static str {
265 match self {
266 Self::Foundations => "foundations",
267 Self::Introspection => "introspection",
268 Self::Layout => "layout",
269 Self::DataLoading => "data-loading",
270 Self::Math => "math",
271 Self::Model => "model",
272 Self::Symbols => "symbols",
273 Self::Text => "text",
274 Self::Visualize => "visualize",
275 Self::Pdf => "pdf",
276 Self::Html => "html",
277 Self::Svg => "svg",
278 Self::Png => "png",
279 }
280 }
281}
282
283fn global(
285 routines: &Routines,
286 math: Module,
287 inputs: Dict,
288 features: &Features,
289) -> Module {
290 let mut global = Scope::deduplicating();
291
292 self::foundations::define(&mut global, inputs, features);
293 self::model::define(&mut global);
294 self::text::define(&mut global);
295 self::layout::define(&mut global);
296 self::visualize::define(&mut global);
297 self::introspection::define(&mut global);
298 self::loading::define(&mut global);
299 self::symbols::define(&mut global);
300
301 global.define("math", math);
302 global.define("pdf", self::pdf::module(features));
303 if features.is_enabled(Feature::Html) {
304 global.define("html", (routines.html_module)());
305 }
306
307 prelude(&mut global);
308
309 Module::new("global", global)
310}
311
312fn prelude(global: &mut Scope) {
314 global.define("black", Color::BLACK);
315 global.define("gray", Color::GRAY);
316 global.define("silver", Color::SILVER);
317 global.define("white", Color::WHITE);
318 global.define("navy", Color::NAVY);
319 global.define("blue", Color::BLUE);
320 global.define("aqua", Color::AQUA);
321 global.define("teal", Color::TEAL);
322 global.define("eastern", Color::EASTERN);
323 global.define("purple", Color::PURPLE);
324 global.define("fuchsia", Color::FUCHSIA);
325 global.define("maroon", Color::MAROON);
326 global.define("red", Color::RED);
327 global.define("orange", Color::ORANGE);
328 global.define("yellow", Color::YELLOW);
329 global.define("olive", Color::OLIVE);
330 global.define("green", Color::GREEN);
331 global.define("lime", Color::LIME);
332 global.define("luma", Color::luma_data());
333 global.define("oklab", Color::oklab_data());
334 global.define("oklch", Color::oklch_data());
335 global.define("rgb", Color::rgb_data());
336 global.define("cmyk", Color::cmyk_data());
337 global.define("range", Array::range_data());
338 global.define("ltr", Dir::LTR);
339 global.define("rtl", Dir::RTL);
340 global.define("ttb", Dir::TTB);
341 global.define("btt", Dir::BTT);
342 global.define("start", Alignment::START);
343 global.define("left", Alignment::LEFT);
344 global.define("center", Alignment::CENTER);
345 global.define("right", Alignment::RIGHT);
346 global.define("end", Alignment::END);
347 global.define("top", Alignment::TOP);
348 global.define("horizon", Alignment::HORIZON);
349 global.define("bottom", Alignment::BOTTOM);
350}