tinymist_world/
snapshot.rs

1//! Project compiler for tinymist.
2
3use core::fmt;
4
5use crate::{CompilerFeat, CompilerWorld, EntryReader, TaskInputs};
6use ecow::EcoString;
7use tinymist_std::typst::TypstDocument;
8
9/// Project instance id. This is slightly different from the project ids that
10/// persist in disk.
11#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct ProjectInsId(pub EcoString);
13
14impl fmt::Display for ProjectInsId {
15    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16        write!(f, "{:?}", self.0)
17    }
18}
19
20impl ProjectInsId {
21    /// The primary project id.
22    pub const PRIMARY: ProjectInsId = ProjectInsId(EcoString::inline("primary"));
23}
24
25/// A signal that possibly triggers an export.
26///
27/// Whether to export depends on the current state of the document and the user
28/// settings.
29#[derive(Debug, Clone, Copy, Default)]
30pub struct ExportSignal {
31    /// Whether the revision is annotated by memory events.
32    pub by_mem_events: bool,
33    /// Whether the revision is annotated by file system events.
34    pub by_fs_events: bool,
35    /// Whether the revision is annotated by entry update.
36    pub by_entry_update: bool,
37}
38
39impl ExportSignal {
40    /// Merge two signals.
41    pub fn merge(&mut self, other: ExportSignal) {
42        self.by_mem_events |= other.by_mem_events;
43        self.by_fs_events |= other.by_fs_events;
44        self.by_entry_update |= other.by_entry_update;
45    }
46}
47
48/// A snapshot of the project and compilation state.
49pub struct CompileSnapshot<F: CompilerFeat> {
50    /// The project id.
51    pub id: ProjectInsId,
52    /// The export signal for the document.
53    pub signal: ExportSignal,
54    /// Using world
55    pub world: CompilerWorld<F>,
56    /// The last successfully compiled document.
57    pub success_doc: Option<TypstDocument>,
58}
59
60impl<F: CompilerFeat + 'static> CompileSnapshot<F> {
61    /// Creates a snapshot from the world.
62    pub fn from_world(world: CompilerWorld<F>) -> Self {
63        Self {
64            id: ProjectInsId("primary".into()),
65            signal: ExportSignal::default(),
66            world,
67            success_doc: None,
68        }
69    }
70
71    /// Forks a new snapshot that compiles a different document.
72    ///
73    /// Note: the resulting document should not be shared in system, because we
74    /// generally believe that the document is revisioned, but temporary
75    /// tasks break this assumption.
76    pub fn task(mut self, inputs: TaskInputs) -> Self {
77        'check_changed: {
78            if let Some(entry) = &inputs.entry {
79                if *entry != self.world.entry_state() {
80                    break 'check_changed;
81                }
82            }
83            if let Some(inputs) = &inputs.inputs {
84                if inputs.clone() != self.world.inputs() {
85                    break 'check_changed;
86                }
87            }
88
89            return self;
90        };
91
92        self.world = self.world.task(inputs);
93
94        self
95    }
96}
97
98impl<F: CompilerFeat> Clone for CompileSnapshot<F> {
99    fn clone(&self) -> Self {
100        Self {
101            id: self.id.clone(),
102            signal: self.signal,
103            world: self.world.clone(),
104            success_doc: self.success_doc.clone(),
105        }
106    }
107}