Fix panic in open urls (#9032)

Co-Authored-By: Nathan <nathan@zed.dev>

Release Notes:

- N/A

Co-authored-by: Nathan <nathan@zed.dev>
This commit is contained in:
Conrad Irwin 2024-03-07 13:52:50 -07:00 committed by GitHub
parent 9068911eb4
commit 284a57d4d1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 176 additions and 225 deletions

View file

@ -106,11 +106,11 @@ fn main() {
let (listener, mut open_rx) = OpenListener::new();
let listener = Arc::new(listener);
let open_listener = listener.clone();
app.on_open_urls(move |urls, cx| open_listener.open_urls(&urls, cx));
app.on_open_urls(move |urls| open_listener.open_urls(urls));
app.on_reopen(move |cx| {
if let Some(app_state) = AppState::try_global(cx).and_then(|app_state| app_state.upgrade())
{
workspace::open_new(&app_state, cx, |workspace, cx| {
workspace::open_new(app_state, cx, |workspace, cx| {
Editor::new_file(workspace, &Default::default(), cx)
})
.detach();
@ -273,7 +273,7 @@ fn main() {
cx.activate(true);
let urls = collect_url_args(cx);
if !urls.is_empty() {
listener.open_urls(&urls, cx)
listener.open_urls(urls)
}
} else {
upload_panics_and_crashes(http.clone(), cx);
@ -282,141 +282,38 @@ fn main() {
if std::env::var(FORCE_CLI_MODE_ENV_VAR_NAME).ok().is_some()
&& !listener.triggered.load(Ordering::Acquire)
{
listener.open_urls(&collect_url_args(cx), cx)
listener.open_urls(collect_url_args(cx))
}
}
let mut triggered_authentication = false;
fn open_paths_and_log_errs(
paths: &[PathBuf],
app_state: &Arc<AppState>,
cx: &mut AppContext,
) {
let task = workspace::open_paths(&paths, &app_state, None, cx);
cx.spawn(|_| async move {
if let Some((_window, results)) = task.await.log_err() {
for result in results.into_iter().flatten() {
if let Err(err) = result {
log::error!("Error opening path: {err}",);
}
}
}
})
.detach();
}
match open_rx.try_next() {
Ok(Some(OpenRequest::Paths { paths })) => {
open_paths_and_log_errs(&paths, &app_state, cx)
match open_rx
.try_next()
.ok()
.flatten()
.and_then(|urls| OpenRequest::parse(urls, cx).log_err())
{
Some(request) => {
triggered_authentication = handle_open_request(request, app_state.clone(), cx)
}
Ok(Some(OpenRequest::CliConnection { connection })) => {
let app_state = app_state.clone();
cx.spawn(move |cx| handle_cli_connection(connection, app_state, cx))
.detach();
}
Ok(Some(OpenRequest::JoinChannel { channel_id })) => {
triggered_authentication = true;
let app_state = app_state.clone();
let client = client.clone();
cx.spawn(|cx| async move {
// ignore errors here, we'll show a generic "not signed in"
let _ = authenticate(client, &cx).await;
cx.update(|cx| {
workspace::join_channel(client::ChannelId(channel_id), app_state, None, cx)
})?
.await?;
anyhow::Ok(())
})
.detach_and_log_err(cx);
}
Ok(Some(OpenRequest::OpenChannelNotes {
channel_id,
heading,
})) => {
triggered_authentication = true;
let app_state = app_state.clone();
let client = client.clone();
cx.spawn(|mut cx| async move {
// ignore errors here, we'll show a generic "not signed in"
let _ = authenticate(client, &cx).await;
let workspace_window =
workspace::get_any_active_workspace(app_state, cx.clone()).await?;
let workspace = workspace_window.root_view(&cx)?;
cx.update_window(workspace_window.into(), |_, cx| {
ChannelView::open(client::ChannelId(channel_id), heading, workspace, cx)
})?
.await?;
anyhow::Ok(())
})
.detach_and_log_err(cx);
}
Ok(None) | Err(_) => cx
None => cx
.spawn({
let app_state = app_state.clone();
|cx| async move { restore_or_create_workspace(&app_state, cx).await }
|cx| async move { restore_or_create_workspace(app_state, cx).await }
})
.detach(),
}
let app_state = app_state.clone();
cx.spawn(move |cx| async move {
while let Some(request) = open_rx.next().await {
match request {
OpenRequest::Paths { paths } => {
cx.update(|cx| open_paths_and_log_errs(&paths, &app_state, cx))
.ok();
while let Some(urls) = open_rx.next().await {
cx.update(|cx| {
if let Some(request) = OpenRequest::parse(urls, cx).log_err() {
handle_open_request(request, app_state.clone(), cx);
}
OpenRequest::CliConnection { connection } => {
let app_state = app_state.clone();
cx.spawn(move |cx| {
handle_cli_connection(connection, app_state.clone(), cx)
})
.detach();
}
OpenRequest::JoinChannel { channel_id } => {
let app_state = app_state.clone();
cx.update(|mut cx| {
cx.spawn(|cx| async move {
cx.update(|cx| {
workspace::join_channel(
client::ChannelId(channel_id),
app_state,
None,
cx,
)
})?
.await?;
anyhow::Ok(())
})
.detach_and_log_err(&mut cx);
})
.log_err();
}
OpenRequest::OpenChannelNotes {
channel_id,
heading,
} => {
let app_state = app_state.clone();
let open_notes_task = cx.spawn(|mut cx| async move {
let workspace_window =
workspace::get_any_active_workspace(app_state, cx.clone()).await?;
let workspace = workspace_window.root_view(&cx)?;
cx.update_window(workspace_window.into(), |_, cx| {
ChannelView::open(
client::ChannelId(channel_id),
heading,
workspace,
cx,
)
})?
.await?;
anyhow::Ok(())
});
cx.update(|cx| open_notes_task.detach_and_log_err(cx))
.log_err();
}
}
})
.ok();
}
})
.detach();
@ -428,6 +325,70 @@ fn main() {
});
}
fn open_paths_and_log_errs(paths: &[PathBuf], app_state: Arc<AppState>, cx: &mut AppContext) {
let task = workspace::open_paths(&paths, app_state, None, cx);
cx.spawn(|_| async move {
if let Some((_window, results)) = task.await.log_err() {
for result in results.into_iter().flatten() {
if let Err(err) = result {
log::error!("Error opening path: {err}",);
}
}
}
})
.detach();
}
fn handle_open_request(
request: OpenRequest,
app_state: Arc<AppState>,
cx: &mut AppContext,
) -> bool {
let mut triggered_authentication = false;
match request {
OpenRequest::Paths { paths } => open_paths_and_log_errs(&paths, app_state, cx),
OpenRequest::CliConnection { connection } => {
let app_state = app_state.clone();
cx.spawn(move |cx| handle_cli_connection(connection, app_state, cx))
.detach();
}
OpenRequest::JoinChannel { channel_id } => {
triggered_authentication = true;
cx.spawn(|cx| async move {
// ignore errors here, we'll show a generic "not signed in"
let _ = authenticate(app_state.client.clone(), &cx).await;
cx.update(|cx| {
workspace::join_channel(client::ChannelId(channel_id), app_state, None, cx)
})?
.await?;
anyhow::Ok(())
})
.detach_and_log_err(cx);
}
OpenRequest::OpenChannelNotes {
channel_id,
heading,
} => {
triggered_authentication = true;
let client = app_state.client.clone();
cx.spawn(|mut cx| async move {
// ignore errors here, we'll show a generic "not signed in"
let _ = authenticate(client, &cx).await;
let workspace_window =
workspace::get_any_active_workspace(app_state, cx.clone()).await?;
let workspace = workspace_window.root_view(&cx)?;
cx.update_window(workspace_window.into(), |_, cx| {
ChannelView::open(client::ChannelId(channel_id), heading, workspace, cx)
})?
.await?;
anyhow::Ok(())
})
.detach_and_log_err(cx);
}
}
triggered_authentication
}
async fn authenticate(client: Arc<Client>, cx: &AsyncAppContext) -> Result<()> {
if stdout_is_a_pty() {
if client::IMPERSONATE_LOGIN.is_some() {
@ -465,7 +426,7 @@ async fn installation_id() -> Result<(String, bool)> {
Ok((installation_id, false))
}
async fn restore_or_create_workspace(app_state: &Arc<AppState>, cx: AsyncAppContext) {
async fn restore_or_create_workspace(app_state: Arc<AppState>, cx: AsyncAppContext) {
async_maybe!({
if let Some(location) = workspace::last_opened_workspace_paths().await {
cx.update(|cx| workspace::open_paths(location.paths().as_ref(), app_state, None, cx))?