pending work

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
João Marcos
2025-03-11 15:34:35 -03:00
parent 3a1c631c91
commit 8aad1df1ad
7 changed files with 162 additions and 36 deletions

View File

@@ -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<Entity<BufferDiff>>,
pending_ops: usize,
}
#[derive(Clone, Debug)]
@@ -197,6 +197,7 @@ impl BufferDiffInner {
buffer: &text::BufferSnapshot,
file_exists: bool,
) -> (Option<Rope>, SumTree<PendingHunk>) {
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<Self>) {
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>) {
self.pending_ops += 1;
}
pub fn end_pending_op(&mut self, cx: &mut Context<Self>) {
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<Self>,
) -> Option<Rope> {
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<Range<Anchor>> {
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<BufferDiff> {
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),

View File

@@ -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");

View File

@@ -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())

View File

@@ -68,7 +68,7 @@ struct SharedBuffer {
}
#[derive(Default)]
struct BufferDiffState {
pub struct BufferDiffState {
unstaged_diff: Option<WeakEntity<BufferDiff>>,
uncommitted_diff: Option<WeakEntity<BufferDiff>>,
recalculate_diff_task: Option<Task<Result<()>>>,
@@ -84,7 +84,7 @@ struct BufferDiffState {
}
#[derive(Clone, Debug)]
enum DiffBasesChange {
pub enum DiffBasesChange {
SetIndex(Option<String>),
SetHead(Option<String>),
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<Entity<BufferDiffState>> {
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,

View File

@@ -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();
}

View File

@@ -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::<Vec<_>>();
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::<Vec<_>>();
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)]

View File

@@ -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;
}