Cargo.lock 🔗
@@ -7129,6 +7129,7 @@ dependencies = [
"serde",
"serde_json",
"settings",
+ "smol",
"strum 0.27.2",
"telemetry",
"theme",
Lukas Wirth created
These are long running foreground tasks that tend to not have pending
await points, meaning once we start executing them they will never
reschedule themselves, starving the foreground thread.
Release Notes:
- Improved git project diff responsiveness
Cargo.lock | 1 +
crates/git_ui/Cargo.toml | 1 +
crates/git_ui/src/project_diff.rs | 4 ++++
crates/project/src/git_store.rs | 11 +++++++++++
4 files changed, 17 insertions(+)
@@ -7129,6 +7129,7 @@ dependencies = [
"serde",
"serde_json",
"settings",
+ "smol",
"strum 0.27.2",
"telemetry",
"theme",
@@ -50,6 +50,7 @@ schemars.workspace = true
serde.workspace = true
serde_json.workspace = true
settings.workspace = true
+smol.workspace = true
strum.workspace = true
telemetry.workspace = true
theme.workspace = true
@@ -32,6 +32,7 @@ use project::{
},
};
use settings::{Settings, SettingsStore};
+use smol::future::yield_now;
use std::any::{Any, TypeId};
use std::ops::Range;
use std::sync::Arc;
@@ -584,6 +585,9 @@ impl ProjectDiff {
for (entry, path_key) in buffers_to_load.into_iter().zip(path_keys.into_iter()) {
if let Some((buffer, diff)) = entry.load.await.log_err() {
+ // We might be lagging behind enough that all future entry.load futures are no longer pending.
+ // If that is the case, this task will never yield, starving the foreground thread of execution time.
+ yield_now().await;
cx.update(|window, cx| {
this.update(cx, |this, cx| {
this.register_buffer(path_key, entry.file_status, buffer, diff, window, cx)
@@ -56,6 +56,7 @@ use rpc::{
};
use serde::Deserialize;
use settings::WorktreeId;
+use smol::future::yield_now;
use std::{
cmp::Ordering,
collections::{BTreeSet, HashSet, VecDeque},
@@ -2984,6 +2985,10 @@ impl BufferGitState {
);
}
+ // Dropping BufferDiff can be expensive, so yield back to the event loop
+ // for a bit
+ yield_now().await;
+
let mut new_uncommitted_diff = None;
if let Some(uncommitted_diff) = &uncommitted_diff {
new_uncommitted_diff = if index_matches_head {
@@ -3005,6 +3010,10 @@ impl BufferGitState {
}
}
+ // Dropping BufferDiff can be expensive, so yield back to the event loop
+ // for a bit
+ yield_now().await;
+
let cancel = this.update(cx, |this, _| {
// This checks whether all pending stage/unstage operations
// have quiesced (i.e. both the corresponding write and the
@@ -3043,6 +3052,8 @@ impl BufferGitState {
None
};
+ yield_now().await;
+
if let Some((uncommitted_diff, new_uncommitted_diff)) =
uncommitted_diff.as_ref().zip(new_uncommitted_diff.clone())
{