diff --git a/zed/src/editor/buffer/mod.rs b/zed/src/editor/buffer/mod.rs index 074d4917e2..dd87362004 100644 --- a/zed/src/editor/buffer/mod.rs +++ b/zed/src/editor/buffer/mod.rs @@ -63,12 +63,11 @@ pub struct Buffer { file: Option, fragments: SumTree, insertion_splits: HashMap>, - edit_ops: HashMap, pub version: time::Global, saved_version: time::Global, last_edit: time::Local, undo_map: UndoMap, - undo_history: UndoHistory, + history: History, selections: HashMap>, pub selections_last_update: SelectionsVersion, deferred_ops: OperationQueue, @@ -82,9 +81,72 @@ pub struct Snapshot { fragments: SumTree, } +#[derive(Clone)] +struct EditGroup { + edits: Vec, + last_edit_at: Instant, +} + #[derive(Clone)] pub struct History { - pub base_text: String, + pub base_text: Arc, + ops: HashMap, + undo_stack: Vec, + redo_stack: Vec, + group_interval: Duration, +} + +impl History { + pub fn new(base_text: Arc) -> Self { + Self { + base_text, + ops: Default::default(), + undo_stack: Vec::new(), + redo_stack: Vec::new(), + group_interval: UNDO_GROUP_INTERVAL, + } + } + + fn push(&mut self, op: EditOperation) { + self.ops.insert(op.id, op); + } + + fn push_undo(&mut self, edit_id: time::Local, now: Instant) { + if let Some(edit_group) = self.undo_stack.last_mut() { + if now - edit_group.last_edit_at <= self.group_interval { + edit_group.edits.push(edit_id); + edit_group.last_edit_at = now; + } else { + self.undo_stack.push(EditGroup { + edits: vec![edit_id], + last_edit_at: now, + }); + } + } else { + self.undo_stack.push(EditGroup { + edits: vec![edit_id], + last_edit_at: now, + }); + } + } + + fn pop_undo(&mut self) -> Option<&EditGroup> { + if let Some(edit_group) = self.undo_stack.pop() { + self.redo_stack.push(edit_group); + self.redo_stack.last() + } else { + None + } + } + + fn pop_redo(&mut self) -> Option<&EditGroup> { + if let Some(edit_group) = self.redo_stack.pop() { + self.undo_stack.push(edit_group); + self.undo_stack.last() + } else { + None + } + } } #[derive(Clone, Debug, Eq, PartialEq)] @@ -130,66 +192,6 @@ impl UndoMap { } } -#[derive(Clone)] -struct EditGroup { - edits: Vec, - last_edit_at: Instant, -} - -#[derive(Clone)] -struct UndoHistory { - group_interval: Duration, - undo_stack: Vec, - redo_stack: Vec, -} - -impl UndoHistory { - fn new(group_interval: Duration) -> Self { - Self { - group_interval, - undo_stack: Vec::new(), - redo_stack: Vec::new(), - } - } - - fn push(&mut self, edit_id: time::Local, now: Instant) { - if let Some(edit_group) = self.undo_stack.last_mut() { - if now - edit_group.last_edit_at <= self.group_interval { - edit_group.edits.push(edit_id); - edit_group.last_edit_at = now; - } else { - self.undo_stack.push(EditGroup { - edits: vec![edit_id], - last_edit_at: now, - }); - } - } else { - self.undo_stack.push(EditGroup { - edits: vec![edit_id], - last_edit_at: now, - }); - } - } - - fn pop_undo(&mut self) -> Option<&EditGroup> { - if let Some(edit_group) = self.undo_stack.pop() { - self.redo_stack.push(edit_group); - self.redo_stack.last() - } else { - None - } - } - - fn pop_redo(&mut self) -> Option<&EditGroup> { - if let Some(edit_group) = self.redo_stack.pop() { - self.undo_stack.push(edit_group); - self.undo_stack.last() - } else { - None - } - } -} - #[derive(Clone)] pub struct CharIter<'a> { fragments_cursor: Cursor<'a, Fragment, usize, usize>, @@ -305,15 +307,15 @@ pub struct UndoOperation { } impl Buffer { - pub fn new>(replica_id: ReplicaId, base_text: T) -> Self { - Self::build(replica_id, None, base_text.into()) + pub fn new>>(replica_id: ReplicaId, base_text: T) -> Self { + Self::build(replica_id, None, History::new(base_text.into())) } pub fn from_history(replica_id: ReplicaId, file: FileHandle, history: History) -> Self { - Self::build(replica_id, Some(file), history.base_text) + Self::build(replica_id, Some(file), history) } - fn build(replica_id: ReplicaId, file: Option, base_text: String) -> Self { + fn build(replica_id: ReplicaId, file: Option, history: History) -> Self { let mut insertion_splits = HashMap::default(); let mut fragments = SumTree::new(); @@ -321,7 +323,7 @@ impl Buffer { id: time::Local::default(), parent_id: time::Local::default(), offset_in_parent: 0, - text: base_text.into(), + text: history.base_text.clone().into(), lamport_timestamp: time::Lamport::default(), }; @@ -366,12 +368,11 @@ impl Buffer { file, fragments, insertion_splits, - edit_ops: HashMap::default(), version: time::Global::new(), saved_version: time::Global::new(), last_edit: time::Local::default(), undo_map: Default::default(), - undo_history: UndoHistory::new(UNDO_GROUP_INTERVAL), + history, selections: HashMap::default(), selections_last_update: 0, deferred_ops: OperationQueue::new(), @@ -602,8 +603,8 @@ impl Buffer { for op in &ops { if let Operation::Edit { edit, .. } = op { - self.edit_ops.insert(edit.id, edit.clone()); - self.undo_history.push(edit.id, now); + self.history.push(edit.clone()); + self.history.push_undo(edit.id, now); } } @@ -864,7 +865,7 @@ impl Buffer { lamport_timestamp, )?; self.version.observe(edit.id); - self.edit_ops.insert(edit.id, edit); + self.history.push(edit); } } Operation::Undo { @@ -1017,7 +1018,7 @@ impl Buffer { let old_version = self.version.clone(); let mut ops = Vec::new(); - if let Some(edit_group) = self.undo_history.pop_undo() { + if let Some(edit_group) = self.history.pop_undo() { for edit_id in edit_group.edits.clone() { ops.push(self.undo_or_redo(edit_id).unwrap()); } @@ -1039,7 +1040,7 @@ impl Buffer { let old_version = self.version.clone(); let mut ops = Vec::new(); - if let Some(edit_group) = self.undo_history.pop_redo() { + if let Some(edit_group) = self.history.pop_redo() { for edit_id in edit_group.edits.clone() { ops.push(self.undo_or_redo(edit_id).unwrap()); } @@ -1075,7 +1076,7 @@ impl Buffer { let mut new_fragments; self.undo_map.insert(undo); - let edit = &self.edit_ops[&undo.edit_id]; + let edit = &self.history.ops[&undo.edit_id]; let start_fragment_id = self.resolve_fragment_id(edit.start_id, edit.start_offset)?; let end_fragment_id = self.resolve_fragment_id(edit.end_id, edit.end_offset)?; let mut cursor = self.fragments.cursor::(); @@ -1700,12 +1701,11 @@ impl Clone for Buffer { file: self.file.clone(), fragments: self.fragments.clone(), insertion_splits: self.insertion_splits.clone(), - edit_ops: self.edit_ops.clone(), version: self.version.clone(), saved_version: self.saved_version.clone(), last_edit: self.last_edit.clone(), undo_map: self.undo_map.clone(), - undo_history: self.undo_history.clone(), + history: self.history.clone(), selections: self.selections.clone(), selections_last_update: self.selections_last_update.clone(), deferred_ops: self.deferred_ops.clone(), @@ -3076,7 +3076,7 @@ mod tests { pub fn randomly_undo_redo(&mut self, rng: &mut impl Rng) -> Vec { let mut ops = Vec::new(); for _ in 0..rng.gen_range(1..5) { - if let Some(edit_id) = self.edit_ops.keys().choose(rng).copied() { + if let Some(edit_id) = self.history.ops.keys().choose(rng).copied() { ops.push(self.undo_or_redo(edit_id).unwrap()); } } diff --git a/zed/src/editor/buffer/text.rs b/zed/src/editor/buffer/text.rs index 147ffdd86a..0fff5c81d1 100644 --- a/zed/src/editor/buffer/text.rs +++ b/zed/src/editor/buffer/text.rs @@ -117,6 +117,18 @@ pub struct Text { impl From for Text { fn from(text: String) -> Self { + Self::from(Arc::from(text)) + } +} + +impl<'a> From<&'a str> for Text { + fn from(text: &'a str) -> Self { + Self::from(Arc::from(text)) + } +} + +impl From> for Text { + fn from(text: Arc) -> Self { let mut runs = Vec::new(); let mut chars_len = 0; @@ -147,19 +159,13 @@ impl From for Text { let mut tree = SumTree::new(); tree.extend(runs); Text { - text: text.into(), + text, runs: tree, range: 0..chars_len, } } } -impl<'a> From<&'a str> for Text { - fn from(text: &'a str) -> Self { - Self::from(String::from(text)) - } -} - impl Debug for Text { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("Text").field(&self.as_str()).finish() diff --git a/zed/src/worktree/worktree.rs b/zed/src/worktree/worktree.rs index bbb264df62..3072ce2904 100644 --- a/zed/src/worktree/worktree.rs +++ b/zed/src/worktree/worktree.rs @@ -345,7 +345,7 @@ impl Worktree { let mut file = smol::fs::File::open(&path).await?; let mut base_text = String::new(); file.read_to_string(&mut base_text).await?; - let history = History { base_text }; + let history = History::new(Arc::from(base_text)); tree.0.write().histories.insert(entry_id, history.clone()); Ok(history) } @@ -717,7 +717,7 @@ mod test { .await .unwrap(); - assert_eq!(history.base_text, buffer.text()); + assert_eq!(history.base_text.as_ref(), buffer.text()); }) } }