//! Typst's standard library. //! //! This crate also contains all of the compiler's central type definitions as //! these are interwoven with the standard library types. //! //! In contrast to the _types,_ most of the compilation _behaviour_ is split out //! into separate crates (`typst-eval`, `typst-realize`, `typst-layout`, etc.) //! //! Note that, unless you are working on the compiler itself, you will rarely //! need to interact with this crate, as it is fully reexported by the `typst` //! crate. extern crate self as typst_library; pub mod diag; pub mod engine; pub mod foundations; pub mod html; pub mod introspection; pub mod layout; pub mod loading; pub mod math; pub mod model; pub mod routines; pub mod symbols; pub mod text; pub mod visualize; use std::ops::{Deref, Range}; use typst_syntax::{FileId, Source, Span}; use typst_utils::{LazyHash, SmallBitSet}; use crate::diag::FileResult; use crate::foundations::{Array, Bytes, Datetime, Dict, Module, Scope, Styles, Value}; use crate::layout::{Alignment, Dir}; use crate::text::{Font, FontBook}; use crate::visualize::Color; /// The environment in which typesetting occurs. /// /// All loading functions (`main`, `source`, `file`, `font`) should perform /// internal caching so that they are relatively cheap on repeated invocations /// with the same argument. [`Source`], [`Bytes`], and [`Font`] are /// all reference-counted and thus cheap to clone. /// /// The compiler doesn't do the caching itself because the world has much more /// information on when something can change. For example, fonts typically don't /// change and can thus even be cached across multiple compilations (for /// long-running applications like `typst watch`). Source files on the other /// hand can change and should thus be cleared after each compilation. Advanced /// clients like language servers can also retain the source files and /// [edit](Source::edit) them in-place to benefit from better incremental /// performance. #[comemo::track] pub trait World: Send + Sync { /// The standard library. /// /// Can be created through `Library::build()`. fn library(&self) -> &LazyHash; /// Metadata about all known fonts. fn book(&self) -> &LazyHash; /// Get the file id of the main source file. fn main(&self) -> FileId; /// Try to access the specified source file. fn source(&self, id: FileId) -> FileResult; /// Try to access the specified file. fn file(&self, id: FileId) -> FileResult; /// Try to access the font with the given index in the font book. fn font(&self, index: usize) -> Option; /// Get the current date. /// /// If no offset is specified, the local date should be chosen. Otherwise, /// the UTC date should be chosen with the corresponding offset in hours. /// /// If this function returns `None`, Typst's `datetime` function will /// return an error. fn today(&self, offset: Option) -> Option; } macro_rules! world_impl { ($W:ident for $ptr:ty) => { impl<$W: World> World for $ptr { fn library(&self) -> &LazyHash { self.deref().library() } fn book(&self) -> &LazyHash { self.deref().book() } fn main(&self) -> FileId { self.deref().main() } fn source(&self, id: FileId) -> FileResult { self.deref().source(id) } fn file(&self, id: FileId) -> FileResult { self.deref().file(id) } fn font(&self, index: usize) -> Option { self.deref().font(index) } fn today(&self, offset: Option) -> Option { self.deref().today(offset) } } }; } world_impl!(W for std::boxed::Box); world_impl!(W for std::sync::Arc); world_impl!(W for &W); /// Helper methods on [`World`] implementations. pub trait WorldExt { /// Get the byte range for a span. /// /// Returns `None` if the `Span` does not point into any file. fn range(&self, span: Span) -> Option>; } impl WorldExt for T { fn range(&self, span: Span) -> Option> { span.range().or_else(|| self.source(span.id()?).ok()?.range(span)) } } /// Definition of Typst's standard library. #[derive(Debug, Clone, Hash)] pub struct Library { /// The module that contains the definitions that are available everywhere. pub global: Module, /// The module that contains the definitions available in math mode. pub math: Module, /// The default style properties (for page size, font selection, and /// everything else configurable via set and show rules). pub styles: Styles, /// The standard library as a value. Used to provide the `std` variable. pub std: Value, /// In-development features that were enabled. pub features: Features, } impl Library { /// Create a new builder for a library. pub fn builder() -> LibraryBuilder { LibraryBuilder::default() } } impl Default for Library { /// Constructs the standard library with the default configuration. fn default() -> Self { Self::builder().build() } } /// Configurable builder for the standard library. /// /// This struct is created by [`Library::builder`]. #[derive(Debug, Clone, Default)] pub struct LibraryBuilder { inputs: Option, features: Features, } impl LibraryBuilder { /// Configure the inputs visible through `sys.inputs`. pub fn with_inputs(mut self, inputs: Dict) -> Self { self.inputs = Some(inputs); self } /// Configure in-development features that should be enabled. /// /// No guarantees whatsover! pub fn with_features(mut self, features: Features) -> Self { self.features = features; self } /// Consumes the builder and returns a `Library`. pub fn build(self) -> Library { let math = math::module(); let inputs = self.inputs.unwrap_or_default(); let global = global(math.clone(), inputs, &self.features); let std = Value::Module(global.clone()); Library { global, math, styles: Styles::new(), std, features: self.features, } } } /// A selection of in-development features that should be enabled. /// /// Can be collected from an iterator of [`Feature`]s. #[derive(Debug, Default, Clone, Hash)] pub struct Features(SmallBitSet); impl Features { /// Check whether the given feature is enabled. pub fn is_enabled(&self, feature: Feature) -> bool { self.0.contains(feature as usize) } } impl FromIterator for Features { fn from_iter>(iter: T) -> Self { let mut set = SmallBitSet::default(); for feature in iter { set.insert(feature as usize); } Self(set) } } /// An in-development feature that should be enabled. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] #[non_exhaustive] pub enum Feature { Html, } /// Construct the module with global definitions. fn global(math: Module, inputs: Dict, features: &Features) -> Module { let mut global = Scope::deduplicating(); self::foundations::define(&mut global, inputs, features); self::model::define(&mut global); self::text::define(&mut global); global.reset_category(); global.define_module(math); self::layout::define(&mut global); self::visualize::define(&mut global); self::introspection::define(&mut global); self::loading::define(&mut global); self::symbols::define(&mut global); global.reset_category(); if features.is_enabled(Feature::Html) { global.define_module(self::html::module()); } prelude(&mut global); Module::new("global", global) } /// Defines scoped values that are globally available, too. fn prelude(global: &mut Scope) { global.reset_category(); global.define("black", Color::BLACK); global.define("gray", Color::GRAY); global.define("silver", Color::SILVER); global.define("white", Color::WHITE); global.define("navy", Color::NAVY); global.define("blue", Color::BLUE); global.define("aqua", Color::AQUA); global.define("teal", Color::TEAL); global.define("eastern", Color::EASTERN); global.define("purple", Color::PURPLE); global.define("fuchsia", Color::FUCHSIA); global.define("maroon", Color::MAROON); global.define("red", Color::RED); global.define("orange", Color::ORANGE); global.define("yellow", Color::YELLOW); global.define("olive", Color::OLIVE); global.define("green", Color::GREEN); global.define("lime", Color::LIME); global.define("luma", Color::luma_data()); global.define("oklab", Color::oklab_data()); global.define("oklch", Color::oklch_data()); global.define("rgb", Color::rgb_data()); global.define("cmyk", Color::cmyk_data()); global.define("range", Array::range_data()); global.define("ltr", Dir::LTR); global.define("rtl", Dir::RTL); global.define("ttb", Dir::TTB); global.define("btt", Dir::BTT); global.define("start", Alignment::START); global.define("left", Alignment::LEFT); global.define("center", Alignment::CENTER); global.define("right", Alignment::RIGHT); global.define("end", Alignment::END); global.define("top", Alignment::TOP); global.define("horizon", Alignment::HORIZON); global.define("bottom", Alignment::BOTTOM); }