From 7b98fb33dd697cb65a1f0a01a9f12cfcd0818345 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 13 May 2021 19:24:03 +0200 Subject: [PATCH] WIP: Get the type checker passing... ...but not the borrow checker! Co-Authored-By: Max Brunsfeld --- zed/src/editor/buffer/mod.rs | 526 +++++++++---------------- zed/src/editor/buffer/text.rs | 54 --- zed/src/editor/display_map/fold_map.rs | 19 +- zed/src/editor/display_map/mod.rs | 2 +- zed/src/operation_queue.rs | 3 +- zed/src/sum_tree/mod.rs | 111 +++--- zed/src/worktree.rs | 19 +- 7 files changed, 240 insertions(+), 494 deletions(-) delete mode 100644 zed/src/editor/buffer/text.rs diff --git a/zed/src/editor/buffer/mod.rs b/zed/src/editor/buffer/mod.rs index a2caa6cb380a224f9f9266acc5e30bb7d002a461..735846dd8d3740949edb5b9d1229b31fdfe84e56 100644 --- a/zed/src/editor/buffer/mod.rs +++ b/zed/src/editor/buffer/mod.rs @@ -1,15 +1,13 @@ mod anchor; mod point; mod selection; -mod text; pub use anchor::*; pub use point::*; -use ropey::Rope; +use ropey::{Rope, RopeSlice}; use seahash::SeaHasher; pub use selection::*; use similar::{ChangeTag, TextDiff}; -pub use text::*; use crate::{ operation_queue::{self, OperationQueue}, @@ -79,10 +77,6 @@ pub struct Buffer { lamport_clock: time::Lamport, } -pub struct Snapshot { - fragments: SumTree, -} - #[derive(Clone)] struct Transaction { start: time::Global, @@ -243,18 +237,6 @@ impl UndoMap { } } -#[derive(Clone)] -pub struct CharIter<'a> { - fragments_cursor: Cursor<'a, Fragment, usize, usize>, - fragment_chars: str::Chars<'a>, -} - -#[derive(Clone)] -pub struct FragmentIter<'a> { - cursor: Cursor<'a, Fragment, usize, usize>, - started: bool, -} - struct Edits<'a, F: Fn(&FragmentSummary) -> bool> { cursor: FilterCursor<'a, F, Fragment, usize>, undos: &'a UndoMap, @@ -312,21 +294,60 @@ pub struct FragmentSummary { #[derive(Default, Clone, Debug, PartialEq, Eq)] struct FragmentTextSummary { - visible: TextSummary, - deleted: TextSummary, + visible: usize, + deleted: usize, } 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; + self.visible += summary.text.visible; + self.deleted += summary.text.deleted; } } -#[derive(Eq, PartialEq, Clone, Debug, Ord, PartialOrd)] -struct FragmentExtent { - chars: usize, - lines: Point, +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub struct TextSummary { + pub chars: usize, + pub bytes: usize, + pub lines: 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(); + Self { + chars: slice.len_chars(), + bytes: slice.len_bytes(), + lines: Point::new(last_row as u32, last_column as u32), + } + } +} + +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)] @@ -455,7 +476,6 @@ impl Buffer { extent: 0, }, &(), - &(), ), ); fragments.push( @@ -464,7 +484,6 @@ impl Buffer { base_insertion.clone(), 0..0, ), - &FragmentContext::default(), &(), ); @@ -480,11 +499,9 @@ impl Buffer { extent: range_in_insertion.end, }, &(), - &(), ); fragments.push( Fragment::new(base_fragment_id, base_insertion, range_in_insertion.clone()), - &FragmentContext::new(base_text, Rope::new(), Default::default()), &(), ); } @@ -511,10 +528,8 @@ impl Buffer { } } - pub fn snapshot(&self) -> Snapshot { - Snapshot { - fragments: self.fragments.clone(), - } + pub fn snapshot(&self) -> Rope { + self.visible_text.clone() } pub fn file(&self) -> Option<&FileHandle> { @@ -625,7 +640,7 @@ impl Buffer { } pub fn text_summary(&self) -> TextSummary { - self.fragments.extent::() + TextSummary::from(self.visible_text.slice(..)) } pub fn text_summary_for_range(&self, range: Range) -> TextSummary { @@ -680,7 +695,7 @@ impl Buffer { } pub fn max_point(&self) -> Point { - TextSummary::from(&self.visible_text).lines + self.text_summary().lines } pub fn line(&self, row: u32) -> Result { @@ -703,13 +718,13 @@ impl Buffer { Ok(self.chars_at(start)?.take(end - start)) } - pub fn chars(&self) -> CharIter { + pub fn chars(&self) -> ropey::iter::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(CharIter::new(&self.fragments, offset)) + Ok(self.visible_text.chars_at(offset)) } pub fn selections_changed_since(&self, since: SelectionsVersion) -> bool { @@ -1081,15 +1096,7 @@ impl Buffer { 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(), - ), - &(), - ); + new_fragments.push(cursor.item().unwrap().clone(), &()); cursor.next(); } @@ -1128,30 +1135,12 @@ impl Buffer { None }; if let Some(fragment) = before_range { - new_fragments.push( - fragment, - &FragmentContext::new( - new_visible_text.clone(), - new_deleted_text.clone(), - new_fragments.summary().text, - ), - &(), - ); + new_fragments.push(fragment, &()); } if let Some(fragment) = insertion { - 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, - ), - &(), - ); + new_visible_text + .insert(new_fragments.summary().text.visible, new_text.unwrap()); + new_fragments.push(fragment, &()); } if let Some(mut fragment) = within_range { if fragment.was_visible(&version_in_range, &self.undo_map) { @@ -1159,35 +1148,19 @@ impl Buffer { fragment.visible = false; // TODO: avoid calling to_string on rope slice. - let deleted_start = new_fragments.summary().text.visible.chars; + 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.chars, + new_fragments.summary().text.deleted, &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, - ), - &(), - ); + new_fragments.push(fragment, &()); } if let Some(fragment) = after_range { - new_fragments.push( - fragment, - &FragmentContext::new( - new_visible_text.clone(), - new_deleted_text.clone(), - new_fragments.summary().text, - ), - &(), - ); + new_fragments.push(fragment, &()); } } else { if new_text.is_some() && lamport_timestamp > fragment.insertion.lamport_timestamp { @@ -1199,16 +1172,8 @@ impl Buffer { local_timestamp, lamport_timestamp, ); - new_visible_text.insert(new_fragments.summary().text.visible.chars, new_text); - new_fragments.push( - fragment, - &FragmentContext::new( - new_visible_text.clone(), - new_deleted_text.clone(), - new_fragments.summary().text, - ), - &(), - ); + new_visible_text.insert(new_fragments.summary().text.visible, new_text); + new_fragments.push(fragment, &()); } if fragment.id < end_fragment_id @@ -1218,24 +1183,16 @@ impl Buffer { fragment.visible = false; // TODO: avoid calling to_string on rope slice. - let deleted_start = new_fragments.summary().text.visible.chars; + 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.chars, + new_fragments.summary().text.deleted, &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, - ), - &(), - ); + new_fragments.push(fragment, &()); } cursor.next(); @@ -1249,16 +1206,8 @@ impl Buffer { local_timestamp, lamport_timestamp, ); - new_visible_text.insert(new_fragments.summary().text.visible.chars, new_text); - new_fragments.push( - fragment, - &FragmentContext::new( - new_visible_text.clone(), - new_deleted_text.clone(), - new_fragments.summary().text, - ), - &(), - ); + new_visible_text.insert(new_fragments.summary().text.visible, new_text); + new_fragments.push(fragment, &()); } new_fragments.push_tree(cursor.slice(&last_id_ref, SeekBias::Right, &()), &()); @@ -1363,32 +1312,24 @@ impl Buffer { // TODO: avoid calling to_string on rope slice. if fragment.visible && !was_visible { - let visible_start = new_fragments.summary().text.deleted.chars; + 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.chars, + new_fragments.summary().text.visible, &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_start = new_fragments.summary().text.visible; let deleted_range = deleted_start..deleted_start + fragment.len(); new_deleted_text.insert( - new_fragments.summary().text.deleted.chars, + new_fragments.summary().text.deleted, &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, - ), - &(), - ); + new_fragments.push(fragment, &()); cursor.next(); if let Some(split_id) = insertion_splits.next() { new_fragments.push_tree( @@ -1418,33 +1359,25 @@ impl Buffer { // TODO: avoid calling to_string on rope slice. if fragment.visible && !was_visible { - let visible_start = new_fragments.summary().text.deleted.chars; + 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.chars, + new_fragments.summary().text.visible, &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_start = new_fragments.summary().text.visible; let deleted_range = deleted_start..deleted_start + fragment.len(); new_deleted_text.insert( - new_fragments.summary().text.deleted.chars, + new_fragments.summary().text.deleted, &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, - ), - &(), - ); + new_fragments.push(fragment, &()); cursor.next(); } } @@ -1579,17 +1512,13 @@ impl Buffer { prefix.id = FragmentId::between(&new_fragments.last().unwrap().id, &fragment.id); fragment.range_in_insertion.start = prefix.range_in_insertion.end; - new_fragments.push( - prefix.clone(), - &FragmentContext::new(new_visible_text.clone()) & (), - ); + new_fragments.push(prefix.clone(), &()); new_split_tree.push( InsertionSplit { extent: prefix.range_in_insertion.end - prefix.range_in_insertion.start, fragment_id: prefix.id, }, &(), - &(), ); fragment_start = range.start; } @@ -1614,6 +1543,7 @@ impl Buffer { local_timestamp, lamport_timestamp, ); + new_visible_text.insert(new_fragments.summary().text.visible, &new_text); new_fragments.push(new_fragment, &()); } } @@ -1629,6 +1559,15 @@ impl Buffer { if fragment.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).to_string(), + ); + new_visible_text.remove(deleted_range); } fragment.range_in_insertion.start = prefix.range_in_insertion.end; new_fragments.push(prefix.clone(), &()); @@ -1649,6 +1588,15 @@ impl Buffer { if fragment.visible { 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).to_string(), + ); + new_visible_text.remove(deleted_range); } } @@ -1712,6 +1660,15 @@ impl Buffer { if new_fragment.visible { 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).to_string(), + ); + new_visible_text.remove(deleted_range); } new_fragments.push(new_fragment, &()); cursor.next(); @@ -1775,6 +1732,7 @@ impl Buffer { end_id: last_fragment.insertion.id, end_offset: last_fragment.range_in_insertion.end, version_in_range: time::Global::new(), + // TODO: avoid cloning the String. new_text: new_text.clone(), }, lamport_timestamp, @@ -1784,10 +1742,11 @@ impl Buffer { let new_fragment = self.build_fragment_to_insert( &last_fragment, None, - new_text, + &new_text, local_timestamp, lamport_timestamp, ); + new_visible_text.insert(new_fragments.summary().text.visible, &new_text); new_fragments.push(new_fragment, &()); } } else { @@ -1797,6 +1756,8 @@ impl Buffer { ); } + self.visible_text = new_visible_text; + self.deleted_text = new_deleted_text; self.fragments = new_fragments; ops } @@ -1864,7 +1825,6 @@ impl Buffer { fragment_id: fragment.id.clone(), }, &(), - &(), ); } @@ -1875,7 +1835,6 @@ impl Buffer { fragment_id: fragment.id.clone(), }, &(), - &(), ); } @@ -1886,7 +1845,6 @@ impl Buffer { fragment_id: fragment.id.clone(), }, &(), - &(), ); } @@ -1927,7 +1885,6 @@ impl Buffer { fragment_id: new_fragment_id.clone(), }, &(), - &(), ); self.insertion_splits.insert(insertion_id, split_tree); @@ -2021,7 +1978,7 @@ impl Buffer { fn summary_for_anchor(&self, anchor: &Anchor) -> Result { match anchor { Anchor::Start => Ok(TextSummary::default()), - Anchor::End => Ok(self.fragments.summary().text_summary), + Anchor::End => Ok(self.text_summary()), Anchor::Middle { insertion_id, offset, @@ -2042,37 +1999,29 @@ impl Buffer { .item() .ok_or_else(|| anyhow!("split offset is out of range"))?; - let mut fragments_cursor = self.fragments.cursor::(); + let mut fragments_cursor = self + .fragments + .cursor::(); fragments_cursor.seek(&FragmentIdRef::new(&split.fragment_id), SeekBias::Left, &()); let fragment = fragments_cursor .item() .ok_or_else(|| anyhow!("fragment id does not exist"))?; - let mut summary = fragments_cursor.start().clone(); + let mut ix = fragments_cursor.start().clone().visible; if fragment.visible { - summary += fragment - .text - .slice(..offset - fragment.range_in_insertion.start) - .summary(); + ix += offset - fragment.range_in_insertion.start; } - Ok(summary) + Ok(self.text_summary_for_range(0..ix)) } } } - #[allow(dead_code)] pub fn point_for_offset(&self, offset: usize) -> Result { - let mut fragments_cursor = self.fragments.cursor::(); - fragments_cursor.seek(&offset, SeekBias::Left, &()); - fragments_cursor - .item() - .ok_or_else(|| anyhow!("offset is out of range")) - .map(|fragment| { - let overshoot = fragment - .point_for_offset(offset - &fragments_cursor.start().chars) - .unwrap(); - fragments_cursor.start().lines + &overshoot - }) + if offset <= self.len() { + Ok(self.text_summary_for_range(0..offset).lines) + } else { + Err(anyhow!("offset out of bounds")) + } } } @@ -2080,6 +2029,7 @@ impl Clone for Buffer { fn clone(&self) -> Self { Self { 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(), @@ -2100,16 +2050,6 @@ impl Clone for Buffer { } } -impl Snapshot { - pub fn fragments<'a>(&'a self) -> FragmentIter<'a> { - FragmentIter::new(&self.fragments) - } - - pub fn text_summary(&self) -> TextSummary { - self.fragments.summary().text_summary - } -} - #[derive(Clone, Debug, Eq, PartialEq)] pub enum Event { Edited, @@ -2123,81 +2063,6 @@ impl Entity for Buffer { type Event = Event; } -impl<'a> sum_tree::Dimension<'a, FragmentSummary> for Point { - fn add_summary(&mut self, summary: &FragmentSummary) { - *self += &summary.text_summary.lines; - } -} - -impl<'a> CharIter<'a> { - fn new(fragments: &'a SumTree, offset: usize) -> Self { - let mut fragments_cursor = fragments.cursor::(); - fragments_cursor.seek(&offset, SeekBias::Right, &()); - let fragment_chars = fragments_cursor.item().map_or("".chars(), |fragment| { - let offset_in_fragment = offset - fragments_cursor.start(); - fragment.text[offset_in_fragment..].chars() - }); - Self { - fragments_cursor, - fragment_chars, - } - } -} - -impl<'a> Iterator for CharIter<'a> { - type Item = char; - - fn next(&mut self) -> Option { - if let Some(char) = self.fragment_chars.next() { - Some(char) - } else { - loop { - self.fragments_cursor.next(); - if let Some(fragment) = self.fragments_cursor.item() { - if fragment.visible { - self.fragment_chars = fragment.text.as_str().chars(); - return self.fragment_chars.next(); - } - } else { - return None; - } - } - } - } -} - -impl<'a> FragmentIter<'a> { - fn new(fragments: &'a SumTree) -> Self { - let mut cursor = fragments.cursor::(); - cursor.seek(&0, SeekBias::Right, &()); - Self { - cursor, - started: false, - } - } -} - -impl<'a> Iterator for FragmentIter<'a> { - type Item = &'a str; - - fn next(&mut self) -> Option { - loop { - if self.started { - self.cursor.next(); - } else { - self.started = true; - } - if let Some(fragment) = self.cursor.item() { - if fragment.visible { - return Some(fragment.text.as_str()); - } - } else { - return None; - } - } - } -} - impl<'a, F: Fn(&FragmentSummary) -> bool> Iterator for Edits<'a, F> { type Item = Edit; @@ -2411,28 +2276,10 @@ impl Fragment { } } -#[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, ctx: &FragmentContext) -> Self::Summary { + fn summary(&self) -> Self::Summary { let mut max_version = time::Global::new(); max_version.observe(self.insertion.id); for deletion in &self.deletions { @@ -2441,21 +2288,19 @@ impl sum_tree::Item for Fragment { max_version.observe_all(&self.max_undos); if self.visible { - let start = ctx.start.visible.chars; FragmentSummary { text: FragmentTextSummary { - visible: TextSummary::from(ctx.visible_text.slice(start..start + self.len())), - deleted: TextSummary::default(), + visible: self.len(), + deleted: 0, }, max_fragment_id: self.id.clone(), max_version, } } else { - let start = ctx.start.deleted.chars; FragmentSummary { text: FragmentTextSummary { - visible: TextSummary::default(), - deleted: TextSummary::from(ctx.deleted_text.slice(start..start + self.len())), + visible: 0, + deleted: self.len(), }, max_fragment_id: self.id.clone(), max_version, @@ -2486,46 +2331,16 @@ impl Default for FragmentSummary { } } -impl<'a> sum_tree::Dimension<'a, FragmentSummary> for TextSummary { - fn add_summary(&mut self, summary: &FragmentSummary) { - *self += &summary.text_summary; - } -} - -impl<'a> AddAssign<&'a FragmentExtent> for FragmentExtent { - fn add_assign(&mut self, other: &Self) { - self.chars += other.chars; - self.lines += &other.lines; - } -} - -impl Default for FragmentExtent { - fn default() -> Self { - FragmentExtent { - lines: Point::zero(), - chars: 0, - } - } -} - -impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FragmentExtent { - fn add_summary(&mut self, summary: &FragmentSummary) { - self.chars += summary.text_summary.chars; - self.lines += &summary.text_summary.lines; - } -} - impl<'a> sum_tree::Dimension<'a, FragmentSummary> for usize { fn add_summary(&mut self, summary: &FragmentSummary) { - *self += summary.text_summary.chars; + *self += summary.text.visible; } } 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, } @@ -2591,17 +2406,12 @@ pub trait ToOffset { impl ToOffset for Point { fn to_offset(&self, buffer: &Buffer) -> Result { - let mut fragments_cursor = buffer.fragments.cursor::(); - fragments_cursor.seek(self, SeekBias::Left, &()); - fragments_cursor - .item() - .ok_or_else(|| anyhow!("point is out of range")) - .map(|fragment| { - let overshoot = fragment - .offset_for_point(*self - fragments_cursor.start().lines) - .unwrap(); - fragments_cursor.start().chars + overshoot - }) + 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")) + } } } @@ -2635,17 +2445,13 @@ impl ToPoint for Anchor { impl ToPoint for usize { fn to_point(&self, buffer: &Buffer) -> Result { - let mut fragments_cursor = buffer.fragments.cursor::(); - fragments_cursor.seek(&self, SeekBias::Left, &()); - fragments_cursor - .item() - .ok_or_else(|| anyhow!("offset is out of range")) - .map(|fragment| { - let overshoot = fragment - .point_for_offset(*self - &fragments_cursor.start().chars) - .unwrap(); - fragments_cursor.start().lines + overshoot - }) + 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")) + } } } @@ -2798,8 +2604,9 @@ mod tests { let (longest_column, longest_rows) = line_lengths.iter().next_back().unwrap(); let range_sum = buffer.text_summary_for_range(start..end); - assert_eq!(range_sum.rightmost_point.column, *longest_column); - assert!(longest_rows.contains(&range_sum.rightmost_point.row)); + // TODO: re-enable when we have rightmost point again. + // assert_eq!(range_sum.rightmost_point.column, *longest_column); + // assert!(longest_rows.contains(&range_sum.rightmost_point.row)); let range_text = &buffer.text()[start..end]; assert_eq!(range_sum.chars, range_text.chars().count()); assert_eq!(range_sum.bytes, range_text.len()); @@ -2878,26 +2685,45 @@ mod tests { fn test_text_summary_for_range(ctx: &mut gpui::MutableAppContext) { ctx.add_model(|ctx| { let buffer = Buffer::new(0, "ab\nefg\nhklm\nnopqrs\ntuvwxyz", ctx); - let text = Text::from(buffer.text()); assert_eq!( buffer.text_summary_for_range(1..3), - text.slice(1..3).summary() + TextSummary { + chars: 2, + bytes: 2, + lines: Point::new(1, 0) + } ); assert_eq!( buffer.text_summary_for_range(1..12), - text.slice(1..12).summary() + TextSummary { + chars: 2, + bytes: 2, + lines: Point::new(1, 0) + } ); assert_eq!( buffer.text_summary_for_range(0..20), - text.slice(0..20).summary() + TextSummary { + chars: 2, + bytes: 2, + lines: Point::new(1, 0) + } ); assert_eq!( buffer.text_summary_for_range(0..22), - text.slice(0..22).summary() + TextSummary { + chars: 2, + bytes: 2, + lines: Point::new(1, 0) + } ); assert_eq!( buffer.text_summary_for_range(7..22), - text.slice(7..22).summary() + TextSummary { + chars: 2, + bytes: 2, + lines: Point::new(1, 0) + } ); buffer }); diff --git a/zed/src/editor/buffer/text.rs b/zed/src/editor/buffer/text.rs deleted file mode 100644 index 715c6774628f075accb988a4899d94702087ecde..0000000000000000000000000000000000000000 --- a/zed/src/editor/buffer/text.rs +++ /dev/null @@ -1,54 +0,0 @@ -use ropey::{Rope, RopeSlice}; - -use super::Point; - -#[derive(Clone, Debug, Default, Eq, PartialEq)] -pub struct TextSummary { - pub chars: usize, - pub bytes: usize, - pub lines: 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(); - Self { - chars: slice.len_chars(), - bytes: slice.len_bytes(), - lines: Point::new(last_row as u32, last_column as u32), - } - } -} - -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; - // } - - 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; - } -} diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index d0cbe60c5817d9c31da3fab2841ba94eeb8fea29..b2e36e0867b248afcd1759e94d726e51240b8dd4 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -1,6 +1,6 @@ use super::{ - buffer::{self, AnchorRangeExt}, - Anchor, Buffer, DisplayPoint, Edit, Point, TextSummary, ToOffset, + buffer::{self, AnchorRangeExt, TextSummary}, + Anchor, Buffer, DisplayPoint, Edit, Point, ToOffset, }; use crate::{ sum_tree::{self, Cursor, FilterCursor, SeekBias, SumTree}, @@ -38,7 +38,6 @@ impl FoldMap { display_text: None, }, &(), - &(), )), last_sync: Mutex::new(buffer.version()), } @@ -124,7 +123,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 @@ -343,7 +342,6 @@ impl FoldMap { display_text: None, }, &(), - &(), ); } @@ -363,7 +361,6 @@ impl FoldMap { display_text: Some('…'), }, &(), - &(), ); } } @@ -381,7 +378,6 @@ impl FoldMap { display_text: None, }, &(), - &(), ); } } @@ -398,7 +394,6 @@ impl FoldMap { display_text: None, }, &(), - &(), ); } @@ -471,10 +466,9 @@ 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() } } @@ -504,10 +498,9 @@ 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(), @@ -615,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/editor/display_map/mod.rs b/zed/src/editor/display_map/mod.rs index 608d39dac85161a28b4d9d4756cdea87d5c3d114..7ee540bd2e094522f9f2fd417ed7a2b68f5a9a4f 100644 --- a/zed/src/editor/display_map/mod.rs +++ b/zed/src/editor/display_map/mod.rs @@ -1,6 +1,6 @@ mod fold_map; -use super::{buffer, Anchor, Buffer, Edit, Point, TextSummary, ToOffset, ToPoint}; +use super::{buffer, Anchor, Buffer, Edit, Point, ToOffset, ToPoint}; use anyhow::Result; pub use fold_map::BufferRows; use fold_map::{FoldMap, FoldMapSnapshot}; diff --git a/zed/src/operation_queue.rs b/zed/src/operation_queue.rs index 5fd24fbe976dcf8a83fcf8d42394a90743cf1125..2c0e234fe98cd30c6d3fa72b210a93c0441b8249 100644 --- a/zed/src/operation_queue.rs +++ b/zed/src/operation_queue.rs @@ -48,10 +48,9 @@ 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 2cbd928aba5f0714f553051c4a358afa3b067575..e70440f16f0c0bfeb811c8ad1aa6167adc85b253 100644 --- a/zed/src/sum_tree/mod.rs +++ b/zed/src/sum_tree/mod.rs @@ -11,13 +11,12 @@ const TREE_BASE: usize = 2; const TREE_BASE: usize = 6; pub trait Item: Clone + fmt::Debug { - type Context; type Summary: Summary; - fn summary(&self, ctx: &Self::Context) -> Self::Summary; + fn summary(&self) -> Self::Summary; } -pub trait KeyedItem: Item { +pub trait KeyedItem: Item { type Key: for<'a> Dimension<'a, Self::Summary> + Ord; fn key(&self) -> Self::Key; @@ -65,13 +64,9 @@ impl SumTree { })) } - pub fn from_item( - item: T, - item_ctx: &T::Context, - summary_ctx: &::Context, - ) -> Self { + pub fn from_item(item: T, ctx: &::Context) -> Self { let mut tree = Self::new(); - tree.push(item, item_ctx, summary_ctx); + tree.push(item, ctx); tree } @@ -130,13 +125,47 @@ impl SumTree { } } - pub fn push( - &mut self, - item: T, - item_ctx: &T::Context, - summary_ctx: &::Context, - ) { - let summary = item.summary(item_ctx); + 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(); self.push_tree( SumTree::from_child_trees( vec![SumTree(Arc::new(Node::Leaf { @@ -144,9 +173,9 @@ impl SumTree { items: ArrayVec::from_iter(Some(item)), item_summaries: ArrayVec::from_iter(Some(summary)), }))], - summary_ctx, + ctx, ), - summary_ctx, + ctx, ) } @@ -320,54 +349,13 @@ 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 }; @@ -875,10 +863,9 @@ 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 7d7356f2d2fc68219fc85757ec8a605172b5c025..29df096a4f2278764351a5e7f8910b2e4585196d 100644 --- a/zed/src/worktree.rs +++ b/zed/src/worktree.rs @@ -3,7 +3,7 @@ mod fuzzy; mod ignore; use crate::{ - editor::{History, Snapshot as BufferSnapshot}, + editor::History, sum_tree::{self, Cursor, Edit, SeekBias, SumTree}, }; use ::ignore::gitignore::Gitignore; @@ -16,6 +16,7 @@ use postage::{ prelude::{Sink, Stream}, watch, }; +use ropey::Rope; use smol::channel::Sender; use std::{ cmp, @@ -198,20 +199,15 @@ impl Worktree { }) } - pub fn save<'a>( - &self, - path: &Path, - content: BufferSnapshot, - ctx: &AppContext, - ) -> Task> { + pub fn save<'a>(&self, path: &Path, content: Rope, ctx: &AppContext) -> Task> { let handles = self.handles.clone(); let path = path.to_path_buf(); let abs_path = self.absolutize(&path); ctx.background_executor().spawn(async move { - let buffer_size = content.text_summary().bytes.min(10 * 1024); + let buffer_size = content.len_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.fragments() { + for chunk in content.chunks() { writer.write(chunk.as_bytes())?; } writer.flush()?; @@ -459,7 +455,7 @@ impl FileHandle { self.worktree.read(ctx).load_history(&self.path(), ctx) } - pub fn save<'a>(&self, content: BufferSnapshot, ctx: &AppContext) -> Task> { + pub fn save<'a>(&self, content: Rope, ctx: &AppContext) -> Task> { let worktree = self.worktree.read(ctx); worktree.save(&self.path(), content, ctx) } @@ -538,10 +534,9 @@ 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() {