1use euclid::default::Vector2D;
2use ropey::Rope;
3use smallvec::SmallVec;
4use std::ops::{Deref, DerefMut};
5
6use crate::{movement, Cursor, OpaqueDiff};
7
8#[derive(Debug, Clone)]
9pub struct Revision {
10 text: Rope,
11 cursor: Cursor,
12 pub parent: Option<Reference>,
13 pub children: SmallVec<[Reference; 1]>,
14 pub redo_index: usize,
15}
16
17impl Revision {
18 fn root(text: Rope) -> Self {
19 let mut cursor = Cursor::new();
20 movement::move_to_start_of_buffer(&text, &mut cursor);
21 Self {
22 text,
23 cursor,
24 parent: None,
25 children: SmallVec::new(),
26 redo_index: 0,
27 }
28 }
29}
30
31#[derive(Debug, Clone)]
32pub struct Reference {
33 pub index: usize,
34 diff: OpaqueDiff,
35}
36
37#[derive(Debug, Clone)]
38pub struct EditTree {
39 pub revisions: Vec<Revision>,
40 pub head_index: usize,
41 staged: Rope,
42 has_staged_changes: bool,
43}
44
45impl EditTree {
46 pub fn new(text: Rope) -> Self {
47 Self {
48 revisions: vec![Revision::root(text.clone())],
49 head_index: 0,
50 staged: text,
51 has_staged_changes: false,
52 }
53 }
54
55 pub fn next_child(&mut self) {
56 let current_revision = &mut self.revisions[self.head_index];
57 if current_revision.redo_index < current_revision.children.len().saturating_sub(1) {
58 current_revision.redo_index += 1;
59 }
60 }
61
62 pub fn previous_child(&mut self) {
63 let current_revision = &mut self.revisions[self.head_index];
64 if current_revision.redo_index > 0 {
65 current_revision.redo_index -= 1;
66 }
67 }
68
69 pub fn create_revision(&mut self, diff: OpaqueDiff, cursor: Cursor) {
70 let parent_to_child_diff = diff;
71 let child_to_parent_diff = parent_to_child_diff.reverse();
72 let new_revision_index = self.revisions.len();
75
76 self.revisions.push(Revision {
77 text: self.staged.clone(),
78 cursor,
79 parent: Some(Reference {
80 index: self.head_index,
81 diff: child_to_parent_diff,
82 }),
83 children: SmallVec::new(),
84 redo_index: 0,
85 });
86 {
87 let head = &mut self.revisions[self.head_index];
88 head.children.push(Reference {
89 index: new_revision_index,
90 diff: parent_to_child_diff,
91 });
92 head.redo_index = head.children.len() - 1;
93 }
94 self.head_index = new_revision_index;
95 self.has_staged_changes = false;
96 }
97
98 pub fn undo(&mut self) -> Option<(OpaqueDiff, Cursor)> {
99 if let Some(Reference {
100 ref diff,
101 index: previous_index,
102 }) = self.revisions[self.head_index].parent
103 {
104 let previous_revision = &self.revisions[previous_index];
105 self.staged = previous_revision.text.clone();
106 self.head_index = previous_index;
107
108 self.has_staged_changes = false;
109 Some((diff.clone(), previous_revision.cursor.clone()))
110 } else {
111 None
112 }
113 }
114
115 pub fn redo(&mut self) -> Option<(OpaqueDiff, Cursor)> {
116 let Self {
117 revisions,
118 head_index,
119 staged,
120 has_staged_changes,
121 ..
122 } = self;
123 let Revision {
124 ref children,
125 redo_index,
126 ..
127 } = revisions[*head_index];
128 children
129 .get(redo_index)
130 .map(|Reference { ref diff, index }| {
131 let Revision {
132 ref cursor,
133 ref text,
134 ..
135 } = revisions[*index];
136 *staged = text.clone();
137 *has_staged_changes = false;
138 *head_index = *index;
139 (diff.clone(), cursor.clone())
140 })
141 }
142
143 pub fn staged(&self) -> &Rope {
144 self.deref()
145 }
146
147 pub fn staged_mut(&mut self) -> &mut Rope {
148 self.deref_mut()
149 }
150}
151
152impl Deref for EditTree {
153 type Target = Rope;
154
155 fn deref(&self) -> &Rope {
156 &self.staged
157 }
158}
159
160impl DerefMut for EditTree {
161 fn deref_mut(&mut self) -> &mut Rope {
162 self.has_staged_changes = true;
163 &mut self.staged
164 }
165}
166
167pub struct FormattedRevision {
168 pub transform: Vector2D<isize>,
169 pub current_branch: bool,
170}
171
172pub fn format_revision(
173 revisions: &[Revision],
174 formatted: &mut [FormattedRevision],
175 index: usize,
176 transform: Vector2D<isize>,
177 current_branch: bool,
178) -> isize {
179 {
180 let formatted_revision = &mut formatted[index];
181 formatted_revision.transform = transform;
182 formatted_revision.current_branch = current_branch;
183 }
184
185 let revision = &revisions[index];
186 let mut subtree_width = 0;
187 for (child_index, child) in revision.children.iter().enumerate() {
188 if child_index > 0 {
189 subtree_width += 8;
190 }
191 subtree_width += format_revision(
192 revisions,
193 formatted,
194 child.index,
195 transform + Vector2D::new(subtree_width, 2),
196 current_branch && (child_index == revision.redo_index),
197 );
198 }
199 subtree_width
200}
201
202pub fn format_tree(tree: &EditTree) -> Vec<FormattedRevision> {
203 let mut formatted = Vec::with_capacity(tree.revisions.len());
204 formatted.resize_with(tree.revisions.len(), || FormattedRevision {
205 transform: Vector2D::zero(),
206 current_branch: true,
207 });
208 format_revision(&tree.revisions, &mut formatted, 0, Vector2D::zero(), true);
209 formatted
210}
211
212#[cfg(test)]
213mod tests {
214 use super::*;
215
216 #[test]
217 fn insert_with_revisions_and_no_undo() {
218 let mut tree = EditTree::new(Rope::new());
219 tree.insert(0, "The flowers are...");
220 tree.create_revision(OpaqueDiff::empty(), Cursor::end_of_buffer(&tree));
221
222 let position = tree.len_chars();
223 tree.insert(position, " so...\n");
224 tree.create_revision(OpaqueDiff::empty(), Cursor::end_of_buffer(&tree));
225
226 let position = tree.len_chars();
227 tree.insert(position, "dunno.");
228
229 assert_eq!("The flowers are... so...\ndunno.", &tree.to_string());
230 }
231
232 #[test]
233 fn undo_at_root_has_no_effect() {
234 let mut tree = EditTree::new("The flowers are violet.\n".into());
235 assert_eq!("The flowers are violet.\n", &tree.to_string());
236 assert_eq!(None, tree.undo());
237 assert_eq!("The flowers are violet.\n", &tree.to_string());
238 }
239
240 #[test]
241 fn insert_and_undo() {
242 let mut tree = EditTree::new(Rope::new());
243 tree.insert(0, "The flowers are...");
244 tree.create_revision(OpaqueDiff::empty(), Cursor::end_of_buffer(&tree));
245
246 let position = tree.len_chars();
247 tree.insert(position, " so...\n");
248 let position = tree.len_chars();
249 tree.insert(position, "dunno.");
250 tree.create_revision(OpaqueDiff::empty(), Cursor::end_of_buffer(&tree));
251
252 assert_eq!("The flowers are... so...\ndunno.", &tree.to_string());
253 tree.undo();
254 assert_eq!("The flowers are...", &tree.to_string());
255
256 let position = tree.len_chars();
257 tree.insert(position, " violet.");
258 assert_eq!("The flowers are... violet.", &tree.to_string());
259 }
260
261 #[test]
262 fn undo_redo_idempotent() {
263 let mut tree = EditTree::new(Rope::new());
264 tree.insert(0, "The flowers are...");
265 tree.create_revision(OpaqueDiff::empty(), Cursor::end_of_buffer(&tree));
266
267 let position = tree.len_chars();
268 tree.insert(position, " so...\n");
269 let position = tree.len_chars();
270 tree.insert(position, "dunno.");
271 tree.create_revision(OpaqueDiff::empty(), Cursor::end_of_buffer(&tree));
272
273 assert_eq!("The flowers are... so...\ndunno.", &tree.to_string());
274 tree.undo();
275 assert_eq!("The flowers are...", &tree.to_string());
276 tree.redo();
277 assert_eq!("The flowers are... so...\ndunno.", &tree.to_string());
278 tree.undo();
279 assert_eq!("The flowers are...", &tree.to_string());
280 tree.undo();
281 assert_eq!("", &tree.to_string());
282 }
283
284 #[test]
285 fn render_undo_tree() {}
286}