Add git blame error reporting with notification (#10408)

<img width="1035" alt="Screenshot 2024-04-11 at 13 13 44"
src="https://github.com/zed-industries/zed/assets/13402668/cd0e96a0-41c6-4757-8840-97d15a75c511">

Release Notes:

- Added a notification to show possible `git blame` errors if it fails to run.

Caveats:
- ~git blame now executes in foreground
executor  (required since the Fut is !Send)~

TODOs:
- After a failed toggle, the app thinks the blame
is shown. This means toggling again will do nothing
instead of retrying. (Caused by editor.show_git_blame
being set to true before the git blame is generated)
- ~(Maybe) Trim error?~ Done

---------

Co-authored-by: Thorsten Ball <mrnugget@gmail.com>
This commit is contained in:
Mehmet Efe Akça 2024-04-12 08:20:34 +03:00 committed by GitHub
parent 08786fa7bf
commit 29a50573a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 67 additions and 10 deletions

View File

@ -256,7 +256,7 @@ impl GitBlame {
let blame = self.project.read(cx).blame_buffer(&self.buffer, None, cx);
self.task = cx.spawn(|this, mut cx| async move {
let (entries, permalinks, messages) = cx
let result = cx
.background_executor()
.spawn({
let snapshot = snapshot.clone();
@ -304,16 +304,23 @@ impl GitBlame {
anyhow::Ok((entries, permalinks, messages))
}
})
.await?;
.await;
this.update(&mut cx, |this, cx| {
this.buffer_edits = buffer_edits;
this.buffer_snapshot = snapshot;
this.entries = entries;
this.permalinks = permalinks;
this.messages = messages;
this.generated = true;
cx.notify();
this.update(&mut cx, |this, cx| match result {
Ok((entries, permalinks, messages)) => {
this.buffer_edits = buffer_edits;
this.buffer_snapshot = snapshot;
this.entries = entries;
this.permalinks = permalinks;
this.messages = messages;
this.generated = true;
cx.notify();
}
Err(error) => this.project.update(cx, |_, cx| {
log::error!("failed to get git blame data: {error:?}");
let notification = format!("{:#}", error).trim().to_string();
cx.emit(project::Event::Notification(notification));
}),
})
});
}
@ -359,6 +366,54 @@ mod tests {
});
}
#[gpui::test]
async fn test_blame_error_notifications(cx: &mut gpui::TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.executor());
fs.insert_tree(
"/my-repo",
json!({
".git": {},
"file.txt": r#"
irrelevant contents
"#
.unindent()
}),
)
.await;
// Creating a GitBlame without a corresponding blame state
// will result in an error.
let project = Project::test(fs, ["/my-repo".as_ref()], cx).await;
let buffer = project
.update(cx, |project, cx| {
project.open_local_buffer("/my-repo/file.txt", cx)
})
.await
.unwrap();
let blame = cx.new_model(|cx| GitBlame::new(buffer.clone(), project.clone(), cx));
let event = project.next_event(cx);
assert_eq!(
event,
project::Event::Notification(
"Failed to blame \"file.txt\": failed to get blame for \"file.txt\"".to_string()
)
);
blame.update(cx, |blame, cx| {
assert_eq!(
blame
.blame_for_rows((0..1).map(Some), cx)
.collect::<Vec<_>>(),
vec![None]
);
});
}
#[gpui::test]
async fn test_blame_for_rows(cx: &mut gpui::TestAppContext) {
init_test(cx);

View File

@ -78,6 +78,7 @@ fn run_git_blame(
.arg(path.as_os_str())
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.map_err(|e| anyhow!("Failed to start git blame process: {}", e))?;

View File

@ -7734,6 +7734,7 @@ impl Project {
let (repo, relative_path, content) = blame_params?;
let lock = repo.lock();
lock.blame(&relative_path, content)
.with_context(|| format!("Failed to blame {relative_path:?}"))
})
} else {
let project_id = self.remote_id();