diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index ec13b37299..5cbfdd0afd 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -430,7 +430,7 @@ impl Buffer { Self { saved_mtime, saved_version: buffer.version(), - saved_version_fingerprint: buffer.text_summary().hex_fingerprint(), + saved_version_fingerprint: buffer.as_rope().fingerprint(), transaction_depth: 0, was_dirty_before_starting_transaction: None, text: buffer, @@ -544,7 +544,7 @@ impl Buffer { if let Some(transaction) = this.apply_diff(diff, cx).cloned() { this.did_reload( this.version(), - this.text_summary().hex_fingerprint(), + this.as_rope().fingerprint(), new_mtime, cx, ); @@ -994,12 +994,12 @@ impl Buffer { } pub fn is_dirty(&self) -> bool { - self.saved_version_fingerprint != self.as_rope().summary().hex_fingerprint() + self.saved_version_fingerprint != self.as_rope().fingerprint() || self.file.as_ref().map_or(false, |file| file.is_deleted()) } pub fn has_conflict(&self) -> bool { - self.saved_version_fingerprint != self.as_rope().summary().hex_fingerprint() + self.saved_version_fingerprint != self.as_rope().fingerprint() && self .file .as_ref() diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index a0d5e4745e..1acf5a8335 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -8112,7 +8112,7 @@ mod tests { events.borrow_mut().clear(); buffer.did_save( buffer.version(), - buffer.as_rope().summary().hex_fingerprint(), + buffer.as_rope().fingerprint(), buffer.file().unwrap().mtime(), None, cx, diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index ed4ea1c986..d5e9b392e7 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -634,7 +634,7 @@ impl LocalWorktree { ) -> Task> { let buffer = buffer_handle.read(cx); let text = buffer.as_rope().clone(); - let fingerprint = text.summary().hex_fingerprint(); + let fingerprint = text.fingerprint(); let version = buffer.version(); let save = self.write_file(path, text, cx); let handle = cx.handle(); @@ -1708,7 +1708,7 @@ impl language::File for File { Worktree::Local(worktree) => { let rpc = worktree.client.clone(); let project_id = worktree.share.as_ref().map(|share| share.project_id); - let fingerprint = text.summary().hex_fingerprint(); + let fingerprint = text.fingerprint(); let save = worktree.write_file(self.path.clone(), text, cx); cx.background().spawn(async move { let entry = save.await?; diff --git a/crates/text/src/rope.rs b/crates/text/src/rope.rs index ddfa9eda8f..1167006249 100644 --- a/crates/text/src/rope.rs +++ b/crates/text/src/rope.rs @@ -116,7 +116,7 @@ impl Rope { } pub fn summary(&self) -> TextSummary { - self.chunks.summary().clone() + self.chunks.summary().text.clone() } pub fn len(&self) -> usize { @@ -291,6 +291,10 @@ impl Rope { self.clip_point(Point::new(row, u32::MAX), Bias::Left) .column } + + pub fn fingerprint(&self) -> String { + self.chunks.summary().fingerprint.to_hex() + } } impl<'a> From<&'a str> for Rope { @@ -710,10 +714,34 @@ impl Chunk { } impl sum_tree::Item for Chunk { - type Summary = TextSummary; + type Summary = ChunkSummary; fn summary(&self) -> Self::Summary { - TextSummary::from(self.0.as_str()) + ChunkSummary::from(self.0.as_str()) + } +} + +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub struct ChunkSummary { + text: TextSummary, + fingerprint: HashMatrix, +} + +impl<'a> From<&'a str> for ChunkSummary { + fn from(text: &'a str) -> Self { + Self { + text: TextSummary::from(text), + fingerprint: bromberg_sl2::hash_strict(text.as_bytes()), + } + } +} + +impl sum_tree::Summary for ChunkSummary { + type Context = (); + + fn add_summary(&mut self, summary: &Self, _: &()) { + self.text += &summary.text; + self.fingerprint = self.fingerprint * summary.fingerprint; } } @@ -726,13 +754,6 @@ pub struct TextSummary { pub last_line_chars: u32, pub longest_row: u32, pub longest_row_chars: u32, - pub fingerprint: HashMatrix, -} - -impl TextSummary { - pub fn hex_fingerprint(&self) -> String { - self.fingerprint.to_hex() - } } impl<'a> From<&'a str> for TextSummary { @@ -772,7 +793,6 @@ impl<'a> From<&'a str> for TextSummary { last_line_chars, longest_row, longest_row_chars, - fingerprint: bromberg_sl2::hash_strict(text.as_bytes()), } } } @@ -819,7 +839,6 @@ impl<'a> std::ops::AddAssign<&'a Self> for TextSummary { self.bytes += other.bytes; self.lines += other.lines; self.lines_utf16 += other.lines_utf16; - self.fingerprint = self.fingerprint * other.fingerprint; } } @@ -829,7 +848,7 @@ impl std::ops::AddAssign for TextSummary { } } -pub trait TextDimension: 'static + for<'a> Dimension<'a, TextSummary> { +pub trait TextDimension: 'static + for<'a> Dimension<'a, ChunkSummary> { fn from_text_summary(summary: &TextSummary) -> Self; fn add_assign(&mut self, other: &Self); } @@ -848,6 +867,12 @@ impl<'a, D1: TextDimension, D2: TextDimension> TextDimension for (D1, D2) { } } +impl<'a> sum_tree::Dimension<'a, ChunkSummary> for TextSummary { + fn add_summary(&mut self, summary: &'a ChunkSummary, _: &()) { + *self += &summary.text; + } +} + impl TextDimension for TextSummary { fn from_text_summary(summary: &TextSummary) -> Self { summary.clone() @@ -858,9 +883,9 @@ impl TextDimension for TextSummary { } } -impl<'a> sum_tree::Dimension<'a, TextSummary> for usize { - fn add_summary(&mut self, summary: &'a TextSummary, _: &()) { - *self += summary.bytes; +impl<'a> sum_tree::Dimension<'a, ChunkSummary> for usize { + fn add_summary(&mut self, summary: &'a ChunkSummary, _: &()) { + *self += summary.text.bytes; } } @@ -874,9 +899,9 @@ impl TextDimension for usize { } } -impl<'a> sum_tree::Dimension<'a, TextSummary> for Point { - fn add_summary(&mut self, summary: &'a TextSummary, _: &()) { - *self += summary.lines; +impl<'a> sum_tree::Dimension<'a, ChunkSummary> for Point { + fn add_summary(&mut self, summary: &'a ChunkSummary, _: &()) { + *self += summary.text.lines; } } @@ -890,9 +915,9 @@ impl TextDimension for Point { } } -impl<'a> sum_tree::Dimension<'a, TextSummary> for PointUtf16 { - fn add_summary(&mut self, summary: &'a TextSummary, _: &()) { - *self += summary.lines_utf16; +impl<'a> sum_tree::Dimension<'a, ChunkSummary> for PointUtf16 { + fn add_summary(&mut self, summary: &'a ChunkSummary, _: &()) { + *self += summary.text.lines_utf16; } } diff --git a/crates/text/src/tests.rs b/crates/text/src/tests.rs index ee260afa6e..e66837f21b 100644 --- a/crates/text/src/tests.rs +++ b/crates/text/src/tests.rs @@ -226,7 +226,6 @@ fn test_text_summary_for_range() { last_line_chars: 0, longest_row: 0, longest_row_chars: 1, - fingerprint: bromberg_sl2::hash_strict(b"b\n") } ); assert_eq!( @@ -239,7 +238,6 @@ fn test_text_summary_for_range() { last_line_chars: 0, longest_row: 2, longest_row_chars: 4, - fingerprint: bromberg_sl2::hash_strict(b"b\nefg\nhklm\n") } ); assert_eq!( @@ -252,7 +250,6 @@ fn test_text_summary_for_range() { last_line_chars: 1, longest_row: 3, longest_row_chars: 6, - fingerprint: bromberg_sl2::hash_strict(b"ab\nefg\nhklm\nnopqrs\nt") } ); assert_eq!( @@ -265,7 +262,6 @@ fn test_text_summary_for_range() { last_line_chars: 3, longest_row: 3, longest_row_chars: 6, - fingerprint: bromberg_sl2::hash_strict(b"ab\nefg\nhklm\nnopqrs\ntuv") } ); assert_eq!( @@ -278,7 +274,6 @@ fn test_text_summary_for_range() { last_line_chars: 3, longest_row: 1, longest_row_chars: 6, - fingerprint: bromberg_sl2::hash_strict(b"hklm\nnopqrs\ntuv") } ); }