diff --git a/Cargo.lock b/Cargo.lock index 21a08332c5e08e81c35c0d9d4db343a38983d0d6..d6e0804b04a7f9d441d0d30aebfd2fe4e9817d8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2188,6 +2188,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" +[[package]] +name = "ropey" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f3ef16589fdbb3e8fbce3dca944c08e61f39c7f16064b21a257d68ea911a83" +dependencies = [ + "smallvec", +] + [[package]] name = "roxmltree" version = "0.14.1" @@ -2978,6 +2987,7 @@ dependencies = [ "parking_lot", "postage", "rand 0.8.3", + "ropey", "rust-embed", "seahash", "serde 1.0.125", diff --git a/zed/Cargo.toml b/zed/Cargo.toml index 2302fc650954c18cb5ee21b902087436575e8006..370f580484df803ac439fe52942fbea1e3e9257b 100644 --- a/zed/Cargo.toml +++ b/zed/Cargo.toml @@ -31,6 +31,7 @@ num_cpus = "1.13.0" parking_lot = "0.11.1" postage = {version = "0.4.1", features = ["futures-traits"]} rand = "0.8.3" +ropey = "1.2" rust-embed = "5.9.0" seahash = "4.1" serde = {version = "1", features = ["derive"]} diff --git a/zed/src/editor/buffer/mod.rs b/zed/src/editor/buffer/mod.rs index 1bdf050f0539dba4553782d41f82e07abfe6fde2..a2caa6cb380a224f9f9266acc5e30bb7d002a461 100644 --- a/zed/src/editor/buffer/mod.rs +++ b/zed/src/editor/buffer/mod.rs @@ -5,6 +5,7 @@ mod text; pub use anchor::*; pub use point::*; +use ropey::Rope; use seahash::SeaHasher; pub use selection::*; use similar::{ChangeTag, TextDiff}; @@ -25,6 +26,7 @@ use std::{ cmp, hash::BuildHasher, iter::{self, Iterator}, + mem, ops::{AddAssign, Range}, str, sync::Arc, @@ -57,6 +59,8 @@ type HashMap = std::collections::HashMap; type HashSet = std::collections::HashSet; pub struct Buffer { + visible_text: Rope, + deleted_text: Rope, fragments: SumTree, insertion_splits: HashMap>, pub version: time::Global, @@ -92,6 +96,7 @@ struct Transaction { #[derive(Clone)] pub struct History { + // TODO: Turn this into a String or Rope, maybe. pub base_text: Arc, ops: HashMap, undo_stack: Vec, @@ -285,15 +290,14 @@ pub struct Insertion { id: time::Local, parent_id: time::Local, offset_in_parent: usize, - text: Text, lamport_timestamp: time::Lamport, } #[derive(Eq, PartialEq, Clone, Debug)] struct Fragment { id: FragmentId, - insertion: Insertion, - text: Text, + insertion: Arc, + range_in_insertion: Range, deletions: HashSet, max_undos: time::Global, visible: bool, @@ -301,11 +305,24 @@ struct Fragment { #[derive(Eq, PartialEq, Clone, Debug)] pub struct FragmentSummary { - text_summary: TextSummary, + text: FragmentTextSummary, max_fragment_id: FragmentId, max_version: time::Global, } +#[derive(Default, Clone, Debug, PartialEq, Eq)] +struct FragmentTextSummary { + visible: TextSummary, + deleted: TextSummary, +} + +impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FragmentTextSummary { + fn add_summary(&mut self, summary: &'a FragmentSummary) { + self.visible += &summary.text.visible; + self.deleted += &summary.text.deleted; + } +} + #[derive(Eq, PartialEq, Clone, Debug, Ord, PartialOrd)] struct FragmentExtent { chars: usize, @@ -348,7 +365,7 @@ pub struct EditOperation { end_id: time::Local, end_offset: usize, version_in_range: time::Global, - new_text: Option, + new_text: Option, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -418,16 +435,17 @@ impl Buffer { saved_mtime = UNIX_EPOCH; } + let mut visible_text = Rope::new(); let mut insertion_splits = HashMap::default(); let mut fragments = SumTree::new(); - let base_insertion = Insertion { + let base_text = Rope::from(history.base_text.as_ref()); + let base_insertion = Arc::new(Insertion { id: time::Local::default(), parent_id: time::Local::default(), offset_in_parent: 0, - text: history.base_text.clone().into(), lamport_timestamp: time::Lamport::default(), - }; + }); insertion_splits.insert( base_insertion.id, @@ -437,45 +455,43 @@ impl Buffer { extent: 0, }, &(), + &(), ), ); fragments.push( - Fragment { - id: FragmentId::min_value().clone(), - insertion: base_insertion.clone(), - text: base_insertion.text.slice(0..0), - deletions: Default::default(), - max_undos: Default::default(), - visible: true, - }, + Fragment::new( + FragmentId::min_value().clone(), + base_insertion.clone(), + 0..0, + ), + &FragmentContext::default(), &(), ); - if base_insertion.text.len() > 0 { + if base_text.len_chars() > 0 { let base_fragment_id = FragmentId::between(&FragmentId::min_value(), &FragmentId::max_value()); + let range_in_insertion = 0..base_text.len_chars(); + visible_text = base_text.clone(); insertion_splits.get_mut(&base_insertion.id).unwrap().push( InsertionSplit { fragment_id: base_fragment_id.clone(), - extent: base_insertion.text.len(), + extent: range_in_insertion.end, }, &(), + &(), ); fragments.push( - Fragment { - id: base_fragment_id, - text: base_insertion.text.clone(), - insertion: base_insertion, - deletions: Default::default(), - max_undos: Default::default(), - visible: true, - }, + Fragment::new(base_fragment_id, base_insertion, range_in_insertion.clone()), + &FragmentContext::new(base_text, Rope::new(), Default::default()), &(), ); } Self { + visible_text, + deleted_text: Rope::new(), fragments, insertion_splits, version: time::Global::new(), @@ -613,29 +629,7 @@ impl Buffer { } pub fn text_summary_for_range(&self, range: Range) -> TextSummary { - let mut summary = TextSummary::default(); - - let mut cursor = self.fragments.cursor::(); - cursor.seek(&range.start, SeekBias::Right, &()); - - if let Some(fragment) = cursor.item() { - let summary_start = cmp::max(*cursor.start(), range.start) - cursor.start(); - let summary_end = cmp::min(range.end - cursor.start(), fragment.len()); - summary += fragment.text.slice(summary_start..summary_end).summary(); - cursor.next(); - } - - if range.end > *cursor.start() { - summary += cursor.summary::(&range.end, SeekBias::Right, &()); - - if let Some(fragment) = cursor.item() { - let summary_start = cmp::max(*cursor.start(), range.start) - cursor.start(); - let summary_end = cmp::min(range.end - cursor.start(), fragment.len()); - summary += fragment.text.slice(summary_start..summary_end).summary(); - } - } - - summary + TextSummary::from(self.visible_text.slice(range)) } pub fn len(&self) -> usize { @@ -654,37 +648,39 @@ impl Buffer { } pub fn rightmost_point(&self) -> Point { - self.fragments.summary().text_summary.rightmost_point + todo!() + // self.fragments.summary().text_summary.rightmost_point } pub fn rightmost_point_in_range(&self, range: Range) -> Point { - let mut summary = TextSummary::default(); + todo!() + // let mut summary = TextSummary::default(); - let mut cursor = self.fragments.cursor::(); - cursor.seek(&range.start, SeekBias::Right, &()); + // let mut cursor = self.fragments.cursor::(); + // cursor.seek(&range.start, SeekBias::Right, &()); - if let Some(fragment) = cursor.item() { - let summary_start = cmp::max(*cursor.start(), range.start) - cursor.start(); - let summary_end = cmp::min(range.end - cursor.start(), fragment.len()); - summary += fragment.text.slice(summary_start..summary_end).summary(); - cursor.next(); - } + // if let Some(fragment) = cursor.item() { + // let summary_start = cmp::max(*cursor.start(), range.start) - cursor.start(); + // let summary_end = cmp::min(range.end - cursor.start(), fragment.len()); + // summary += fragment.text.slice(summary_start..summary_end).summary(); + // cursor.next(); + // } - if range.end > *cursor.start() { - summary += cursor.summary::(&range.end, SeekBias::Right, &()); + // if range.end > *cursor.start() { + // summary += cursor.summary::(&range.end, SeekBias::Right, &()); - if let Some(fragment) = cursor.item() { - let summary_start = cmp::max(*cursor.start(), range.start) - cursor.start(); - let summary_end = cmp::min(range.end - cursor.start(), fragment.len()); - summary += fragment.text.slice(summary_start..summary_end).summary(); - } - } + // if let Some(fragment) = cursor.item() { + // let summary_start = cmp::max(*cursor.start(), range.start) - cursor.start(); + // let summary_end = cmp::min(range.end - cursor.start(), fragment.len()); + // summary += fragment.text.slice(summary_start..summary_end).summary(); + // } + // } - summary.rightmost_point + // summary.rightmost_point } pub fn max_point(&self) -> Point { - self.fragments.extent() + TextSummary::from(&self.visible_text).lines } pub fn line(&self, row: u32) -> Result { @@ -807,7 +803,7 @@ impl Buffer { where I: IntoIterator>, S: ToOffset, - T: Into, + T: Into, { self.start_transaction_at(None, Instant::now())?; @@ -827,7 +823,7 @@ impl Buffer { old_ranges .into_iter() .filter(|old_range| new_text.is_some() || old_range.end > old_range.start), - new_text.clone(), + new_text.into(), ); for op in &ops { @@ -1022,7 +1018,7 @@ impl Buffer { edit.start_offset, edit.end_id, edit.end_offset, - edit.new_text.as_ref().cloned(), + edit.new_text.as_deref(), &edit.version_in_range, edit.id, lamport_timestamp, @@ -1064,12 +1060,11 @@ impl Buffer { start_offset: usize, end_id: time::Local, end_offset: usize, - new_text: Option, + new_text: Option<&str>, version_in_range: &time::Global, local_timestamp: time::Local, lamport_timestamp: time::Lamport, ) -> Result<()> { - let mut new_text = new_text.as_ref().cloned(); let start_fragment_id = self.resolve_fragment_id(start_id, start_offset)?; let end_fragment_id = self.resolve_fragment_id(end_id, end_offset)?; @@ -1077,12 +1072,24 @@ impl Buffer { let last_id = old_fragments.extent::().0.unwrap(); let last_id_ref = FragmentIdRef::new(&last_id); - let mut cursor = old_fragments.cursor::(); + let mut cursor = old_fragments.cursor::(); let mut new_fragments = cursor.slice(&FragmentIdRef::new(&start_fragment_id), SeekBias::Left, &()); + let mut new_visible_text = self.visible_text.clone(); + let mut new_deleted_text = self.deleted_text.clone(); - if start_offset == cursor.item().unwrap().end_offset() { - new_fragments.push(cursor.item().unwrap().clone(), &()); + let start_fragment = cursor.item().unwrap(); + if start_offset == start_fragment.range_in_insertion.end { + // TODO: maybe don't recompute this fragment and its summary. + new_fragments.push( + cursor.item().unwrap().clone(), + &FragmentContext::new( + new_visible_text.clone(), + new_deleted_text.clone(), + cursor.start().clone(), + ), + &(), + ); cursor.next(); } @@ -1097,12 +1104,12 @@ impl Buffer { let split_start = if start_fragment_id == fragment.id { start_offset } else { - fragment.start_offset() + fragment.range_in_insertion.start }; let split_end = if end_fragment_id == fragment.id { end_offset } else { - fragment.end_offset() + fragment.range_in_insertion.end }; let (before_range, within_range, after_range) = self.split_fragment( cursor.prev_item().as_ref().unwrap(), @@ -1121,30 +1128,84 @@ impl Buffer { None }; if let Some(fragment) = before_range { - new_fragments.push(fragment, &()); + new_fragments.push( + fragment, + &FragmentContext::new( + new_visible_text.clone(), + new_deleted_text.clone(), + new_fragments.summary().text, + ), + &(), + ); } if let Some(fragment) = insertion { - new_fragments.push(fragment, &()); + new_visible_text.insert( + new_fragments.summary().text.visible.chars, + new_text.unwrap(), + ); + new_fragments.push( + fragment, + &FragmentContext::new( + new_visible_text.clone(), + new_deleted_text.clone(), + new_fragments.summary().text, + ), + &(), + ); } if let Some(mut fragment) = within_range { if fragment.was_visible(&version_in_range, &self.undo_map) { fragment.deletions.insert(local_timestamp); fragment.visible = false; + + // TODO: avoid calling to_string on rope slice. + let deleted_start = new_fragments.summary().text.visible.chars; + let deleted_range = deleted_start..deleted_start + fragment.len(); + new_deleted_text.insert( + new_fragments.summary().text.deleted.chars, + &new_visible_text.slice(deleted_range).to_string(), + ); + new_visible_text.remove(deleted_range); } - new_fragments.push(fragment, &()); + + new_fragments.push( + fragment, + &FragmentContext::new( + new_visible_text.clone(), + new_deleted_text.clone(), + new_fragments.summary().text, + ), + &(), + ); } if let Some(fragment) = after_range { - new_fragments.push(fragment, &()); + new_fragments.push( + fragment, + &FragmentContext::new( + new_visible_text.clone(), + new_deleted_text.clone(), + new_fragments.summary().text, + ), + &(), + ); } } else { if new_text.is_some() && lamport_timestamp > fragment.insertion.lamport_timestamp { + let new_text = new_text.take().unwrap(); + let fragment = self.build_fragment_to_insert( + cursor.prev_item().as_ref().unwrap(), + Some(&fragment), + new_text, + local_timestamp, + lamport_timestamp, + ); + new_visible_text.insert(new_fragments.summary().text.visible.chars, new_text); new_fragments.push( - self.build_fragment_to_insert( - cursor.prev_item().as_ref().unwrap(), - Some(&fragment), - new_text.take().unwrap(), - local_timestamp, - lamport_timestamp, + fragment, + &FragmentContext::new( + new_visible_text.clone(), + new_deleted_text.clone(), + new_fragments.summary().text, ), &(), ); @@ -1155,27 +1216,54 @@ impl Buffer { { fragment.deletions.insert(local_timestamp); fragment.visible = false; + + // TODO: avoid calling to_string on rope slice. + let deleted_start = new_fragments.summary().text.visible.chars; + let deleted_range = deleted_start..deleted_start + fragment.len(); + new_deleted_text.insert( + new_fragments.summary().text.deleted.chars, + &new_visible_text.slice(deleted_range).to_string(), + ); + new_visible_text.remove(deleted_range); } - new_fragments.push(fragment, &()); + + new_fragments.push( + fragment, + &FragmentContext::new( + new_visible_text.clone(), + new_deleted_text.clone(), + new_fragments.summary().text, + ), + &(), + ); } cursor.next(); } if let Some(new_text) = new_text { + let fragment = self.build_fragment_to_insert( + cursor.prev_item().as_ref().unwrap(), + None, + new_text, + local_timestamp, + lamport_timestamp, + ); + new_visible_text.insert(new_fragments.summary().text.visible.chars, new_text); new_fragments.push( - self.build_fragment_to_insert( - cursor.prev_item().as_ref().unwrap(), - None, - new_text, - local_timestamp, - lamport_timestamp, + fragment, + &FragmentContext::new( + new_visible_text.clone(), + new_deleted_text.clone(), + new_fragments.summary().text, ), &(), ); } new_fragments.push_tree(cursor.slice(&last_id_ref, SeekBias::Right, &()), &()); + self.visible_text = new_visible_text; + self.deleted_text = new_deleted_text; self.fragments = new_fragments; self.local_clock.observe(local_timestamp); self.lamport_clock.observe(lamport_timestamp); @@ -1251,6 +1339,8 @@ impl Buffer { fn apply_undo(&mut self, undo: UndoOperation) -> Result<()> { let mut new_fragments; + let mut new_visible_text = self.visible_text.clone(); + let mut new_deleted_text = self.deleted_text.clone(); self.undo_map.insert(undo); let edit = &self.history.ops[&undo.edit_id]; @@ -1267,9 +1357,38 @@ impl Buffer { loop { let mut fragment = cursor.item().unwrap().clone(); - fragment.visible = fragment.is_visible(&self.undo_map); + let was_visible = + mem::replace(&mut fragment.visible, fragment.is_visible(&self.undo_map)); fragment.max_undos.observe(undo.id); - new_fragments.push(fragment, &()); + + // TODO: avoid calling to_string on rope slice. + if fragment.visible && !was_visible { + let visible_start = new_fragments.summary().text.deleted.chars; + let visible_range = visible_start..visible_start + fragment.len(); + new_visible_text.insert( + new_fragments.summary().text.visible.chars, + &new_deleted_text.slice(visible_range).to_string(), + ); + new_deleted_text.remove(visible_range); + } else if !fragment.visible && was_visible { + let deleted_start = new_fragments.summary().text.visible.chars; + let deleted_range = deleted_start..deleted_start + fragment.len(); + new_deleted_text.insert( + new_fragments.summary().text.deleted.chars, + &new_visible_text.slice(deleted_range).to_string(), + ); + new_visible_text.remove(deleted_range); + } + + new_fragments.push( + fragment, + &FragmentContext::new( + new_visible_text.clone(), + new_deleted_text.clone(), + new_fragments.summary().text, + ), + &(), + ); cursor.next(); if let Some(split_id) = insertion_splits.next() { new_fragments.push_tree( @@ -1291,10 +1410,41 @@ impl Buffer { if edit.version_in_range.observed(fragment.insertion.id) || fragment.insertion.id == undo.edit_id { - fragment.visible = fragment.is_visible(&self.undo_map); + let was_visible = mem::replace( + &mut fragment.visible, + fragment.is_visible(&self.undo_map), + ); fragment.max_undos.observe(undo.id); + + // TODO: avoid calling to_string on rope slice. + if fragment.visible && !was_visible { + let visible_start = new_fragments.summary().text.deleted.chars; + let visible_range = visible_start..visible_start + fragment.len(); + new_visible_text.insert( + new_fragments.summary().text.visible.chars, + &new_deleted_text.slice(visible_range).to_string(), + ); + new_deleted_text.remove(visible_range); + } else if !fragment.visible && was_visible { + let deleted_start = new_fragments.summary().text.visible.chars; + let deleted_range = deleted_start..deleted_start + fragment.len(); + new_deleted_text.insert( + new_fragments.summary().text.deleted.chars, + &new_visible_text.slice(deleted_range).to_string(), + ); + new_visible_text.remove(deleted_range); + } } - new_fragments.push(fragment, &()); + + new_fragments.push( + fragment, + &FragmentContext::new( + new_visible_text.clone(), + new_deleted_text.clone(), + new_fragments.summary().text, + ), + &(), + ); cursor.next(); } } @@ -1372,7 +1522,7 @@ impl Buffer { .clone()) } - fn splice_fragments(&mut self, mut old_ranges: I, new_text: Option) -> Vec + fn splice_fragments(&mut self, mut old_ranges: I, new_text: Option) -> Vec where I: Iterator>, { @@ -1386,6 +1536,9 @@ impl Buffer { let old_fragments = self.fragments.clone(); let mut cursor = old_fragments.cursor::(); let mut new_fragments = SumTree::new(); + let mut new_visible_text = self.visible_text.clone(); + let mut new_deleted_text = self.deleted_text.clone(); + new_fragments.push_tree( cursor.slice(&cur_range.as_ref().unwrap().start, SeekBias::Right, &()), &(), @@ -1412,7 +1565,7 @@ impl Buffer { .unwrap(); let mut splits_cursor = old_split_tree.cursor::(); let mut new_split_tree = - splits_cursor.slice(&fragment.start_offset(), SeekBias::Right, &()); + splits_cursor.slice(&fragment.range_in_insertion.start, SeekBias::Right, &()); // Find all splices that start or end within the current fragment. Then, split the // fragment and reassemble it in both trees accounting for the deleted and the newly @@ -1421,38 +1574,43 @@ impl Buffer { let range = cur_range.clone().unwrap(); if range.start > fragment_start { let mut prefix = fragment.clone(); - prefix.set_end_offset(prefix.start_offset() + (range.start - fragment_start)); + prefix.range_in_insertion.end = + prefix.range_in_insertion.start + (range.start - fragment_start); prefix.id = FragmentId::between(&new_fragments.last().unwrap().id, &fragment.id); - fragment.set_start_offset(prefix.end_offset()); - new_fragments.push(prefix.clone(), &()); + fragment.range_in_insertion.start = prefix.range_in_insertion.end; + new_fragments.push( + prefix.clone(), + &FragmentContext::new(new_visible_text.clone()) & (), + ); new_split_tree.push( InsertionSplit { - extent: prefix.end_offset() - prefix.start_offset(), + extent: prefix.range_in_insertion.end - prefix.range_in_insertion.start, fragment_id: prefix.id, }, &(), + &(), ); fragment_start = range.start; } if range.end == fragment_start { end_id = Some(new_fragments.last().unwrap().insertion.id); - end_offset = Some(new_fragments.last().unwrap().end_offset()); + end_offset = Some(new_fragments.last().unwrap().range_in_insertion.end); } else if range.end == fragment_end { end_id = Some(fragment.insertion.id); - end_offset = Some(fragment.end_offset()); + end_offset = Some(fragment.range_in_insertion.end); } if range.start == fragment_start { start_id = Some(new_fragments.last().unwrap().insertion.id); - start_offset = Some(new_fragments.last().unwrap().end_offset()); + start_offset = Some(new_fragments.last().unwrap().range_in_insertion.end); if let Some(new_text) = new_text.clone() { let new_fragment = self.build_fragment_to_insert( &new_fragments.last().unwrap(), Some(&fragment), - new_text, + &new_text, local_timestamp, lamport_timestamp, ); @@ -1463,7 +1621,8 @@ impl Buffer { if range.end < fragment_end { if range.end > fragment_start { let mut prefix = fragment.clone(); - prefix.set_end_offset(prefix.start_offset() + (range.end - fragment_start)); + prefix.range_in_insertion.end = + prefix.range_in_insertion.start + (range.end - fragment_start); prefix.id = FragmentId::between(&new_fragments.last().unwrap().id, &fragment.id); version_in_range.observe_all(&fragment_summary.max_version); @@ -1471,18 +1630,19 @@ impl Buffer { prefix.deletions.insert(local_timestamp); prefix.visible = false; } - fragment.set_start_offset(prefix.end_offset()); + fragment.range_in_insertion.start = prefix.range_in_insertion.end; new_fragments.push(prefix.clone(), &()); new_split_tree.push( InsertionSplit { - extent: prefix.end_offset() - prefix.start_offset(), + extent: prefix.range_in_insertion.end + - prefix.range_in_insertion.start, fragment_id: prefix.id, }, &(), ); fragment_start = range.end; end_id = Some(fragment.insertion.id); - end_offset = Some(fragment.start_offset()); + end_offset = Some(fragment.range_in_insertion.start); } } else { version_in_range.observe_all(&fragment_summary.max_version); @@ -1525,7 +1685,7 @@ impl Buffer { } new_split_tree.push( InsertionSplit { - extent: fragment.end_offset() - fragment.start_offset(), + extent: fragment.range_in_insertion.end - fragment.range_in_insertion.start, fragment_id: fragment.id.clone(), }, &(), @@ -1558,7 +1718,7 @@ impl Buffer { if range.end == fragment_end { end_id = Some(fragment.insertion.id); - end_offset = Some(fragment.end_offset()); + end_offset = Some(fragment.range_in_insertion.end); ops.push(Operation::Edit { edit: EditOperation { id: local_timestamp, @@ -1611,9 +1771,9 @@ impl Buffer { edit: EditOperation { id: local_timestamp, start_id: last_fragment.insertion.id, - start_offset: last_fragment.end_offset(), + start_offset: last_fragment.range_in_insertion.end, end_id: last_fragment.insertion.id, - end_offset: last_fragment.end_offset(), + end_offset: last_fragment.range_in_insertion.end, version_in_range: time::Global::new(), new_text: new_text.clone(), }, @@ -1647,24 +1807,26 @@ impl Buffer { fragment: &Fragment, range: Range, ) -> (Option, Option, Option) { - debug_assert!(range.start >= fragment.start_offset()); - debug_assert!(range.start <= fragment.end_offset()); - debug_assert!(range.end <= fragment.end_offset()); - debug_assert!(range.end >= fragment.start_offset()); + debug_assert!(range.start >= fragment.range_in_insertion.start); + debug_assert!(range.start <= fragment.range_in_insertion.end); + debug_assert!(range.end <= fragment.range_in_insertion.end); + debug_assert!(range.end >= fragment.range_in_insertion.start); - if range.end == fragment.start_offset() { + if range.end == fragment.range_in_insertion.start { (None, None, Some(fragment.clone())) - } else if range.start == fragment.end_offset() { + } else if range.start == fragment.range_in_insertion.end { (Some(fragment.clone()), None, None) - } else if range.start == fragment.start_offset() && range.end == fragment.end_offset() { + } else if range.start == fragment.range_in_insertion.start + && range.end == fragment.range_in_insertion.end + { (None, Some(fragment.clone()), None) } else { let mut prefix = fragment.clone(); - let after_range = if range.end < fragment.end_offset() { + let after_range = if range.end < fragment.range_in_insertion.end { let mut suffix = prefix.clone(); - suffix.set_start_offset(range.end); - prefix.set_end_offset(range.end); + suffix.range_in_insertion.start = range.end; + prefix.range_in_insertion.end = range.end; prefix.id = FragmentId::between(&prev_fragment.id, &suffix.id); Some(suffix) } else { @@ -1673,15 +1835,15 @@ impl Buffer { let within_range = if range.start != range.end { let mut suffix = prefix.clone(); - suffix.set_start_offset(range.start); - prefix.set_end_offset(range.start); + suffix.range_in_insertion.start = range.start; + prefix.range_in_insertion.end = range.start; prefix.id = FragmentId::between(&prev_fragment.id, &suffix.id); Some(suffix) } else { None }; - let before_range = if range.start > fragment.start_offset() { + let before_range = if range.start > fragment.range_in_insertion.start { Some(prefix) } else { None @@ -1692,15 +1854,17 @@ impl Buffer { .remove(&fragment.insertion.id) .unwrap(); let mut cursor = old_split_tree.cursor::(); - let mut new_split_tree = cursor.slice(&fragment.start_offset(), SeekBias::Right, &()); + let mut new_split_tree = + cursor.slice(&fragment.range_in_insertion.start, SeekBias::Right, &()); if let Some(ref fragment) = before_range { new_split_tree.push( InsertionSplit { - extent: range.start - fragment.start_offset(), + extent: range.start - fragment.range_in_insertion.start, fragment_id: fragment.id.clone(), }, &(), + &(), ); } @@ -1711,16 +1875,18 @@ impl Buffer { fragment_id: fragment.id.clone(), }, &(), + &(), ); } if let Some(ref fragment) = after_range { new_split_tree.push( InsertionSplit { - extent: fragment.end_offset() - range.end, + extent: fragment.range_in_insertion.end - range.end, fragment_id: fragment.id.clone(), }, &(), + &(), ); } @@ -1741,8 +1907,8 @@ impl Buffer { &mut self, prev_fragment: &Fragment, next_fragment: Option<&Fragment>, - text: Text, - local_timestamp: time::Local, + text: &str, + insertion_id: time::Local, lamport_timestamp: time::Lamport, ) -> Fragment { let new_fragment_id = FragmentId::between( @@ -1752,25 +1918,28 @@ impl Buffer { .unwrap_or(&FragmentId::max_value()), ); + // TODO: extent could be expressed in bytes, which would save a linear scan. + let range_in_insertion = 0..text.chars().count(); let mut split_tree = SumTree::new(); split_tree.push( InsertionSplit { - extent: text.len(), + extent: range_in_insertion.len(), fragment_id: new_fragment_id.clone(), }, &(), + &(), ); - self.insertion_splits.insert(local_timestamp, split_tree); + self.insertion_splits.insert(insertion_id, split_tree); Fragment::new( new_fragment_id, - Insertion { - id: local_timestamp, + Arc::new(Insertion { + id: insertion_id, parent_id: prev_fragment.insertion.id, - offset_in_parent: prev_fragment.end_offset(), - text, + offset_in_parent: prev_fragment.range_in_insertion.end, lamport_timestamp, - }, + }), + range_in_insertion, ) } @@ -1811,7 +1980,7 @@ impl Buffer { cursor.seek(&offset, seek_bias, &()); let fragment = cursor.item().unwrap(); let offset_in_fragment = offset - cursor.start(); - let offset_in_insertion = fragment.start_offset() + offset_in_fragment; + let offset_in_insertion = fragment.range_in_insertion.start + offset_in_fragment; let anchor = Anchor::Middle { insertion_id: fragment.insertion.id, offset: offset_in_insertion, @@ -1883,7 +2052,7 @@ impl Buffer { if fragment.visible { summary += fragment .text - .slice(..offset - fragment.start_offset()) + .slice(..offset - fragment.range_in_insertion.start) .summary(); } Ok(summary) @@ -1910,6 +2079,7 @@ impl Buffer { impl Clone for Buffer { fn clone(&self) -> Self { Self { + visible_text: self.visible_text.clone(), fragments: self.fragments.clone(), insertion_splits: self.insertion_splits.clone(), version: self.version.clone(), @@ -2205,45 +2375,17 @@ impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FragmentIdRef<'a> { } impl Fragment { - fn new(id: FragmentId, insertion: Insertion) -> Self { + fn new(id: FragmentId, insertion: Arc, range_in_insertion: Range) -> Self { Self { id, - text: insertion.text.clone(), insertion, + range_in_insertion, deletions: Default::default(), max_undos: Default::default(), visible: true, } } - fn start_offset(&self) -> usize { - self.text.range().start - } - - fn set_start_offset(&mut self, offset: usize) { - self.text = self.insertion.text.slice(offset..self.end_offset()); - } - - fn end_offset(&self) -> usize { - self.text.range().end - } - - fn set_end_offset(&mut self, offset: usize) { - self.text = self.insertion.text.slice(self.start_offset()..offset); - } - - fn visible_len(&self) -> usize { - if self.visible { - self.len() - } else { - 0 - } - } - - fn len(&self) -> usize { - self.text.len() - } - fn is_visible(&self, undos: &UndoMap) -> bool { !undos.is_undone(self.insertion.id) && self.deletions.iter().all(|d| undos.is_undone(*d)) } @@ -2256,19 +2398,41 @@ impl Fragment { .all(|d| !version.observed(*d) || undos.was_undone(*d, version)) } - fn point_for_offset(&self, offset: usize) -> Result { - Ok(self.text.point_for_offset(offset)) + fn len(&self) -> usize { + self.range_in_insertion.len() } - fn offset_for_point(&self, point: Point) -> Result { - Ok(self.text.offset_for_point(point)) + fn visible_len(&self) -> usize { + if self.visible { + self.range_in_insertion.len() + } else { + 0 + } + } +} + +#[derive(Default)] +struct FragmentContext { + visible_text: Rope, + deleted_text: Rope, + start: FragmentTextSummary, +} + +impl FragmentContext { + fn new(visible_text: Rope, deleted_text: Rope, start: FragmentTextSummary) -> Self { + Self { + visible_text, + deleted_text, + start, + } } } impl sum_tree::Item for Fragment { + type Context = FragmentContext; type Summary = FragmentSummary; - fn summary(&self) -> Self::Summary { + fn summary(&self, ctx: &FragmentContext) -> Self::Summary { let mut max_version = time::Global::new(); max_version.observe(self.insertion.id); for deletion in &self.deletions { @@ -2277,14 +2441,22 @@ impl sum_tree::Item for Fragment { max_version.observe_all(&self.max_undos); if self.visible { + let start = ctx.start.visible.chars; FragmentSummary { - text_summary: self.text.summary(), + text: FragmentTextSummary { + visible: TextSummary::from(ctx.visible_text.slice(start..start + self.len())), + deleted: TextSummary::default(), + }, max_fragment_id: self.id.clone(), max_version, } } else { + let start = ctx.start.deleted.chars; FragmentSummary { - text_summary: TextSummary::default(), + text: FragmentTextSummary { + visible: TextSummary::default(), + deleted: TextSummary::from(ctx.deleted_text.slice(start..start + self.len())), + }, max_fragment_id: self.id.clone(), max_version, } @@ -2295,8 +2467,9 @@ impl sum_tree::Item for Fragment { impl sum_tree::Summary for FragmentSummary { type Context = (); - fn add_summary(&mut self, other: &Self, _: &()) { - self.text_summary += &other.text_summary; + fn add_summary(&mut self, other: &Self, _: &Self::Context) { + self.text.visible += &other.text.visible; + self.text.deleted += &other.text.deleted; debug_assert!(self.max_fragment_id <= other.max_fragment_id); self.max_fragment_id = other.max_fragment_id.clone(); self.max_version.observe_all(&other.max_version); @@ -2306,7 +2479,7 @@ impl sum_tree::Summary for FragmentSummary { impl Default for FragmentSummary { fn default() -> Self { FragmentSummary { - text_summary: TextSummary::default(), + text: FragmentTextSummary::default(), max_fragment_id: FragmentId::min_value().clone(), max_version: time::Global::new(), } @@ -2349,9 +2522,10 @@ impl<'a> sum_tree::Dimension<'a, FragmentSummary> for usize { } impl sum_tree::Item for InsertionSplit { + type Context = (); type Summary = InsertionSplitSummary; - fn summary(&self) -> Self::Summary { + fn summary(&self, _: &()) -> Self::Summary { InsertionSplitSummary { extent: self.extent, } diff --git a/zed/src/editor/buffer/text.rs b/zed/src/editor/buffer/text.rs index 03b8b528547c5abab29bd6e650835044a9ebe684..715c6774628f075accb988a4899d94702087ecde 100644 --- a/zed/src/editor/buffer/text.rs +++ b/zed/src/editor/buffer/text.rs @@ -1,84 +1,45 @@ -use super::Point; -use crate::sum_tree::{self, SeekBias, SumTree}; -use arrayvec::ArrayVec; -use std::{ - cmp, - fmt::{self, Debug}, - ops::{Bound, Index, Range, RangeBounds}, - sync::Arc, -}; - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -enum Run { - Newline, - Chars { len: usize, char_size: u8 }, -} - -#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)] -struct ByteOffset(usize); +use ropey::{Rope, RopeSlice}; -impl sum_tree::Item for Run { - type Summary = TextSummary; - - fn summary(&self) -> Self::Summary { - match *self { - Run::Newline => TextSummary { - chars: 1, - bytes: 1, - lines: Point::new(1, 0), - first_line_len: 0, - rightmost_point: Point::new(0, 0), - }, - Run::Chars { len, char_size } => TextSummary { - chars: len, - bytes: len * char_size as usize, - lines: Point::new(0, len as u32), - first_line_len: len as u32, - rightmost_point: Point::new(0, len as u32), - }, - } - } -} - -impl Run { - fn char_size(&self) -> u8 { - match self { - Run::Newline => 1, - Run::Chars { char_size, .. } => *char_size, - } - } -} +use super::Point; #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct TextSummary { pub chars: usize, pub bytes: usize, pub lines: Point, - pub first_line_len: u32, - pub rightmost_point: Point, } -impl sum_tree::Summary for TextSummary { - type Context = (); +impl<'a> From> for TextSummary { + fn from(slice: RopeSlice<'a>) -> Self { + let last_row = slice.len_lines() - 1; + let last_column = slice.line(last_row).len_chars(); + Self { + chars: slice.len_chars(), + bytes: slice.len_bytes(), + lines: Point::new(last_row as u32, last_column as u32), + } + } +} - fn add_summary(&mut self, other: &Self, _: &()) { - *self += other; +impl<'a> From<&'a Rope> for TextSummary { + fn from(text: &'a Rope) -> Self { + Self::from(text.slice(..)) } } impl<'a> std::ops::AddAssign<&'a Self> for TextSummary { fn add_assign(&mut self, other: &'a Self) { - let joined_line_len = self.lines.column + other.first_line_len; - if joined_line_len > self.rightmost_point.column { - self.rightmost_point = Point::new(self.lines.row, joined_line_len); - } - if other.rightmost_point.column > self.rightmost_point.column { - self.rightmost_point = self.lines + &other.rightmost_point; - } - - if self.lines.row == 0 { - self.first_line_len += other.first_line_len; - } + // let joined_line_len = self.lines.column + other.first_line_len; + // if joined_line_len > self.rightmost_point.column { + // self.rightmost_point = Point::new(self.lines.row, joined_line_len); + // } + // if other.rightmost_point.column > self.rightmost_point.column { + // self.rightmost_point = self.lines + &other.rightmost_point; + // } + + // if self.lines.row == 0 { + // self.first_line_len += other.first_line_len; + // } self.chars += other.chars; self.bytes += other.bytes; @@ -91,371 +52,3 @@ impl std::ops::AddAssign for TextSummary { *self += &other; } } - -impl<'a> sum_tree::Dimension<'a, TextSummary> for TextSummary { - fn add_summary(&mut self, other: &TextSummary) { - *self += other; - } -} - -impl<'a> sum_tree::Dimension<'a, TextSummary> for Point { - fn add_summary(&mut self, summary: &TextSummary) { - *self += &summary.lines; - } -} - -impl<'a> sum_tree::Dimension<'a, TextSummary> for ByteOffset { - fn add_summary(&mut self, summary: &TextSummary) { - self.0 += summary.bytes - } -} - -impl<'a> sum_tree::Dimension<'a, TextSummary> for usize { - fn add_summary(&mut self, summary: &TextSummary) { - *self += summary.chars; - } -} - -#[derive(Clone)] -pub struct Text { - text: Arc, - runs: SumTree, - range: Range, -} - -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; - let mut run_char_size = 0; - let mut run_chars = 0; - - let mut chars = text.chars(); - loop { - let ch = chars.next(); - let ch_size = ch.map_or(0, |ch| ch.len_utf8()); - if run_chars != 0 && (ch.is_none() || ch == Some('\n') || run_char_size != ch_size) { - runs.push(Run::Chars { - len: run_chars, - char_size: run_char_size as u8, - }); - run_chars = 0; - } - run_char_size = ch_size; - - match ch { - Some('\n') => runs.push(Run::Newline), - Some(_) => run_chars += 1, - None => break, - } - chars_len += 1; - } - - let mut tree = SumTree::new(); - tree.extend(runs, &()); - Text { - text, - runs: tree, - range: 0..chars_len, - } - } -} - -impl Debug for Text { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Text").field(&self.as_str()).finish() - } -} - -impl PartialEq for Text { - fn eq(&self, other: &Self) -> bool { - self.text == other.text - } -} - -impl Eq for Text {} - -impl> Index for Text { - type Output = str; - - fn index(&self, range: T) -> &Self::Output { - let start = match range.start_bound() { - Bound::Included(start) => cmp::min(self.range.start + start, self.range.end), - Bound::Excluded(_) => unimplemented!(), - Bound::Unbounded => self.range.start, - }; - let end = match range.end_bound() { - Bound::Included(end) => cmp::min(self.range.start + end + 1, self.range.end), - Bound::Excluded(end) => cmp::min(self.range.start + end, self.range.end), - Bound::Unbounded => self.range.end, - }; - - let byte_start = self.abs_byte_offset_for_offset(start); - let byte_end = self.abs_byte_offset_for_offset(end); - &self.text[byte_start..byte_end] - } -} - -impl Text { - pub fn range(&self) -> Range { - self.range.clone() - } - - pub fn as_str(&self) -> &str { - &self[..] - } - - pub fn slice>(&self, range: T) -> Text { - let start = match range.start_bound() { - Bound::Included(start) => cmp::min(self.range.start + start, self.range.end), - Bound::Excluded(_) => unimplemented!(), - Bound::Unbounded => self.range.start, - }; - let end = match range.end_bound() { - Bound::Included(end) => cmp::min(self.range.start + end + 1, self.range.end), - Bound::Excluded(end) => cmp::min(self.range.start + end, self.range.end), - Bound::Unbounded => self.range.end, - }; - - Text { - text: self.text.clone(), - runs: self.runs.clone(), - range: start..end, - } - } - - pub fn line_len(&self, row: u32) -> u32 { - let mut cursor = self.runs.cursor::(); - cursor.seek(&self.range.start, SeekBias::Right, &()); - let absolute_row = cursor.start().row + row; - - let mut cursor = self.runs.cursor::(); - cursor.seek(&Point::new(absolute_row, 0), SeekBias::Right, &()); - let prefix_len = self.range.start.saturating_sub(*cursor.start()); - let line_len = - cursor.summary::(&Point::new(absolute_row + 1, 0), SeekBias::Left, &()); - let suffix_len = cursor.start().saturating_sub(self.range.end); - - line_len - .saturating_sub(prefix_len) - .saturating_sub(suffix_len) as u32 - } - - pub fn len(&self) -> usize { - self.range.end - self.range.start - } - - pub fn lines(&self) -> Point { - self.abs_point_for_offset(self.range.end) - &self.abs_point_for_offset(self.range.start) - } - - pub fn rightmost_point(&self) -> Point { - let lines = self.lines(); - - let mut candidates = ArrayVec::<[Point; 3]>::new(); - candidates.push(lines); - if lines.row > 0 { - candidates.push(Point::new(0, self.line_len(0))); - if lines.row > 1 { - let mut cursor = self.runs.cursor::(); - cursor.seek(&self.range.start, SeekBias::Right, &()); - let absolute_start_row = cursor.start().row; - - let mut cursor = self.runs.cursor::(); - cursor.seek(&Point::new(absolute_start_row + 1, 0), SeekBias::Right, &()); - let summary = cursor.summary::( - &Point::new(absolute_start_row + lines.row, 0), - SeekBias::Left, - &(), - ); - - candidates.push(Point::new(1, 0) + &summary.rightmost_point); - } - } - - candidates.into_iter().max_by_key(|p| p.column).unwrap() - } - - pub fn point_for_offset(&self, offset: usize) -> Point { - self.abs_point_for_offset(self.range.start + offset) - - &self.abs_point_for_offset(self.range.start) - } - - pub fn offset_for_point(&self, point: Point) -> usize { - let mut cursor = self.runs.cursor::(); - let abs_point = self.abs_point_for_offset(self.range.start) + &point; - cursor.seek(&abs_point, SeekBias::Right, &()); - let overshoot = abs_point - &cursor.start().lines; - let abs_offset = cursor.start().chars + overshoot.column as usize; - abs_offset - self.range.start - } - - pub fn summary(&self) -> TextSummary { - TextSummary { - chars: self.range.end - self.range.start, - bytes: self.abs_byte_offset_for_offset(self.range.end) - - self.abs_byte_offset_for_offset(self.range.start), - lines: self.abs_point_for_offset(self.range.end) - - &self.abs_point_for_offset(self.range.start), - first_line_len: self.line_len(0), - rightmost_point: self.rightmost_point(), - } - } - - fn abs_point_for_offset(&self, offset: usize) -> Point { - let mut cursor = self.runs.cursor::(); - cursor.seek(&offset, SeekBias::Right, &()); - let overshoot = (offset - cursor.start().chars) as u32; - cursor.start().lines + &Point::new(0, overshoot) - } - - fn abs_byte_offset_for_offset(&self, offset: usize) -> usize { - let mut cursor = self.runs.cursor::(); - cursor.seek(&offset, SeekBias::Right, &()); - let overshoot = offset - cursor.start().chars; - cursor.start().bytes + overshoot * cursor.item().map_or(0, |run| run.char_size()) as usize - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::collections::HashSet; - use std::iter::FromIterator; - - #[test] - fn test_basic() { - let text = Text::from(String::from("ab\ncd€\nfghij\nkl¢m")); - assert_eq!(text.len(), 17); - assert_eq!(text.as_str(), "ab\ncd€\nfghij\nkl¢m"); - assert_eq!(text.lines(), Point::new(3, 4)); - assert_eq!(text.line_len(0), 2); - assert_eq!(text.line_len(1), 3); - assert_eq!(text.line_len(2), 5); - assert_eq!(text.line_len(3), 4); - assert_eq!(text.rightmost_point(), Point::new(2, 5)); - - let b_to_g = text.slice(1..9); - assert_eq!(b_to_g.as_str(), "b\ncd€\nfg"); - assert_eq!(b_to_g.len(), 8); - assert_eq!(b_to_g.lines(), Point::new(2, 2)); - assert_eq!(b_to_g.line_len(0), 1); - assert_eq!(b_to_g.line_len(1), 3); - assert_eq!(b_to_g.line_len(2), 2); - assert_eq!(b_to_g.line_len(3), 0); - assert_eq!(b_to_g.rightmost_point(), Point::new(1, 3)); - - let d_to_i = text.slice(4..11); - assert_eq!(d_to_i.as_str(), "d€\nfghi"); - assert_eq!(&d_to_i[1..5], "€\nfg"); - assert_eq!(d_to_i.len(), 7); - assert_eq!(d_to_i.lines(), Point::new(1, 4)); - assert_eq!(d_to_i.line_len(0), 2); - assert_eq!(d_to_i.line_len(1), 4); - assert_eq!(d_to_i.line_len(2), 0); - assert_eq!(d_to_i.rightmost_point(), Point::new(1, 4)); - - let d_to_j = text.slice(4..=11); - assert_eq!(d_to_j.as_str(), "d€\nfghij"); - assert_eq!(&d_to_j[1..], "€\nfghij"); - assert_eq!(d_to_j.len(), 8); - } - - #[test] - fn test_random() { - use rand::prelude::*; - - for seed in 0..100 { - println!("buffer::text seed: {}", seed); - let rng = &mut StdRng::seed_from_u64(seed); - - let len = rng.gen_range(0..50); - let mut string = String::new(); - for _ in 0..len { - if rng.gen_ratio(1, 5) { - string.push('\n'); - } else { - string.push(rng.gen()); - } - } - let text = Text::from(string.clone()); - - for _ in 0..10 { - let start = rng.gen_range(0..text.len() + 1); - let end = rng.gen_range(start..text.len() + 2); - - let string_slice = string - .chars() - .skip(start) - .take(end - start) - .collect::(); - let expected_line_endpoints = string_slice - .split('\n') - .enumerate() - .map(|(row, line)| Point::new(row as u32, line.chars().count() as u32)) - .collect::>(); - let text_slice = text.slice(start..end); - - assert_eq!(text_slice.lines(), lines(&string_slice)); - - let mut rightmost_points: HashSet = HashSet::new(); - for endpoint in &expected_line_endpoints { - if let Some(rightmost_point) = rightmost_points.iter().next().cloned() { - if endpoint.column > rightmost_point.column { - rightmost_points.clear(); - } - if endpoint.column >= rightmost_point.column { - rightmost_points.insert(*endpoint); - } - } else { - rightmost_points.insert(*endpoint); - } - - assert_eq!(text_slice.line_len(endpoint.row as u32), endpoint.column); - } - - assert!(rightmost_points.contains(&text_slice.rightmost_point())); - - for _ in 0..10 { - let offset = rng.gen_range(0..string_slice.chars().count() + 1); - let point = lines(&string_slice.chars().take(offset).collect::()); - assert_eq!(text_slice.point_for_offset(offset), point); - assert_eq!(text_slice.offset_for_point(point), offset); - if offset < string_slice.chars().count() { - assert_eq!( - &text_slice[offset..offset + 1], - String::from_iter(string_slice.chars().nth(offset)).as_str() - ); - } - } - } - } - } - - pub fn lines(s: &str) -> Point { - let mut row = 0; - let mut column = 0; - for ch in s.chars() { - if ch == '\n' { - row += 1; - column = 0; - } else { - column += 1; - } - } - Point::new(row, column) - } -} diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index e33013565f66fc1a2d0a650850a1ad7e46e751e0..d0cbe60c5817d9c31da3fab2841ba94eeb8fea29 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -38,6 +38,7 @@ impl FoldMap { display_text: None, }, &(), + &(), )), last_sync: Mutex::new(buffer.version()), } @@ -72,7 +73,8 @@ impl FoldMap { } pub fn rightmost_point(&self, ctx: &AppContext) -> DisplayPoint { - DisplayPoint(self.sync(ctx).summary().display.rightmost_point) + todo!() + // DisplayPoint(self.sync(ctx).summary().display.rightmost_point) } pub fn folds_in_range<'a, T>( @@ -122,7 +124,7 @@ impl FoldMap { let mut cursor = self.folds.cursor::<_, ()>(); for fold in folds { new_tree.push_tree(cursor.slice(&fold, SeekBias::Right, buffer), buffer); - new_tree.push(fold, buffer); + new_tree.push(fold, &(), buffer); } new_tree.push_tree(cursor.suffix(buffer), buffer); new_tree @@ -341,6 +343,7 @@ impl FoldMap { display_text: None, }, &(), + &(), ); } @@ -352,14 +355,15 @@ impl FoldMap { chars: 1, bytes: '…'.len_utf8(), lines: Point::new(0, 1), - first_line_len: 1, - rightmost_point: Point::new(0, 1), + // first_line_len: 1, + // rightmost_point: Point::new(0, 1), }, buffer: buffer.text_summary_for_range(fold.start..fold.end), }, display_text: Some('…'), }, &(), + &(), ); } } @@ -377,6 +381,7 @@ impl FoldMap { display_text: None, }, &(), + &(), ); } } @@ -393,6 +398,7 @@ impl FoldMap { display_text: None, }, &(), + &(), ); } @@ -465,9 +471,10 @@ struct TransformSummary { } impl sum_tree::Item for Transform { + type Context = (); type Summary = TransformSummary; - fn summary(&self) -> Self::Summary { + fn summary(&self, _: &()) -> Self::Summary { self.summary.clone() } } @@ -497,9 +504,10 @@ impl Default for Fold { } impl sum_tree::Item for Fold { + type Context = (); type Summary = FoldSummary; - fn summary(&self) -> Self::Summary { + fn summary(&self, _: &()) -> Self::Summary { FoldSummary { start: self.0.start.clone(), end: self.0.end.clone(), diff --git a/zed/src/operation_queue.rs b/zed/src/operation_queue.rs index 2c0e234fe98cd30c6d3fa72b210a93c0441b8249..5fd24fbe976dcf8a83fcf8d42394a90743cf1125 100644 --- a/zed/src/operation_queue.rs +++ b/zed/src/operation_queue.rs @@ -48,9 +48,10 @@ impl OperationQueue { } impl Item for T { + type Context = (); type Summary = OperationSummary; - fn summary(&self) -> Self::Summary { + fn summary(&self, _: &()) -> Self::Summary { OperationSummary { key: OperationKey(self.timestamp()), len: 1, diff --git a/zed/src/sum_tree/mod.rs b/zed/src/sum_tree/mod.rs index e70440f16f0c0bfeb811c8ad1aa6167adc85b253..2cbd928aba5f0714f553051c4a358afa3b067575 100644 --- a/zed/src/sum_tree/mod.rs +++ b/zed/src/sum_tree/mod.rs @@ -11,12 +11,13 @@ const TREE_BASE: usize = 2; const TREE_BASE: usize = 6; pub trait Item: Clone + fmt::Debug { + type Context; type Summary: Summary; - fn summary(&self) -> Self::Summary; + fn summary(&self, ctx: &Self::Context) -> Self::Summary; } -pub trait KeyedItem: Item { +pub trait KeyedItem: Item { type Key: for<'a> Dimension<'a, Self::Summary> + Ord; fn key(&self) -> Self::Key; @@ -64,9 +65,13 @@ impl SumTree { })) } - pub fn from_item(item: T, ctx: &::Context) -> Self { + pub fn from_item( + item: T, + item_ctx: &T::Context, + summary_ctx: &::Context, + ) -> Self { let mut tree = Self::new(); - tree.push(item, ctx); + tree.push(item, item_ctx, summary_ctx); tree } @@ -125,47 +130,13 @@ impl SumTree { } } - pub fn extend(&mut self, iter: I, ctx: &::Context) - where - I: IntoIterator, - { - let mut leaf: Option> = None; - - for item in iter { - if leaf.is_some() && leaf.as_ref().unwrap().items().len() == 2 * TREE_BASE { - self.push_tree(SumTree(Arc::new(leaf.take().unwrap())), ctx); - } - - if leaf.is_none() { - leaf = Some(Node::Leaf:: { - summary: T::Summary::default(), - items: ArrayVec::new(), - item_summaries: ArrayVec::new(), - }); - } - - if let Some(Node::Leaf { - summary, - items, - item_summaries, - }) = leaf.as_mut() - { - let item_summary = item.summary(); - summary.add_summary(&item_summary, ctx); - items.push(item); - item_summaries.push(item_summary); - } else { - unreachable!() - } - } - - if leaf.is_some() { - self.push_tree(SumTree(Arc::new(leaf.take().unwrap())), ctx); - } - } - - pub fn push(&mut self, item: T, ctx: &::Context) { - let summary = item.summary(); + pub fn push( + &mut self, + item: T, + item_ctx: &T::Context, + summary_ctx: &::Context, + ) { + let summary = item.summary(item_ctx); self.push_tree( SumTree::from_child_trees( vec![SumTree(Arc::new(Node::Leaf { @@ -173,9 +144,9 @@ impl SumTree { items: ArrayVec::from_iter(Some(item)), item_summaries: ArrayVec::from_iter(Some(summary)), }))], - ctx, + summary_ctx, ), - ctx, + summary_ctx, ) } @@ -349,13 +320,54 @@ impl SumTree { } } +impl> SumTree { + pub fn extend(&mut self, iter: I, ctx: &::Context) + where + I: IntoIterator, + { + let mut leaf: Option> = None; + + for item in iter { + if leaf.is_some() && leaf.as_ref().unwrap().items().len() == 2 * TREE_BASE { + self.push_tree(SumTree(Arc::new(leaf.take().unwrap())), ctx); + } + + if leaf.is_none() { + leaf = Some(Node::Leaf:: { + summary: T::Summary::default(), + items: ArrayVec::new(), + item_summaries: ArrayVec::new(), + }); + } + + if let Some(Node::Leaf { + summary, + items, + item_summaries, + }) = leaf.as_mut() + { + let item_summary = item.summary(&()); + summary.add_summary(&item_summary, ctx); + items.push(item); + item_summaries.push(item_summary); + } else { + unreachable!() + } + } + + if leaf.is_some() { + self.push_tree(SumTree(Arc::new(leaf.take().unwrap())), ctx); + } + } +} + impl SumTree { #[allow(unused)] pub fn insert(&mut self, item: T, ctx: &::Context) { *self = { let mut cursor = self.cursor::(); let mut new_tree = cursor.slice(&item.key(), SeekBias::Left, ctx); - new_tree.push(item, ctx); + new_tree.push(item, &(), ctx); new_tree.push_tree(cursor.suffix(ctx), ctx); new_tree }; @@ -863,9 +875,10 @@ mod tests { struct Sum(usize); impl Item for u8 { + type Context = (); type Summary = IntegersSummary; - fn summary(&self) -> Self::Summary { + fn summary(&self, _: &()) -> Self::Summary { IntegersSummary { count: Count(1), sum: Sum(*self as usize), diff --git a/zed/src/worktree.rs b/zed/src/worktree.rs index 0f69ea833113b37f87b4658a12b407a757368897..7d7356f2d2fc68219fc85757ec8a605172b5c025 100644 --- a/zed/src/worktree.rs +++ b/zed/src/worktree.rs @@ -538,9 +538,10 @@ impl Entry { } impl sum_tree::Item for Entry { + type Context = (); type Summary = EntrySummary; - fn summary(&self) -> Self::Summary { + fn summary(&self, _: &()) -> Self::Summary { let file_count; let visible_file_count; if self.is_file() {