makepad_code_editor/
history.rs1use 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}