Detailed changes
@@ -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",
@@ -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" }
@@ -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::<StatusNotification, _>(
@@ -645,7 +645,7 @@ struct LanguageRegistryState {
pub struct PendingLanguageServer {
pub server_id: LanguageServerId,
- pub task: Task<Result<Option<lsp::LanguageServer>>>,
+ pub task: Task<Result<lsp::LanguageServer>>,
pub container_dir: Option<Arc<Path>>,
}
@@ -884,6 +884,7 @@ impl LanguageRegistry {
pub fn create_pending_language_server(
self: &Arc<Self>,
+ stderr_capture: Arc<Mutex<Option<String>>>,
language: Arc<Language>,
adapter: Arc<CachedLspAdapter>,
root_path: Arc<Path>,
@@ -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,
- )?))
+ )
})
};
@@ -136,6 +136,7 @@ struct Error {
impl LanguageServer {
pub fn new(
+ stderr_capture: Arc<Mutex<Option<String>>>,
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>,
+ stderr_capture: Arc<Mutex<Option<String>>>,
server: Option<Child>,
root_path: &Path,
code_action_kinds: Option<Vec<CodeActionKind>>,
@@ -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: Stderr,
io_handlers: Arc<Mutex<HashMap<usize, IoHandler>>>,
+ stderr_capture: Arc<Mutex<Option<String>>>,
) -> 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::<async_pipe::PipeReader>,
+ Arc::new(Mutex::new(None)),
None,
Path::new("/"),
None,
@@ -950,6 +963,7 @@ impl LanguageServer {
stdout_writer,
stdin_reader,
None::<async_pipe::PipeReader>,
+ Arc::new(Mutex::new(None)),
None,
Path::new("/"),
None,
@@ -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"] }
@@ -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,
@@ -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<Option<Arc<LanguageServer>>> {
- let setup = Self::setup_pending_language_server(
+ ) -> Result<Arc<LanguageServer>> {
+ 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<CachedLspAdapter>,
server_id: LanguageServerId,
cx: &mut AsyncAppContext,
- ) -> Result<Option<Arc<LanguageServer>>> {
+ ) -> Result<Arc<LanguageServer>> {
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::<lsp::notification::PublishDiagnostics, _>({
@@ -2978,6 +2979,7 @@ impl Project {
},
)
.detach();
+
language_server
.on_request::<lsp::request::RegisterCapability, _, _>({
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(