tinymist_world/
snapshot.rs1use core::fmt;
4
5use crate::{args::TaskWhen, CompilerFeat, CompilerWorld, EntryReader, TaskInputs};
6use ecow::EcoString;
7use serde::{Deserialize, Serialize};
8use tinymist_std::typst::TypstDocument;
9
10#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub struct ProjectInsId(pub EcoString);
14
15impl fmt::Display for ProjectInsId {
16 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
17 self.0.fmt(f)
18 }
19}
20
21impl ProjectInsId {
22 pub const PRIMARY: ProjectInsId = ProjectInsId(EcoString::inline("primary"));
24}
25
26#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
31#[serde(rename_all = "camelCase")]
32pub struct ExportSignal {
33 pub by_mem_events: bool,
35 pub by_fs_events: bool,
37 pub by_entry_update: bool,
39}
40
41impl ExportSignal {
42 pub fn merge(&mut self, other: ExportSignal) {
44 self.by_mem_events |= other.by_mem_events;
45 self.by_fs_events |= other.by_fs_events;
46 self.by_entry_update |= other.by_entry_update;
47 }
48
49 pub fn should_run_task_dyn(
50 &self,
51 when: &TaskWhen,
52 docs: Option<&TypstDocument>,
53 ) -> Option<bool> {
54 match docs {
55 Some(TypstDocument::Paged(doc)) => self.should_run_task(when, Some(doc.as_ref())),
56 Some(TypstDocument::Html(doc)) => self.should_run_task(when, Some(doc.as_ref())),
57 None => self.should_run_task::<typst::layout::PagedDocument>(when, None),
58 }
59 }
60
61 pub fn should_run_task<D: typst::Document>(
62 &self,
63 when: &TaskWhen,
64 docs: Option<&D>,
65 ) -> Option<bool> {
66 match when {
67 TaskWhen::Never => Some(false),
68 TaskWhen::Script => Some(self.by_entry_update),
70 TaskWhen::OnType => Some(self.by_mem_events),
71 TaskWhen::OnSave => Some(self.by_fs_events),
72 TaskWhen::OnDocumentHasTitle if self.by_fs_events => {
73 docs.map(|doc| doc.info().title.is_some())
74 }
75 TaskWhen::OnDocumentHasTitle => Some(false),
76 }
77 }
78}
79
80pub struct CompileSnapshot<F: CompilerFeat> {
82 pub id: ProjectInsId,
84 pub signal: ExportSignal,
86 pub world: CompilerWorld<F>,
88 pub success_doc: Option<TypstDocument>,
90}
91
92impl<F: CompilerFeat + 'static> CompileSnapshot<F> {
93 pub fn from_world(world: CompilerWorld<F>) -> Self {
95 Self {
96 id: ProjectInsId("primary".into()),
97 signal: ExportSignal::default(),
98 world,
99 success_doc: None,
100 }
101 }
102
103 pub fn task(mut self, inputs: TaskInputs) -> Self {
109 'check_changed: {
110 if let Some(entry) = &inputs.entry {
111 if *entry != self.world.entry_state() {
112 break 'check_changed;
113 }
114 }
115 if let Some(inputs) = &inputs.inputs {
116 if inputs.clone() != self.world.inputs() {
117 break 'check_changed;
118 }
119 }
120
121 return self;
122 };
123
124 self.world = self.world.task(inputs);
125
126 self
127 }
128}
129
130impl<F: CompilerFeat> Clone for CompileSnapshot<F> {
131 fn clone(&self) -> Self {
132 Self {
133 id: self.id.clone(),
134 signal: self.signal,
135 world: self.world.clone(),
136 success_doc: self.success_doc.clone(),
137 }
138 }
139}