diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 1d595d0e24..e2c7b99763 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -141,7 +141,7 @@ impl CachedLspAdapter { self.adapter.cached_server_binary(container_dir).await } - async fn installation_test_binary( + pub async fn installation_test_binary( &self, container_dir: PathBuf, ) -> Option { @@ -544,6 +544,7 @@ struct LanguageRegistryState { pub struct PendingLanguageServer { pub server_id: LanguageServerId, pub task: Task>, + pub container_dir: Option>, } impl LanguageRegistry { @@ -824,8 +825,8 @@ impl LanguageRegistry { cx: &mut AppContext, ) -> Option { let server_id = self.state.write().next_language_server_id(); - log::info!( - "starting language server name:{}, path:{root_path:?}, id:{server_id}", + println!( + "starting language server {:?}, path: {root_path:?}, id: {server_id}", adapter.name.0 ); @@ -858,7 +859,11 @@ impl LanguageRegistry { Ok(server) }); - return Some(PendingLanguageServer { server_id, task }); + return Some(PendingLanguageServer { + server_id, + task, + container_dir: None, + }); } let download_dir = self @@ -869,46 +874,54 @@ impl LanguageRegistry { let this = self.clone(); let language = language.clone(); let http_client = http_client.clone(); - let download_dir = download_dir.clone(); + let container_dir: Arc = Arc::from(download_dir.join(adapter.name.0.as_ref())); let root_path = root_path.clone(); let adapter = adapter.clone(); let lsp_binary_statuses = self.lsp_binary_statuses_tx.clone(); let login_shell_env_loaded = self.login_shell_env_loaded.clone(); - let task = cx.spawn(|cx| async move { - login_shell_env_loaded.await; + let task = { + let container_dir = container_dir.clone(); + cx.spawn(|cx| async move { + login_shell_env_loaded.await; - let mut lock = this.lsp_binary_paths.lock(); - let entry = lock - .entry(adapter.name.clone()) - .or_insert_with(|| { - get_binary( - adapter.clone(), - language.clone(), - http_client, - download_dir, - lsp_binary_statuses, - ) - .map_err(Arc::new) - .boxed() - .shared() - }) - .clone(); - drop(lock); + let mut lock = this.lsp_binary_paths.lock(); + let entry = lock + .entry(adapter.name.clone()) + .or_insert_with(|| { + get_binaries( + adapter.clone(), + language.clone(), + http_client, + container_dir, + lsp_binary_statuses, + ) + .map_err(Arc::new) + .boxed() + .shared() + }) + .clone(); + drop(lock); - let binary = entry.clone().map_err(|e| anyhow!(e)).await?; - let server = lsp::LanguageServer::new( - server_id, - binary, - &root_path, - adapter.code_action_kinds(), - cx, - )?; + let binaries = entry.clone().map_err(|e| anyhow!(e)).await?; + println!("starting server"); + let server = lsp::LanguageServer::new( + server_id, + binaries, + &root_path, + adapter.code_action_kinds(), + cx, + )?; - Ok(server) - }); + Ok(server) + }) + }; - Some(PendingLanguageServer { server_id, task }) + Some(PendingLanguageServer { + server_id, + task, + container_dir: Some(container_dir), + }) } pub fn language_server_binary_statuses( @@ -922,6 +935,7 @@ impl LanguageRegistry { adapter: Arc, cx: &mut AppContext, ) -> Task<()> { + println!("deleting server container"); let mut lock = self.lsp_binary_paths.lock(); lock.remove(&adapter.name); @@ -984,20 +998,20 @@ impl Default for LanguageRegistry { } } -async fn get_binary( +async fn get_binaries( adapter: Arc, language: Arc, http_client: Arc, - download_dir: Arc, + container_dir: Arc, statuses: async_broadcast::Sender<(Arc, LanguageServerBinaryStatus)>, ) -> Result { - let container_dir = download_dir.join(adapter.name.0.as_ref()); if !container_dir.exists() { smol::fs::create_dir_all(&container_dir) .await .context("failed to create container directory")?; } + println!("fetching binary"); let binary = fetch_latest_binary( adapter.clone(), language.clone(), @@ -1008,11 +1022,16 @@ async fn get_binary( .await; if let Err(error) = binary.as_ref() { - if let Some(binary) = adapter.cached_server_binary(container_dir.clone()).await { + if let Some(binary) = adapter + .cached_server_binary(container_dir.to_path_buf()) + .await + { statuses .broadcast((language.clone(), LanguageServerBinaryStatus::Cached)) .await?; - let installation_test_binary = adapter.installation_test_binary(container_dir).await; + let installation_test_binary = adapter + .installation_test_binary(container_dir.to_path_buf()) + .await; return Ok(LanguageServerBinaries { binary, installation_test_binary, diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index f7d924604b..cd7c1a0355 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -65,7 +65,7 @@ pub struct LanguageServer { output_done_rx: Mutex>, root_path: PathBuf, server: Option>, - test_installation_binary: Option, + installation_test_binary: Option, } #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -190,7 +190,7 @@ impl LanguageServer { stdin: Stdin, stdout: Stdout, server: Option, - test_installation_binary: Option, + installation_test_binary: Option, root_path: &Path, code_action_kinds: Option>, cx: AsyncAppContext, @@ -245,7 +245,7 @@ impl LanguageServer { output_done_rx: Mutex::new(Some(output_done_rx)), root_path: root_path.to_path_buf(), server: server.map(|server| Mutex::new(server)), - test_installation_binary, + installation_test_binary, } } @@ -262,8 +262,8 @@ impl LanguageServer { } } - pub fn test_installation_binary(&self) -> &Option { - &self.test_installation_binary + pub fn installation_test_binary(&self) -> &Option { + &self.installation_test_binary } pub fn code_action_kinds(&self) -> Option> { diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 41a9d65069..44e1523bd1 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -45,7 +45,7 @@ use language::{ use log::error; use lsp::{ DiagnosticSeverity, DiagnosticTag, DidChangeWatchedFilesRegistrationOptions, - DocumentHighlightKind, LanguageServer, LanguageServerId, OneOf, + DocumentHighlightKind, LanguageServer, LanguageServerBinary, LanguageServerId, OneOf, }; use lsp_command::*; use postage::watch; @@ -2442,22 +2442,23 @@ impl Project { } let server_id = pending_server.server_id; + let container_dir = pending_server.container_dir.clone(); let state = LanguageServerState::Starting({ let server_name = adapter.name.0.clone(); let languages = self.languages.clone(); let key = key.clone(); - cx.spawn_weak(|this, cx| async move { + cx.spawn_weak(|this, mut cx| async move { let result = Self::setup_and_insert_language_server( this, initialization_options, pending_server, - adapter, + adapter.clone(), languages, language, server_id, key, - cx, + &mut cx, ) .await; @@ -2465,8 +2466,24 @@ impl Project { Ok(server) => Some(server), Err(err) => { - log::warn!("Error starting language server {:?}: {}", server_name, err); - // TODO: Prompt installation validity check LSP ERROR + println!("failed to start language server {:?}: {}", server_name, err); + + if let Some(this) = this.upgrade(&cx) { + if let Some(container_dir) = container_dir { + let installation_test_binary = adapter + .installation_test_binary(container_dir.to_path_buf()) + .await; + + this.update(&mut cx, |_, cx| { + Self::check_errored_server_id( + server_id, + installation_test_binary, + cx, + ) + }); + } + } + None } } @@ -2482,6 +2499,7 @@ impl Project { server_id: LanguageServerId, cx: &mut ModelContext, ) -> Option> { + println!("starting to reinstall server"); let (adapter, language, server) = match self.language_servers.remove(&server_id) { Some(LanguageServerState::Running { adapter, @@ -2495,6 +2513,7 @@ impl Project { Some(cx.spawn(move |this, mut cx| async move { if let Some(task) = server.shutdown() { + println!("shutting down existing server"); task.await; } @@ -2516,6 +2535,7 @@ impl Project { let worktree_id = worktree.id(); let root_path = worktree.abs_path(); + println!("prompting server start: {:?}", &adapter.name.0); this.start_language_server( worktree_id, root_path, @@ -2537,7 +2557,7 @@ impl Project { language: Arc, server_id: LanguageServerId, key: (WorktreeId, LanguageServerName), - mut cx: AsyncAppContext, + cx: &mut AsyncAppContext, ) -> Result> { let language_server = Self::setup_pending_language_server( this, @@ -2546,16 +2566,16 @@ impl Project { adapter.clone(), languages, server_id, - &mut cx, + cx, ) .await?; - let this = match this.upgrade(&mut cx) { + let this = match this.upgrade(cx) { Some(this) => this, None => return Err(anyhow!("failed to upgrade project handle")), }; - this.update(&mut cx, |this, cx| { + this.update(cx, |this, cx| { this.insert_newly_running_language_server( language, adapter, @@ -3012,32 +3032,39 @@ impl Project { .detach(); } - fn check_errored_lsp_installation( + fn check_errored_language_server( &self, language_server: Arc, cx: &mut ModelContext, ) { - cx.spawn(|this, mut cx| async move { - if !language_server.is_dead() { - return; - } - let server_id = language_server.server_id(); + if !language_server.is_dead() { + return; + } + let server_id = language_server.server_id(); + let installation_test_binary = language_server.installation_test_binary().clone(); + Self::check_errored_server_id(server_id, installation_test_binary, cx); + } + + fn check_errored_server_id( + server_id: LanguageServerId, + installation_test_binary: Option, + cx: &mut ModelContext, + ) { + cx.spawn(|this, mut cx| async move { + println!("About to spawn test binary"); // A lack of test binary counts as a failure - let process = language_server - .test_installation_binary() - .as_ref() - .and_then(|binary| { - smol::process::Command::new(&binary.path) - .current_dir(&binary.path) - .args(&binary.arguments) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::inherit()) - .kill_on_drop(true) - .spawn() - .ok() - }); + let process = installation_test_binary.and_then(|binary| { + smol::process::Command::new(&binary.path) + .current_dir(&binary.path) + .args(binary.arguments) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::inherit()) + .kill_on_drop(true) + .spawn() + .ok() + }); const PROCESS_TIMEOUT: Duration = Duration::from_secs(5); let mut timeout = cx.background().timer(PROCESS_TIMEOUT).fuse(); @@ -3046,13 +3073,14 @@ impl Project { if let Some(mut process) = process { futures::select! { status = process.status().fuse() => match status { - Ok(status) => errored = !status.success(), + Ok(status) => errored = !dbg!(status.success()), Err(_) => errored = true, }, - _ = timeout => {} + _ = timeout => { println!("test binary time-ed out"); } } } else { + println!("test binary failed to launch"); errored = true; } @@ -3883,7 +3911,7 @@ impl Project { ); this.update(cx, |this, cx| { - this.check_errored_lsp_installation(language_server.clone(), cx); + this.check_errored_language_server(language_server.clone(), cx); }); None