From 2cdf315d956ece44c86c89abf82a2bde43f5910b Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 14 May 2021 18:30:47 +0200 Subject: [PATCH] WIP: Replace ropey with our own Rope Co-Authored-By: Nathan Sobo --- Cargo.lock | 10 - zed/Cargo.toml | 1 - zed/src/editor/buffer/mod.rs | 405 ++++++++++++------------- zed/src/editor/buffer/rope.rs | 39 ++- zed/src/editor/display_map/fold_map.rs | 3 +- zed/src/worktree.rs | 5 +- 6 files changed, 220 insertions(+), 243 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d6e0804b04..21a08332c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2188,15 +2188,6 @@ 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" @@ -2987,7 +2978,6 @@ 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 370f580484..2302fc6509 100644 --- a/zed/Cargo.toml +++ b/zed/Cargo.toml @@ -31,7 +31,6 @@ 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 5cb2e1920d..5538f6474f 100644 --- a/zed/src/editor/buffer/mod.rs +++ b/zed/src/editor/buffer/mod.rs @@ -1,11 +1,11 @@ mod anchor; mod point; -mod rope; +pub mod rope; mod selection; pub use anchor::*; pub use point::*; -use ropey::{Rope, RopeSlice}; +pub use rope::{Rope, TextSummary}; use seahash::SeaHasher; pub use selection::*; use similar::{ChangeTag, TextDiff}; @@ -57,9 +57,9 @@ type HashMap = std::collections::HashMap; type HashSet = std::collections::HashSet; pub struct Buffer { + fragments: SumTree, visible_text: Rope, deleted_text: Rope, - fragments: SumTree, insertion_splits: HashMap>, pub version: time::Global, saved_version: time::Global, @@ -305,74 +305,6 @@ impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FragmentTextSummary { } } -#[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<'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(); - - let mut point = Point::default(); - let mut rightmost_point = point; - let mut first_line_len = None; - for (i, c) in slice.chars().enumerate() { - if c == '\n' { - if first_line_len.is_none() { - first_line_len = Some(i as u32); - } - point.row += 1; - point.column = 0; - } else { - point.column += 1; - if point.column > rightmost_point.column { - rightmost_point = point; - } - } - } - - Self { - chars: slice.len_chars(), - bytes: slice.len_bytes(), - lines: Point::new(last_row as u32, last_column as u32), - first_line_len: first_line_len.unwrap_or(slice.len_chars() as u32), - rightmost_point, - } - } -} - -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; - } - - self.chars += other.chars; - self.bytes += other.bytes; - self.lines += &other.lines; - } -} - -impl std::ops::AddAssign for TextSummary { - fn add_assign(&mut self, other: Self) { - *self += &other; - } -} - #[derive(Eq, PartialEq, Clone, Debug)] struct InsertionSplit { extent: usize, @@ -510,10 +442,10 @@ impl Buffer { &(), ); - if base_text.len_chars() > 0 { + if base_text.len() > 0 { let base_fragment_id = FragmentId::between(&FragmentId::min_value(), &FragmentId::max_value()); - let range_in_insertion = 0..base_text.len_chars(); + let range_in_insertion = 0..base_text.len(); visible_text = base_text.clone(); insertion_splits.get_mut(&base_insertion.id).unwrap().push( @@ -663,11 +595,12 @@ impl Buffer { } pub fn text_summary(&self) -> TextSummary { - TextSummary::from(self.visible_text.slice(..)) + self.visible_text.summary() } pub fn text_summary_for_range(&self, range: Range) -> TextSummary { - TextSummary::from(self.visible_text.slice(range)) + // TODO: Use a dedicated ::summarize method in Rope. + self.visible_text.slice(range).summary() } pub fn len(&self) -> usize { @@ -686,7 +619,7 @@ impl Buffer { } pub fn rightmost_point(&self) -> Point { - self.rightmost_point_in_range(0..self.len()) + self.visible_text.summary().rightmost_point } pub fn rightmost_point_in_range(&self, range: Range) -> Point { @@ -694,7 +627,7 @@ impl Buffer { } pub fn max_point(&self) -> Point { - self.text_summary().lines + self.visible_text.max_point() } pub fn line(&self, row: u32) -> Result { @@ -717,11 +650,11 @@ impl Buffer { Ok(self.chars_at(start)?.take(end - start)) } - pub fn chars(&self) -> ropey::iter::Chars { + pub fn chars(&self) -> rope::Chars { self.chars_at(0).unwrap() } - pub fn chars_at(&self, position: T) -> Result { + pub fn chars_at(&self, position: T) -> Result { let offset = position.to_offset(self)?; Ok(self.visible_text.chars_at(offset)) } @@ -1084,22 +1017,25 @@ impl Buffer { let end_fragment_id = self.resolve_fragment_id(end_id, end_offset)?; let old_fragments = self.fragments.clone(); - let last_id = old_fragments.extent::().0.unwrap(); - let last_id_ref = FragmentIdRef::new(&last_id); + let old_visible_text = self.visible_text.clone(); + let old_deleted_text = self.deleted_text.clone(); + + let mut fragments_cursor = old_fragments.cursor::(); + let mut visible_text_cursor = old_visible_text.cursor(0); + let mut deleted_text_cursor = old_deleted_text.cursor(0); - 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(); + fragments_cursor.slice(&FragmentIdRef::new(&start_fragment_id), SeekBias::Left, &()); + let mut new_visible_text = visible_text_cursor.slice(fragments_cursor.start().visible); + let mut new_deleted_text = deleted_text_cursor.slice(fragments_cursor.start().deleted); - let start_fragment = cursor.item().unwrap(); + let start_fragment = fragments_cursor.item().unwrap(); if start_offset == start_fragment.range_in_insertion.end { - new_fragments.push(cursor.item().unwrap().clone(), &()); - cursor.next(); + new_fragments.push(fragments_cursor.item().unwrap().clone(), &()); + fragments_cursor.next(); } - while let Some(fragment) = cursor.item() { + while let Some(fragment) = fragments_cursor.item() { if new_text.is_none() && fragment.id > end_fragment_id { break; } @@ -1118,13 +1054,14 @@ impl Buffer { fragment.range_in_insertion.end }; let (before_range, within_range, after_range) = self.split_fragment( - cursor.prev_item().as_ref().unwrap(), + fragments_cursor.prev_item().as_ref().unwrap(), &fragment, split_start..split_end, ); let insertion = if let Some(new_text) = new_text { + let prev_fragment = fragments_cursor.prev_item(); Some(self.build_fragment_to_insert( - before_range.as_ref().or(cursor.prev_item()).unwrap(), + before_range.as_ref().or(prev_fragment).unwrap(), within_range.as_ref().or(after_range.as_ref()), new_text, local_timestamp, @@ -1137,25 +1074,26 @@ impl Buffer { new_fragments.push(fragment, &()); } if let Some(fragment) = insertion { - new_visible_text.insert( - new_fragments.summary().text.visible, - new_text.take().unwrap(), - ); + new_visible_text + .append(visible_text_cursor.slice(new_fragments.summary().text.visible)); new_fragments.push(fragment, &()); + new_visible_text.push(new_text.take().unwrap()); } if let Some(mut fragment) = within_range { if fragment.was_visible(&version_in_range, &self.undo_map) { fragment.deletions.insert(local_timestamp); if fragment.visible { fragment.visible = false; - // TODO: avoid calling to_string on rope slice. - let deleted_start = new_fragments.summary().text.visible; - let deleted_range = deleted_start..deleted_start + fragment.len(); - new_deleted_text.insert( - new_fragments.summary().text.deleted, - &new_visible_text.slice(deleted_range.clone()).to_string(), + new_visible_text.append( + visible_text_cursor.slice(new_fragments.summary().text.visible), + ); + new_deleted_text.append( + deleted_text_cursor.slice(new_fragments.summary().text.deleted), + ); + new_deleted_text.append( + visible_text_cursor + .slice(new_fragments.summary().text.visible + fragment.len()), ); - new_visible_text.remove(deleted_range); } } @@ -1168,14 +1106,16 @@ impl Buffer { 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(), + fragments_cursor.prev_item().as_ref().unwrap(), Some(&fragment), new_text, local_timestamp, lamport_timestamp, ); - new_visible_text.insert(new_fragments.summary().text.visible, new_text); + new_visible_text + .append(visible_text_cursor.slice(new_fragments.summary().text.visible)); new_fragments.push(fragment, &()); + new_visible_text.push(new_text); } if fragment.id < end_fragment_id @@ -1184,39 +1124,46 @@ impl Buffer { fragment.deletions.insert(local_timestamp); if fragment.visible { fragment.visible = false; - // TODO: avoid calling to_string on rope slice. - let deleted_start = new_fragments.summary().text.visible; - let deleted_range = deleted_start..deleted_start + fragment.len(); - new_deleted_text.insert( - new_fragments.summary().text.deleted, - &new_visible_text.slice(deleted_range.clone()).to_string(), + new_visible_text.append( + visible_text_cursor.slice(new_fragments.summary().text.visible), + ); + new_deleted_text.append( + deleted_text_cursor.slice(new_fragments.summary().text.deleted), + ); + new_deleted_text.append( + visible_text_cursor + .slice(new_fragments.summary().text.visible + fragment.len()), ); - new_visible_text.remove(deleted_range); } } new_fragments.push(fragment, &()); } - cursor.next(); + fragments_cursor.next(); } if let Some(new_text) = new_text { let fragment = self.build_fragment_to_insert( - cursor.prev_item().as_ref().unwrap(), + fragments_cursor.prev_item().as_ref().unwrap(), None, new_text, local_timestamp, lamport_timestamp, ); - new_visible_text.insert(new_fragments.summary().text.visible, new_text); + new_visible_text + .append(visible_text_cursor.slice(new_fragments.summary().text.visible)); new_fragments.push(fragment, &()); + new_visible_text.push(new_text); } - new_fragments.push_tree(cursor.slice(&last_id_ref, SeekBias::Right, &()), &()); + new_fragments.push_tree(fragments_cursor.suffix(&()), &()); + new_visible_text.append(visible_text_cursor.suffix()); + new_deleted_text.append(deleted_text_cursor.suffix()); + + self.fragments = new_fragments; 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); Ok(()) @@ -1291,52 +1238,60 @@ 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(); + let mut new_visible_text = Rope::new(); + let mut new_deleted_text = Rope::new(); self.undo_map.insert(undo); 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::(); + + let mut fragments_cursor = self.fragments.cursor::(); + let mut visible_text_cursor = self.visible_text.cursor(0); + let mut deleted_text_cursor = self.deleted_text.cursor(0); if edit.start_id == edit.end_id && edit.start_offset == edit.end_offset { let splits = &self.insertion_splits[&undo.edit_id]; let mut insertion_splits = splits.cursor::<(), ()>().map(|s| &s.fragment_id).peekable(); let first_split_id = insertion_splits.next().unwrap(); - new_fragments = cursor.slice(&FragmentIdRef::new(first_split_id), SeekBias::Left, &()); + new_fragments = + fragments_cursor.slice(&FragmentIdRef::new(first_split_id), SeekBias::Left, &()); + new_visible_text + .append(visible_text_cursor.slice(new_fragments.summary().text.visible)); + new_deleted_text + .append(deleted_text_cursor.slice(new_fragments.summary().text.deleted)); loop { - let mut fragment = cursor.item().unwrap().clone(); + let mut fragment = fragments_cursor.item().unwrap().clone(); let was_visible = fragment.visible; 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 { + new_visible_text + .append(visible_text_cursor.slice(new_fragments.summary().text.visible)); + new_deleted_text + .append(deleted_text_cursor.slice(new_fragments.summary().text.deleted)); + } + if fragment.visible && !was_visible { - let visible_start = new_fragments.summary().text.deleted; - let visible_range = visible_start..visible_start + fragment.len(); - new_visible_text.insert( - new_fragments.summary().text.visible, - &new_deleted_text.slice(visible_range.clone()).to_string(), + new_visible_text.append( + deleted_text_cursor + .slice(new_fragments.summary().text.deleted + fragment.len()), ); - new_deleted_text.remove(visible_range); } else if !fragment.visible && was_visible { - let deleted_start = new_fragments.summary().text.visible; - let deleted_range = deleted_start..deleted_start + fragment.len(); - new_deleted_text.insert( - new_fragments.summary().text.deleted, - &new_visible_text.slice(deleted_range.clone()).to_string(), + new_deleted_text.append( + visible_text_cursor + .slice(new_fragments.summary().text.visible + fragment.len()), ); - new_visible_text.remove(deleted_range); } new_fragments.push(fragment, &()); - cursor.next(); + fragments_cursor.next(); if let Some(split_id) = insertion_splits.next() { new_fragments.push_tree( - cursor.slice(&FragmentIdRef::new(split_id), SeekBias::Left, &()), + fragments_cursor.slice(&FragmentIdRef::new(split_id), SeekBias::Left, &()), &(), ); } else { @@ -1344,9 +1299,12 @@ impl Buffer { } } } else { - new_fragments = - cursor.slice(&FragmentIdRef::new(&start_fragment_id), SeekBias::Left, &()); - while let Some(fragment) = cursor.item() { + new_fragments = fragments_cursor.slice( + &FragmentIdRef::new(&start_fragment_id), + SeekBias::Left, + &(), + ); + while let Some(fragment) = fragments_cursor.item() { if fragment.id > end_fragment_id { break; } else { @@ -1358,37 +1316,42 @@ impl Buffer { 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 { + new_visible_text.append( + visible_text_cursor.slice(new_fragments.summary().text.visible), + ); + new_deleted_text.append( + deleted_text_cursor.slice(new_fragments.summary().text.deleted), + ); + } + if fragment.visible && !was_visible { - let visible_start = new_fragments.summary().text.deleted; - let visible_range = visible_start..visible_start + fragment.len(); - new_visible_text.insert( - new_fragments.summary().text.visible, - &new_deleted_text.slice(visible_range.clone()).to_string(), + new_visible_text.append( + deleted_text_cursor + .slice(new_fragments.summary().text.deleted + fragment.len()), ); - new_deleted_text.remove(visible_range); } else if !fragment.visible && was_visible { - let deleted_start = new_fragments.summary().text.visible; - let deleted_range = deleted_start..deleted_start + fragment.len(); - new_deleted_text.insert( - new_fragments.summary().text.deleted, - &new_visible_text.slice(deleted_range.clone()).to_string(), + new_deleted_text.append( + visible_text_cursor + .slice(new_fragments.summary().text.visible + fragment.len()), ); - new_visible_text.remove(deleted_range); } } new_fragments.push(fragment, &()); - cursor.next(); + fragments_cursor.next(); } } } - new_fragments.push_tree(cursor.suffix(&()), &()); - drop(cursor); + new_fragments.push_tree(fragments_cursor.suffix(&()), &()); + new_visible_text.append(visible_text_cursor.suffix()); + new_deleted_text.append(deleted_text_cursor.suffix()); + drop(fragments_cursor); + + self.fragments = new_fragments; self.visible_text = new_visible_text; self.deleted_text = new_deleted_text; - self.fragments = new_fragments; Ok(()) } @@ -1470,15 +1433,23 @@ impl Buffer { let mut ops = Vec::with_capacity(old_ranges.size_hint().0); let old_fragments = self.fragments.clone(); - let mut cursor = old_fragments.cursor::(); + let old_visible_text = self.visible_text.clone(); + let old_deleted_text = self.deleted_text.clone(); + + let mut fragments_cursor = old_fragments.cursor::(); + let mut visible_text_cursor = old_visible_text.cursor(0); + let mut deleted_text_cursor = old_deleted_text.cursor(0); + let mut new_fragments = SumTree::new(); - let mut new_visible_text = self.visible_text.clone(); - let mut new_deleted_text = self.deleted_text.clone(); + let mut new_visible_text = Rope::new(); + let mut new_deleted_text = Rope::new(); new_fragments.push_tree( - cursor.slice(&cur_range.as_ref().unwrap().start, SeekBias::Right, &()), + fragments_cursor.slice(&cur_range.as_ref().unwrap().start, SeekBias::Right, &()), &(), ); + new_visible_text.append(visible_text_cursor.slice(new_fragments.summary().text.visible)); + new_deleted_text.append(deleted_text_cursor.slice(new_fragments.summary().text.deleted)); let mut start_id = None; let mut start_offset = None; @@ -1489,10 +1460,10 @@ impl Buffer { let mut local_timestamp = self.local_clock.tick(); let mut lamport_timestamp = self.lamport_clock.tick(); - while cur_range.is_some() && cursor.item().is_some() { - let mut fragment = cursor.item().unwrap().clone(); - let fragment_summary = cursor.item_summary().unwrap(); - let mut fragment_start = *cursor.start(); + while cur_range.is_some() && fragments_cursor.item().is_some() { + let mut fragment = fragments_cursor.item().unwrap().clone(); + let fragment_summary = fragments_cursor.item_summary().unwrap(); + let mut fragment_start = *fragments_cursor.start(); let mut fragment_end = fragment_start + fragment.visible_len(); let old_split_tree = self @@ -1546,8 +1517,12 @@ impl Buffer { local_timestamp, lamport_timestamp, ); - new_visible_text.insert(new_fragments.summary().text.visible, &new_text); + + new_visible_text.append( + visible_text_cursor.slice(new_fragments.summary().text.visible), + ); new_fragments.push(new_fragment, &()); + new_visible_text.push(&new_text); } } @@ -1559,18 +1534,20 @@ impl Buffer { prefix.id = FragmentId::between(&new_fragments.last().unwrap().id, &fragment.id); version_in_range.observe_all(&fragment_summary.max_version); - if fragment.visible { + if prefix.visible { prefix.deletions.insert(local_timestamp); prefix.visible = false; - // TODO: avoid calling to_string on rope slice. - let deleted_start = new_fragments.summary().text.visible; - let deleted_range = deleted_start..deleted_start + prefix.len(); - new_deleted_text.insert( - new_fragments.summary().text.deleted, - &new_visible_text.slice(deleted_range.clone()).to_string(), + new_visible_text.append( + visible_text_cursor.slice(new_fragments.summary().text.visible), + ); + new_deleted_text.append( + deleted_text_cursor.slice(new_fragments.summary().text.deleted), + ); + new_deleted_text.append( + visible_text_cursor + .slice(new_fragments.summary().text.visible + prefix.len()), ); - new_visible_text.remove(deleted_range); } fragment.range_in_insertion.start = prefix.range_in_insertion.end; new_fragments.push(prefix.clone(), &()); @@ -1592,14 +1569,16 @@ 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; - let deleted_range = deleted_start..deleted_start + fragment.len(); - new_deleted_text.insert( - new_fragments.summary().text.deleted, - &new_visible_text.slice(deleted_range.clone()).to_string(), + new_visible_text.append( + visible_text_cursor.slice(new_fragments.summary().text.visible), + ); + new_deleted_text.append( + deleted_text_cursor.slice(new_fragments.summary().text.deleted), + ); + new_deleted_text.append( + visible_text_cursor + .slice(new_fragments.summary().text.visible + fragment.len()), ); - new_visible_text.remove(deleted_range); } } @@ -1651,11 +1630,11 @@ impl Buffer { new_fragments.push(fragment, &()); // Scan forward until we find a fragment that is not fully contained by the current splice. - cursor.next(); + fragments_cursor.next(); if let Some(range) = cur_range.clone() { - while let Some(fragment) = cursor.item() { - let fragment_summary = cursor.item_summary().unwrap(); - fragment_start = *cursor.start(); + while let Some(fragment) = fragments_cursor.item() { + let fragment_summary = fragments_cursor.item_summary().unwrap(); + fragment_start = *fragments_cursor.start(); fragment_end = fragment_start + fragment.visible_len(); if range.start < fragment_start && range.end >= fragment_end { let mut new_fragment = fragment.clone(); @@ -1664,17 +1643,20 @@ impl Buffer { new_fragment.deletions.insert(local_timestamp); new_fragment.visible = false; - // TODO: avoid calling to_string on rope slice. - let deleted_start = new_fragments.summary().text.visible; - let deleted_range = deleted_start..deleted_start + new_fragment.len(); - new_deleted_text.insert( - new_fragments.summary().text.deleted, - &new_visible_text.slice(deleted_range.clone()).to_string(), + new_visible_text.append( + visible_text_cursor.slice(new_fragments.summary().text.visible), + ); + new_deleted_text.append( + deleted_text_cursor.slice(new_fragments.summary().text.deleted), + ); + new_deleted_text.append( + visible_text_cursor.slice( + new_fragments.summary().text.visible + new_fragment.len(), + ), ); - new_visible_text.remove(deleted_range); } new_fragments.push(new_fragment, &()); - cursor.next(); + fragments_cursor.next(); if range.end == fragment_end { end_id = Some(fragment.insertion.id); @@ -1715,7 +1697,11 @@ impl Buffer { // and push all the fragments in between into the new tree. if cur_range.as_ref().map_or(false, |r| r.start > fragment_end) { new_fragments.push_tree( - cursor.slice(&cur_range.as_ref().unwrap().start, SeekBias::Right, &()), + fragments_cursor.slice( + &cur_range.as_ref().unwrap().start, + SeekBias::Right, + &(), + ), &(), ); } @@ -1749,19 +1735,21 @@ impl Buffer { local_timestamp, lamport_timestamp, ); - new_visible_text.insert(new_fragments.summary().text.visible, &new_text); + + new_visible_text + .append(visible_text_cursor.slice(new_fragments.summary().text.visible)); new_fragments.push(new_fragment, &()); + new_visible_text.push(&new_text); } - } else { - new_fragments.push_tree( - cursor.slice(&old_fragments.extent::(), SeekBias::Right, &()), - &(), - ); } + new_fragments.push_tree(fragments_cursor.suffix(&()), &()); + new_visible_text.append(visible_text_cursor.suffix()); + new_deleted_text.append(deleted_text_cursor.suffix()); + + self.fragments = new_fragments; self.visible_text = new_visible_text; self.deleted_text = new_deleted_text; - self.fragments = new_fragments; ops } @@ -2031,9 +2019,9 @@ impl Buffer { impl Clone for Buffer { fn clone(&self) -> Self { Self { + fragments: self.fragments.clone(), visible_text: self.visible_text.clone(), deleted_text: self.deleted_text.clone(), - fragments: self.fragments.clone(), insertion_splits: self.insertion_splits.clone(), version: self.version.clone(), saved_version: self.saved_version.clone(), @@ -2409,12 +2397,7 @@ pub trait ToOffset { impl ToOffset for Point { fn to_offset(&self, buffer: &Buffer) -> Result { - if *self <= buffer.max_point() { - // TODO: return an error if line is shorter than column. - Ok(buffer.visible_text.line_to_char(self.row as usize) + self.column as usize) - } else { - Err(anyhow!("point is out of bounds")) - } + buffer.visible_text.to_offset(*self) } } @@ -2448,13 +2431,7 @@ impl ToPoint for Anchor { impl ToPoint for usize { fn to_point(&self, buffer: &Buffer) -> Result { - if *self <= buffer.len() { - let row = buffer.visible_text.char_to_line(*self); - let column = *self - buffer.visible_text.line_to_char(row); - Ok(Point::new(row as u32, column as u32)) - } else { - Err(anyhow!("offset is out of bounds")) - } + buffer.visible_text.to_point(*self) } } diff --git a/zed/src/editor/buffer/rope.rs b/zed/src/editor/buffer/rope.rs index ff80fffc0e..c08733f625 100644 --- a/zed/src/editor/buffer/rope.rs +++ b/zed/src/editor/buffer/rope.rs @@ -100,6 +100,14 @@ impl Rope { self.chunks.summary() } + pub fn len(&self) -> usize { + self.chunks.extent() + } + + pub fn max_point(&self) -> Point { + self.chunks.extent() + } + pub fn cursor(&self, offset: usize) -> Cursor { Cursor::new(self, offset) } @@ -116,15 +124,7 @@ impl Rope { self.chunks.cursor::<(), ()>().map(|c| c.0.as_str()) } - fn text(&self) -> String { - let mut text = String::new(); - for chunk in self.chunks.cursor::<(), ()>() { - text.push_str(&chunk.0); - } - text - } - - fn to_point(&self, offset: usize) -> Result { + pub fn to_point(&self, offset: usize) -> Result { if offset <= self.summary().chars { let mut cursor = self.chunks.cursor::(); cursor.seek(&offset, SeekBias::Left, &()); @@ -135,7 +135,8 @@ impl Rope { } } - fn to_offset(&self, point: Point) -> Result { + pub fn to_offset(&self, point: Point) -> Result { + // TODO: Verify the point actually exists. if point <= self.summary().lines { let mut cursor = self.chunks.cursor::(); cursor.seek(&point, SeekBias::Left, &()); @@ -162,7 +163,7 @@ pub struct Cursor<'a> { } impl<'a> Cursor<'a> { - fn new(rope: &'a Rope, offset: usize) -> Self { + pub fn new(rope: &'a Rope, offset: usize) -> Self { let mut chunks = rope.chunks.cursor(); chunks.seek(&offset, SeekBias::Right, &()); Self { @@ -172,14 +173,14 @@ impl<'a> Cursor<'a> { } } - fn seek_forward(&mut self, end_offset: usize) { + pub fn seek_forward(&mut self, end_offset: usize) { debug_assert!(end_offset >= self.offset); self.chunks.seek_forward(&end_offset, SeekBias::Right, &()); self.offset = end_offset; } - fn slice(&mut self, end_offset: usize) -> Rope { + pub fn slice(&mut self, end_offset: usize) -> Rope { debug_assert!(end_offset >= self.offset); let mut slice = Rope::new(); @@ -203,7 +204,7 @@ impl<'a> Cursor<'a> { slice } - fn suffix(mut self) -> Rope { + pub fn suffix(mut self) -> Rope { self.slice(self.rope.chunks.extent()) } } @@ -456,4 +457,14 @@ mod tests { } } } + + impl Rope { + fn text(&self) -> String { + let mut text = String::new(); + for chunk in self.chunks.cursor::<(), ()>() { + text.push_str(&chunk.0); + } + text + } + } } diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index daf182c2e7..b404bcb3dc 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -3,6 +3,7 @@ use super::{ Anchor, Buffer, DisplayPoint, Edit, Point, ToOffset, }; use crate::{ + editor::rope, sum_tree::{self, Cursor, FilterCursor, SeekBias, SumTree}, time, }; @@ -607,7 +608,7 @@ pub struct Chars<'a> { cursor: Cursor<'a, Transform, DisplayOffset, TransformSummary>, offset: usize, buffer: &'a Buffer, - buffer_chars: Option>>, + buffer_chars: Option>>, } impl<'a> Iterator for Chars<'a> { diff --git a/zed/src/worktree.rs b/zed/src/worktree.rs index 29df096a4f..2a924cf586 100644 --- a/zed/src/worktree.rs +++ b/zed/src/worktree.rs @@ -3,7 +3,7 @@ mod fuzzy; mod ignore; use crate::{ - editor::History, + editor::{History, Rope}, sum_tree::{self, Cursor, Edit, SeekBias, SumTree}, }; use ::ignore::gitignore::Gitignore; @@ -16,7 +16,6 @@ use postage::{ prelude::{Sink, Stream}, watch, }; -use ropey::Rope; use smol::channel::Sender; use std::{ cmp, @@ -204,7 +203,7 @@ impl Worktree { let path = path.to_path_buf(); let abs_path = self.absolutize(&path); ctx.background_executor().spawn(async move { - let buffer_size = content.len_bytes().min(10 * 1024); + let buffer_size = content.summary().bytes.min(10 * 1024); let file = fs::File::create(&abs_path)?; let mut writer = io::BufWriter::with_capacity(buffer_size, &file); for chunk in content.chunks() {