Derive worktree update messages from existing change events
This commit is contained in:
parent
6628c4df28
commit
02b95ef320
3 changed files with 486 additions and 468 deletions
|
@ -1459,7 +1459,7 @@ impl Project {
|
|||
};
|
||||
|
||||
cx.foreground().spawn(async move {
|
||||
pump_loading_buffer_reciever(loading_watch)
|
||||
wait_for_loading_buffer(loading_watch)
|
||||
.await
|
||||
.map_err(|error| anyhow!("{}", error))
|
||||
})
|
||||
|
@ -5057,98 +5057,102 @@ impl Project {
|
|||
fn update_local_worktree_buffers_git_repos(
|
||||
&mut self,
|
||||
worktree_handle: ModelHandle<Worktree>,
|
||||
repos: &HashMap<Arc<Path>, LocalRepositoryEntry>,
|
||||
changed_repos: &UpdatedGitRepositoriesSet,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) {
|
||||
debug_assert!(worktree_handle.read(cx).is_local());
|
||||
|
||||
// Setup the pending buffers
|
||||
// Identify the loading buffers whose containing repository that has changed.
|
||||
let future_buffers = self
|
||||
.loading_buffers_by_path
|
||||
.iter()
|
||||
.filter_map(|(path, receiver)| {
|
||||
let path = &path.path;
|
||||
let (work_directory, repo) = repos
|
||||
.filter_map(|(project_path, receiver)| {
|
||||
if project_path.worktree_id != worktree_handle.read(cx).id() {
|
||||
return None;
|
||||
}
|
||||
let path = &project_path.path;
|
||||
changed_repos
|
||||
.iter()
|
||||
.find(|(work_directory, _)| path.starts_with(work_directory))?;
|
||||
|
||||
let repo_relative_path = path.strip_prefix(work_directory).log_err()?;
|
||||
|
||||
.find(|(work_dir, _)| path.starts_with(work_dir))?;
|
||||
let receiver = receiver.clone();
|
||||
let repo_ptr = repo.repo_ptr.clone();
|
||||
let repo_relative_path = repo_relative_path.to_owned();
|
||||
let path = path.clone();
|
||||
Some(async move {
|
||||
pump_loading_buffer_reciever(receiver)
|
||||
wait_for_loading_buffer(receiver)
|
||||
.await
|
||||
.ok()
|
||||
.map(|buffer| (buffer, repo_relative_path, repo_ptr))
|
||||
.map(|buffer| (buffer, path))
|
||||
})
|
||||
})
|
||||
.collect::<FuturesUnordered<_>>()
|
||||
.filter_map(|result| async move {
|
||||
let (buffer_handle, repo_relative_path, repo_ptr) = result?;
|
||||
.collect::<FuturesUnordered<_>>();
|
||||
|
||||
let lock = repo_ptr.lock();
|
||||
lock.load_index_text(&repo_relative_path)
|
||||
.map(|diff_base| (diff_base, buffer_handle))
|
||||
});
|
||||
// Identify the current buffers whose containing repository has changed.
|
||||
let current_buffers = self
|
||||
.opened_buffers
|
||||
.values()
|
||||
.filter_map(|buffer| {
|
||||
let buffer = buffer.upgrade(cx)?;
|
||||
let file = File::from_dyn(buffer.read(cx).file())?;
|
||||
if file.worktree != worktree_handle {
|
||||
return None;
|
||||
}
|
||||
let path = file.path();
|
||||
changed_repos
|
||||
.iter()
|
||||
.find(|(work_dir, _)| path.starts_with(work_dir))?;
|
||||
Some((buffer, path.clone()))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let update_diff_base_fn = update_diff_base(self);
|
||||
cx.spawn(|_, mut cx| async move {
|
||||
let diff_base_tasks = cx
|
||||
if future_buffers.len() + current_buffers.len() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let remote_id = self.remote_id();
|
||||
let client = self.client.clone();
|
||||
cx.spawn_weak(move |_, mut cx| async move {
|
||||
// Wait for all of the buffers to load.
|
||||
let future_buffers = future_buffers.collect::<Vec<_>>().await;
|
||||
|
||||
// Reload the diff base for every buffer whose containing git repository has changed.
|
||||
let snapshot =
|
||||
worktree_handle.read_with(&cx, |tree, _| tree.as_local().unwrap().snapshot());
|
||||
let diff_bases_by_buffer = cx
|
||||
.background()
|
||||
.spawn(future_buffers.collect::<Vec<_>>())
|
||||
.spawn(async move {
|
||||
future_buffers
|
||||
.into_iter()
|
||||
.filter_map(|e| e)
|
||||
.chain(current_buffers)
|
||||
.filter_map(|(buffer, path)| {
|
||||
let (work_directory, repo) =
|
||||
snapshot.repository_and_work_directory_for_path(&path)?;
|
||||
let repo = snapshot.get_local_repo(&repo)?;
|
||||
let relative_path = path.strip_prefix(&work_directory).ok()?;
|
||||
let base_text = repo.repo_ptr.lock().load_index_text(&relative_path);
|
||||
Some((buffer, base_text))
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.await;
|
||||
|
||||
for (diff_base, buffer) in diff_base_tasks.into_iter() {
|
||||
update_diff_base_fn(Some(diff_base), buffer, &mut cx);
|
||||
// Assign the new diff bases on all of the buffers.
|
||||
for (buffer, diff_base) in diff_bases_by_buffer {
|
||||
let buffer_id = buffer.update(&mut cx, |buffer, cx| {
|
||||
buffer.set_diff_base(diff_base.clone(), cx);
|
||||
buffer.remote_id()
|
||||
});
|
||||
if let Some(project_id) = remote_id {
|
||||
client
|
||||
.send(proto::UpdateDiffBase {
|
||||
project_id,
|
||||
buffer_id,
|
||||
diff_base,
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
// And the current buffers
|
||||
for (_, buffer) in &self.opened_buffers {
|
||||
if let Some(buffer) = buffer.upgrade(cx) {
|
||||
let file = match File::from_dyn(buffer.read(cx).file()) {
|
||||
Some(file) => file,
|
||||
None => continue,
|
||||
};
|
||||
if file.worktree != worktree_handle {
|
||||
continue;
|
||||
}
|
||||
|
||||
let path = file.path().clone();
|
||||
|
||||
let worktree = worktree_handle.read(cx);
|
||||
|
||||
let (work_directory, repo) = match repos
|
||||
.iter()
|
||||
.find(|(work_directory, _)| path.starts_with(work_directory))
|
||||
{
|
||||
Some(repo) => repo.clone(),
|
||||
None => continue,
|
||||
};
|
||||
|
||||
let relative_repo = match path.strip_prefix(work_directory).log_err() {
|
||||
Some(relative_repo) => relative_repo.to_owned(),
|
||||
None => continue,
|
||||
};
|
||||
|
||||
drop(worktree);
|
||||
|
||||
let update_diff_base_fn = update_diff_base(self);
|
||||
let git_ptr = repo.repo_ptr.clone();
|
||||
let diff_base_task = cx
|
||||
.background()
|
||||
.spawn(async move { git_ptr.lock().load_index_text(&relative_repo) });
|
||||
|
||||
cx.spawn(|_, mut cx| async move {
|
||||
let diff_base = diff_base_task.await;
|
||||
update_diff_base_fn(diff_base, buffer, &mut cx);
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_active_path(&mut self, entry: Option<ProjectPath>, cx: &mut ModelContext<Self>) {
|
||||
|
@ -7070,7 +7074,7 @@ impl Item for Buffer {
|
|||
}
|
||||
}
|
||||
|
||||
async fn pump_loading_buffer_reciever(
|
||||
async fn wait_for_loading_buffer(
|
||||
mut receiver: postage::watch::Receiver<Option<Result<ModelHandle<Buffer>, Arc<anyhow::Error>>>>,
|
||||
) -> Result<ModelHandle<Buffer>, Arc<anyhow::Error>> {
|
||||
loop {
|
||||
|
@ -7083,26 +7087,3 @@ async fn pump_loading_buffer_reciever(
|
|||
receiver.next().await;
|
||||
}
|
||||
}
|
||||
|
||||
fn update_diff_base(
|
||||
project: &Project,
|
||||
) -> impl Fn(Option<String>, ModelHandle<Buffer>, &mut AsyncAppContext) {
|
||||
let remote_id = project.remote_id();
|
||||
let client = project.client().clone();
|
||||
move |diff_base, buffer, cx| {
|
||||
let buffer_id = buffer.update(cx, |buffer, cx| {
|
||||
buffer.set_diff_base(diff_base.clone(), cx);
|
||||
buffer.remote_id()
|
||||
});
|
||||
|
||||
if let Some(project_id) = remote_id {
|
||||
client
|
||||
.send(proto::UpdateDiffBase {
|
||||
project_id,
|
||||
buffer_id: buffer_id as u64,
|
||||
diff_base,
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue