makepad_code_editor/
history.rs

1use crate::{
2    selection::SelectionSet,
3    session::SessionId,
4    text::{Edit, Text},
5};
6
7#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
8pub struct History {
9    text: Text,
10    current_desc: Option<GroupDesc>,
11    undo_stack: Stack,
12    redo_stack: Stack,
13}
14
15#[derive(Clone,Copy)]
16pub enum NewGroup{
17    Yes,
18    No
19}
20
21impl History {
22    pub fn new() -> Self {
23        Self::default()
24    }
25
26    pub fn as_text(&self) -> &Text {
27        &self.text
28    }
29
30    pub fn force_new_group(&mut self) {
31        self.current_desc = None;
32    }
33
34    pub fn push_or_extend_group(
35        &mut self,
36        session_id: SessionId,
37        edit_kind: EditKind,
38        selections: &SelectionSet,
39    ) {
40        let desc = GroupDesc {
41            session_id,
42            edit_kind,
43        };
44        if !self
45            .current_desc
46            .map_or(false, |current_desc| current_desc.can_merge_with(desc))
47        {
48            self.undo_stack.push_group(selections.clone());
49            self.current_desc = Some(desc);
50        }
51    }
52
53    pub fn apply_edit(&mut self, edit: Edit) {
54        let inverted_edit = edit.clone().invert(&self.text);
55        self.text.apply_change(edit.change);
56        self.undo_stack.push_edit(inverted_edit);
57        self.redo_stack.clear();
58    }
59
60    pub fn undo(
61        &mut self,
62        selections: &SelectionSet,
63        edits: &mut Vec<Edit>,
64    ) -> Option<SelectionSet> {
65        if let Some(new_selections) = self.undo_stack.pop_group(edits) {
66            self.redo_stack.push_group(selections.clone());
67            for edit in edits {
68                let inverted_edit = edit.clone().invert(&self.text);
69                self.text.apply_change(edit.change.clone());
70                self.redo_stack.push_edit(inverted_edit);
71            }
72            self.current_desc = None;
73            Some(new_selections)
74        } else {
75            None
76        }
77    }
78
79    pub fn redo(
80        &mut self,
81        selections: &SelectionSet,
82        edits: &mut Vec<Edit>,
83    ) -> Option<SelectionSet> {
84        if let Some(new_selections) = self.redo_stack.pop_group(edits) {
85            self.undo_stack.push_group(selections.clone());
86            for edit in edits {
87                let inverted_edit = edit.clone().invert(&self.text);
88                self.text.apply_change(edit.change.clone());
89                self.undo_stack.push_edit(inverted_edit);
90            }
91            self.current_desc = None;
92            Some(new_selections)
93        } else {
94            None
95        }
96    }
97
98    pub fn into_text(self) -> Text {
99        self.text
100    }
101}
102
103impl From<Text> for History {
104    fn from(text: Text) -> Self {
105        Self {
106            text,
107            ..Self::default()
108        }
109    }
110}
111
112#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
113pub enum EditKind {
114    Insert,
115    InsertSpace,
116    Delete,
117    Indent,
118    Group(u64),
119    Outdent,
120    Other,
121}
122
123impl EditKind {
124    fn can_merge_with(self, other: Self) -> bool {
125        if self == Self::Other {
126            return false;
127        }
128        self == other
129    }
130}
131
132#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
133struct GroupDesc {
134    session_id: SessionId,
135    edit_kind: EditKind,
136}
137
138impl GroupDesc {
139    fn can_merge_with(self, other: GroupDesc) -> bool {
140        self.session_id == other.session_id && self.edit_kind.can_merge_with(other.edit_kind)
141    }
142}
143
144#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
145struct Stack {
146    groups: Vec<Group>,
147    edits: Vec<Edit>,
148}
149
150impl Stack {
151    fn push_group(&mut self, selections: SelectionSet) {
152        self.groups.push(Group {
153            selections,
154            edit_start: self.edits.len(),
155        });
156    }
157
158    fn push_edit(&mut self, edit: Edit) {
159        self.edits.push(edit);
160    }
161
162    fn pop_group(&mut self, edits: &mut Vec<Edit>) -> Option<SelectionSet> {
163        match self.groups.pop() {
164            Some(group) => {
165                edits.extend(self.edits.drain(group.edit_start..).rev());
166                Some(group.selections)
167            }
168            None => None,
169        }
170    }
171
172    fn clear(&mut self) {
173        self.groups.clear();
174        self.edits.clear();
175    }
176}
177
178#[derive(Clone, Debug, Eq, Hash, PartialEq)]
179struct Group {
180    selections: SelectionSet,
181    edit_start: usize,
182}