summaryrefslogtreecommitdiff
path: root/crates/typst-library/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/typst-library/src/lib.rs')
-rw-r--r--crates/typst-library/src/lib.rs264
1 files changed, 264 insertions, 0 deletions
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<Library>;
+
+ /// Metadata about all known fonts.
+ fn book(&self) -> &LazyHash<FontBook>;
+
+ /// 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<Source>;
+
+ /// Try to access the specified file.
+ fn file(&self, id: FileId) -> FileResult<Bytes>;
+
+ /// Try to access the font with the given index in the font book.
+ fn font(&self, index: usize) -> Option<Font>;
+
+ /// 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<i64>) -> Option<Datetime>;
+
+ /// 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<EcoString>)] {
+ &[]
+ }
+}
+
+macro_rules! world_impl {
+ ($W:ident for $ptr:ty) => {
+ impl<$W: World> World for $ptr {
+ fn library(&self) -> &LazyHash<Library> {
+ self.deref().library()
+ }
+
+ fn book(&self) -> &LazyHash<FontBook> {
+ self.deref().book()
+ }
+
+ fn main(&self) -> FileId {
+ self.deref().main()
+ }
+
+ fn source(&self, id: FileId) -> FileResult<Source> {
+ self.deref().source(id)
+ }
+
+ fn file(&self, id: FileId) -> FileResult<Bytes> {
+ self.deref().file(id)
+ }
+
+ fn font(&self, index: usize) -> Option<Font> {
+ self.deref().font(index)
+ }
+
+ fn today(&self, offset: Option<i64>) -> Option<Datetime> {
+ self.deref().today(offset)
+ }
+
+ fn packages(&self) -> &[(PackageSpec, Option<EcoString>)] {
+ self.deref().packages()
+ }
+ }
+ };
+}
+
+world_impl!(W for std::boxed::Box<W>);
+world_impl!(W for std::sync::Arc<W>);
+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<Range<usize>>;
+}
+
+impl<T: World> WorldExt for T {
+ fn range(&self, span: Span) -> Option<Range<usize>> {
+ 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<Dict>,
+}
+
+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);
+}