Fix the project diff sometimes missing updates (#40662)

This PR does two related things:

- First, it gets rid of the undifferentiated `RepositoryEvent::Updated`
in favor of three new events that have clearer definitions:
`BranchChanged`, `StashEntriesChanged`, and `StatusesChanged`. An
implication of this is that we no longer emit a `RepositoryEvent` unless
some git state changed; previously we would emit `RepositoryUpdated`
after doing a git status scan even if no statuses changed.
- Second, it changes the subscription strategy of the project diff to
make it update more robustly. Previously, the project diff only
subscribed to the `GitStore`, so it relied on getting a `GitStoreEvent`
when some buffer's diff hunks changed, even if the git status of the
buffer's file didn't change (e.g. a second hunk in a file that was
already modified). After this PR, it also subscribes to the individual
`BufferDiff` entities for buffers that have a git status, so the
`GitStore` is freed from that responsibility. This also fixes some real
cases where the previous strategy was not effective in keeping the
project diff up to date (captured in a test).

Release Notes:

- Fixed some cases where the project diff would fail to update in
response to git events.
This commit is contained in:
Cole Miller
2025-10-23 16:46:27 +00:00
committed by GitHub
parent a66098b485
commit 8b6f3ec647
13 changed files with 214 additions and 159 deletions
+2 -9
View File
@@ -156,7 +156,7 @@ use project::{
},
session::{Session, SessionEvent},
},
git_store::{GitStoreEvent, RepositoryEvent},
git_store::GitStoreEvent,
lsp_store::{
CacheInlayHints, CompletionDocumentation, FormatTrigger, LspFormatTarget,
OpenLspBufferHandle,
@@ -1978,14 +1978,7 @@ impl Editor {
let git_store = project.read(cx).git_store().clone();
let project = project.clone();
project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
if let GitStoreEvent::RepositoryUpdated(
_,
RepositoryEvent::Updated {
new_instance: true, ..
},
_,
) = event
{
if let GitStoreEvent::RepositoryAdded = event {
this.load_diff_task = Some(
update_uncommitted_diff_for_buffer(
cx.entity(),
+12 -14
View File
@@ -12615,18 +12615,6 @@ async fn test_strip_whitespace_and_format_via_lsp(cx: &mut TestAppContext) {
)
.await;
cx.run_until_parked();
// Set up a buffer white some trailing whitespace and no trailing newline.
cx.set_state(
&[
"one ", //
"twoˇ", //
"three ", //
"four", //
]
.join("\n"),
);
// Record which buffer changes have been sent to the language server
let buffer_changes = Arc::new(Mutex::new(Vec::new()));
cx.lsp
@@ -12641,8 +12629,6 @@ async fn test_strip_whitespace_and_format_via_lsp(cx: &mut TestAppContext) {
);
}
});
cx.run_until_parked();
// Handle formatting requests to the language server.
cx.lsp
.set_request_handler::<lsp::request::Formatting, _, _>({
@@ -12691,6 +12677,18 @@ async fn test_strip_whitespace_and_format_via_lsp(cx: &mut TestAppContext) {
}
});
// Set up a buffer white some trailing whitespace and no trailing newline.
cx.set_state(
&[
"one ", //
"twoˇ", //
"three ", //
"four", //
]
.join("\n"),
);
cx.run_until_parked();
// Submit a format request.
let format = cx
.update_editor(|editor, window, cx| editor.format(&Format, window, cx))
+3 -3
View File
@@ -16,7 +16,7 @@ use markdown::Markdown;
use multi_buffer::{MultiBuffer, RowInfo};
use project::{
Project, ProjectItem as _,
git_store::{GitStoreEvent, Repository, RepositoryEvent},
git_store::{GitStoreEvent, Repository},
};
use smallvec::SmallVec;
use std::{sync::Arc, time::Duration};
@@ -235,8 +235,8 @@ impl GitBlame {
let git_store = project.read(cx).git_store().clone();
let git_store_subscription =
cx.subscribe(&git_store, move |this, _, event, cx| match event {
GitStoreEvent::RepositoryUpdated(_, RepositoryEvent::Updated { .. }, _)
| GitStoreEvent::RepositoryAdded(_)
GitStoreEvent::RepositoryUpdated(_, _, _)
| GitStoreEvent::RepositoryAdded
| GitStoreEvent::RepositoryRemoved(_) => {
log::debug!("Status of git repositories updated. Regenerating blame data...",);
this.generate(cx);