1use std::{borrow::Cow, sync::Arc};
2
3use tinymist_std::{error::prelude::*, ImmutPath};
4use tinymist_vfs::{system::SystemAccessModel, ImmutDict, Vfs};
5use typst::{utils::LazyHash, Features};
6
7use crate::{
8 args::{CompileFontArgs, CompilePackageArgs},
9 config::{CompileFontOpts, CompileOpts},
10 font::{system::SystemFontSearcher, FontResolverImpl},
11 package::{registry::HttpRegistry, RegistryPathMapper},
12 EntryState,
13};
14
15mod diag;
16pub use diag::*;
17
18#[derive(Debug, Clone, Copy)]
20pub struct SystemCompilerFeat;
21
22impl crate::CompilerFeat for SystemCompilerFeat {
23 type FontResolver = FontResolverImpl;
25 type AccessModel = SystemAccessModel;
27 type Registry = HttpRegistry;
29}
30
31pub type TypstSystemUniverse = crate::world::CompilerUniverse<SystemCompilerFeat>;
33pub type TypstSystemWorld = crate::world::CompilerWorld<SystemCompilerFeat>;
35pub type SystemWorldComputeGraph = crate::WorldComputeGraph<SystemCompilerFeat>;
37
38impl TypstSystemUniverse {
39 pub fn new(mut opts: CompileOpts) -> Result<Self> {
43 let registry: Arc<HttpRegistry> = Arc::default();
44 let resolver = Arc::new(RegistryPathMapper::new(registry.clone()));
45 let inputs = std::mem::take(&mut opts.inputs);
46
47 Ok(Self::new_raw(
49 opts.entry.clone().try_into()?,
50 Features::default(),
51 Some(Arc::new(LazyHash::new(inputs))),
52 Vfs::new(resolver, SystemAccessModel {}),
53 registry,
54 Arc::new(Self::resolve_fonts(opts)?),
55 ))
56 }
57
58 fn resolve_fonts(opts: CompileOpts) -> Result<FontResolverImpl> {
60 let mut searcher = SystemFontSearcher::new();
61 searcher.resolve_opts(opts.into())?;
62 Ok(searcher.build())
63 }
64}
65
66pub struct SystemUniverseBuilder;
68
69impl SystemUniverseBuilder {
70 pub fn build(
73 entry: EntryState,
74 inputs: ImmutDict,
75 font_resolver: Arc<FontResolverImpl>,
76 package_registry: HttpRegistry,
77 ) -> TypstSystemUniverse {
78 let registry = Arc::new(package_registry);
79 let resolver = Arc::new(RegistryPathMapper::new(registry.clone()));
80
81 TypstSystemUniverse::new_raw(
83 entry,
84 Features::default(),
85 Some(inputs),
86 Vfs::new(resolver, SystemAccessModel {}),
87 registry,
88 font_resolver,
89 )
90 }
91
92 pub fn resolve_fonts(args: CompileFontArgs) -> Result<FontResolverImpl> {
94 let mut searcher = SystemFontSearcher::new();
95 searcher.resolve_opts(CompileFontOpts {
96 font_paths: args.font_paths,
97 no_system_fonts: args.ignore_system_fonts,
98 with_embedded_fonts: typst_assets::fonts().map(Cow::Borrowed).collect(),
99 })?;
100 Ok(searcher.build())
101 }
102
103 pub fn resolve_package(
105 cert_path: Option<ImmutPath>,
106 args: Option<&CompilePackageArgs>,
107 ) -> HttpRegistry {
108 HttpRegistry::new(
109 cert_path,
110 args.and_then(|args| Some(args.package_path.clone()?.into())),
111 args.and_then(|args| Some(args.package_cache_path.clone()?.into())),
112 )
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use std::sync::atomic::AtomicBool;
119
120 use super::*;
121 use clap::Parser;
122
123 use crate::args::CompileOnceArgs;
124 use crate::{CompileSnapshot, WorldComputable, WorldComputeGraph};
125
126 #[test]
127 fn test_args() {
128 use tinymist_std::typst::TypstPagedDocument;
129
130 let args = CompileOnceArgs::parse_from(["tinymist", "main.typ"]);
131 let verse = args
132 .resolve_system()
133 .expect("failed to resolve system universe");
134
135 let world = verse.snapshot();
136 let _res = typst::compile::<TypstPagedDocument>(&world);
137 }
138
139 static FONT_COMPUTED: AtomicBool = AtomicBool::new(false);
140
141 pub struct FontsOnce {
142 fonts: Arc<FontResolverImpl>,
143 }
144
145 impl WorldComputable<SystemCompilerFeat> for FontsOnce {
146 type Output = Self;
147
148 fn compute(graph: &Arc<WorldComputeGraph<SystemCompilerFeat>>) -> Result<Self> {
149 if FONT_COMPUTED.swap(true, std::sync::atomic::Ordering::SeqCst) {
151 bail!("font already computed");
152 }
153
154 Ok(Self {
155 fonts: graph.snap.world.font_resolver.clone(),
156 })
157 }
158 }
159
160 #[test]
161 fn compute_system_fonts() {
162 let args = CompileOnceArgs::parse_from(["tinymist", "main.typ"]);
163 let verse = args
164 .resolve_system()
165 .expect("failed to resolve system universe");
166
167 let snap = CompileSnapshot::from_world(verse.snapshot());
168
169 let graph = WorldComputeGraph::new(snap);
170
171 let font = graph.compute::<FontsOnce>().expect("font").fonts.clone();
172 let _ = font;
173
174 let font = graph.compute::<FontsOnce>().expect("font").fonts.clone();
175 let _ = font;
176
177 assert!(FONT_COMPUTED.load(std::sync::atomic::Ordering::SeqCst));
178 }
179}