pending work
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com> Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
@@ -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),
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user