diff --git a/Cargo.lock b/Cargo.lock index 08ffcac7cf..83aa2b9a8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1713,6 +1713,7 @@ dependencies = [ "log", "lsp", "node_runtime", + "parking_lot 0.11.2", "rpc", "serde", "serde_derive", @@ -5562,6 +5563,7 @@ dependencies = [ "log", "lsp", "node_runtime", + "parking_lot 0.11.2", "serde", "serde_derive", "serde_json", diff --git a/crates/copilot/Cargo.toml b/crates/copilot/Cargo.toml index bac335f7b7..2558974753 100644 --- a/crates/copilot/Cargo.toml +++ b/crates/copilot/Cargo.toml @@ -36,6 +36,7 @@ serde.workspace = true serde_derive.workspace = true smol.workspace = true futures.workspace = true +parking_lot.workspace = true [dev-dependencies] clock = { path = "../clock" } diff --git a/crates/copilot/src/copilot.rs b/crates/copilot/src/copilot.rs index 4b81bebc02..3b383c2ac9 100644 --- a/crates/copilot/src/copilot.rs +++ b/crates/copilot/src/copilot.rs @@ -16,6 +16,7 @@ use language::{ }; use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId}; use node_runtime::NodeRuntime; +use parking_lot::Mutex; use request::StatusNotification; use settings::SettingsStore; use smol::{fs, io::BufReader, stream::StreamExt}; @@ -387,8 +388,15 @@ impl Copilot { path: node_path, arguments, }; - let server = - LanguageServer::new(new_server_id, binary, Path::new("/"), None, cx.clone())?; + + let server = LanguageServer::new( + Arc::new(Mutex::new(None)), + new_server_id, + binary, + Path::new("/"), + None, + cx.clone(), + )?; server .on_notification::( diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 59d1d12cb9..6a40c7974c 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -645,7 +645,7 @@ struct LanguageRegistryState { pub struct PendingLanguageServer { pub server_id: LanguageServerId, - pub task: Task>>, + pub task: Task>, pub container_dir: Option>, } @@ -884,6 +884,7 @@ impl LanguageRegistry { pub fn create_pending_language_server( self: &Arc, + stderr_capture: Arc>>, language: Arc, adapter: Arc, root_path: Arc, @@ -923,7 +924,7 @@ impl LanguageRegistry { }) .detach(); - Ok(Some(server)) + Ok(server) }); return Some(PendingLanguageServer { @@ -971,24 +972,23 @@ impl LanguageRegistry { .clone(); drop(lock); - let binary = match entry.clone().await.log_err() { - Some(binary) => binary, - None => return Ok(None), + let binary = match entry.clone().await { + Ok(binary) => binary, + Err(err) => anyhow::bail!("{err}"), }; if let Some(task) = adapter.will_start_server(&delegate, &mut cx) { - if task.await.log_err().is_none() { - return Ok(None); - } + task.await?; } - Ok(Some(lsp::LanguageServer::new( + lsp::LanguageServer::new( + stderr_capture, server_id, binary, &root_path, adapter.code_action_kinds(), cx, - )?)) + ) }) }; diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index b4099e2f6e..98fd81f012 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -136,6 +136,7 @@ struct Error { impl LanguageServer { pub fn new( + stderr_capture: Arc>>, server_id: LanguageServerId, binary: LanguageServerBinary, root_path: &Path, @@ -165,6 +166,7 @@ impl LanguageServer { stdin, stdout, Some(stderr), + stderr_capture, Some(server), root_path, code_action_kinds, @@ -197,6 +199,7 @@ impl LanguageServer { stdin: Stdin, stdout: Stdout, stderr: Option, + stderr_capture: Arc>>, server: Option, root_path: &Path, code_action_kinds: Option>, @@ -218,20 +221,23 @@ impl LanguageServer { let io_handlers = Arc::new(Mutex::new(HashMap::default())); let stdout_input_task = cx.spawn(|cx| { - { - Self::handle_input( - stdout, - on_unhandled_notification.clone(), - notification_handlers.clone(), - response_handlers.clone(), - io_handlers.clone(), - cx, - ) - } + Self::handle_input( + stdout, + on_unhandled_notification.clone(), + notification_handlers.clone(), + response_handlers.clone(), + io_handlers.clone(), + cx, + ) .log_err() }); let stderr_input_task = stderr - .map(|stderr| cx.spawn(|_| Self::handle_stderr(stderr, io_handlers.clone()).log_err())) + .map(|stderr| { + cx.spawn(|_| { + Self::handle_stderr(stderr, io_handlers.clone(), stderr_capture.clone()) + .log_err() + }) + }) .unwrap_or_else(|| Task::Ready(Some(None))); let input_task = cx.spawn(|_| async move { let (stdout, stderr) = futures::join!(stdout_input_task, stderr_input_task); @@ -353,12 +359,14 @@ impl LanguageServer { async fn handle_stderr( stderr: Stderr, io_handlers: Arc>>, + stderr_capture: Arc>>, ) -> anyhow::Result<()> where Stderr: AsyncRead + Unpin + Send + 'static, { let mut stderr = BufReader::new(stderr); let mut buffer = Vec::new(); + loop { buffer.clear(); stderr.read_until(b'\n', &mut buffer).await?; @@ -367,6 +375,10 @@ impl LanguageServer { for handler in io_handlers.lock().values_mut() { handler(IoKind::StdErr, message); } + + if let Some(stderr) = stderr_capture.lock().as_mut() { + stderr.push_str(message); + } } // Don't starve the main thread when receiving lots of messages at once. @@ -938,6 +950,7 @@ impl LanguageServer { stdin_writer, stdout_reader, None::, + Arc::new(Mutex::new(None)), None, Path::new("/"), None, @@ -950,6 +963,7 @@ impl LanguageServer { stdout_writer, stdin_reader, None::, + Arc::new(Mutex::new(None)), None, Path::new("/"), None, diff --git a/crates/prettier/Cargo.toml b/crates/prettier/Cargo.toml index 997fa87126..4419112baf 100644 --- a/crates/prettier/Cargo.toml +++ b/crates/prettier/Cargo.toml @@ -27,6 +27,7 @@ serde_derive.workspace = true serde_json.workspace = true anyhow.workspace = true futures.workspace = true +parking_lot.workspace = true [dev-dependencies] language = { path = "../language", features = ["test-support"] } diff --git a/crates/prettier/src/prettier.rs b/crates/prettier/src/prettier.rs index bddfcb3a8f..79fef40908 100644 --- a/crates/prettier/src/prettier.rs +++ b/crates/prettier/src/prettier.rs @@ -210,6 +210,7 @@ impl Prettier { .spawn(async move { node.binary_path().await }) .await?; let server = LanguageServer::new( + Arc::new(parking_lot::Mutex::new(None)), server_id, LanguageServerBinary { path: node_path, diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index fd21c64945..924c3d0095 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -52,6 +52,7 @@ use lsp::{ }; use lsp_command::*; use node_runtime::NodeRuntime; +use parking_lot::Mutex; use postage::watch; use prettier::{LocateStart, Prettier}; use project_settings::{LspSettings, ProjectSettings}; @@ -2726,7 +2727,9 @@ impl Project { return; } + let stderr_capture = Arc::new(Mutex::new(Some(String::new()))); let pending_server = match self.languages.create_pending_language_server( + stderr_capture.clone(), language.clone(), adapter.clone(), worktree_path, @@ -2763,10 +2766,14 @@ impl Project { .await; match result { - Ok(server) => server, + Ok(server) => { + stderr_capture.lock().take(); + Some(server) + } Err(err) => { log::error!("failed to start language server {:?}: {}", server_name, err); + log::error!("server stderr: {:?}", stderr_capture.lock().take()); if let Some(this) = this.upgrade(&cx) { if let Some(container_dir) = container_dir { @@ -2862,20 +2869,17 @@ impl Project { server_id: LanguageServerId, key: (WorktreeId, LanguageServerName), cx: &mut AsyncAppContext, - ) -> Result>> { - let setup = Self::setup_pending_language_server( + ) -> Result> { + let language_server = Self::setup_pending_language_server( this, override_initialization_options, pending_server, adapter.clone(), server_id, cx, - ); + ) + .await?; - let language_server = match setup.await? { - Some(language_server) => language_server, - None => return Ok(None), - }; let this = match this.upgrade(cx) { Some(this) => this, None => return Err(anyhow!("failed to upgrade project handle")), @@ -2892,7 +2896,7 @@ impl Project { ) })?; - Ok(Some(language_server)) + Ok(language_server) } async fn setup_pending_language_server( @@ -2902,12 +2906,9 @@ impl Project { adapter: Arc, server_id: LanguageServerId, cx: &mut AsyncAppContext, - ) -> Result>> { + ) -> Result> { let workspace_config = cx.update(|cx| adapter.workspace_configuration(cx)).await; - let language_server = match pending_server.task.await? { - Some(server) => server, - None => return Ok(None), - }; + let language_server = pending_server.task.await?; language_server .on_notification::({ @@ -2978,6 +2979,7 @@ impl Project { }, ) .detach(); + language_server .on_request::({ move |params, mut cx| async move { @@ -3043,6 +3045,7 @@ impl Project { } }) .detach(); + let mut initialization_options = adapter.adapter.initialization_options().await; match (&mut initialization_options, override_options) { (Some(initialization_options), Some(override_options)) => { @@ -3062,7 +3065,7 @@ impl Project { ) .ok(); - Ok(Some(language_server)) + Ok(language_server) } fn insert_newly_running_language_server(