Skip to main content

code_moniker_workspace/live/
model.rs

1use std::path::PathBuf;
2
3#[derive(Clone, Debug, Eq, PartialEq)]
4pub struct WorkspaceWatchRoot {
5	pub path: PathBuf,
6	pub git_root: Option<PathBuf>,
7	pub ignored_paths: Vec<PathBuf>,
8	pub notes_path: Option<PathBuf>,
9}
10
11#[derive(Clone, Debug, Eq, PartialEq)]
12pub enum WorkspaceLiveEvent {
13	GitBaseChanged,
14	Notes,
15	GitBaseAndNotes,
16	SourcesChanged(Vec<PathBuf>),
17	SourcesAndNotes(Vec<PathBuf>),
18	SourcesAndGitBase(Vec<PathBuf>),
19	SourcesGitBaseAndNotes(Vec<PathBuf>),
20	RescanRequired,
21	RescanAndNotes,
22	RescanAndGitBase,
23	RescanGitBaseAndNotes,
24}
25
26impl WorkspaceLiveEvent {
27	pub fn coalesce(self, other: Self) -> Self {
28		WorkspaceLiveRefreshPlan::from_event(self)
29			.coalesce(WorkspaceLiveRefreshPlan::from_event(other))
30			.into_event()
31	}
32
33	pub fn source_paths(&self) -> Option<&[PathBuf]> {
34		match self {
35			Self::SourcesChanged(paths)
36			| Self::SourcesAndNotes(paths)
37			| Self::SourcesAndGitBase(paths)
38			| Self::SourcesGitBaseAndNotes(paths) => Some(paths),
39			Self::GitBaseChanged
40			| Self::Notes
41			| Self::GitBaseAndNotes
42			| Self::RescanRequired
43			| Self::RescanAndNotes
44			| Self::RescanAndGitBase
45			| Self::RescanGitBaseAndNotes => None,
46		}
47	}
48
49	pub fn includes_notes(&self) -> bool {
50		matches!(
51			self,
52			Self::Notes
53				| Self::GitBaseAndNotes
54				| Self::SourcesAndNotes(_)
55				| Self::SourcesGitBaseAndNotes(_)
56				| Self::RescanAndNotes
57				| Self::RescanGitBaseAndNotes
58		)
59	}
60
61	pub fn includes_git_base(&self) -> bool {
62		matches!(
63			self,
64			Self::GitBaseChanged
65				| Self::GitBaseAndNotes
66				| Self::SourcesAndGitBase(_)
67				| Self::SourcesGitBaseAndNotes(_)
68				| Self::RescanAndGitBase
69				| Self::RescanGitBaseAndNotes
70		)
71	}
72}
73
74#[derive(Clone, Debug, Default, Eq, PartialEq)]
75pub struct WorkspaceLiveRefreshPlan {
76	rescan: bool,
77	source_paths: Vec<PathBuf>,
78	git_base: bool,
79	notes: bool,
80}
81
82impl WorkspaceLiveRefreshPlan {
83	pub fn from_event(event: WorkspaceLiveEvent) -> Self {
84		refresh_plan_from_event(event)
85	}
86
87	pub fn requires_rescan(&self) -> bool {
88		self.rescan
89	}
90
91	pub fn source_paths(&self) -> &[PathBuf] {
92		&self.source_paths
93	}
94
95	pub fn includes_git_base(&self) -> bool {
96		self.git_base
97	}
98
99	pub fn includes_notes(&self) -> bool {
100		self.notes
101	}
102
103	pub fn coalesce(mut self, other: Self) -> Self {
104		self.rescan |= other.rescan;
105		self.git_base |= other.git_base;
106		self.notes |= other.notes;
107		for path in other.source_paths {
108			push_unique(&mut self.source_paths, path);
109		}
110		self
111	}
112
113	pub fn is_empty(&self) -> bool {
114		refresh_plan_is_empty(self)
115	}
116
117	pub fn without_notes(self) -> Self {
118		refresh_plan_without_notes(self)
119	}
120
121	pub fn into_event(self) -> WorkspaceLiveEvent {
122		refresh_plan_into_event(self)
123	}
124}
125
126fn refresh_plan_is_empty(plan: &WorkspaceLiveRefreshPlan) -> bool {
127	!plan.rescan && plan.source_paths.is_empty() && !plan.git_base && !plan.notes
128}
129
130fn refresh_plan_without_notes(mut plan: WorkspaceLiveRefreshPlan) -> WorkspaceLiveRefreshPlan {
131	plan.notes = false;
132	plan
133}
134
135fn refresh_plan_from_event(event: WorkspaceLiveEvent) -> WorkspaceLiveRefreshPlan {
136	match event {
137		WorkspaceLiveEvent::RescanRequired => WorkspaceLiveRefreshPlan {
138			rescan: true,
139			..WorkspaceLiveRefreshPlan::default()
140		},
141		WorkspaceLiveEvent::RescanAndNotes => WorkspaceLiveRefreshPlan {
142			rescan: true,
143			notes: true,
144			..WorkspaceLiveRefreshPlan::default()
145		},
146		WorkspaceLiveEvent::RescanAndGitBase => WorkspaceLiveRefreshPlan {
147			rescan: true,
148			git_base: true,
149			..WorkspaceLiveRefreshPlan::default()
150		},
151		WorkspaceLiveEvent::RescanGitBaseAndNotes => WorkspaceLiveRefreshPlan {
152			rescan: true,
153			git_base: true,
154			notes: true,
155			..WorkspaceLiveRefreshPlan::default()
156		},
157		WorkspaceLiveEvent::GitBaseChanged => WorkspaceLiveRefreshPlan {
158			git_base: true,
159			..WorkspaceLiveRefreshPlan::default()
160		},
161		WorkspaceLiveEvent::Notes => WorkspaceLiveRefreshPlan {
162			notes: true,
163			..WorkspaceLiveRefreshPlan::default()
164		},
165		WorkspaceLiveEvent::GitBaseAndNotes => WorkspaceLiveRefreshPlan {
166			git_base: true,
167			notes: true,
168			..WorkspaceLiveRefreshPlan::default()
169		},
170		WorkspaceLiveEvent::SourcesChanged(source_paths) => WorkspaceLiveRefreshPlan {
171			source_paths,
172			..WorkspaceLiveRefreshPlan::default()
173		},
174		WorkspaceLiveEvent::SourcesAndNotes(source_paths) => WorkspaceLiveRefreshPlan {
175			source_paths,
176			notes: true,
177			..WorkspaceLiveRefreshPlan::default()
178		},
179		WorkspaceLiveEvent::SourcesAndGitBase(source_paths) => WorkspaceLiveRefreshPlan {
180			source_paths,
181			git_base: true,
182			..WorkspaceLiveRefreshPlan::default()
183		},
184		WorkspaceLiveEvent::SourcesGitBaseAndNotes(source_paths) => WorkspaceLiveRefreshPlan {
185			source_paths,
186			git_base: true,
187			notes: true,
188			..WorkspaceLiveRefreshPlan::default()
189		},
190	}
191}
192
193fn refresh_plan_into_event(plan: WorkspaceLiveRefreshPlan) -> WorkspaceLiveEvent {
194	if plan.rescan {
195		return match (plan.git_base, plan.notes) {
196			(true, true) => WorkspaceLiveEvent::RescanGitBaseAndNotes,
197			(true, false) => WorkspaceLiveEvent::RescanAndGitBase,
198			(false, true) => WorkspaceLiveEvent::RescanAndNotes,
199			(false, false) => WorkspaceLiveEvent::RescanRequired,
200		};
201	}
202	match (plan.source_paths.is_empty(), plan.git_base, plan.notes) {
203		(false, true, true) => WorkspaceLiveEvent::SourcesGitBaseAndNotes(plan.source_paths),
204		(false, true, false) => WorkspaceLiveEvent::SourcesAndGitBase(plan.source_paths),
205		(false, false, true) => WorkspaceLiveEvent::SourcesAndNotes(plan.source_paths),
206		(false, false, false) => WorkspaceLiveEvent::SourcesChanged(plan.source_paths),
207		(true, true, true) => WorkspaceLiveEvent::GitBaseAndNotes,
208		(true, true, false) => WorkspaceLiveEvent::GitBaseChanged,
209		(true, false, true) => WorkspaceLiveEvent::Notes,
210		(true, false, false) => WorkspaceLiveEvent::RescanRequired,
211	}
212}
213
214pub(super) fn push_unique(paths: &mut Vec<PathBuf>, path: PathBuf) {
215	if !paths.iter().any(|existing| existing == &path) {
216		paths.push(path);
217	}
218}