zee_edit/
tree.rs

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 child_to_parent_diff = diff;
73        // let parent_to_child_diff = child_to_parent_diff.reverse();
74        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}