diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index 1d09b7008fbd20fd59fb29b80741cada2306216d..72b88f837d2768b565026a5e58001035b598431a 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -313,11 +313,13 @@ impl MultiBuffer { } pub fn update_git(&mut self, cx: &mut ModelContext) { - let mut buffers = self.buffers.borrow_mut(); - for buffer in buffers.values_mut() { - buffer.buffer.update(cx, |buffer, _| { - buffer.update_git(); - }) + let buffers = self.buffers.borrow(); + for buffer_state in buffers.values() { + if buffer_state.buffer.read(cx).needs_git_update() { + buffer_state + .buffer + .update(cx, |buffer, cx| buffer.update_git(cx)) + } } } diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index e75e17e54134cc92ffa120c3d5a2305c3cf617b3..2cff3796bc1927d736b69227a2b323bd51dd0219 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -1,4 +1,4 @@ -use crate::git::{BufferDiff, BufferDiffSnapshot, DiffHunk}; +use crate::git::{BufferDiff, DiffHunk}; pub use crate::{ diagnostic_set::DiagnosticSet, highlight_map::{HighlightId, HighlightMap}, @@ -48,7 +48,7 @@ pub use lsp::DiagnosticSeverity; pub struct Buffer { text: TextBuffer, - head_text: Option, + head_text: Option>, git_diff: BufferDiff, file: Option>, saved_version: clock::Global, @@ -77,7 +77,7 @@ pub struct Buffer { pub struct BufferSnapshot { text: text::BufferSnapshot, - pub diff_snapshot: BufferDiffSnapshot, + pub diff_snapshot: BufferDiff, pub(crate) syntax: SyntaxSnapshot, file: Option>, diagnostics: DiagnosticSet, @@ -347,7 +347,7 @@ impl Buffer { ) -> Self { Self::build( TextBuffer::new(replica_id, cx.model_id() as u64, base_text.into()), - head_text.map(|h| h.into()), + head_text.map(|h| Arc::new(h.into())), Some(file), ) } @@ -358,7 +358,7 @@ impl Buffer { file: Option>, ) -> Result { let buffer = TextBuffer::new(replica_id, message.id, message.base_text); - let mut this = Self::build(buffer, message.head_text, file); + let mut this = Self::build(buffer, message.head_text.map(|text| Arc::new(text)), file); this.text.set_line_ending(proto::deserialize_line_ending( proto::LineEnding::from_i32(message.line_ending) .ok_or_else(|| anyhow!("missing line_ending"))?, @@ -414,14 +414,18 @@ impl Buffer { self } - fn build(buffer: TextBuffer, head_text: Option, file: Option>) -> Self { + fn build( + buffer: TextBuffer, + head_text: Option>, + file: Option>, + ) -> Self { let saved_mtime = if let Some(file) = file.as_ref() { file.mtime() } else { UNIX_EPOCH }; - let git_diff = BufferDiff::new(&head_text, &buffer); + let git_diff = smol::block_on(BufferDiff::new(head_text.clone(), &buffer)); Self { saved_mtime, @@ -462,7 +466,7 @@ impl Buffer { BufferSnapshot { text, syntax, - diff_snapshot: self.git_diff.snapshot(), + diff_snapshot: self.git_diff.clone(), file: self.file.clone(), remote_selections: self.remote_selections.clone(), diagnostics: self.diagnostics.clone(), @@ -650,11 +654,29 @@ impl Buffer { task } - pub fn update_git(&mut self) { - if let Some(head_text) = &self.head_text { + pub fn needs_git_update(&self) -> bool { + self.git_diff.needs_update(self) + } + + pub fn update_git(&mut self, cx: &mut ModelContext) { + if self.head_text.is_some() { let snapshot = self.snapshot(); - self.git_diff.update(head_text, &snapshot); + let head_text = self.head_text.clone(); self.diff_update_count += 1; + + let buffer_diff = cx + .background() + .spawn(async move { BufferDiff::new(head_text, &snapshot).await }); + + cx.spawn_weak(|this, mut cx| async move { + let buffer_diff = buffer_diff.await; + if let Some(this) = this.upgrade(&cx) { + this.update(&mut cx, |this, _| { + this.git_diff = buffer_diff; + }) + } + }) + .detach() } } diff --git a/crates/language/src/git.rs b/crates/language/src/git.rs index 9065ef560620cfb1c84cf5dd91ddede0de36a18f..65ac373f7aa7aa8966400a0c5430b9307ca77f7c 100644 --- a/crates/language/src/git.rs +++ b/crates/language/src/git.rs @@ -1,4 +1,4 @@ -use std::ops::Range; +use std::{ops::Range, sync::Arc}; use sum_tree::SumTree; use text::{Anchor, BufferSnapshot, OffsetRangeExt, Point, ToPoint}; @@ -97,11 +97,25 @@ impl<'a> sum_tree::Dimension<'a, DiffHunkSummary> for HunkBufferEnd { } #[derive(Clone)] -pub struct BufferDiffSnapshot { +pub struct BufferDiff { + last_buffer_version: clock::Global, tree: SumTree>, } -impl BufferDiffSnapshot { +impl BufferDiff { + pub async fn new(head_text: Option>, buffer: &text::BufferSnapshot) -> BufferDiff { + let mut instance = BufferDiff { + last_buffer_version: buffer.version().clone(), + tree: SumTree::new(), + }; + + if let Some(head_text) = head_text { + instance.update(&*head_text, buffer); + } + + instance + } + pub fn hunks_in_range<'a>( &'a self, query_row_range: Range, @@ -127,36 +141,11 @@ impl BufferDiffSnapshot { }) } - #[cfg(test)] - fn hunks<'a>(&'a self, text: &'a BufferSnapshot) -> impl 'a + Iterator> { - self.hunks_in_range(0..u32::MAX, text) + pub fn needs_update(&self, buffer: &text::BufferSnapshot) -> bool { + buffer.version().changed_since(&self.last_buffer_version) } -} - -pub struct BufferDiff { - snapshot: BufferDiffSnapshot, -} -impl BufferDiff { - pub fn new(head_text: &Option, buffer: &text::BufferSnapshot) -> BufferDiff { - let mut instance = BufferDiff { - snapshot: BufferDiffSnapshot { - tree: SumTree::new(), - }, - }; - - if let Some(head_text) = head_text { - instance.update(head_text, buffer); - } - - instance - } - - pub fn snapshot(&self) -> BufferDiffSnapshot { - self.snapshot.clone() - } - - pub fn update(&mut self, head_text: &str, buffer: &text::BufferSnapshot) { + fn update(&mut self, head_text: &str, buffer: &text::BufferSnapshot) { let mut tree = SumTree::new(); let buffer_text = buffer.as_rope().to_string(); @@ -170,7 +159,13 @@ impl BufferDiff { } } - self.snapshot.tree = tree; + self.tree = tree; + self.last_buffer_version = buffer.version().clone(); + } + + #[cfg(test)] + fn hunks<'a>(&'a self, text: &'a BufferSnapshot) -> impl 'a + Iterator> { + self.hunks_in_range(0..u32::MAX, text) } fn diff<'a>(head: &'a str, current: &'a str) -> Option> { @@ -284,7 +279,7 @@ mod tests { .unindent(); let mut buffer = Buffer::new(0, 0, buffer_text); - let diff = BufferDiff::new(&Some(head_text.clone()), &buffer); + let diff = smol::block_on(BufferDiff::new(Some(Arc::new(head_text.clone())), &buffer)); assert_hunks(&diff, &buffer, &head_text, &[(1..2, "two\n")]); buffer.edit([(0..0, "point five\n")]); @@ -298,7 +293,7 @@ mod tests { head_text: &str, expected_hunks: &[(Range, &str)], ) { - let hunks = diff.snapshot.hunks(buffer).collect::>(); + let hunks = diff.hunks(buffer).collect::>(); assert_eq!( hunks.len(), expected_hunks.len(), diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index ad3862c56ff2a60e7715f9858780b37c5e344fef..e28e4d66d1acba19bdd1714de679201c4a160452 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -734,7 +734,7 @@ impl ItemHandle for ViewHandle { ); } - const GIT_DELAY: Duration = Duration::from_millis(600); + const GIT_DELAY: Duration = Duration::from_millis(10); let item = item.clone(); pending_git_update.fire_new( GIT_DELAY,