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::{DiagSpan, DiagSpanKind, FileId, Source};
33use typst_utils::{LazyHash, SmallBitSet};
34
35use crate::diag::FileResult;
36use crate::foundations::{
37 Array, Binding, Bytes, Datetime, Dict, Duration, Module, NativeRuleMap, Scope, Styles,
38};
39use crate::layout::{Alignment, Dir};
40use crate::routines::Routines;
41use crate::text::{Font, FontBook};
42use crate::visualize::Color;
43
44#[comemo::track]
60pub trait World: Send + Sync {
61 fn library(&self) -> &LazyHash<Library>;
65
66 fn book(&self) -> &LazyHash<FontBook>;
68
69 fn main(&self) -> FileId;
71
72 fn source(&self, id: FileId) -> FileResult<Source>;
74
75 fn file(&self, id: FileId) -> FileResult<Bytes>;
81
82 fn font(&self, index: usize) -> Option<Font>;
89
90 fn today(&self, offset: Option<Duration>) -> Option<Datetime>;
98}
99
100macro_rules! world_impl {
101 ($W:ident for $ptr:ty) => {
102 impl<$W: World> World for $ptr {
103 fn library(&self) -> &LazyHash<Library> {
104 self.deref().library()
105 }
106
107 fn book(&self) -> &LazyHash<FontBook> {
108 self.deref().book()
109 }
110
111 fn main(&self) -> FileId {
112 self.deref().main()
113 }
114
115 fn source(&self, id: FileId) -> FileResult<Source> {
116 self.deref().source(id)
117 }
118
119 fn file(&self, id: FileId) -> FileResult<Bytes> {
120 self.deref().file(id)
121 }
122
123 fn font(&self, index: usize) -> Option<Font> {
124 self.deref().font(index)
125 }
126
127 fn today(&self, offset: Option<Duration>) -> Option<Datetime> {
128 self.deref().today(offset)
129 }
130 }
131 };
132}
133
134world_impl!(W for std::boxed::Box<W>);
135world_impl!(W for std::sync::Arc<W>);
136world_impl!(W for &W);
137
138pub trait WorldExt {
140 fn range(&self, span: impl Into<DiagSpan>) -> Option<Range<usize>>;
144}
145
146impl<T: World + ?Sized> WorldExt for T {
147 fn range(&self, span: impl Into<DiagSpan>) -> Option<Range<usize>> {
148 match span.into().get() {
149 DiagSpanKind::Detached => None,
150 DiagSpanKind::Number { id, num, sub_range } => {
151 self.source(id).ok()?.range(num, sub_range)
152 }
153 DiagSpanKind::Range { id: _, range } => Some(range),
154 }
155 }
156}
157
158#[derive(Debug, Clone, Hash)]
165#[non_exhaustive]
166pub struct Library {
167 pub routines: &'static Routines,
170 pub global: Module,
172 pub math: Module,
174 pub styles: Styles,
177 pub rules: NativeRuleMap,
179 pub std: Binding,
181 pub features: Features,
183}
184
185#[derive(Debug, Clone)]
189pub struct LibraryBuilder {
190 routines: &'static Routines,
191 inputs: Option<Dict>,
192 features: Features,
193}
194
195impl LibraryBuilder {
196 #[doc(hidden)]
198 pub fn from_routines(routines: &'static Routines) -> Self {
199 Self {
200 routines,
201 inputs: None,
202 features: Features::default(),
203 }
204 }
205
206 pub fn with_inputs(mut self, inputs: Dict) -> Self {
208 self.inputs = Some(inputs);
209 self
210 }
211
212 pub fn with_features(mut self, features: Features) -> Self {
216 self.features = features;
217 self
218 }
219
220 pub fn build(self) -> Library {
222 let math = math::module();
223 let inputs = self.inputs.unwrap_or_default();
224 let global = global(self.routines, math.clone(), inputs, &self.features);
225 Library {
226 routines: self.routines,
227 global: global.clone(),
228 math,
229 styles: Styles::new(),
230 rules: (self.routines.rules)(),
231 std: Binding::detached(global),
232 features: self.features,
233 }
234 }
235}
236
237#[derive(Debug, Default, Clone, Hash)]
241pub struct Features(SmallBitSet);
242
243impl Features {
244 pub fn all() -> Self {
246 Feature::all().collect()
247 }
248
249 pub fn none() -> Self {
251 Self::default()
252 }
253
254 pub fn is_enabled(&self, feature: Feature) -> bool {
256 self.0.contains(feature as usize)
257 }
258}
259
260impl FromIterator<Feature> for Features {
261 fn from_iter<T: IntoIterator<Item = Feature>>(iter: T) -> Self {
262 let mut set = SmallBitSet::default();
263 for feature in iter {
264 set.insert(feature as usize);
265 }
266 Self(set)
267 }
268}
269
270#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
272#[non_exhaustive]
273pub enum Feature {
274 Html,
275 Bundle,
276 A11yExtras,
277}
278
279impl Feature {
280 pub fn all() -> impl Iterator<Item = Self> {
282 [Self::Html, Self::Bundle, Self::A11yExtras].into_iter()
283 }
284}
285
286#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
288#[serde(rename_all = "kebab-case")]
289pub enum Category {
290 Foundations,
291 Introspection,
292 Layout,
293 DataLoading,
294 Math,
295 Model,
296 Symbols,
297 Text,
298 Visualize,
299 Pdf,
300 Html,
301 Svg,
302 Png,
303 Bundle,
304}
305
306impl Category {
307 pub fn name(&self) -> &'static str {
309 match self {
310 Self::Foundations => "foundations",
311 Self::Introspection => "introspection",
312 Self::Layout => "layout",
313 Self::DataLoading => "data-loading",
314 Self::Math => "math",
315 Self::Model => "model",
316 Self::Symbols => "symbols",
317 Self::Text => "text",
318 Self::Visualize => "visualize",
319 Self::Pdf => "pdf",
320 Self::Html => "html",
321 Self::Svg => "svg",
322 Self::Png => "png",
323 Self::Bundle => "bundle",
324 }
325 }
326}
327
328fn global(
330 routines: &Routines,
331 math: Module,
332 inputs: Dict,
333 features: &Features,
334) -> Module {
335 let mut global = Scope::deduplicating();
336
337 self::foundations::define(&mut global, inputs);
338 self::model::define(&mut global, features);
339 self::text::define(&mut global);
340 self::layout::define(&mut global);
341 self::visualize::define(&mut global);
342 self::introspection::define(&mut global);
343 self::loading::define(&mut global);
344 self::symbols::define(&mut global);
345
346 global.define("math", math);
347 global.define("pdf", self::pdf::module(features));
348 if features.is_enabled(Feature::Html) {
349 global.define("html", (routines.html_module)());
350 }
351
352 prelude(&mut global);
353
354 Module::new("global", global)
355}
356
357fn prelude(global: &mut Scope) {
359 global.define("black", Color::BLACK);
360 global.define("gray", Color::GRAY);
361 global.define("silver", Color::SILVER);
362 global.define("white", Color::WHITE);
363 global.define("navy", Color::NAVY);
364 global.define("blue", Color::BLUE);
365 global.define("aqua", Color::AQUA);
366 global.define("teal", Color::TEAL);
367 global.define("eastern", Color::EASTERN);
368 global.define("purple", Color::PURPLE);
369 global.define("fuchsia", Color::FUCHSIA);
370 global.define("maroon", Color::MAROON);
371 global.define("red", Color::RED);
372 global.define("orange", Color::ORANGE);
373 global.define("yellow", Color::YELLOW);
374 global.define("olive", Color::OLIVE);
375 global.define("green", Color::GREEN);
376 global.define("lime", Color::LIME);
377 global.define("luma", Color::luma_data());
378 global.define("oklab", Color::oklab_data());
379 global.define("oklch", Color::oklch_data());
380 global.define("rgb", Color::rgb_data());
381 global.define("cmyk", Color::cmyk_data());
382 global.define("range", Array::range_data());
383 global.define("ltr", Dir::LTR);
384 global.define("rtl", Dir::RTL);
385 global.define("ttb", Dir::TTB);
386 global.define("btt", Dir::BTT);
387 global.define("start", Alignment::START);
388 global.define("left", Alignment::LEFT);
389 global.define("center", Alignment::CENTER);
390 global.define("right", Alignment::RIGHT);
391 global.define("end", Alignment::END);
392 global.define("top", Alignment::TOP);
393 global.define("horizon", Alignment::HORIZON);
394 global.define("bottom", Alignment::BOTTOM);
395}