tinymist_debug/
instrument.rs

1//! Tinymist instrument support for Typst.
2
3use std::sync::Arc;
4
5use parking_lot::Mutex;
6use tinymist_std::hash::FxHashMap;
7use tinymist_world::SourceWorld;
8use tinymist_world::vfs::PathResolution;
9use tinymist_world::{CompilerFeat, CompilerWorld, vfs::FileId};
10use typst::Library;
11use typst::diag::FileResult;
12use typst::foundations::Duration;
13use typst::foundations::{Bytes, Datetime};
14use typst::syntax::Source;
15use typst::text::{Font, FontBook};
16use typst::utils::LazyHash;
17
18pub trait Instrumenter: Send + Sync {
19    fn instrument(&self, source: Source) -> FileResult<Source>;
20}
21
22pub struct InstrumentWorld<'a, F: CompilerFeat, I> {
23    pub base: &'a CompilerWorld<F>,
24    pub library: Arc<LazyHash<Library>>,
25    pub instr: I,
26    pub instrumented: Mutex<FxHashMap<FileId, FileResult<Source>>>,
27}
28
29impl<F: CompilerFeat, I: Instrumenter> typst::World for InstrumentWorld<'_, F, I>
30where
31    I:,
32{
33    fn library(&self) -> &LazyHash<Library> {
34        &self.library
35    }
36
37    fn book(&self) -> &LazyHash<FontBook> {
38        self.base.book()
39    }
40
41    fn main(&self) -> FileId {
42        self.base.main()
43    }
44
45    fn source(&self, id: FileId) -> FileResult<Source> {
46        let mut instrumented = self.instrumented.lock();
47        if let Some(source) = instrumented.get(&id) {
48            return source.clone();
49        }
50
51        let source = self.base.source(id).and_then(|s| self.instr.instrument(s));
52        instrumented.insert(id, source.clone());
53        source
54    }
55
56    fn file(&self, id: FileId) -> FileResult<Bytes> {
57        self.base.file(id)
58    }
59
60    fn font(&self, index: usize) -> Option<Font> {
61        self.base.font(index)
62    }
63
64    fn today(&self, offset: Option<Duration>) -> Option<Datetime> {
65        self.base.today(offset)
66    }
67}
68
69impl<F: CompilerFeat, I: Instrumenter> SourceWorld for InstrumentWorld<'_, F, I> {
70    fn as_world(&self) -> &dyn typst::World {
71        self
72    }
73
74    fn path_for_id(&self, id: FileId) -> FileResult<PathResolution> {
75        self.base.path_for_id(id)
76    }
77}