summaryrefslogtreecommitdiff
path: root/src/lib.rs
blob: 646f3922db9fb7c0747b0a46af7e0573a037d726 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
//! The compiler for the _Typst_ markup language.
//!
//! # Steps
//! - **Parsing:**
//!   The compiler first transforms a plain string into an iterator of [tokens].
//!   This token stream is [parsed] into a [syntax tree]. The tree itself is
//!   untyped, but the [AST] module provides a typed layer over it.
//! - **Evaluation:**
//!   The next step is to [evaluate] the markup. This produces a [module],
//!   consisting of a scope of values that were exported by the code and
//!   [content], a hierarchical, styled representation of what was written in
//!   the source file. The elements of the content tree are well structured and
//!   order-independent and thus much better suited for further processing than
//!   the raw markup.
//! - **Typesetting:**
//!   Next, the content is [typeset] into a [document] containing one [frame]
//!   per page with items at fixed positions.
//! - **Exporting:**
//!   These frames can finally be exported into an output format (currently
//!   supported are [PDF] and [raster images]).
//!
//! [tokens]: syntax::SyntaxKind
//! [parsed]: syntax::parse
//! [syntax tree]: syntax::SyntaxNode
//! [AST]: syntax::ast
//! [evaluate]: eval::eval
//! [module]: eval::Module
//! [content]: model::Content
//! [typeset]: model::typeset
//! [document]: doc::Document
//! [frame]: doc::Frame
//! [PDF]: export::pdf
//! [raster images]: export::render

#![recursion_limit = "1000"]
#![allow(clippy::comparison_chain)]

extern crate self as typst;

#[macro_use]
pub mod util;
#[macro_use]
pub mod diag;
#[macro_use]
pub mod eval;
pub mod doc;
pub mod export;
pub mod font;
pub mod geom;
pub mod ide;
pub mod image;
pub mod model;
pub mod syntax;

use std::path::Path;

use comemo::{Prehashed, Track, TrackedMut};

use crate::diag::{FileResult, SourceResult};
use crate::doc::Document;
use crate::eval::{Datetime, Library, Route, Tracer};
use crate::font::{Font, FontBook};
use crate::syntax::{Source, SourceId};
use crate::util::Buffer;

/// Compile a source file into a fully layouted document.
#[tracing::instrument(skip(world))]
pub fn compile(world: &dyn World) -> SourceResult<Document> {
    let route = Route::default();
    let mut tracer = Tracer::default();

    // Call `track` just once to keep comemo's ID stable.
    let world = world.track();
    let mut tracer = tracer.track_mut();

    // Evaluate the source file into a module.
    tracing::info!("Starting evaluation");
    let module = eval::eval(
        world,
        route.track(),
        TrackedMut::reborrow_mut(&mut tracer),
        world.main(),
    )?;

    // Typeset the module's contents.
    model::typeset(world, tracer, &module.content())
}

/// The environment in which typesetting occurs.
#[comemo::track]
pub trait World {
    /// The path relative to which absolute paths are.
    ///
    /// Defaults to the empty path.
    fn root(&self) -> &Path {
        Path::new("")
    }

    /// The standard library.
    fn library(&self) -> &Prehashed<Library>;

    /// The main source file.
    fn main(&self) -> &Source;

    /// Try to resolve the unique id of a source file.
    fn resolve(&self, path: &Path) -> FileResult<SourceId>;

    /// Access a source file by id.
    fn source(&self, id: SourceId) -> &Source;

    /// Metadata about all known fonts.
    fn book(&self) -> &Prehashed<FontBook>;

    /// Try to access the font with the given id.
    fn font(&self, id: usize) -> Option<Font>;

    /// Try to access a file at a path.
    fn file(&self, path: &Path) -> FileResult<Buffer>;

    /// 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.
    fn today(&self, offset: Option<i64>) -> Option<Datetime>;
}