@@ -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<LanguageServer>,
+ language_server: &Arc<ProjectLanguageServer>,
cx: &AppContext,
) -> <Self::LspRequest as lsp::request::Request>::Params;
@@ -156,7 +156,7 @@ impl LspCommand for PrepareRename {
&self,
path: &Path,
_: &Buffer,
- _: &Arc<LanguageServer>,
+ _: &Arc<ProjectLanguageServer>,
_: &AppContext,
) -> lsp::TextDocumentPositionParams {
lsp::TextDocumentPositionParams {
@@ -279,7 +279,7 @@ impl LspCommand for PerformRename {
&self,
path: &Path,
_: &Buffer,
- _: &Arc<LanguageServer>,
+ _: &Arc<ProjectLanguageServer>,
_: &AppContext,
) -> lsp::RenameParams {
lsp::RenameParams {
@@ -398,7 +398,7 @@ impl LspCommand for GetDefinition {
&self,
path: &Path,
_: &Buffer,
- _: &Arc<LanguageServer>,
+ _: &Arc<ProjectLanguageServer>,
_: &AppContext,
) -> lsp::GotoDefinitionParams {
lsp::GotoDefinitionParams {
@@ -499,7 +499,7 @@ impl LspCommand for GetTypeDefinition {
&self,
path: &Path,
_: &Buffer,
- _: &Arc<LanguageServer>,
+ _: &Arc<ProjectLanguageServer>,
_: &AppContext,
) -> lsp::GotoTypeDefinitionParams {
lsp::GotoTypeDefinitionParams {
@@ -587,7 +587,7 @@ fn language_server_for_buffer(
buffer: &ModelHandle<Buffer>,
server_id: LanguageServerId,
cx: &mut AsyncAppContext,
-) -> Result<(Arc<CachedLspAdapter>, Arc<LanguageServer>)> {
+) -> Result<(Arc<CachedLspAdapter>, Arc<ProjectLanguageServer>)> {
project
.read_with(cx, |project, cx| {
project
@@ -784,7 +784,7 @@ impl LspCommand for GetReferences {
&self,
path: &Path,
_: &Buffer,
- _: &Arc<LanguageServer>,
+ _: &Arc<ProjectLanguageServer>,
_: &AppContext,
) -> lsp::ReferenceParams {
lsp::ReferenceParams {
@@ -949,7 +949,7 @@ impl LspCommand for GetDocumentHighlights {
&self,
path: &Path,
_: &Buffer,
- _: &Arc<LanguageServer>,
+ _: &Arc<ProjectLanguageServer>,
_: &AppContext,
) -> lsp::DocumentHighlightParams {
lsp::DocumentHighlightParams {
@@ -1096,7 +1096,7 @@ impl LspCommand for GetHover {
&self,
path: &Path,
_: &Buffer,
- _: &Arc<LanguageServer>,
+ _: &Arc<ProjectLanguageServer>,
_: &AppContext,
) -> lsp::HoverParams {
lsp::HoverParams {
@@ -1314,7 +1314,7 @@ impl LspCommand for GetCompletions {
&self,
path: &Path,
_: &Buffer,
- _: &Arc<LanguageServer>,
+ _: &Arc<ProjectLanguageServer>,
_: &AppContext,
) -> lsp::CompletionParams {
lsp::CompletionParams {
@@ -1530,7 +1530,7 @@ impl LspCommand for GetCodeActions {
&self,
path: &Path,
buffer: &Buffer,
- language_server: &Arc<LanguageServer>,
+ language_server: &Arc<ProjectLanguageServer>,
_: &AppContext,
) -> lsp::CodeActionParams {
let relevant_diagnostics = buffer
@@ -1673,7 +1673,7 @@ impl LspCommand for OnTypeFormatting {
&self,
path: &Path,
_: &Buffer,
- _: &Arc<LanguageServer>,
+ _: &Arc<ProjectLanguageServer>,
_: &AppContext,
) -> lsp::DocumentOnTypeFormattingParams {
lsp::DocumentOnTypeFormattingParams {
@@ -279,19 +279,79 @@ pub enum Event {
CollaboratorLeft(proto::PeerId),
}
+pub struct ProjectLanguageServer {
+ server: Arc<LanguageServer>,
+ project: WeakModelHandle<Project>,
+}
+
+impl std::ops::Deref for ProjectLanguageServer {
+ type Target = LanguageServer;
+
+ fn deref(&self) -> &Self::Target {
+ &self.server
+ }
+}
+
+impl ProjectLanguageServer {
+ pub fn new(server: Arc<LanguageServer>, project: WeakModelHandle<Project>) -> Self {
+ ProjectLanguageServer { server, project }
+ }
+
+ pub fn request<T: lsp::request::Request + 'static>(
+ &self,
+ params: T::Params,
+ cx: &mut AsyncAppContext,
+ ) -> impl Future<Output = Result<T::Result>>
+ where
+ T::Result: 'static + Send,
+ {
+ let server = self.server.clone();
+ let project = self.project.clone();
+
+ let future = server.request::<T>(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<T: lsp::notification::Notification>(&self, params: T::Params) -> Result<()> {
+ let result = self.server.notify::<T>(params);
+ if result.is_ok() {
+ return Ok(());
+ }
+
+ result
+ }
+}
+
pub enum LanguageServerState {
- Validating(Task<Option<Arc<LanguageServer>>>),
+ Validating(Task<Option<Arc<ProjectLanguageServer>>>),
Starting {
language: Arc<Language>,
adapter: Arc<CachedLspAdapter>,
- task: Task<Option<Arc<LanguageServer>>>,
+ task: Task<Option<Arc<ProjectLanguageServer>>>,
},
Running {
language: Arc<Language>,
adapter: Arc<CachedLspAdapter>,
- server: Arc<LanguageServer>,
+ server: Arc<ProjectLanguageServer>,
watched_paths: HashMap<WorktreeId, GlobSet>,
simulate_disk_based_diagnostics_completion: Option<Task<()>>,
},
@@ -2237,7 +2297,13 @@ impl Project {
fn language_servers_for_worktree(
&self,
worktree_id: WorktreeId,
- ) -> impl Iterator<Item = (&Arc<CachedLspAdapter>, &Arc<Language>, &Arc<LanguageServer>)> {
+ ) -> impl Iterator<
+ Item = (
+ &Arc<CachedLspAdapter>,
+ &Arc<Language>,
+ &Arc<ProjectLanguageServer>,
+ ),
+ > {
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<LanguageServer>,
cx: &mut ModelContext<Self>,
) {
@@ -3897,7 +3965,7 @@ impl Project {
this: &ModelHandle<Self>,
buffer: &ModelHandle<Buffer>,
abs_path: &Path,
- language_server: &Arc<LanguageServer>,
+ language_server: &Arc<ProjectLanguageServer>,
tab_size: NonZeroU32,
cx: &mut AsyncAppContext,
) -> Result<Vec<(Range<Anchor>, String)>> {
@@ -3911,23 +3979,29 @@ impl Project {
let result = if !matches!(formatting_provider, Some(OneOf::Left(false))) {
language_server
- .request::<lsp::request::Formatting>(lsp::DocumentFormattingParams {
- text_document,
- options: lsp_command::lsp_formatting_options(tab_size.get()),
- work_done_progress_params: Default::default(),
- })
+ .request::<lsp::request::Formatting>(
+ 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::request::RangeFormatting>(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::request::RangeFormatting>(
+ 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::<lsp::request::ResolveCompletionItem>(completion.lsp_completion)
+ .request::<lsp::request::ResolveCompletionItem>(
+ 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::<lsp::request::CodeActionResolveRequest>(action.lsp_action)
+ .request::<lsp::request::CodeActionResolveRequest>(
+ action.lsp_action,
+ &mut cx,
+ )
.await
{
Ok(lsp_action) => lsp_action,
@@ -4496,11 +4577,14 @@ impl Project {
});
let result = lang_server
- .request::<lsp::request::ExecuteCommand>(lsp::ExecuteCommandParams {
- command: command.command,
- arguments: command.arguments.unwrap_or_default(),
- ..Default::default()
- })
+ .request::<lsp::request::ExecuteCommand>(
+ 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<lsp::TextEdit>,
push_to_history: bool,
_: Arc<CachedLspAdapter>,
- language_server: Arc<LanguageServer>,
+ language_server: Arc<ProjectLanguageServer>,
cx: &mut AsyncAppContext,
) -> Result<Option<Transaction>> {
let edits = this
@@ -4648,7 +4732,7 @@ impl Project {
edit: lsp::WorkspaceEdit,
push_to_history: bool,
lsp_adapter: Arc<CachedLspAdapter>,
- language_server: Arc<LanguageServer>,
+ language_server: Arc<ProjectLanguageServer>,
cx: &mut AsyncAppContext,
) -> Result<ProjectTransaction> {
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::<R::LspRequest>(lsp_params).await;
+ let result = language_server
+ .request::<R::LspRequest>(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<Arc<LanguageServer>> {
+ pub fn language_server_for_id(
+ &self,
+ id: LanguageServerId,
+ ) -> Option<Arc<ProjectLanguageServer>> {
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<Item = (&Arc<CachedLspAdapter>, &Arc<LanguageServer>)> {
+ ) -> impl Iterator<Item = (&Arc<CachedLspAdapter>, &Arc<ProjectLanguageServer>)> {
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<CachedLspAdapter>, &Arc<LanguageServer>)> {
+ ) -> Option<(&Arc<CachedLspAdapter>, &Arc<ProjectLanguageServer>)> {
self.language_servers_for_buffer(buffer, cx).next()
}
@@ -7318,7 +7408,7 @@ impl Project {
buffer: &Buffer,
server_id: LanguageServerId,
cx: &AppContext,
- ) -> Option<(&Arc<CachedLspAdapter>, &Arc<LanguageServer>)> {
+ ) -> Option<(&Arc<CachedLspAdapter>, &Arc<ProjectLanguageServer>)> {
self.language_servers_for_buffer(buffer, cx)
.find(|(_, s)| s.server_id() == server_id)
}