@@ -7,13 +7,14 @@ use gpui::{App, AppContext, AsyncApp, Context, Entity, Task, WeakEntity};
use parking_lot::Mutex;
use project::Project;
use smol::process::Child;
-use std::{io::Write as _, path::Path, sync::Arc};
+use std::{io::Write as _, path::Path, process::ExitStatus, sync::Arc};
use util::ResultExt;
pub struct AcpServer {
connection: Arc<acp::AgentConnection>,
threads: Arc<Mutex<HashMap<ThreadId, WeakEntity<AcpThread>>>>,
project: Entity<Project>,
+ exit_status: Arc<Mutex<Option<ExitStatus>>>,
_handler_task: Task<()>,
_io_task: Task<()>,
}
@@ -248,22 +249,26 @@ impl AcpServer {
stdout,
);
- let io_task = cx.background_spawn(async move {
- io_fut.await.log_err();
- process.status().await.log_err();
+ let exit_status: Arc<Mutex<Option<ExitStatus>>> = Default::default();
+ let io_task = cx.background_spawn({
+ let exit_status = exit_status.clone();
+ async move {
+ io_fut.await.log_err();
+ let result = process.status().await.log_err();
+ *exit_status.lock() = result;
+ }
});
Arc::new(Self {
project,
connection: Arc::new(connection),
threads,
+ exit_status,
_handler_task: cx.foreground_executor().spawn(handler_fut),
_io_task: io_task,
})
}
-}
-impl AcpServer {
pub async fn create_thread(self: Arc<Self>, cx: &mut AsyncApp) -> Result<Entity<AcpThread>> {
let response = self.connection.request(acp::CreateThreadParams).await?;
let thread_id: ThreadId = response.thread_id.into();
@@ -295,6 +300,10 @@ impl AcpServer {
.await?;
Ok(())
}
+
+ pub fn exit_status(&self) -> Option<ExitStatus> {
+ self.exit_status.lock().clone()
+ }
}
impl From<acp::ThreadId> for ThreadId {
@@ -92,7 +92,7 @@ impl AcpThreadView {
let project = project.clone();
let load_task = cx.spawn_in(window, async move |this, cx| {
let agent = AcpServer::stdio(child, project, cx);
- let result = agent.create_thread(cx).await;
+ let result = agent.clone().create_thread(cx).await;
this.update(cx, |this, cx| {
match result {
@@ -117,7 +117,19 @@ impl AcpThreadView {
_subscription: subscription,
};
}
- Err(e) => this.thread_state = ThreadState::LoadError(e.to_string().into()),
+ Err(e) => {
+ if let Some(exit_status) = agent.exit_status() {
+ this.thread_state = ThreadState::LoadError(
+ format!(
+ "Gemini exited with status {}",
+ exit_status.code().unwrap_or(-127)
+ )
+ .into(),
+ )
+ } else {
+ this.thread_state = ThreadState::LoadError(e.to_string().into())
+ }
+ }
};
cx.notify();
})
@@ -743,7 +755,7 @@ impl Render for AcpThreadView {
.p_2()
.flex_1()
.justify_end()
- .child(Label::new(format!("Failed to load {e}")).into_any_element()),
+ .child(Label::new(format!("Failed to load: {e}")).into_any_element()),
ThreadState::Ready { thread, .. } => v_flex()
.flex_1()
.gap_2()