lsp: make LspDiagnostics response optional

This commit is contained in:
Vitaly Slobodin 2024-12-10 19:21:14 +01:00
parent 6601140870
commit 63f7686d49
No known key found for this signature in database
GPG key ID: 28B37FE223E24CB7
5 changed files with 105 additions and 144 deletions

View file

@ -13535,11 +13535,11 @@ pub trait DiagnosticsProvider {
buffer: &Model<Buffer>,
position: text::Anchor,
cx: &mut AppContext,
) -> Task<Result<Vec<LspDiagnostics>>>;
) -> Task<Result<Vec<Option<LspDiagnostics>>>>;
fn update_diagnostics(
&self,
diagnostics: Vec<LspDiagnostics>,
diagnostics: Vec<Option<LspDiagnostics>>,
cx: &mut AppContext,
) -> Result<()>;
}
@ -13884,7 +13884,7 @@ impl DiagnosticsProvider for Model<Project> {
buffer: &Model<Buffer>,
position: text::Anchor,
cx: &mut AppContext,
) -> Task<Result<Vec<LspDiagnostics>>> {
) -> Task<Result<Vec<Option<LspDiagnostics>>>> {
self.update(cx, |project, cx| {
project.document_diagnostics(buffer, position, cx)
})
@ -13892,23 +13892,27 @@ impl DiagnosticsProvider for Model<Project> {
fn update_diagnostics(
&self,
diagnostics: Vec<LspDiagnostics>,
diagnostics: Vec<Option<LspDiagnostics>>,
cx: &mut AppContext,
) -> Result<()> {
self.update(cx, |project, cx| {
diagnostics
.into_iter()
.map(|diagnostic_set| {
project.update_diagnostics(
.iter()
.filter_map(|diagnostic_set| match diagnostic_set {
Some(diagnostic_set) => Some(project.update_diagnostics(
diagnostic_set.server_id,
lsp::PublishDiagnosticsParams {
uri: diagnostic_set.uri.unwrap(),
diagnostics: diagnostic_set.diagnostics.unwrap_or_else(Vec::new),
uri: diagnostic_set.uri.as_ref().unwrap().clone(),
diagnostics: match diagnostic_set.diagnostics.as_ref() {
Some(diagnostics) => diagnostics.clone(),
None => Vec::new(),
},
version: None,
},
&[],
cx,
)
)),
None => None,
})
.collect()
})

View file

@ -318,7 +318,7 @@ pub fn deserialize_operation(message: proto::Operation) -> Result<crate::Operati
value: message.lamport_timestamp,
},
server_id: LanguageServerId(message.server_id as usize),
diagnostics: Arc::from(deserialize_diagnostics(message.diagnostics)),
diagnostics: deserialize_diagnostics(message.diagnostics),
}
}
proto::operation::Variant::UpdateCompletionTriggers(message) => {
@ -397,7 +397,7 @@ pub fn deserialize_selection(selection: proto::Selection) -> Option<Selection<An
/// Deserializes a list of diagnostics from the RPC representation.
pub fn deserialize_diagnostics(
diagnostics: Vec<proto::Diagnostic>,
) -> Vec<DiagnosticEntry<Anchor>> {
) -> Arc<[DiagnosticEntry<Anchor>]> {
diagnostics
.into_iter()
.filter_map(|diagnostic| {

View file

@ -4,7 +4,7 @@ use crate::{
lsp_store::{LocalLspStore, LspStore},
CodeAction, CoreCompletion, DocumentHighlight, Hover, HoverBlock, HoverBlockKind, InlayHint,
InlayHintLabel, InlayHintLabelPart, InlayHintLabelPartTooltip, InlayHintTooltip, Location,
LocationLink, MarkupContent, ProjectTransaction, ResolveState,
LocationLink, LspDiagnostics, MarkupContent, ProjectTransaction, ResolveState,
};
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
@ -3161,7 +3161,7 @@ impl GetDocumentDiagnostics {
#[async_trait(?Send)]
impl LspCommand for GetDocumentDiagnostics {
type Response = LspDiagnostics;
type Response = Option<LspDiagnostics>;
type LspRequest = lsp::request::DocumentDiagnosticRequest;
type ProtoRequest = proto::GetDocumentDiagnostics;
@ -3211,24 +3211,28 @@ impl LspCommand for GetDocumentDiagnostics {
Some(lsp::Url::from_file_path(file.abs_path(cx).clone()).unwrap())
})?;
if uri.is_none() {
return Ok(None);
}
match message {
lsp::DocumentDiagnosticReportResult::Report(report) => match report {
lsp::DocumentDiagnosticReport::Full(report) => Ok(LspDiagnostics {
lsp::DocumentDiagnosticReport::Full(report) => Ok(Some(LspDiagnostics {
server_id,
uri,
diagnostics: Some(report.full_document_diagnostic_report.items.clone()),
}),
lsp::DocumentDiagnosticReport::Unchanged(_) => Ok(LspDiagnostics {
})),
lsp::DocumentDiagnosticReport::Unchanged(_) => Ok(Some(LspDiagnostics {
server_id,
uri,
diagnostics: None,
}),
})),
},
lsp::DocumentDiagnosticReportResult::Partial(_) => Ok(LspDiagnostics {
lsp::DocumentDiagnosticReportResult::Partial(_) => Ok(Some(LspDiagnostics {
server_id,
uri,
diagnostics: None,
}),
})),
}
}
@ -3268,19 +3272,27 @@ impl LspCommand for GetDocumentDiagnostics {
_: &clock::Global,
_: &mut AppContext,
) -> proto::GetDocumentDiagnosticsResponse {
let diagnostics = if let Some(diagnostics) = response.diagnostics {
diagnostics
.into_iter()
.map(GetDocumentDiagnostics::serialize_lsp_diagnostic)
.collect()
} else {
Vec::new()
};
if let Some(response) = response {
let diagnostics = if let Some(diagnostics) = response.diagnostics {
diagnostics
.into_iter()
.map(GetDocumentDiagnostics::serialize_lsp_diagnostic)
.collect()
} else {
Vec::new()
};
proto::GetDocumentDiagnosticsResponse {
server_id: LanguageServerId::to_proto(response.server_id),
uri: response.uri.unwrap().to_string(),
diagnostics,
proto::GetDocumentDiagnosticsResponse {
server_id: LanguageServerId::to_proto(response.server_id),
uri: response.uri.unwrap().to_string(),
diagnostics,
}
} else {
proto::GetDocumentDiagnosticsResponse {
server_id: 0,
uri: Default::default(),
diagnostics: Vec::new(),
}
}
}
@ -3297,11 +3309,11 @@ impl LspCommand for GetDocumentDiagnostics {
.map(GetDocumentDiagnostics::deserialize_lsp_diagnostic)
.collect();
Ok(LspDiagnostics {
Ok(Some(LspDiagnostics {
server_id: LanguageServerId::from_proto(response.server_id),
uri: Some(lsp::Url::from_str(response.uri.as_str()).unwrap()),
diagnostics: Some(diagnostics),
})
}))
}
fn buffer_id_from_proto(message: &proto::GetDocumentDiagnostics) -> Result<BufferId> {

View file

@ -4497,7 +4497,7 @@ impl LspStore {
buffer_handle: &Model<Buffer>,
position: Anchor,
cx: &mut ModelContext<Self>,
) -> Task<Result<Vec<LspDiagnostics>>> {
) -> Task<Result<Vec<Option<LspDiagnostics>>>> {
let buffer = buffer_handle.read(cx);
let buffer_id = buffer.remote_id();
@ -4933,57 +4933,6 @@ impl LspStore {
}
}
fn pull_diagnostic(
&mut self,
language_server_id: LanguageServerId,
buffer_handle: Model<Buffer>,
cx: &mut ModelContext<Self>,
) -> Option<()> {
const PULL_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_millis(125);
let previous_result_id = match self.as_local()?.language_servers.get(&language_server_id) {
Some(LanguageServerState::Running {
previous_document_diagnostic_result_id,
..
}) => previous_document_diagnostic_result_id.clone(),
_ => None,
};
let lsp_request_task = self.request_lsp(
buffer_handle.clone(),
LanguageServerToQuery::Other(language_server_id),
GetDocumentDiagnostics {
language_server_id,
previous_result_id,
},
cx,
);
let snapshot =
self.buffer_snapshot_for_lsp_version(&buffer_handle, language_server_id, None, cx);
cx.spawn(move |_, mut cx| async move {
let snapshot = snapshot?;
cx.background_executor()
.timer(PULL_DIAGNOSTICS_DEBOUNCE)
.await;
let diagnostics = lsp_request_task
.await
.context("Unable to pull document diagnostic")
.unwrap_or_default();
buffer_handle.update(&mut cx, |buffer, cx| {
let set = DiagnosticSet::from_sorted_entries(diagnostics, &snapshot);
buffer.update_diagnostics(language_server_id, set, cx);
})
})
.detach();
None
}
pub fn diagnostic_summary(&self, include_ignored: bool, cx: &AppContext) -> DiagnosticSummary {
let mut summary = DiagnosticSummary::default();
for (_, _, path_summary) in self.diagnostic_summaries(include_ignored, cx) {
@ -5898,6 +5847,47 @@ impl LspStore {
.collect(),
})
}
Some(proto::multi_lsp_query::Request::GetDocumentDiagnostics(
get_document_diagnostics,
)) => {
let get_document_diagnostics = GetDocumentDiagnostics::from_proto(
get_document_diagnostics,
this.clone(),
buffer.clone(),
cx.clone(),
)
.await?;
let all_diagnostics = this
.update(&mut cx, |project, cx| {
project.request_multiple_lsp_locally(
&buffer,
Some(get_document_diagnostics.position),
get_document_diagnostics,
cx,
)
})?
.await
.into_iter();
this.update(&mut cx, |project, cx| proto::MultiLspQueryResponse {
responses: all_diagnostics
.map(|lsp_diagnostic| proto::LspResponse {
response: Some(
proto::lsp_response::Response::GetDocumentDiagnosticsResponse(
GetDocumentDiagnostics::response_to_proto(
lsp_diagnostic,
project,
sender_id,
&buffer_version,
cx,
),
),
),
})
.collect(),
})
}
None => anyhow::bail!("empty multi lsp query request"),
}
}
@ -7318,63 +7308,6 @@ impl LspStore {
.detach();
}
fn pull_diagnostic(
&mut self,
language_server_id: LanguageServerId,
buffer_handle: Model<Buffer>,
cx: &mut ModelContext<Self>,
) -> Option<()> {
let buffer = buffer_handle.read(cx);
let file = File::from_dyn(buffer.file())?;
let abs_path = file.as_local()?.abs_path(cx);
let uri = lsp::Url::from_file_path(abs_path).log_err()?;
const PULL_DIAGNOSTICS_DEBOUNCE: Duration = Duration::from_millis(125);
let previous_result_id = match self.as_local()?.language_servers.get(&language_server_id) {
Some(LanguageServerState::Running {
previous_document_diagnostic_result_id,
..
}) => previous_document_diagnostic_result_id.clone(),
_ => None,
};
let lsp_request_task = self.request_lsp(
buffer_handle,
LanguageServerToQuery::Other(language_server_id),
GetDocumentDiagnostics {
language_server_id,
previous_result_id,
},
cx,
);
cx.spawn(move |this, mut cx| async move {
cx.background_executor()
.timer(PULL_DIAGNOSTICS_DEBOUNCE)
.await;
let diagnostics = lsp_request_task.await;
this.update(&mut cx, |this, cx| {
this.update_diagnostics(
language_server_id,
lsp::PublishDiagnosticsParams {
uri: uri.clone(),
diagnostics: diagnostics.unwrap(),
version: None,
},
&[],
cx,
)
.log_err()
})
.ok();
})
.detach();
None
}
pub fn update_diagnostics(
&mut self,
language_server_id: LanguageServerId,

View file

@ -3037,12 +3037,24 @@ impl Project {
buffer_handle: &Model<Buffer>,
position: Anchor,
cx: &mut ModelContext<Self>,
) -> Task<Result<Vec<LspDiagnostics>>> {
) -> Task<Result<Vec<Option<LspDiagnostics>>>> {
self.lsp_store.update(cx, |lsp_store, cx| {
lsp_store.document_diagnostic(buffer_handle, position, cx)
})
}
pub fn update_diagnostics(
&mut self,
language_server_id: LanguageServerId,
params: lsp::PublishDiagnosticsParams,
disk_based_sources: &[String],
cx: &mut ModelContext<Self>,
) -> Result<(), anyhow::Error> {
self.lsp_store.update(cx, |lsp_store, cx| {
lsp_store.update_diagnostics(language_server_id, params, disk_based_sources, cx)
})
}
pub fn search(
&mut self,
query: SearchQuery,