Use anyhow more idiomatically (#31052)

https://github.com/zed-industries/zed/issues/30972 brought up another
case where our context is not enough to track the actual source of the
issue: we get a general top-level error without inner error.

The reason for this was `.ok_or_else(|| anyhow!("failed to read HEAD
SHA"))?; ` on the top level.

The PR finally reworks the way we use anyhow to reduce such issues (or
at least make it simpler to bubble them up later in a fix).
On top of that, uses a few more anyhow methods for better readability.

* `.ok_or_else(|| anyhow!("..."))`, `map_err` and other similar error
conversion/option reporting cases are replaced with `context` and
`with_context` calls
* in addition to that, various `anyhow!("failed to do ...")` are
stripped with `.context("Doing ...")` messages instead to remove the
parasitic `failed to` text
* `anyhow::ensure!` is used instead of `if ... { return Err(...); }`
calls
* `anyhow::bail!` is used instead of `return Err(anyhow!(...));`

Release Notes:

- N/A
This commit is contained in:
Kirill Bulatov 2025-05-21 02:06:07 +03:00 committed by GitHub
parent 1e51a7ac44
commit 16366cf9f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
294 changed files with 2037 additions and 2610 deletions

View file

@ -1316,7 +1316,7 @@ pub mod test {
_project: &Entity<Project>,
_path: &ProjectPath,
_cx: &mut App,
) -> Option<Task<gpui::Result<Entity<Self>>>> {
) -> Option<Task<anyhow::Result<Entity<Self>>>> {
None
}
fn entry_id(&self, _: &App) -> Option<ProjectEntryId> {

View file

@ -1,4 +1,5 @@
use crate::{SuppressNotification, Toast, Workspace};
use anyhow::Context as _;
use gpui::{
AnyView, App, AppContext as _, AsyncWindowContext, ClickEvent, ClipboardItem, Context,
DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, PromptLevel, Render, ScrollHandle,
@ -239,9 +240,9 @@ impl LanguageServerPrompt {
});
potential_future? // App Closed
.ok_or_else(|| anyhow::anyhow!("Response already sent"))?
.context("Response already sent")?
.await
.ok_or_else(|| anyhow::anyhow!("Stream already closed"))?;
.context("Stream already closed")?;
this.update(cx, |_, cx| cx.emit(DismissEvent))?;

View file

@ -3,7 +3,7 @@ use crate::{
pane_group::element::pane_axis,
workspace_settings::{PaneSplitDirectionHorizontal, PaneSplitDirectionVertical},
};
use anyhow::{Result, anyhow};
use anyhow::Result;
use call::{ActiveCall, ParticipantLocation};
use collections::HashMap;
use gpui::{
@ -58,7 +58,7 @@ impl PaneGroup {
self.root = Member::new_axis(old_pane.clone(), new_pane.clone(), direction);
Ok(())
} else {
Err(anyhow!("Pane not found"))
anyhow::bail!("Pane not found");
}
}
Member::Axis(axis) => axis.split(old_pane, new_pane, direction),
@ -538,7 +538,7 @@ impl PaneAxis {
}
}
}
Err(anyhow!("Pane not found"))
anyhow::bail!("Pane not found");
}
fn remove(&mut self, pane_to_remove: &Entity<Pane>) -> Result<Option<Member>> {
@ -579,7 +579,7 @@ impl PaneAxis {
Ok(None)
}
} else {
Err(anyhow!("Pane not found"))
anyhow::bail!("Pane not found");
}
}

View file

@ -8,7 +8,7 @@ use std::{
sync::Arc,
};
use anyhow::{Context, Result, anyhow, bail};
use anyhow::{Context as _, Result, bail};
use client::DevServerProjectId;
use db::{define_connection, query, sqlez::connection::Connection, sqlez_macros::sql};
use gpui::{Axis, Bounds, Task, WindowBounds, WindowId, point, size};
@ -181,7 +181,7 @@ impl Column for BreakpointStateWrapper<'_> {
match state {
0 => Ok((BreakpointState::Enabled.into(), start_index + 1)),
1 => Ok((BreakpointState::Disabled.into(), start_index + 1)),
_ => Err(anyhow::anyhow!("Invalid BreakpointState discriminant")),
_ => anyhow::bail!("Invalid BreakpointState discriminant {state}"),
}
}
}
@ -914,7 +914,7 @@ impl WorkspaceDb {
log::debug!("Inserting SSH project at host {host}");
self.insert_ssh_project(host, port, paths, user)
.await?
.ok_or_else(|| anyhow!("failed to insert ssh project"))
.context("failed to insert ssh project")
}
}
@ -1244,7 +1244,7 @@ impl WorkspaceDb {
*axis,
flex_string,
))?
.ok_or_else(|| anyhow!("Couldn't retrieve group_id from inserted pane_group"))?;
.context("Couldn't retrieve group_id from inserted pane_group")?;
for (position, group) in children.iter().enumerate() {
Self::save_pane_group(conn, workspace_id, group, Some((group_id, position)))?
@ -1270,7 +1270,7 @@ impl WorkspaceDb {
VALUES (?, ?, ?)
RETURNING pane_id
))?((workspace_id, pane.active, pane.pinned_count))?
.ok_or_else(|| anyhow!("Could not retrieve inserted pane_id"))?;
.context("Could not retrieve inserted pane_id")?;
let (parent_id, order) = parent.unzip();
conn.exec_bound(sql!(

View file

@ -1296,7 +1296,7 @@ impl Workspace {
) -> Task<
anyhow::Result<(
WindowHandle<Workspace>,
Vec<Option<Result<Box<dyn ItemHandle>, anyhow::Error>>>,
Vec<Option<anyhow::Result<Box<dyn ItemHandle>>>>,
)>,
> {
let project_handle = Project::local(
@ -2187,7 +2187,7 @@ impl Workspace {
}
*keystrokes.borrow_mut() = Default::default();
Err(anyhow!("over 100 keystrokes passed to send_keystrokes"))
anyhow::bail!("over 100 keystrokes passed to send_keystrokes");
})
.detach_and_log_err(cx);
}
@ -2324,7 +2324,7 @@ impl Workspace {
pane: Option<WeakEntity<Pane>>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Vec<Option<Result<Box<dyn ItemHandle>, anyhow::Error>>>> {
) -> Task<Vec<Option<anyhow::Result<Box<dyn ItemHandle>>>>> {
log::info!("open paths {abs_paths:?}");
let fs = self.app_state.fs.clone();
@ -3076,7 +3076,7 @@ impl Workspace {
focus_item: bool,
window: &mut Window,
cx: &mut App,
) -> Task<Result<Box<dyn ItemHandle>, anyhow::Error>> {
) -> Task<anyhow::Result<Box<dyn ItemHandle>>> {
self.open_path_preview(path, pane, focus_item, false, true, window, cx)
}
@ -3089,7 +3089,7 @@ impl Workspace {
activate: bool,
window: &mut Window,
cx: &mut App,
) -> Task<Result<Box<dyn ItemHandle>, anyhow::Error>> {
) -> Task<anyhow::Result<Box<dyn ItemHandle>>> {
let pane = pane.unwrap_or_else(|| {
self.last_active_center_pane.clone().unwrap_or_else(|| {
self.panes
@ -3127,7 +3127,7 @@ impl Workspace {
path: impl Into<ProjectPath>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Result<Box<dyn ItemHandle>, anyhow::Error>> {
) -> Task<anyhow::Result<Box<dyn ItemHandle>>> {
self.split_path_preview(path, false, None, window, cx)
}
@ -3138,7 +3138,7 @@ impl Workspace {
split_direction: Option<SplitDirection>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Task<Result<Box<dyn ItemHandle>, anyhow::Error>> {
) -> Task<anyhow::Result<Box<dyn ItemHandle>>> {
let pane = self.last_active_center_pane.clone().unwrap_or_else(|| {
self.panes
.first()
@ -3178,7 +3178,7 @@ impl Workspace {
))
})
})
.map(|option| option.ok_or_else(|| anyhow!("pane was dropped")))?
.map(|option| option.context("pane was dropped"))?
})
}
@ -3938,12 +3938,12 @@ impl Workspace {
let state = this
.follower_states
.get_mut(&leader_id)
.ok_or_else(|| anyhow!("following interrupted"))?;
.context("following interrupted")?;
state.active_view_id = response
.active_view
.as_ref()
.and_then(|view| ViewId::from_proto(view.id.clone()?).ok());
Ok::<_, anyhow::Error>(())
anyhow::Ok(())
})??;
if let Some(view) = response.active_view {
Self::add_view_from_leader(this.clone(), leader_peer_id, &view, cx).await?;
@ -4286,7 +4286,7 @@ impl Workspace {
update: proto::UpdateFollowers,
cx: &mut AsyncWindowContext,
) -> Result<()> {
match update.variant.ok_or_else(|| anyhow!("invalid update"))? {
match update.variant.context("invalid update")? {
proto::update_followers::Variant::CreateView(view) => {
let view_id = ViewId::from_proto(view.id.clone().context("invalid view id")?)?;
let should_add_view = this.update(cx, |this, _| {
@ -4328,12 +4328,8 @@ impl Workspace {
}
}
proto::update_followers::Variant::UpdateView(update_view) => {
let variant = update_view
.variant
.ok_or_else(|| anyhow!("missing update view variant"))?;
let id = update_view
.id
.ok_or_else(|| anyhow!("missing update view id"))?;
let variant = update_view.variant.context("missing update view variant")?;
let id = update_view.id.context("missing update view id")?;
let mut tasks = Vec::new();
this.update_in(cx, |this, window, cx| {
let project = this.project.clone();
@ -4368,7 +4364,7 @@ impl Workspace {
let this = this.upgrade().context("workspace dropped")?;
let Some(id) = view.id.clone() else {
return Err(anyhow!("no id for view"));
anyhow::bail!("no id for view");
};
let id = ViewId::from_proto(id)?;
let panel_id = view.panel_id.and_then(proto::PanelId::from_i32);
@ -4395,18 +4391,16 @@ impl Workspace {
existing_item
} else {
let variant = view.variant.clone();
if variant.is_none() {
Err(anyhow!("missing view variant"))?;
}
anyhow::ensure!(variant.is_some(), "missing view variant");
let task = cx.update(|window, cx| {
FollowableViewRegistry::from_state_proto(this.clone(), id, variant, window, cx)
})?;
let Some(task) = task else {
return Err(anyhow!(
anyhow::bail!(
"failed to construct view from leader (maybe from a different version of zed?)"
));
);
};
let mut new_item = task.await?;
@ -5099,7 +5093,7 @@ impl Workspace {
) -> Result<()> {
self.serializable_items_tx
.unbounded_send(item)
.map_err(|err| anyhow!("failed to send serializable item over channel: {}", err))
.map_err(|err| anyhow!("failed to send serializable item over channel: {err}"))
}
pub(crate) fn load_workspace(
@ -6298,7 +6292,7 @@ impl ViewId {
creator: message
.creator
.map(CollaboratorId::PeerId)
.ok_or_else(|| anyhow!("creator is missing"))?,
.context("creator is missing")?,
id: message.id,
})
}
@ -6440,7 +6434,7 @@ async fn join_channel_internal(
// this loop will terminate within client::CONNECTION_TIMEOUT seconds.
'outer: loop {
let Some(status) = client_status.recv().await else {
return Err(anyhow!("error connecting"));
anyhow::bail!("error connecting");
};
match status {
@ -6662,7 +6656,7 @@ pub fn open_paths(
) -> Task<
anyhow::Result<(
WindowHandle<Workspace>,
Vec<Option<Result<Box<dyn ItemHandle>, anyhow::Error>>>,
Vec<Option<anyhow::Result<Box<dyn ItemHandle>>>>,
)>,
> {
let abs_paths = abs_paths.to_vec();
@ -6824,7 +6818,7 @@ pub fn create_and_open_local_file(
.await;
let item = items.pop().flatten();
item.ok_or_else(|| anyhow!("path {path:?} is not a file"))?
item.with_context(|| format!("path {path:?} is not a file"))?
})
}
@ -6945,9 +6939,7 @@ async fn open_ssh_project_inner(
}
if project_paths_to_open.is_empty() {
return Err(project_path_errors
.pop()
.unwrap_or_else(|| anyhow!("no paths given")));
return Err(project_path_errors.pop().context("no paths given")?);
}
cx.update_window(window.into(), |_, window, cx| {
@ -7053,7 +7045,7 @@ pub fn join_in_room_project(
let active_call = cx.update(|cx| ActiveCall::global(cx))?;
let room = active_call
.read_with(cx, |call, _| call.room().cloned())?
.ok_or_else(|| anyhow!("not in a call"))?;
.context("not in a call")?;
let project = room
.update(cx, |room, cx| {
room.join_project(
@ -9351,7 +9343,7 @@ mod tests {
_project: &Entity<Project>,
path: &ProjectPath,
cx: &mut App,
) -> Option<Task<gpui::Result<Entity<Self>>>> {
) -> Option<Task<anyhow::Result<Entity<Self>>>> {
if path.path.extension().unwrap() == "png" {
Some(cx.spawn(async move |cx| cx.new(|_| TestPngItem {})))
} else {
@ -9426,7 +9418,7 @@ mod tests {
_project: &Entity<Project>,
path: &ProjectPath,
cx: &mut App,
) -> Option<Task<gpui::Result<Entity<Self>>>> {
) -> Option<Task<anyhow::Result<Entity<Self>>>> {
if path.path.extension().unwrap() == "ipynb" {
Some(cx.spawn(async move |cx| cx.new(|_| TestIpynbItem {})))
} else {