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