1use crate::node::Node;
11use crate::plugin::{Plugin, PluginKey, PluginSet, PluginStates};
12use crate::schema::Schema;
13use crate::selection::Selection;
14use crate::step::{Step, StepError};
15use crate::transform::Transform;
16
17const DEFAULT_HISTORY_DEPTH: usize = 100;
18
19fn apply_steps(doc: &Node, steps: &[Box<dyn Step>], schema: &Schema) -> Result<Node, StepError> {
20 let mut cur = doc.clone();
21 for s in steps {
22 cur = s.apply(&cur, schema)?;
23 }
24 Ok(cur)
25}
26
27#[derive(Debug, Clone)]
28struct HistEntry {
29 undo: Vec<Box<dyn Step>>,
31 redo: Vec<Box<dyn Step>>,
33 selection_before: Selection,
34 selection_after: Selection,
35}
36
37#[derive(Debug, Clone)]
39pub struct History {
40 done: Vec<HistEntry>,
41 undone: Vec<HistEntry>,
42 depth: usize,
43}
44
45impl Default for History {
46 fn default() -> Self {
47 History {
48 done: Vec::new(),
49 undone: Vec::new(),
50 depth: DEFAULT_HISTORY_DEPTH,
51 }
52 }
53}
54
55impl History {
56 pub fn with_depth(depth: usize) -> Self {
58 History {
59 depth,
60 ..Default::default()
61 }
62 }
63
64 pub fn undo_depth(&self) -> usize {
66 self.done.len()
67 }
68
69 pub fn redo_depth(&self) -> usize {
71 self.undone.len()
72 }
73
74 fn record(&mut self, mut entry: HistEntry, join: bool) {
75 self.undone.clear();
76 if join {
77 if let Some(prev) = self.done.last_mut() {
78 let mut undo = std::mem::take(&mut entry.undo);
81 undo.extend(std::mem::take(&mut prev.undo));
82 prev.undo = undo;
83 prev.redo.extend(std::mem::take(&mut entry.redo));
84 prev.selection_after = entry.selection_after;
85 return;
86 }
87 }
88 self.done.push(entry);
89 if self.done.len() > self.depth {
90 self.done.remove(0);
91 }
92 }
93}
94
95#[derive(Debug, Clone)]
97pub struct EditorState {
98 doc: Node,
99 selection: Selection,
100 schema: Schema,
101 history: History,
102 plugins: PluginStates,
103}
104
105impl EditorState {
106 pub fn new(doc: Node, schema: Schema) -> Self {
108 Self::with_plugins(doc, schema, PluginSet::new())
109 }
110
111 pub fn with_plugins(doc: Node, schema: Schema, plugins: PluginSet) -> Self {
115 let seed = EditorState {
116 doc,
117 selection: Selection::caret(0),
118 schema,
119 history: History::default(),
120 plugins: PluginStates::default(),
121 };
122 let plugin_states = PluginStates::from_set(plugins, &seed);
123 EditorState {
124 plugins: plugin_states,
125 ..seed
126 }
127 }
128
129 pub fn with_history(mut self, history: History) -> Self {
131 self.history = history;
132 self
133 }
134
135 pub fn plugin<P: Plugin>(&self, _key: PluginKey<P>) -> Option<&P::State> {
138 self.plugins.get::<P>()
139 }
140
141 pub fn doc(&self) -> &Node {
143 &self.doc
144 }
145 pub fn selection(&self) -> Selection {
147 self.selection
148 }
149 pub fn schema(&self) -> &Schema {
151 &self.schema
152 }
153 pub fn history(&self) -> &History {
155 &self.history
156 }
157
158 pub fn tr(&self) -> Transaction {
160 Transaction {
161 tr: Transform::new(self.doc.clone()),
162 selection: self.selection,
163 selection_set: false,
164 add_to_history: true,
165 join: false,
166 history_intent: None,
167 }
168 }
169
170 pub fn apply(&self, tx: Transaction) -> EditorState {
177 if let Some(intent) = tx.history_intent {
178 return match intent {
179 HistoryIntent::Undo => self.undo().unwrap_or_else(|| self.clone()),
180 HistoryIntent::Redo => self.redo().unwrap_or_else(|| self.clone()),
181 };
182 }
183 let new_doc = tx.tr.doc().clone();
184 let selection = if tx.selection_set {
185 tx.selection
186 } else {
187 self.selection.map(&new_doc, tx.tr.mapping())
188 };
189
190 let mut history = self.history.clone();
191 if tx.add_to_history && tx.tr.doc_changed() {
192 if let Ok(undo) = tx.tr.invert_steps() {
193 let redo: Vec<Box<dyn Step>> = tx.tr.steps().to_vec();
194 history.record(
195 HistEntry {
196 undo,
197 redo,
198 selection_before: self.selection,
199 selection_after: selection,
200 },
201 tx.join,
202 );
203 }
204 }
205
206 let plugins = self.plugins.apply(&tx, self);
208
209 EditorState {
210 doc: new_doc,
211 selection,
212 schema: self.schema.clone(),
213 history,
214 plugins,
215 }
216 }
217
218 pub fn undo(&self) -> Option<EditorState> {
220 let entry = self.history.done.last()?.clone();
221 let doc = apply_steps(&self.doc, &entry.undo, &self.schema).ok()?;
222 let mut history = self.history.clone();
223 history.done.pop();
224 history.undone.push(entry.clone());
225 Some(EditorState {
226 doc,
227 selection: entry.selection_before,
228 schema: self.schema.clone(),
229 history,
230 plugins: self.plugins.clone(),
231 })
232 }
233
234 pub fn redo(&self) -> Option<EditorState> {
236 let entry = self.history.undone.last()?.clone();
237 let doc = apply_steps(&self.doc, &entry.redo, &self.schema).ok()?;
238 let mut history = self.history.clone();
239 history.undone.pop();
240 history.done.push(entry.clone());
241 Some(EditorState {
242 doc,
243 selection: entry.selection_after,
244 schema: self.schema.clone(),
245 history,
246 plugins: self.plugins.clone(),
247 })
248 }
249}
250
251#[derive(Debug, Clone, Copy, PartialEq, Eq)]
254pub enum HistoryIntent {
255 Undo,
257 Redo,
259}
260
261#[derive(Debug, Clone)]
263pub struct Transaction {
264 tr: Transform,
265 selection: Selection,
266 selection_set: bool,
267 add_to_history: bool,
268 join: bool,
269 history_intent: Option<HistoryIntent>,
270}
271
272impl Transaction {
273 pub fn doc(&self) -> &Node {
275 self.tr.doc()
276 }
277
278 pub fn transform(&mut self) -> &mut Transform {
281 &mut self.tr
282 }
283
284 pub fn set_selection(&mut self, selection: Selection) -> &mut Self {
286 self.selection = selection;
287 self.selection_set = true;
288 self
289 }
290
291 pub fn no_history(&mut self) -> &mut Self {
293 self.add_to_history = false;
294 self
295 }
296
297 pub fn join_history(&mut self) -> &mut Self {
300 self.join = true;
301 self
302 }
303
304 pub fn doc_changed(&self) -> bool {
306 self.tr.doc_changed()
307 }
308
309 pub fn set_history_intent(&mut self, intent: HistoryIntent) -> &mut Self {
313 self.history_intent = Some(intent);
314 self
315 }
316
317 pub fn history_intent(&self) -> Option<HistoryIntent> {
319 self.history_intent
320 }
321}