From 232e4f0fa52aadc4bf767993a76a2ed192bd9a48 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Sun, 23 Aug 2026 19:36:31 +0300 Subject: [PATCH] Do not show useless toasts during recursive blaming --- crates/editor/src/element.rs | 12 +++++- crates/editor/src/git.rs | 70 ++++++++++++++--------------------- crates/git/src/blame.rs | 12 ++++++ crates/git_ui/src/blame_ui.rs | 9 +---- 4 files changed, 52 insertions(+), 51 deletions(-) diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index ac32816a807d89..f88b928a3b3338 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -511,8 +511,16 @@ impl EditorElement { register_action(editor, window, Editor::toggle_git_blame_inline); if editor.read(cx).blame().is_some() { register_action(editor, window, Editor::open_git_blame_commit); - register_action(editor, window, Editor::blame_revision); - register_action(editor, window, Editor::blame_previous_revision); + if editor.update(cx, |editor, cx| { + editor.blame_revision_target(window, cx).is_some() + }) { + register_action(editor, window, Editor::blame_revision); + } + if editor.update(cx, |editor, cx| { + editor.blame_previous_revision_target(window, cx).is_some() + }) { + register_action(editor, window, Editor::blame_previous_revision); + } } register_action(editor, window, Editor::toggle_selected_diff_hunks); register_action(editor, window, Editor::toggle_staged_selected_diff_hunks); diff --git a/crates/editor/src/git.rs b/crates/editor/src/git.rs index e6552a1d33eea1..97d00ec2ea0530 100644 --- a/crates/editor/src/git.rs +++ b/crates/editor/src/git.rs @@ -2310,32 +2310,40 @@ impl Editor { Some((blame_entry, repository)) } + pub(crate) fn blame_revision_target( + &mut self, + window: &mut Window, + cx: &mut Context, + ) -> Option<(RepoPath, Oid, Entity)> { + let (blame_entry, repository) = self.blame_entry_at_cursor(window, cx)?; + let highlighted_sha = self + .blame + .as_ref() + .and_then(|blame| blame.read(cx).highlighted_sha()); + let (revision, path) = blame_entry.revision_target(highlighted_sha)?; + Some((path, revision, repository)) + } + + pub(crate) fn blame_previous_revision_target( + &mut self, + window: &mut Window, + cx: &mut Context, + ) -> Option<(RepoPath, Oid, Entity)> { + let (blame_entry, repository) = self.blame_entry_at_cursor(window, cx)?; + let (revision, path) = blame_entry.previous_revision_target()?; + Some((path, revision, repository)) + } + pub(super) fn blame_revision( &mut self, _: &BlameRevision, window: &mut Window, cx: &mut Context, ) { - let Some((blame_entry, repository)) = self.blame_entry_at_cursor(window, cx) else { - self.show_blame_revision_toast("No blame entry for this line", cx); + let Some((path, revision, repository)) = self.blame_revision_target(window, cx) else { return; }; - if blame_entry.sha.is_zero() { - self.show_blame_revision_toast("Cannot blame revision: the line is not committed", cx); - return; - } - if self - .blame - .as_ref() - .is_some_and(|blame| blame.read(cx).highlighted_sha() == Some(blame_entry.sha)) - { - self.show_blame_revision_toast("Already blaming at this revision", cx); - return; - } - let Some(path) = RepoPath::new(&blame_entry.filename).log_err() else { - return; - }; - self.open_blame_revision(path, blame_entry.sha, repository, window, cx); + self.open_blame_revision(path, revision, repository, window, cx); } pub(super) fn blame_previous_revision( @@ -2344,15 +2352,8 @@ impl Editor { window: &mut Window, cx: &mut Context, ) { - let Some((blame_entry, repository)) = self.blame_entry_at_cursor(window, cx) else { - self.show_blame_revision_toast("No blame entry for this line", cx); - return; - }; - let Some((revision, filename)) = blame_entry.previous_sha_and_filename() else { - self.show_blame_revision_toast("No previous revision for this line", cx); - return; - }; - let Some(path) = RepoPath::new(filename).log_err() else { + let Some((path, revision, repository)) = self.blame_previous_revision_target(window, cx) + else { return; }; self.open_blame_revision(path, revision, repository, window, cx); @@ -2380,21 +2381,6 @@ impl Editor { ); } - fn show_blame_revision_toast(&self, message: &str, cx: &mut Context) { - struct BlameRevisionToast; - if let Some(workspace) = self.workspace() { - workspace.update(cx, |workspace, cx| { - workspace.show_toast( - Toast::new( - NotificationId::unique::(), - message.to_owned(), - ), - cx, - ); - }); - } - } - fn has_blame_entries(&self, cx: &App) -> bool { self.blame() .is_some_and(|blame| blame.read(cx).has_generated_entries()) diff --git a/crates/git/src/blame.rs b/crates/git/src/blame.rs index 85c8f8a4ac0d0a..2fd39f402ff166 100644 --- a/crates/git/src/blame.rs +++ b/crates/git/src/blame.rs @@ -270,6 +270,18 @@ impl BlameEntry { Some((sha.parse().ok()?, filename)) } + pub fn revision_target(&self, highlighted_sha: Option) -> Option<(Oid, RepoPath)> { + if self.sha.is_zero() || Some(self.sha) == highlighted_sha { + return None; + } + Some((self.sha, RepoPath::new(&self.filename).ok()?)) + } + + pub fn previous_revision_target(&self) -> Option<(Oid, RepoPath)> { + let (sha, filename) = self.previous_sha_and_filename()?; + Some((sha, RepoPath::new(filename).ok()?)) + } + pub fn author_offset_date_time(&self) -> Result { if let (Some(author_time), Some(author_tz)) = (self.author_time, &self.author_tz) { let format = format_description!("[offset_hour][offset_minute]"); diff --git a/crates/git_ui/src/blame_ui.rs b/crates/git_ui/src/blame_ui.rs index 7413f40c7fb6dc..1caa6eefcfd92b 100644 --- a/crates/git_ui/src/blame_ui.rs +++ b/crates/git_ui/src/blame_ui.rs @@ -555,13 +555,8 @@ fn deploy_blame_entry_context_menu( .and_then(|blame| blame.read(cx).highlighted_sha()); let context_menu = ContextMenu::build(window, cx, move |menu, _, _| { let sha = format!("{}", blame_entry.sha); - let blame_revision = (!blame_entry.sha.is_zero() - && Some(blame_entry.sha) != highlighted_sha) - .then_some(blame_entry.sha) - .zip(RepoPath::new(&blame_entry.filename).ok()); - let blame_previous_revision = blame_entry - .previous_sha_and_filename() - .and_then(|(sha, filename)| Some((sha, RepoPath::new(filename).ok()?))); + let blame_revision = blame_entry.revision_target(highlighted_sha); + let blame_previous_revision = blame_entry.previous_revision_target(); let has_blame_targets = blame_revision.is_some() || blame_previous_revision.is_some(); menu.on_blur_subscription(Subscription::new(|| {})) .entry("Copy Commit SHA", None, move |_, cx| {