lsp: Query first capable language server for requests using primary LS (#25591)
Release Notes: - Improved Zed's handling of the following requests when the first language server in language server settings for a given language is not capable of handling them: - Perform Rename - Prepare Rename - Document Highlights - Find all references - Go to implementation - Go to definition - Go to declaration - Go to type definition
This commit is contained in:
parent
e5b6194914
commit
0066071a89
2 changed files with 105 additions and 99 deletions
|
@ -3505,13 +3505,21 @@ impl LspStore {
|
|||
}
|
||||
|
||||
let Some(language_server) = buffer_handle.update(cx, |buffer, cx| match server {
|
||||
LanguageServerToQuery::Primary => self
|
||||
.as_local()
|
||||
.and_then(|local| local.primary_language_server_for_buffer(buffer, cx))
|
||||
.map(|(_, server)| server.clone()),
|
||||
LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
|
||||
local
|
||||
.language_servers_for_buffer(buffer, cx)
|
||||
.find(|(_, server)| {
|
||||
request.check_capabilities(server.adapter_server_capabilities())
|
||||
})
|
||||
.map(|(_, server)| server.clone())
|
||||
}),
|
||||
LanguageServerToQuery::Other(id) => self
|
||||
.language_server_for_local_buffer(buffer, id, cx)
|
||||
.map(|(_, server)| Arc::clone(server)),
|
||||
.and_then(|(_, server)| {
|
||||
request
|
||||
.check_capabilities(server.adapter_server_capabilities())
|
||||
.then(|| Arc::clone(server))
|
||||
}),
|
||||
}) else {
|
||||
return Task::ready(Ok(Default::default()));
|
||||
};
|
||||
|
@ -3519,99 +3527,95 @@ impl LspStore {
|
|||
let buffer = buffer_handle.read(cx);
|
||||
let file = File::from_dyn(buffer.file()).and_then(File::as_local);
|
||||
|
||||
if let Some(file) = file {
|
||||
let lsp_params = match request.to_lsp_params_or_response(
|
||||
&file.abs_path(cx),
|
||||
buffer,
|
||||
&language_server,
|
||||
cx,
|
||||
) {
|
||||
Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
|
||||
Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
|
||||
let Some(file) = file else {
|
||||
return Task::ready(Ok(Default::default()));
|
||||
};
|
||||
|
||||
Err(err) => {
|
||||
let message = format!(
|
||||
"{} via {} failed: {}",
|
||||
request.display_name(),
|
||||
language_server.name(),
|
||||
err
|
||||
);
|
||||
log::warn!("{}", message);
|
||||
return Task::ready(Err(anyhow!(message)));
|
||||
}
|
||||
};
|
||||
let lsp_params = match request.to_lsp_params_or_response(
|
||||
&file.abs_path(cx),
|
||||
buffer,
|
||||
&language_server,
|
||||
cx,
|
||||
) {
|
||||
Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
|
||||
Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
|
||||
|
||||
let status = request.status();
|
||||
if !request.check_capabilities(language_server.adapter_server_capabilities()) {
|
||||
return Task::ready(Ok(Default::default()));
|
||||
Err(err) => {
|
||||
let message = format!(
|
||||
"{} via {} failed: {}",
|
||||
request.display_name(),
|
||||
language_server.name(),
|
||||
err
|
||||
);
|
||||
log::warn!("{}", message);
|
||||
return Task::ready(Err(anyhow!(message)));
|
||||
}
|
||||
return cx.spawn(move |this, cx| async move {
|
||||
let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
|
||||
};
|
||||
|
||||
let id = lsp_request.id();
|
||||
let _cleanup = if status.is_some() {
|
||||
let status = request.status();
|
||||
if !request.check_capabilities(language_server.adapter_server_capabilities()) {
|
||||
return Task::ready(Ok(Default::default()));
|
||||
}
|
||||
return cx.spawn(move |this, cx| async move {
|
||||
let lsp_request = language_server.request::<R::LspRequest>(lsp_params);
|
||||
|
||||
let id = lsp_request.id();
|
||||
let _cleanup = if status.is_some() {
|
||||
cx.update(|cx| {
|
||||
this.update(cx, |this, cx| {
|
||||
this.on_lsp_work_start(
|
||||
language_server.server_id(),
|
||||
id.to_string(),
|
||||
LanguageServerProgress {
|
||||
is_disk_based_diagnostics_progress: false,
|
||||
is_cancellable: false,
|
||||
title: None,
|
||||
message: status.clone(),
|
||||
percentage: None,
|
||||
last_update_at: cx.background_executor().now(),
|
||||
},
|
||||
cx,
|
||||
);
|
||||
})
|
||||
})
|
||||
.log_err();
|
||||
|
||||
Some(defer(|| {
|
||||
cx.update(|cx| {
|
||||
this.update(cx, |this, cx| {
|
||||
this.on_lsp_work_start(
|
||||
language_server.server_id(),
|
||||
id.to_string(),
|
||||
LanguageServerProgress {
|
||||
is_disk_based_diagnostics_progress: false,
|
||||
is_cancellable: false,
|
||||
title: None,
|
||||
message: status.clone(),
|
||||
percentage: None,
|
||||
last_update_at: cx.background_executor().now(),
|
||||
},
|
||||
cx,
|
||||
);
|
||||
this.on_lsp_work_end(language_server.server_id(), id.to_string(), cx);
|
||||
})
|
||||
})
|
||||
.log_err();
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Some(defer(|| {
|
||||
cx.update(|cx| {
|
||||
this.update(cx, |this, cx| {
|
||||
this.on_lsp_work_end(
|
||||
language_server.server_id(),
|
||||
id.to_string(),
|
||||
cx,
|
||||
);
|
||||
})
|
||||
})
|
||||
.log_err();
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let result = lsp_request.await;
|
||||
|
||||
let result = lsp_request.await;
|
||||
let response = result.map_err(|err| {
|
||||
let message = format!(
|
||||
"{} via {} failed: {}",
|
||||
request.display_name(),
|
||||
language_server.name(),
|
||||
err
|
||||
);
|
||||
log::warn!("{}", message);
|
||||
anyhow!(message)
|
||||
})?;
|
||||
|
||||
let response = result.map_err(|err| {
|
||||
let message = format!(
|
||||
"{} via {} failed: {}",
|
||||
request.display_name(),
|
||||
language_server.name(),
|
||||
err
|
||||
);
|
||||
log::warn!("{}", message);
|
||||
anyhow!(message)
|
||||
})?;
|
||||
|
||||
let response = request
|
||||
.response_from_lsp(
|
||||
response,
|
||||
this.upgrade().ok_or_else(|| anyhow!("no app context"))?,
|
||||
buffer_handle,
|
||||
language_server.server_id(),
|
||||
cx.clone(),
|
||||
)
|
||||
.await;
|
||||
response
|
||||
});
|
||||
}
|
||||
|
||||
Task::ready(Ok(Default::default()))
|
||||
let response = request
|
||||
.response_from_lsp(
|
||||
response,
|
||||
this.upgrade().ok_or_else(|| anyhow!("no app context"))?,
|
||||
buffer_handle,
|
||||
language_server.server_id(),
|
||||
cx.clone(),
|
||||
)
|
||||
.await;
|
||||
response
|
||||
});
|
||||
}
|
||||
|
||||
fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
|
||||
|
@ -3950,7 +3954,7 @@ impl LspStore {
|
|||
.or_else(|| {
|
||||
self.upstream_client()
|
||||
.is_some()
|
||||
.then_some(LanguageServerToQuery::Primary)
|
||||
.then_some(LanguageServerToQuery::FirstCapable)
|
||||
})
|
||||
.filter(|_| {
|
||||
maybe!({
|
||||
|
@ -4061,7 +4065,7 @@ impl LspStore {
|
|||
});
|
||||
self.request_lsp(
|
||||
buffer.clone(),
|
||||
LanguageServerToQuery::Primary,
|
||||
LanguageServerToQuery::FirstCapable,
|
||||
OnTypeFormatting {
|
||||
position,
|
||||
trigger,
|
||||
|
@ -4660,7 +4664,7 @@ impl LspStore {
|
|||
} else {
|
||||
let lsp_request_task = self.request_lsp(
|
||||
buffer_handle.clone(),
|
||||
LanguageServerToQuery::Primary,
|
||||
LanguageServerToQuery::FirstCapable,
|
||||
lsp_request,
|
||||
cx,
|
||||
);
|
||||
|
@ -5774,7 +5778,7 @@ impl LspStore {
|
|||
.update(&mut cx, |this, cx| {
|
||||
this.request_lsp(
|
||||
buffer_handle.clone(),
|
||||
LanguageServerToQuery::Primary,
|
||||
LanguageServerToQuery::FirstCapable,
|
||||
request,
|
||||
cx,
|
||||
)
|
||||
|
@ -8069,7 +8073,9 @@ async fn populate_labels_for_completions(
|
|||
|
||||
#[derive(Debug)]
|
||||
pub enum LanguageServerToQuery {
|
||||
Primary,
|
||||
/// Query language servers in order of users preference, up until one capable of handling the request is found.
|
||||
FirstCapable,
|
||||
/// Query a specific language server.
|
||||
Other(LanguageServerId),
|
||||
}
|
||||
|
||||
|
|
|
@ -2777,7 +2777,7 @@ impl Project {
|
|||
) -> Task<Result<Vec<LocationLink>>> {
|
||||
self.request_lsp(
|
||||
buffer.clone(),
|
||||
LanguageServerToQuery::Primary,
|
||||
LanguageServerToQuery::FirstCapable,
|
||||
GetDefinition { position },
|
||||
cx,
|
||||
)
|
||||
|
@ -2800,7 +2800,7 @@ impl Project {
|
|||
) -> Task<Result<Vec<LocationLink>>> {
|
||||
self.request_lsp(
|
||||
buffer.clone(),
|
||||
LanguageServerToQuery::Primary,
|
||||
LanguageServerToQuery::FirstCapable,
|
||||
GetDeclaration { position },
|
||||
cx,
|
||||
)
|
||||
|
@ -2824,7 +2824,7 @@ impl Project {
|
|||
) -> Task<Result<Vec<LocationLink>>> {
|
||||
self.request_lsp(
|
||||
buffer.clone(),
|
||||
LanguageServerToQuery::Primary,
|
||||
LanguageServerToQuery::FirstCapable,
|
||||
GetTypeDefinition { position },
|
||||
cx,
|
||||
)
|
||||
|
@ -2849,7 +2849,7 @@ impl Project {
|
|||
let position = position.to_point_utf16(buffer.read(cx));
|
||||
self.request_lsp(
|
||||
buffer.clone(),
|
||||
LanguageServerToQuery::Primary,
|
||||
LanguageServerToQuery::FirstCapable,
|
||||
GetImplementation { position },
|
||||
cx,
|
||||
)
|
||||
|
@ -2864,7 +2864,7 @@ impl Project {
|
|||
let position = position.to_point_utf16(buffer.read(cx));
|
||||
self.request_lsp(
|
||||
buffer.clone(),
|
||||
LanguageServerToQuery::Primary,
|
||||
LanguageServerToQuery::FirstCapable,
|
||||
GetReferences { position },
|
||||
cx,
|
||||
)
|
||||
|
@ -2878,7 +2878,7 @@ impl Project {
|
|||
) -> Task<Result<Vec<DocumentHighlight>>> {
|
||||
self.request_lsp(
|
||||
buffer.clone(),
|
||||
LanguageServerToQuery::Primary,
|
||||
LanguageServerToQuery::FirstCapable,
|
||||
GetDocumentHighlights { position },
|
||||
cx,
|
||||
)
|
||||
|
@ -3037,7 +3037,7 @@ impl Project {
|
|||
) -> Task<Result<PrepareRenameResponse>> {
|
||||
self.request_lsp(
|
||||
buffer,
|
||||
LanguageServerToQuery::Primary,
|
||||
LanguageServerToQuery::FirstCapable,
|
||||
PrepareRename { position },
|
||||
cx,
|
||||
)
|
||||
|
@ -3063,7 +3063,7 @@ impl Project {
|
|||
let position = position.to_point_utf16(buffer.read(cx));
|
||||
self.request_lsp(
|
||||
buffer,
|
||||
LanguageServerToQuery::Primary,
|
||||
LanguageServerToQuery::FirstCapable,
|
||||
PerformRename {
|
||||
position,
|
||||
new_name,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue