use std::{borrow::Cow, sync::Arc};
use tinymist_std::{error::prelude::*, ImmutPath};
use tinymist_vfs::{system::SystemAccessModel, ImmutDict, Vfs};
use typst::{utils::LazyHash, Features};
use crate::{
args::{CompileFontArgs, CompilePackageArgs},
config::{CompileFontOpts, CompileOpts},
font::{system::SystemFontSearcher, FontResolverImpl},
package::{registry::HttpRegistry, RegistryPathMapper},
EntryState,
};
mod diag;
pub use diag::*;
#[derive(Debug, Clone, Copy)]
pub struct SystemCompilerFeat;
impl crate::CompilerFeat for SystemCompilerFeat {
type FontResolver = FontResolverImpl;
type AccessModel = SystemAccessModel;
type Registry = HttpRegistry;
}
pub type TypstSystemUniverse = crate::world::CompilerUniverse<SystemCompilerFeat>;
pub type TypstSystemWorld = crate::world::CompilerWorld<SystemCompilerFeat>;
pub type SystemWorldComputeGraph = crate::WorldComputeGraph<SystemCompilerFeat>;
impl TypstSystemUniverse {
pub fn new(mut opts: CompileOpts) -> Result<Self> {
let registry: Arc<HttpRegistry> = Arc::default();
let resolver = Arc::new(RegistryPathMapper::new(registry.clone()));
let inputs = std::mem::take(&mut opts.inputs);
Ok(Self::new_raw(
opts.entry.clone().try_into()?,
Features::default(),
Some(Arc::new(LazyHash::new(inputs))),
Vfs::new(resolver, SystemAccessModel {}),
registry,
Arc::new(Self::resolve_fonts(opts)?),
))
}
fn resolve_fonts(opts: CompileOpts) -> Result<FontResolverImpl> {
let mut searcher = SystemFontSearcher::new();
searcher.resolve_opts(opts.into())?;
Ok(searcher.build())
}
}
pub struct SystemUniverseBuilder;
impl SystemUniverseBuilder {
pub fn build(
entry: EntryState,
inputs: ImmutDict,
font_resolver: Arc<FontResolverImpl>,
package_registry: HttpRegistry,
) -> TypstSystemUniverse {
let registry = Arc::new(package_registry);
let resolver = Arc::new(RegistryPathMapper::new(registry.clone()));
TypstSystemUniverse::new_raw(
entry,
Features::default(),
Some(inputs),
Vfs::new(resolver, SystemAccessModel {}),
registry,
font_resolver,
)
}
pub fn resolve_fonts(args: CompileFontArgs) -> Result<FontResolverImpl> {
let mut searcher = SystemFontSearcher::new();
searcher.resolve_opts(CompileFontOpts {
font_paths: args.font_paths,
no_system_fonts: args.ignore_system_fonts,
with_embedded_fonts: typst_assets::fonts().map(Cow::Borrowed).collect(),
})?;
Ok(searcher.build())
}
pub fn resolve_package(
cert_path: Option<ImmutPath>,
args: Option<&CompilePackageArgs>,
) -> HttpRegistry {
HttpRegistry::new(
cert_path,
args.and_then(|args| Some(args.package_path.clone()?.into())),
args.and_then(|args| Some(args.package_cache_path.clone()?.into())),
)
}
}
#[cfg(test)]
mod tests {
use std::sync::atomic::AtomicBool;
use super::*;
use clap::Parser;
use crate::args::CompileOnceArgs;
use crate::{CompileSnapshot, WorldComputable, WorldComputeGraph};
#[test]
fn test_args() {
use tinymist_std::typst::TypstPagedDocument;
let args = CompileOnceArgs::parse_from(["tinymist", "main.typ"]);
let verse = args
.resolve_system()
.expect("failed to resolve system universe");
let world = verse.snapshot();
let _res = typst::compile::<TypstPagedDocument>(&world);
}
static FONT_COMPUTED: AtomicBool = AtomicBool::new(false);
pub struct FontsOnce {
fonts: Arc<FontResolverImpl>,
}
impl WorldComputable<SystemCompilerFeat> for FontsOnce {
type Output = Self;
fn compute(graph: &Arc<WorldComputeGraph<SystemCompilerFeat>>) -> Result<Self> {
if FONT_COMPUTED.swap(true, std::sync::atomic::Ordering::SeqCst) {
bail!("font already computed");
}
Ok(Self {
fonts: graph.snap.world.font_resolver.clone(),
})
}
}
#[test]
fn compute_system_fonts() {
let args = CompileOnceArgs::parse_from(["tinymist", "main.typ"]);
let verse = args
.resolve_system()
.expect("failed to resolve system universe");
let snap = CompileSnapshot::from_world(verse.snapshot());
let graph = WorldComputeGraph::new(snap);
let font = graph.compute::<FontsOnce>().expect("font").fonts.clone();
let _ = font;
let font = graph.compute::<FontsOnce>().expect("font").fonts.clone();
let _ = font;
assert!(FONT_COMPUTED.load(std::sync::atomic::Ordering::SeqCst));
}
}