From 8aad1df1add54cfcd2ba210ef624cf25da5b9b28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Marcos?= Date: Tue, 11 Mar 2025 15:34:35 -0300 Subject: [PATCH] pending work Co-authored-by: Conrad Irwin Co-authored-by: Max Brunsfeld --- crates/buffer_diff/src/buffer_diff.rs | 78 ++++++++++++++-------- crates/fs/src/fs.rs | 2 + crates/git/src/repository.rs | 1 + crates/project/src/buffer_store.rs | 14 +++- crates/project/src/git.rs | 9 +-- crates/project/src/project_tests.rs | 93 ++++++++++++++++++++++++++- crates/worktree/src/worktree.rs | 1 + 7 files changed, 162 insertions(+), 36 deletions(-) diff --git a/crates/buffer_diff/src/buffer_diff.rs b/crates/buffer_diff/src/buffer_diff.rs index 62f46e4c19..45a71cd595 100644 --- a/crates/buffer_diff/src/buffer_diff.rs +++ b/crates/buffer_diff/src/buffer_diff.rs @@ -4,7 +4,6 @@ use gpui::{App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, Task}; use language::{Language, LanguageRegistry}; use rope::Rope; use std::cmp::Ordering; -use std::mem; use std::{future::Future, iter, ops::Range, sync::Arc}; use sum_tree::SumTree; use text::{Anchor, Bias, BufferId, OffsetRangeExt, Point}; @@ -15,6 +14,7 @@ pub struct BufferDiff { pub buffer_id: BufferId, inner: BufferDiffInner, secondary_diff: Option>, + pending_ops: usize, } #[derive(Clone, Debug)] @@ -197,6 +197,7 @@ impl BufferDiffInner { buffer: &text::BufferSnapshot, file_exists: bool, ) -> (Option, SumTree) { + println!("------------------------------------------"); let head_text = self .base_text_exists .then(|| self.base_text.as_rope().clone()); @@ -835,14 +836,21 @@ impl BufferDiff { self.secondary_diff.clone() } - pub fn clear_pending_hunks(&mut self, cx: &mut Context) { - if let Some(secondary_diff) = &self.secondary_diff { - secondary_diff.update(cx, |diff, _| { - diff.inner.pending_hunks = SumTree::from_summary(DiffHunkSummary::default()); - }); - cx.emit(BufferDiffEvent::DiffChanged { - changed_range: Some(Anchor::MIN..Anchor::MAX), - }); + pub fn start_pending_op(&mut self, _cx: &mut Context) { + self.pending_ops += 1; + } + + pub fn end_pending_op(&mut self, cx: &mut Context) { + self.pending_ops -= 1; + if self.pending_ops == 0 { + if let Some(secondary_diff) = &self.secondary_diff { + secondary_diff.update(cx, |diff, _| { + diff.inner.pending_hunks = SumTree::from_summary(DiffHunkSummary::default()); + }); + // cx.emit(BufferDiffEvent::DiffChanged { + // changed_range: Some(Anchor::MIN..Anchor::MAX), + // }); + } } } @@ -854,7 +862,7 @@ impl BufferDiff { file_exists: bool, cx: &mut Context, ) -> Option { - let (new_index_text, new_pending_hunks) = self.inner.stage_or_unstage_hunks( + let (new_index_text, merged_pending_hunks) = self.inner.stage_or_unstage_hunks( &self.secondary_diff.as_ref()?.read(cx).inner, stage, &hunks, @@ -862,9 +870,20 @@ impl BufferDiff { file_exists, ); + // println!( + // "----\nnew_pending_hunks.len() = {}\n----", + // new_pending_hunks.iter().count(), + // ); + // println!( + // "----\nnew_index_text = {}\n----", + // new_index_text + // .as_ref() + // .map_or_else(String::new, Rope::to_string), + // ); + if let Some(unstaged_diff) = &self.secondary_diff { unstaged_diff.update(cx, |diff, _| { - diff.inner.pending_hunks = new_pending_hunks; + diff.inner.pending_hunks = merged_pending_hunks; }); } cx.emit(BufferDiffEvent::HunksStagedOrUnstaged( @@ -973,26 +992,27 @@ impl BufferDiff { fn set_state( &mut self, - new_state: BufferDiffInner, + mut new_state: BufferDiffInner, buffer: &text::BufferSnapshot, ) -> Option> { - let (base_text_changed, changed_range) = - match (self.inner.base_text_exists, new_state.base_text_exists) { - (false, false) => (true, None), - (true, true) - if self.inner.base_text.remote_id() == new_state.base_text.remote_id() => - { - (false, new_state.compare(&self.inner, buffer)) - } - _ => (true, Some(text::Anchor::MIN..text::Anchor::MAX)), - }; - - let pending_hunks = mem::replace(&mut self.inner.pending_hunks, SumTree::new(buffer)); + let changed_range = match (self.inner.base_text_exists, new_state.base_text_exists) { + (false, false) => { + dbg!("1"); + None + } + (true, true) if self.inner.base_text.remote_id() == new_state.base_text.remote_id() => { + dbg!("2"); + new_state.compare(&self.inner, buffer) + } + _ => { + // it's always here........... + dbg!("3"); + Some(text::Anchor::MIN..text::Anchor::MAX) + } + }; + new_state.pending_hunks = self.inner.pending_hunks.clone(); self.inner = new_state; - if !base_text_changed { - self.inner.pending_hunks = pending_hunks; - } changed_range } @@ -1106,6 +1126,7 @@ impl BufferDiff { buffer_id: buffer.remote_id(), inner: BufferDiff::build_empty(buffer, cx), secondary_diff: None, + pending_ops: 0, } } @@ -1129,6 +1150,7 @@ impl BufferDiff { buffer_id: buffer.read(cx).remote_id(), inner: snapshot, secondary_diff: None, + pending_ops: 0, } } @@ -1901,6 +1923,7 @@ mod tests { ) -> Entity { let inner = BufferDiff::build_sync(working_copy.text.clone(), head_text, cx); let secondary = BufferDiff { + pending_ops: 0, buffer_id: working_copy.remote_id(), inner: BufferDiff::build_sync( working_copy.text.clone(), @@ -1911,6 +1934,7 @@ mod tests { }; let secondary = cx.new(|_| secondary); cx.new(|_| BufferDiff { + pending_ops: 0, buffer_id: working_copy.remote_id(), inner, secondary_diff: Some(secondary), diff --git a/crates/fs/src/fs.rs b/crates/fs/src/fs.rs index 05946de3b7..0bce246abc 100644 --- a/crates/fs/src/fs.rs +++ b/crates/fs/src/fs.rs @@ -1036,7 +1036,9 @@ impl FakeFs { let this = this.clone(); async move { while let Ok(git_event) = rx.recv().await { + dbg!("Recevied", &git_event); if let Some(mut state) = this.state.try_lock() { + dbg!("emitting"); state.emit_event([(git_event, None)]); } else { panic!("Failed to lock file system state, this execution would have caused a test hang"); diff --git a/crates/git/src/repository.rs b/crates/git/src/repository.rs index 31f4a5d4c4..cfa78e6d4e 100644 --- a/crates/git/src/repository.rs +++ b/crates/git/src/repository.rs @@ -994,6 +994,7 @@ impl GitRepository for FakeGitRepository { } else { state.index_contents.remove(path); } + dbg!("emitting event"); state .event_emitter .try_send(state.path.clone()) diff --git a/crates/project/src/buffer_store.rs b/crates/project/src/buffer_store.rs index f4ae0ce05a..8aea4faacc 100644 --- a/crates/project/src/buffer_store.rs +++ b/crates/project/src/buffer_store.rs @@ -68,7 +68,7 @@ struct SharedBuffer { } #[derive(Default)] -struct BufferDiffState { +pub struct BufferDiffState { unstaged_diff: Option>, uncommitted_diff: Option>, recalculate_diff_task: Option>>, @@ -84,7 +84,7 @@ struct BufferDiffState { } #[derive(Clone, Debug)] -enum DiffBasesChange { +pub enum DiffBasesChange { SetIndex(Option), SetHead(Option), SetEach { @@ -143,7 +143,7 @@ impl BufferDiffState { Some(rx) } - fn diff_bases_changed( + pub fn diff_bases_changed( &mut self, buffer: text::BufferSnapshot, diff_bases_change: DiffBasesChange, @@ -1852,6 +1852,14 @@ impl BufferStore { } } + pub fn get_diff_state(&self, buffer_id: BufferId, cx: &App) -> Option> { + if let OpenBuffer::Complete { diff_state, .. } = self.opened_buffers.get(&buffer_id)? { + Some(diff_state.clone()) + } else { + None + } + } + pub fn get_uncommitted_diff( &self, buffer_id: BufferId, diff --git a/crates/project/src/git.rs b/crates/project/src/git.rs index 6e24caa8b5..b4d9ee6bea 100644 --- a/crates/project/src/git.rs +++ b/crates/project/src/git.rs @@ -291,6 +291,7 @@ impl GitStore { if let BufferDiffEvent::HunksStagedOrUnstaged(new_index_text) = event { let buffer_id = diff.read(cx).buffer_id; if let Some((repo, path)) = this.repository_and_path_for_buffer_id(buffer_id, cx) { + diff.update(cx, |diff, cx| diff.start_pending_op(cx)); let recv = repo.update(cx, |repo, cx| { repo.set_index_text( &path, @@ -303,14 +304,14 @@ impl GitStore { if let Some(result) = cx.background_spawn(async move { recv.await.ok() }).await { if let Err(error) = result { - diff.update(&mut cx, |diff, cx| { - diff.clear_pending_hunks(cx); - }) - .ok(); this.update(&mut cx, |_, cx| cx.emit(GitEvent::IndexWriteError(error))) .ok(); } } + diff.update(&mut cx, |diff, cx| { + diff.end_pending_op(cx); + }) + .ok(); }) .detach(); } diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index 45ae65132b..80059161ac 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -1,4 +1,4 @@ -use crate::{task_inventory::TaskContexts, Event, *}; +use crate::{buffer_store::DiffBasesChange, task_inventory::TaskContexts, Event, *}; use buffer_diff::{ assert_hunks, BufferDiffEvent, DiffHunkSecondaryStatus, DiffHunkStatus, DiffHunkStatusKind, }; @@ -6238,7 +6238,7 @@ async fn test_staging_hunks(cx: &mut gpui::TestAppContext) { ); }); assert!(matches!( - diff_events.next().await.unwrap(), + dbg!(diff_events.next().await.unwrap()), BufferDiffEvent::HunksStagedOrUnstaged(_) )); let event = diff_events.next().await.unwrap(); @@ -6356,6 +6356,95 @@ async fn test_staging_hunks(cx: &mut gpui::TestAppContext) { ], ); }); + + // Unstage two hunks, detect update from index, and then stage a third hunk. + let after_one = uncommitted_diff.update(cx, |diff, cx| { + let hunks = diff.hunks(&snapshot, cx).collect::>(); + let after_one = diff.stage_or_unstage_hunks(false, &hunks[0..=0], &snapshot, true, cx); + diff.stage_or_unstage_hunks(false, &hunks[1..=1], &snapshot, true, cx); + after_one.unwrap().to_string() + }); + + let recv = project + .update(cx, |project, cx| { + project.buffer_store().update(cx, |buffer_store, cx| { + let diff_state = buffer_store + .get_diff_state(snapshot.remote_id(), cx) + .unwrap(); + diff_state.update(cx, |diff_state, cx| { + diff_state.diff_bases_changed( + snapshot.text.clone(), + DiffBasesChange::SetIndex(Some(after_one)), + cx, + ) + }) + }) + }) + .unwrap(); + recv.await; + + uncommitted_diff.update(cx, |diff, cx| { + let hunks = diff.hunks(&snapshot, cx).collect::>(); + diff.stage_or_unstage_hunks(false, &hunks[2..=2], &snapshot, true, cx); + }); + + // uncommitted_diff.update(cx, |diff, cx| { + // assert_hunks( + // diff.hunks(&snapshot, cx), + // &snapshot, + // &diff.base_text_string().unwrap(), + // &[ + // ( + // 0..0, + // "zero\n", + // "", + // DiffHunkStatus::deleted(SecondaryHunkAdditionPending), + // ), + // ( + // 1..2, + // "two\n", + // "TWO\n", + // DiffHunkStatus::modified(SecondaryHunkAdditionPending), + // ), + // ( + // 3..4, + // "four\n", + // "FOUR\n", + // DiffHunkStatus::modified(SecondaryHunkAdditionPending), + // ), + // ], + // ); + // }); + + // Wait till all unstaging operations take effect. + cx.run_until_parked(); + uncommitted_diff.update(cx, |diff, cx| { + assert_hunks( + diff.hunks(&snapshot, cx), + &snapshot, + &diff.base_text_string().unwrap(), + &[ + ( + 0..0, + "zero\n", + "", + DiffHunkStatus::deleted(HasSecondaryHunk), + ), + ( + 1..2, + "two\n", + "TWO\n", + DiffHunkStatus::modified(HasSecondaryHunk), // NoSecondaryHunk + ), + ( + 3..4, + "four\n", + "FOUR\n", + DiffHunkStatus::modified(HasSecondaryHunk), + ), + ], + ); + }); } #[allow(clippy::format_collect)] diff --git a/crates/worktree/src/worktree.rs b/crates/worktree/src/worktree.rs index a4d36e8c90..793ab3b287 100644 --- a/crates/worktree/src/worktree.rs +++ b/crates/worktree/src/worktree.rs @@ -4442,6 +4442,7 @@ impl BackgroundScanner { while let Poll::Ready(Some(more_paths)) = futures::poll!(fs_events_rx.next()) { paths.extend(more_paths); } + dbg!(&paths); self.process_events(paths.into_iter().map(Into::into).collect()) .await; }