code_moniker_workspace/live/
model.rs1use 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}