From 74b4013e67ce1a11497806300ca886ba4231ef15 Mon Sep 17 00:00:00 2001 From: Ramon <55579979+van-sprundel@users.noreply.github.com> Date: Wed, 17 Dec 2025 17:32:50 +0100 Subject: [PATCH] git: Mark entries as pending when staging a files making the staged highlighting more "optimistic" (#43434) This at least speeds it up, not sure if this would close the issue On main (342eba6f220625c015d00334c6bc354f0e2c52e1): https://github.com/user-attachments/assets/55d10187-b4e6-410d-9002-06509e8015c9 This branch: https://github.com/user-attachments/assets/e9a5c14f-9694-4321-a81c-88d6f62fb342 Closes #26870 Release Notes: - Added optimistic staged hunk updating --- crates/project/src/git_store.rs | 81 +++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/crates/project/src/git_store.rs b/crates/project/src/git_store.rs index c73ab914b788fb92e69ea3a47db5446223098c2d..a414a03320a2defa4c9dbd4b6193a131e761d2c7 100644 --- a/crates/project/src/git_store.rs +++ b/crates/project/src/git_store.rs @@ -1672,6 +1672,59 @@ impl GitStore { } } + fn mark_entries_pending_by_project_paths( + &mut self, + project_paths: &[ProjectPath], + stage: bool, + cx: &mut Context, + ) { + let buffer_store = &self.buffer_store; + + for project_path in project_paths { + let Some(buffer) = buffer_store.read(cx).get_by_path(project_path) else { + continue; + }; + + let buffer_id = buffer.read(cx).remote_id(); + let Some(diff_state) = self.diffs.get(&buffer_id) else { + continue; + }; + + diff_state.update(cx, |diff_state, cx| { + let Some(uncommitted_diff) = diff_state.uncommitted_diff() else { + return; + }; + + let buffer_snapshot = buffer.read(cx).text_snapshot(); + let file_exists = buffer + .read(cx) + .file() + .is_some_and(|file| file.disk_state().exists()); + + let all_hunks: Vec<_> = uncommitted_diff + .read(cx) + .hunks_intersecting_range( + text::Anchor::MIN..text::Anchor::MAX, + &buffer_snapshot, + cx, + ) + .collect(); + + if !all_hunks.is_empty() { + uncommitted_diff.update(cx, |diff, cx| { + diff.stage_or_unstage_hunks( + stage, + &all_hunks, + &buffer_snapshot, + file_exists, + cx, + ); + }); + } + }); + } + } + pub fn git_clone( &self, repo: String, @@ -4200,6 +4253,28 @@ impl Repository { save_futures } + fn mark_entries_pending_for_stage( + &self, + entries: &[RepoPath], + stage: bool, + cx: &mut Context, + ) { + let Some(git_store) = self.git_store() else { + return; + }; + + let mut project_paths = Vec::new(); + for repo_path in entries { + if let Some(project_path) = self.repo_path_to_project_path(repo_path, cx) { + project_paths.push(project_path); + } + } + + git_store.update(cx, move |git_store, cx| { + git_store.mark_entries_pending_by_project_paths(&project_paths, stage, cx); + }); + } + pub fn stage_entries( &mut self, entries: Vec, @@ -4208,6 +4283,9 @@ impl Repository { if entries.is_empty() { return Task::ready(Ok(())); } + + self.mark_entries_pending_for_stage(&entries, true, cx); + let id = self.id; let save_tasks = self.save_buffers(&entries, cx); let paths = entries @@ -4273,6 +4351,9 @@ impl Repository { if entries.is_empty() { return Task::ready(Ok(())); } + + self.mark_entries_pending_for_stage(&entries, false, cx); + let id = self.id; let save_tasks = self.save_buffers(&entries, cx); let paths = entries