mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 19:10:24 +00:00
Route language server requests through wrapper object
This commit is contained in:
parent
e15be61ded
commit
9b63d6f832
3 changed files with 142 additions and 52 deletions
|
@ -665,11 +665,11 @@ impl LanguageServer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn name<'a>(self: &'a Arc<Self>) -> &'a str {
|
||||
pub fn name<'a>(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn capabilities<'a>(self: &'a Arc<Self>) -> &'a ServerCapabilities {
|
||||
pub fn capabilities<'a>(&self) -> &ServerCapabilities {
|
||||
&self.capabilities
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue