From be7cfc85d08c545abfac08098b7b33b4bd71f37e Mon Sep 17 00:00:00 2001 From: Laurenz Date: Sun, 27 Oct 2024 19:04:55 +0100 Subject: Split out four new crates (#5302) --- crates/typst-library/src/lib.rs | 264 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 crates/typst-library/src/lib.rs (limited to 'crates/typst-library/src/lib.rs') diff --git a/crates/typst-library/src/lib.rs b/crates/typst-library/src/lib.rs new file mode 100644 index 00000000..34c2e526 --- /dev/null +++ b/crates/typst-library/src/lib.rs @@ -0,0 +1,264 @@ +//! 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 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 ecow::EcoString; +use typst_syntax::package::PackageSpec; +use typst_syntax::{FileId, Source, Span}; +use typst_utils::LazyHash; + +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; + + /// A list of all available packages and optionally descriptions for them. + /// + /// This function is optional to implement. It enhances the user experience + /// by enabling autocompletion for packages. Details about packages from the + /// `@preview` namespace are available from + /// `https://packages.typst.org/preview/index.json`. + fn packages(&self) -> &[(PackageSpec, 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) + } + + fn packages(&self) -> &[(PackageSpec, Option)] { + self.deref().packages() + } + } + }; +} + +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 source file. + fn range(&self, span: Span) -> Option>; +} + +impl WorldExt for T { + fn range(&self, span: Span) -> Option> { + 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, +} + +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, +} + +impl LibraryBuilder { + /// Configure the inputs visible through `sys.inputs`. + pub fn with_inputs(mut self, inputs: Dict) -> Self { + self.inputs = Some(inputs); + 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); + let std = Value::Module(global.clone()); + Library { global, math, styles: Styles::new(), std } + } +} + +/// Construct the module with global definitions. +fn global(math: Module, inputs: Dict) -> Module { + let mut global = Scope::deduplicating(); + self::foundations::define(&mut global, inputs); + 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); + 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); +} -- cgit v1.2.3