#typst #template #templating #source-file #resolver #lib

typst-as-lib

Small wrapper for typst that makes it easier to use it as a templating engine

17 releases (10 breaking)

0.11.1 Nov 11, 2024
0.10.0 Oct 18, 2024
0.8.0 Jul 22, 2024

#48 in Template engine

Download history 127/week @ 2024-07-29 11/week @ 2024-08-26 13/week @ 2024-09-02 10/week @ 2024-09-09 5/week @ 2024-09-16 10/week @ 2024-09-23 151/week @ 2024-09-30 191/week @ 2024-10-07 218/week @ 2024-10-14 31/week @ 2024-10-21 53/week @ 2024-10-28 133/week @ 2024-11-04 359/week @ 2024-11-11

595 downloads per month

MIT license

115KB
1K SLoC

Typst as lib

Small wrapper around Typst that makes it easier to use it as a templating engine. This API is currently not really stable, although I try to implement the features with as little change to the API as possible.

Usage

rust code

// main.rs
static TEMPLATE_FILE: &str = include_str!("./templates/template.typ");
static FONT: &[u8] = include_bytes!("./fonts/texgyrecursor-regular.otf");
static OUTPUT: &str = "./examples/output.pdf";
static IMAGE: &[u8] = include_bytes!("./templates/images/typst.png");

fn main() {
    let font = Font::new(Bytes::from(FONT), 0)
        .expect("Could not parse font!");

    // Read in fonts and the main source file.
    // We can use this template more than once, if needed (Possibly
    // with different input each time).
    let template = TypstTemplate::new(vec![font], TEMPLATE_FILE);

    // Run it
    let doc = template
        .compile_with_input(dummy_data())
        .output
        .expect("typst::compile() returned an error!");

    // Create pdf
    let options = Default::default();
    let pdf = typst_pdf::pdf(&doc, &options)
        .expect("Could not generate pdf.");
    fs::write(OUTPUT, pdf).expect("Could not write pdf.");
}

Full example file

Typst code

// template.typ
#import sys: inputs

#set page(paper: "a4")
#set text(font: "TeX Gyre Cursor", 11pt)

#let content = inputs.v
#let last_index = content.len() - 1

#for (i, elem) in content.enumerate() [
  == #elem.heading
  Text: #elem.text \
  Num1: #elem.num1 \
  Num2: #elem.num2 \
  #if elem.image != none [#image.decode(elem.image, height: 40pt)]
  #if i < last_index [
    #pagebreak()
  ]
]

Run example with:

cargo r --example=small_example

Resolving files

Binaries

Use TypstTemplate::with_static_file_resolver and add the binaries as key value pairs ((file_name, &[u8])).

Sources

Use TypstTemplate::with_static_source_file_resolver and add the sources as key value pairs ((file_name, String)).

Local files

Resolving local files can be enabled with TypstTemplate::with_file_system_resolver. The root should be the template folder. Files cannot be resolved, if they are outside of root.

Can be enabled like this:

let template = TypstTemplate::new(vec![font], TEMPLATE_FILE)
    .with_file_system_resolver("./examples/templates");

If you want to use another local package install path, use:

let template = TypstTemplate::new(vec![font], TEMPLATE_FILE)
    .add_file_resolver(
        FileSystemResolver::new("./examples/templates")
            .with_local_package_root("local/packages")
            .cached()
    );

Remote Packages

The package feature needs to be enabled.

Can be enabled like this:

let template = TypstTemplate::new(vec![font], TEMPLATE_FILE)
    .with_package_file_resolver(None);

This uses the file system as a cache.

If you want to use another cache root path, use:

let template = TypstTemplate::new(vec![font], TEMPLATE_FILE)
    .add_file_resolver(PackageResolverBuilder::new()
        .set_cache(
            FileSystemCache(PathBuf::from("cache/root"))
        )
        .build().cached()
    );

If you want to instead use the memory as cache, use:

let template = TypstTemplate::new(vec![font], TEMPLATE_FILE)
    .add_file_resolver(PackageResolverBuilder::new()
        .set_cache(
            InMemoryCache::new()
        )
        .build().cached()
    );

Examples

Static binaries and sources

See example which uses the static file resolvers.

cargo r --example=resolve_static

Local files and remote packages

See example which uses the file and the package resolver.

cargo r --example=resolve_files --features=package

Custom file resolver

You can also write your own file resolver. You need to implement the Trait FileResolver and pass it to the TypstTemplate::add_file_resolver function.

TypstTemplateCollection

If you want to compile multiple typst (main) source files you might want to use the TypstTemplateCollection, which allows you to specify the source file, when calling TypstTemplateCollection::compile, instead of passing it to new. The source file has to be added with TypstTemplateCollection::add_static_file_resolver first. TypstTemplate is just a wrapper around TypstTemplateCollection, that also saves a FileId for the main source file.

Loading fonts

Loading fonts is not in the scope of this library (yet?). If you are interested in that, write an issue.

  • This is how the typst-cli loads system fonts.
  • Here is an example of loading fonts from a folder.

TODO

  • allow usage of reqwest instead of ureq with a feature flag
  • fonts

Dependencies

~66MB
~1M SLoC