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 {
|
let Some(language_server) = buffer_handle.update(cx, |buffer, cx| match server {
|
||||||
LanguageServerToQuery::Primary => self
|
LanguageServerToQuery::FirstCapable => self.as_local().and_then(|local| {
|
||||||
.as_local()
|
local
|
||||||
.and_then(|local| local.primary_language_server_for_buffer(buffer, cx))
|
.language_servers_for_buffer(buffer, cx)
|
||||||
.map(|(_, server)| server.clone()),
|
.find(|(_, server)| {
|
||||||
|
request.check_capabilities(server.adapter_server_capabilities())
|
||||||
|
})
|
||||||
|
.map(|(_, server)| server.clone())
|
||||||
|
}),
|
||||||
LanguageServerToQuery::Other(id) => self
|
LanguageServerToQuery::Other(id) => self
|
||||||
.language_server_for_local_buffer(buffer, id, cx)
|
.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 {
|
}) else {
|
||||||
return Task::ready(Ok(Default::default()));
|
return Task::ready(Ok(Default::default()));
|
||||||
};
|
};
|
||||||
|
@ -3519,99 +3527,95 @@ impl LspStore {
|
||||||
let buffer = buffer_handle.read(cx);
|
let buffer = buffer_handle.read(cx);
|
||||||
let file = File::from_dyn(buffer.file()).and_then(File::as_local);
|
let file = File::from_dyn(buffer.file()).and_then(File::as_local);
|
||||||
|
|
||||||
if let Some(file) = file {
|
let Some(file) = file else {
|
||||||
let lsp_params = match request.to_lsp_params_or_response(
|
return Task::ready(Ok(Default::default()));
|
||||||
&file.abs_path(cx),
|
};
|
||||||
buffer,
|
|
||||||
&language_server,
|
|
||||||
cx,
|
|
||||||
) {
|
|
||||||
Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
|
|
||||||
Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
|
|
||||||
|
|
||||||
Err(err) => {
|
let lsp_params = match request.to_lsp_params_or_response(
|
||||||
let message = format!(
|
&file.abs_path(cx),
|
||||||
"{} via {} failed: {}",
|
buffer,
|
||||||
request.display_name(),
|
&language_server,
|
||||||
language_server.name(),
|
cx,
|
||||||
err
|
) {
|
||||||
);
|
Ok(LspParamsOrResponse::Params(lsp_params)) => lsp_params,
|
||||||
log::warn!("{}", message);
|
Ok(LspParamsOrResponse::Response(response)) => return Task::ready(Ok(response)),
|
||||||
return Task::ready(Err(anyhow!(message)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let status = request.status();
|
Err(err) => {
|
||||||
if !request.check_capabilities(language_server.adapter_server_capabilities()) {
|
let message = format!(
|
||||||
return Task::ready(Ok(Default::default()));
|
"{} 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 status = request.status();
|
||||||
let _cleanup = if status.is_some() {
|
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| {
|
cx.update(|cx| {
|
||||||
this.update(cx, |this, cx| {
|
this.update(cx, |this, cx| {
|
||||||
this.on_lsp_work_start(
|
this.on_lsp_work_end(language_server.server_id(), id.to_string(), cx);
|
||||||
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();
|
.log_err();
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
Some(defer(|| {
|
let result = lsp_request.await;
|
||||||
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 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 response = request
|
||||||
let message = format!(
|
.response_from_lsp(
|
||||||
"{} via {} failed: {}",
|
response,
|
||||||
request.display_name(),
|
this.upgrade().ok_or_else(|| anyhow!("no app context"))?,
|
||||||
language_server.name(),
|
buffer_handle,
|
||||||
err
|
language_server.server_id(),
|
||||||
);
|
cx.clone(),
|
||||||
log::warn!("{}", message);
|
)
|
||||||
anyhow!(message)
|
.await;
|
||||||
})?;
|
response
|
||||||
|
});
|
||||||
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()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
|
fn on_settings_changed(&mut self, cx: &mut Context<Self>) {
|
||||||
|
@ -3950,7 +3954,7 @@ impl LspStore {
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
self.upstream_client()
|
self.upstream_client()
|
||||||
.is_some()
|
.is_some()
|
||||||
.then_some(LanguageServerToQuery::Primary)
|
.then_some(LanguageServerToQuery::FirstCapable)
|
||||||
})
|
})
|
||||||
.filter(|_| {
|
.filter(|_| {
|
||||||
maybe!({
|
maybe!({
|
||||||
|
@ -4061,7 +4065,7 @@ impl LspStore {
|
||||||
});
|
});
|
||||||
self.request_lsp(
|
self.request_lsp(
|
||||||
buffer.clone(),
|
buffer.clone(),
|
||||||
LanguageServerToQuery::Primary,
|
LanguageServerToQuery::FirstCapable,
|
||||||
OnTypeFormatting {
|
OnTypeFormatting {
|
||||||
position,
|
position,
|
||||||
trigger,
|
trigger,
|
||||||
|
@ -4660,7 +4664,7 @@ impl LspStore {
|
||||||
} else {
|
} else {
|
||||||
let lsp_request_task = self.request_lsp(
|
let lsp_request_task = self.request_lsp(
|
||||||
buffer_handle.clone(),
|
buffer_handle.clone(),
|
||||||
LanguageServerToQuery::Primary,
|
LanguageServerToQuery::FirstCapable,
|
||||||
lsp_request,
|
lsp_request,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
@ -5774,7 +5778,7 @@ impl LspStore {
|
||||||
.update(&mut cx, |this, cx| {
|
.update(&mut cx, |this, cx| {
|
||||||
this.request_lsp(
|
this.request_lsp(
|
||||||
buffer_handle.clone(),
|
buffer_handle.clone(),
|
||||||
LanguageServerToQuery::Primary,
|
LanguageServerToQuery::FirstCapable,
|
||||||
request,
|
request,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -8069,7 +8073,9 @@ async fn populate_labels_for_completions(
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum LanguageServerToQuery {
|
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),
|
Other(LanguageServerId),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2777,7 +2777,7 @@ impl Project {
|
||||||
) -> Task<Result<Vec<LocationLink>>> {
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
self.request_lsp(
|
self.request_lsp(
|
||||||
buffer.clone(),
|
buffer.clone(),
|
||||||
LanguageServerToQuery::Primary,
|
LanguageServerToQuery::FirstCapable,
|
||||||
GetDefinition { position },
|
GetDefinition { position },
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -2800,7 +2800,7 @@ impl Project {
|
||||||
) -> Task<Result<Vec<LocationLink>>> {
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
self.request_lsp(
|
self.request_lsp(
|
||||||
buffer.clone(),
|
buffer.clone(),
|
||||||
LanguageServerToQuery::Primary,
|
LanguageServerToQuery::FirstCapable,
|
||||||
GetDeclaration { position },
|
GetDeclaration { position },
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -2824,7 +2824,7 @@ impl Project {
|
||||||
) -> Task<Result<Vec<LocationLink>>> {
|
) -> Task<Result<Vec<LocationLink>>> {
|
||||||
self.request_lsp(
|
self.request_lsp(
|
||||||
buffer.clone(),
|
buffer.clone(),
|
||||||
LanguageServerToQuery::Primary,
|
LanguageServerToQuery::FirstCapable,
|
||||||
GetTypeDefinition { position },
|
GetTypeDefinition { position },
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -2849,7 +2849,7 @@ impl Project {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(buffer.read(cx));
|
||||||
self.request_lsp(
|
self.request_lsp(
|
||||||
buffer.clone(),
|
buffer.clone(),
|
||||||
LanguageServerToQuery::Primary,
|
LanguageServerToQuery::FirstCapable,
|
||||||
GetImplementation { position },
|
GetImplementation { position },
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -2864,7 +2864,7 @@ impl Project {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(buffer.read(cx));
|
||||||
self.request_lsp(
|
self.request_lsp(
|
||||||
buffer.clone(),
|
buffer.clone(),
|
||||||
LanguageServerToQuery::Primary,
|
LanguageServerToQuery::FirstCapable,
|
||||||
GetReferences { position },
|
GetReferences { position },
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -2878,7 +2878,7 @@ impl Project {
|
||||||
) -> Task<Result<Vec<DocumentHighlight>>> {
|
) -> Task<Result<Vec<DocumentHighlight>>> {
|
||||||
self.request_lsp(
|
self.request_lsp(
|
||||||
buffer.clone(),
|
buffer.clone(),
|
||||||
LanguageServerToQuery::Primary,
|
LanguageServerToQuery::FirstCapable,
|
||||||
GetDocumentHighlights { position },
|
GetDocumentHighlights { position },
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -3037,7 +3037,7 @@ impl Project {
|
||||||
) -> Task<Result<PrepareRenameResponse>> {
|
) -> Task<Result<PrepareRenameResponse>> {
|
||||||
self.request_lsp(
|
self.request_lsp(
|
||||||
buffer,
|
buffer,
|
||||||
LanguageServerToQuery::Primary,
|
LanguageServerToQuery::FirstCapable,
|
||||||
PrepareRename { position },
|
PrepareRename { position },
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -3063,7 +3063,7 @@ impl Project {
|
||||||
let position = position.to_point_utf16(buffer.read(cx));
|
let position = position.to_point_utf16(buffer.read(cx));
|
||||||
self.request_lsp(
|
self.request_lsp(
|
||||||
buffer,
|
buffer,
|
||||||
LanguageServerToQuery::Primary,
|
LanguageServerToQuery::FirstCapable,
|
||||||
PerformRename {
|
PerformRename {
|
||||||
position,
|
position,
|
||||||
new_name,
|
new_name,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue