diff --git a/crates/lsp/src/lsp.rs b/crates/lsp/src/lsp.rs index d52de667d4..e973a77f4f 100644 --- a/crates/lsp/src/lsp.rs +++ b/crates/lsp/src/lsp.rs @@ -665,11 +665,11 @@ impl LanguageServer { } } - pub fn name<'a>(self: &'a Arc) -> &'a str { + pub fn name<'a>(&self) -> &str { &self.name } - pub fn capabilities<'a>(self: &'a Arc) -> &'a ServerCapabilities { + pub fn capabilities<'a>(&self) -> &ServerCapabilities { &self.capabilities } diff --git a/crates/project/src/lsp_command.rs b/crates/project/src/lsp_command.rs index 8435de71e2..82e2c0c5a5 100644 --- a/crates/project/src/lsp_command.rs +++ b/crates/project/src/lsp_command.rs @@ -1,6 +1,6 @@ use crate::{ DocumentHighlight, Hover, HoverBlock, HoverBlockKind, Location, LocationLink, Project, - ProjectTransaction, + ProjectLanguageServer, ProjectTransaction, }; use anyhow::{anyhow, Result}; use async_trait::async_trait; @@ -14,7 +14,7 @@ use language::{ range_from_lsp, range_to_lsp, Anchor, Bias, Buffer, CachedLspAdapter, CharKind, CodeAction, Completion, OffsetRangeExt, PointUtf16, ToOffset, ToPointUtf16, Transaction, Unclipped, }; -use lsp::{DocumentHighlightKind, LanguageServer, LanguageServerId, ServerCapabilities}; +use lsp::{DocumentHighlightKind, LanguageServerId, ServerCapabilities}; use std::{cmp::Reverse, ops::Range, path::Path, sync::Arc}; pub fn lsp_formatting_options(tab_size: u32) -> lsp::FormattingOptions { @@ -40,7 +40,7 @@ pub(crate) trait LspCommand: 'static + Sized { &self, path: &Path, buffer: &Buffer, - language_server: &Arc, + language_server: &Arc, cx: &AppContext, ) -> ::Params; @@ -156,7 +156,7 @@ impl LspCommand for PrepareRename { &self, path: &Path, _: &Buffer, - _: &Arc, + _: &Arc, _: &AppContext, ) -> lsp::TextDocumentPositionParams { lsp::TextDocumentPositionParams { @@ -279,7 +279,7 @@ impl LspCommand for PerformRename { &self, path: &Path, _: &Buffer, - _: &Arc, + _: &Arc, _: &AppContext, ) -> lsp::RenameParams { lsp::RenameParams { @@ -398,7 +398,7 @@ impl LspCommand for GetDefinition { &self, path: &Path, _: &Buffer, - _: &Arc, + _: &Arc, _: &AppContext, ) -> lsp::GotoDefinitionParams { lsp::GotoDefinitionParams { @@ -499,7 +499,7 @@ impl LspCommand for GetTypeDefinition { &self, path: &Path, _: &Buffer, - _: &Arc, + _: &Arc, _: &AppContext, ) -> lsp::GotoTypeDefinitionParams { lsp::GotoTypeDefinitionParams { @@ -587,7 +587,7 @@ fn language_server_for_buffer( buffer: &ModelHandle, server_id: LanguageServerId, cx: &mut AsyncAppContext, -) -> Result<(Arc, Arc)> { +) -> Result<(Arc, Arc)> { project .read_with(cx, |project, cx| { project @@ -784,7 +784,7 @@ impl LspCommand for GetReferences { &self, path: &Path, _: &Buffer, - _: &Arc, + _: &Arc, _: &AppContext, ) -> lsp::ReferenceParams { lsp::ReferenceParams { @@ -949,7 +949,7 @@ impl LspCommand for GetDocumentHighlights { &self, path: &Path, _: &Buffer, - _: &Arc, + _: &Arc, _: &AppContext, ) -> lsp::DocumentHighlightParams { lsp::DocumentHighlightParams { @@ -1096,7 +1096,7 @@ impl LspCommand for GetHover { &self, path: &Path, _: &Buffer, - _: &Arc, + _: &Arc, _: &AppContext, ) -> lsp::HoverParams { lsp::HoverParams { @@ -1314,7 +1314,7 @@ impl LspCommand for GetCompletions { &self, path: &Path, _: &Buffer, - _: &Arc, + _: &Arc, _: &AppContext, ) -> lsp::CompletionParams { lsp::CompletionParams { @@ -1530,7 +1530,7 @@ impl LspCommand for GetCodeActions { &self, path: &Path, buffer: &Buffer, - language_server: &Arc, + language_server: &Arc, _: &AppContext, ) -> lsp::CodeActionParams { let relevant_diagnostics = buffer @@ -1673,7 +1673,7 @@ impl LspCommand for OnTypeFormatting { &self, path: &Path, _: &Buffer, - _: &Arc, + _: &Arc, _: &AppContext, ) -> lsp::DocumentOnTypeFormattingParams { lsp::DocumentOnTypeFormattingParams { diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 2536c94225..5c22a14d4d 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -279,19 +279,79 @@ pub enum Event { CollaboratorLeft(proto::PeerId), } +pub struct ProjectLanguageServer { + server: Arc, + project: WeakModelHandle, +} + +impl std::ops::Deref for ProjectLanguageServer { + type Target = LanguageServer; + + fn deref(&self) -> &Self::Target { + &self.server + } +} + +impl ProjectLanguageServer { + pub fn new(server: Arc, project: WeakModelHandle) -> Self { + ProjectLanguageServer { server, project } + } + + pub fn request( + &self, + params: T::Params, + cx: &mut AsyncAppContext, + ) -> impl Future> + where + T::Result: 'static + Send, + { + let server = self.server.clone(); + let project = self.project.clone(); + + let future = server.request::(params); + + cx.spawn(|mut cx| async move { + let result = future.await; + if result.is_ok() { + return result; + } + + let project = match project.upgrade(&cx) { + Some(project) => project, + None => return result, + }; + + project.update(&mut cx, |_, cx| { + Project::check_errored_language_server(server, cx); + }); + + result + }) + } + + pub fn notify(&self, params: T::Params) -> Result<()> { + let result = self.server.notify::(params); + if result.is_ok() { + return Ok(()); + } + + result + } +} + pub enum LanguageServerState { - Validating(Task>>), + Validating(Task>>), Starting { language: Arc, adapter: Arc, - task: Task>>, + task: Task>>, }, Running { language: Arc, adapter: Arc, - server: Arc, + server: Arc, watched_paths: HashMap, simulate_disk_based_diagnostics_completion: Option>, }, @@ -2237,7 +2297,13 @@ impl Project { fn language_servers_for_worktree( &self, worktree_id: WorktreeId, - ) -> impl Iterator, &Arc, &Arc)> { + ) -> impl Iterator< + Item = ( + &Arc, + &Arc, + &Arc, + ), + > { self.language_server_ids .iter() .filter_map(move |((language_server_worktree_id, _), id)| { @@ -2477,7 +2543,7 @@ impl Project { .await; match result { - Ok(server) => Some(server), + Ok(server) => Some(Arc::new(ProjectLanguageServer::new(server, this))), Err(err) => { log::error!("failed to start language server {:?}: {}", server_name, err); @@ -2803,7 +2869,10 @@ impl Project { adapter: adapter.clone(), language: language.clone(), watched_paths: Default::default(), - server: language_server.clone(), + server: Arc::new(ProjectLanguageServer::new( + language_server.clone(), + cx.weak_handle(), + )), simulate_disk_based_diagnostics_completion: None, }, ); @@ -3062,7 +3131,6 @@ impl Project { } fn check_errored_language_server( - &self, language_server: Arc, cx: &mut ModelContext, ) { @@ -3897,7 +3965,7 @@ impl Project { this: &ModelHandle, buffer: &ModelHandle, abs_path: &Path, - language_server: &Arc, + language_server: &Arc, tab_size: NonZeroU32, cx: &mut AsyncAppContext, ) -> Result, String)>> { @@ -3911,23 +3979,29 @@ impl Project { let result = if !matches!(formatting_provider, Some(OneOf::Left(false))) { language_server - .request::(lsp::DocumentFormattingParams { - text_document, - options: lsp_command::lsp_formatting_options(tab_size.get()), - work_done_progress_params: Default::default(), - }) + .request::( + lsp::DocumentFormattingParams { + text_document, + options: lsp_command::lsp_formatting_options(tab_size.get()), + work_done_progress_params: Default::default(), + }, + cx, + ) .await } else if !matches!(range_formatting_provider, Some(OneOf::Left(false))) { let buffer_start = lsp::Position::new(0, 0); let buffer_end = buffer.read_with(cx, |b, _| point_to_lsp(b.max_point_utf16())); language_server - .request::(lsp::DocumentRangeFormattingParams { - text_document, - range: lsp::Range::new(buffer_start, buffer_end), - options: lsp_command::lsp_formatting_options(tab_size.get()), - work_done_progress_params: Default::default(), - }) + .request::( + lsp::DocumentRangeFormattingParams { + text_document, + range: lsp::Range::new(buffer_start, buffer_end), + options: lsp_command::lsp_formatting_options(tab_size.get()), + work_done_progress_params: Default::default(), + }, + cx, + ) .await } else { Ok(None) @@ -3943,8 +4017,8 @@ impl Project { err ); - this.update(cx, |this, cx| { - this.check_errored_language_server(language_server.clone(), cx); + this.update(cx, |_, cx| { + Self::check_errored_language_server(language_server.server.clone(), cx); }); None @@ -4090,6 +4164,7 @@ impl Project { query: query.to_string(), ..Default::default() }, + &mut cx.to_async(), ) .map_ok(move |response| { let lsp_symbols = response.map(|symbol_response| match symbol_response { @@ -4323,7 +4398,10 @@ impl Project { cx.spawn(|this, mut cx| async move { let resolved_completion = match lang_server - .request::(completion.lsp_completion) + .request::( + completion.lsp_completion, + &mut cx, + ) .await { Ok(resolved_completion) => resolved_completion, @@ -4452,7 +4530,10 @@ impl Project { { *lsp_range = serde_json::to_value(&range_to_lsp(range)).unwrap(); action.lsp_action = match lang_server - .request::(action.lsp_action) + .request::( + action.lsp_action, + &mut cx, + ) .await { Ok(lsp_action) => lsp_action, @@ -4496,11 +4577,14 @@ impl Project { }); let result = lang_server - .request::(lsp::ExecuteCommandParams { - command: command.command, - arguments: command.arguments.unwrap_or_default(), - ..Default::default() - }) + .request::( + lsp::ExecuteCommandParams { + command: command.command, + arguments: command.arguments.unwrap_or_default(), + ..Default::default() + }, + &mut cx, + ) .await; if let Err(err) = result { @@ -4607,7 +4691,7 @@ impl Project { edits: Vec, push_to_history: bool, _: Arc, - language_server: Arc, + language_server: Arc, cx: &mut AsyncAppContext, ) -> Result> { let edits = this @@ -4648,7 +4732,7 @@ impl Project { edit: lsp::WorkspaceEdit, push_to_history: bool, lsp_adapter: Arc, - language_server: Arc, + language_server: Arc, cx: &mut AsyncAppContext, ) -> Result { let fs = this.read_with(cx, |this, _| this.fs.clone()); @@ -5070,12 +5154,15 @@ impl Project { .map(|(_, server)| server.clone()), ) { let lsp_params = request.to_lsp(&file.abs_path(cx), buffer, &language_server, cx); - return cx.spawn(|this, cx| async move { + return cx.spawn(|this, mut cx| async move { if !request.check_capabilities(language_server.capabilities()) { return Ok(Default::default()); } - let result = language_server.request::(lsp_params).await; + let result = language_server + .request::(lsp_params, &mut cx) + .await; + let response = match result { Ok(response) => response, @@ -7277,7 +7364,10 @@ impl Project { }) } - pub fn language_server_for_id(&self, id: LanguageServerId) -> Option> { + pub fn language_server_for_id( + &self, + id: LanguageServerId, + ) -> Option> { if let LanguageServerState::Running { server, .. } = self.language_servers.get(&id)? { Some(server.clone()) } else { @@ -7289,7 +7379,7 @@ impl Project { &self, buffer: &Buffer, cx: &AppContext, - ) -> impl Iterator, &Arc)> { + ) -> impl Iterator, &Arc)> { self.language_server_ids_for_buffer(buffer, cx) .into_iter() .filter_map(|server_id| { @@ -7309,7 +7399,7 @@ impl Project { &self, buffer: &Buffer, cx: &AppContext, - ) -> Option<(&Arc, &Arc)> { + ) -> Option<(&Arc, &Arc)> { self.language_servers_for_buffer(buffer, cx).next() } @@ -7318,7 +7408,7 @@ impl Project { buffer: &Buffer, server_id: LanguageServerId, cx: &AppContext, - ) -> Option<(&Arc, &Arc)> { + ) -> Option<(&Arc, &Arc)> { self.language_servers_for_buffer(buffer, cx) .find(|(_, s)| s.server_id() == server_id) }