grus/
actions.rs

1use crate::app::{Application, CommandType, Error, Mode};
2use crate::flattree::{FlatTreeBuilder, FlatTreeState};
3use crate::node::{Node, NodeData, Priority, wrap_text};
4use crate::store::{Store, StoreReader};
5use crate::ui::tree::SelRetention;
6
7pub trait Actions {
8	fn enter_command_mode(&mut self, cmd: CommandType);
9	fn add_child(&mut self) -> Result<(), Error>;
10	fn delete(&mut self) -> Result<(), Error>;
11	fn rename(&mut self) -> Result<(), Error>;
12	fn set_priority(&mut self, priority: Priority) -> Result<(), Error>;
13	fn set_due_date(&mut self) -> Result<(), Error>;
14	fn unset_due_date(&mut self) -> Result<(), Error>;
15	fn move_into(&mut self) -> Result<(), Error>;
16	fn move_out(&mut self) -> Result<(), Error>;
17	fn cancel(&mut self);
18	fn resize(&mut self, width: u16, height: u16) -> Result<(), Error>;
19}
20
21impl Actions for Application {
22	fn enter_command_mode(&mut self, cmd: CommandType) {
23		self.mode = Mode::Command(cmd);
24		let title = match cmd {
25			CommandType::AddChild => "add: ",
26			CommandType::Rename => "rename: ",
27			CommandType::SetDueDate => "due date: ",
28		};
29		self.status_view.set_title(title);
30	}
31
32	fn add_child(&mut self) -> Result<(), Error> {
33		let Some(sel_node) = self.tree_view.sel_node() else { return Ok(()) };
34
35		let name = self.status_view.get_command();
36		let data = bincode::serialize(&NodeData::with_name(name))?;
37
38		let mut writer = self.store.writer()?;
39		writer.add_child(sel_node.id, &data)?;
40		writer.commit()?;
41
42		let height = self.screen.tree_height().into();
43		let width = self.screen.tree_width().into();
44		let flattree = build_flattree(self.root_id, &self.store, height, width)?;
45		self.tree_view.reset(flattree, SelRetention::Stay);
46
47		self.cancel();
48		Ok(())
49	}
50
51	fn delete(&mut self) -> Result<(), Error> {
52		let Some(sel_node) = self.tree_view.sel_node() else { return Ok(()) };
53		if self.tree_view.is_root_selected() { return Ok(()) }
54
55		let mut writer = self.store.writer()?;
56		writer.delete(sel_node.pid, sel_node.id)?;
57		writer.commit()?;
58
59		let height = self.screen.tree_height().into();
60		let width = self.screen.tree_width().into();
61		let flattree = build_flattree(self.root_id, &self.store, height, width)?;
62		self.tree_view.reset(flattree, SelRetention::MoveUp);
63		Ok(())
64	}
65
66	fn rename(&mut self) -> Result<(), Error> {
67		let Some(sel_node) = self.tree_view.sel_node() else { return Ok(()) };
68
69		let reader = self.store.reader()?;
70		let original = bincode::deserialize(reader.read(sel_node.id)?.unwrap())?;
71		drop(reader);
72
73		let name = self.status_view.get_command();
74		let data = bincode::serialize(&NodeData { name: name.into(), ..original })?;
75
76		let mut writer = self.store.writer()?;
77		writer.modify(sel_node.id, &data)?;
78		writer.commit()?;
79
80		let height = self.screen.tree_height().into();
81		let width = self.screen.tree_width().into();
82		let flattree = build_flattree(self.root_id, &self.store, height, width)?;
83		self.tree_view.reset(flattree, SelRetention::SameId);
84
85		self.cancel();
86		Ok(())
87	}
88
89	fn set_priority(&mut self, priority: Priority) -> Result<(), Error> {
90		let Some(sel_node) = self.tree_view.sel_node() else { return Ok(()) };
91
92		let reader = self.store.reader()?;
93		let original = bincode::deserialize(reader.read(sel_node.id)?.unwrap())?;
94		drop(reader);
95
96		let data = bincode::serialize(&NodeData { priority, ..original })?;
97
98		let mut writer = self.store.writer()?;
99		writer.modify(sel_node.id, &data)?;
100		writer.commit()?;
101
102		let height = self.screen.tree_height().into();
103		let width = self.screen.tree_width().into();
104		let flattree = build_flattree(self.root_id, &self.store, height, width)?;
105		self.tree_view.reset(flattree, SelRetention::SameId);
106
107		self.cancel();
108		Ok(())
109	}
110
111	fn set_due_date(&mut self) -> Result<(), Error> {
112		let Some(sel_node) = self.tree_view.sel_node() else { return Ok(()) };
113
114		let reader = self.store.reader()?;
115		let original = bincode::deserialize(reader.read(sel_node.id)?.unwrap())?;
116		drop(reader);
117
118		let Ok(due_date) = fuzzydate::parse(self.status_view.get_command()) else {
119			return Ok(());
120		};
121		let data = bincode::serialize(&NodeData { due_date: Some(due_date), ..original })?;
122
123		let mut writer = self.store.writer()?;
124		writer.modify(sel_node.id, &data)?;
125		writer.commit()?;
126
127		let height = self.screen.tree_height().into();
128		let width = self.screen.tree_width().into();
129		let flattree = build_flattree(self.root_id, &self.store, height, width)?;
130		self.tree_view.reset(flattree, SelRetention::SameId);
131
132		self.cancel();
133		Ok(())
134	}
135
136	fn unset_due_date(&mut self) -> Result<(), Error> {
137		let Some(sel_node) = self.tree_view.sel_node() else { return Ok(()) };
138
139		let reader = self.store.reader()?;
140		let original = bincode::deserialize(reader.read(sel_node.id)?.unwrap())?;
141		drop(reader);
142
143		let data = bincode::serialize(&NodeData { due_date: None, ..original })?;
144
145		let mut writer = self.store.writer()?;
146		writer.modify(sel_node.id, &data)?;
147		writer.commit()?;
148
149		let height = self.screen.tree_height().into();
150		let width = self.screen.tree_width().into();
151		let flattree = build_flattree(self.root_id, &self.store, height, width)?;
152		self.tree_view.reset(flattree, SelRetention::SameId);
153		Ok(())
154	}
155
156	fn move_into(&mut self) -> Result<(), Error> {
157		let Some(sel_node) = self.tree_view.sel_node() else { return Ok(()) };
158
159		if self.tree_view.is_root_selected() { return Ok(()) }
160
161		self.stack.push(self.root_id);
162		self.root_id = sel_node.id;
163
164		let height = self.screen.tree_height().into();
165		let width = self.screen.tree_width().into();
166		let flattree = build_flattree(sel_node.id, &self.store, height, width)?;
167		self.tree_view.reset(flattree, SelRetention::Reset);
168		Ok(())
169	}
170
171	fn move_out(&mut self) -> Result<(), Error> {
172		let Some(root_id) = self.stack.pop() else { return Ok(()) };
173		self.root_id = root_id;
174
175		let height = self.screen.tree_height().into();
176		let width = self.screen.tree_width().into();
177		let flattree = build_flattree(root_id, &self.store, height, width)?;
178		self.tree_view.reset(flattree, SelRetention::Reset);
179		Ok(())
180	}
181
182	fn cancel(&mut self) {
183		self.status_view.clear();
184		self.mode = Mode::Normal;
185	}
186
187	fn resize(&mut self, width: u16, height: u16) -> Result<(), Error> {
188		self.screen.update(width, height);
189		let height = self.screen.tree_height().into();
190		let width = self.screen.tree_width().into();
191		let flattree = build_flattree(self.root_id, &self.store, height, width)?;
192		self.tree_view.reset(flattree, SelRetention::SameId);
193		Ok(())
194	}
195}
196
197pub fn build_flattree(
198	id: u64,
199	store: &Store,
200	height: usize,
201	width: usize,
202) -> Result<Vec<Node<'static>>, Error> {
203	if width == 0 { return Ok(Vec::new()) }
204
205	let reader = store.reader()?;
206	let root_data: NodeData = bincode::deserialize(reader.read(id)?.unwrap())?;
207	let root_splits = wrap_text(&root_data.name, width);
208	if root_splits.len() - 1 > height { return Ok(Vec::new()) }
209	let root = Node { id, pid: id, data: root_data, depth: 0, splits: root_splits };
210	let mut builder = FlatTreeBuilder::new(root, height);
211
212	loop {
213		match builder.step() {
214			FlatTreeState::Build => continue,
215			FlatTreeState::Refill => {
216				for i in builder.fill_range() {
217					builder.fill(get_children(builder.id(i), &reader, builder.depth(i), width)?, i);
218				}
219				builder.finish_fill();
220			}
221			FlatTreeState::Done => return Ok(builder.finish()),
222		}
223	}
224}
225
226fn get_children(
227	pid: u64,
228	reader: &StoreReader,
229	mut depth: usize,
230	width: usize
231) -> Result<Vec<Node<'static>>, Error> {
232	depth += 1;
233	let mut children = Vec::new();
234	for entry in reader.children(pid)? {
235		let (id, data) = entry?;
236		let data: NodeData = bincode::deserialize(data)?;
237		let width = width.saturating_sub(2 * depth);
238		if width == 0 { continue }
239		let splits = wrap_text(&data.name, width);
240		children.push(Node { id, pid, depth, data, splits });
241	}
242	Ok(children)
243}