|
|
@ -2169,82 +2169,83 @@ impl Editor {
|
|
|
|
document_version: Option<i32>,
|
|
|
|
document_version: Option<i32>,
|
|
|
|
result_id: Option<String>,
|
|
|
|
result_id: Option<String>,
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
let doc = self.documents.values_mut()
|
|
|
|
let Some(doc) = self
|
|
|
|
.find(|doc| doc.uri().is_some_and(|u| u == uri))
|
|
|
|
.documents
|
|
|
|
.filter(|doc| {
|
|
|
|
.values_mut()
|
|
|
|
if let Some(version) = document_version{
|
|
|
|
.find(|doc| doc.uri().is_some_and(|u| u == uri))
|
|
|
|
if version != doc.version() {
|
|
|
|
else {
|
|
|
|
log::info!("Version ({version}) is out of date for {uri:?} (expected ({}), dropping PublishDiagnostic notification", doc.version());
|
|
|
|
return;
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
if let Some(version) = document_version {
|
|
|
|
true
|
|
|
|
if version != doc.version() {
|
|
|
|
});
|
|
|
|
log::info!("Version ({version}) is out of date for {uri:?} (expected ({}), dropping PublishDiagnostic notification", doc.version());
|
|
|
|
|
|
|
|
return;
|
|
|
|
if let Some(doc) = doc {
|
|
|
|
|
|
|
|
let mut unchanged_diag_sources = Vec::new();
|
|
|
|
|
|
|
|
if let Some(old_diagnostics) = self.diagnostics.get(&uri) {
|
|
|
|
|
|
|
|
if let Some(lang_conf) = doc.language_config() {
|
|
|
|
|
|
|
|
for source in &lang_conf.persistent_diagnostic_sources {
|
|
|
|
|
|
|
|
let new_diagnostics = diagnostics
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.filter(|d| d.0.source.as_ref() == Some(source));
|
|
|
|
|
|
|
|
let old_diagnostics = old_diagnostics
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.filter(|(d, d_server)| {
|
|
|
|
|
|
|
|
*d_server == server_id && d.source.as_ref() == Some(source)
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.map(|(d, _)| d);
|
|
|
|
|
|
|
|
if new_diagnostics.map(|x| &x.0).eq(old_diagnostics) {
|
|
|
|
|
|
|
|
unchanged_diag_sources.push(source.clone())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Insert the original lsp::Diagnostics here because we may have no open document
|
|
|
|
let mut unchanged_diag_sources = Vec::new();
|
|
|
|
// for diagnosic message and so we can't calculate the exact position.
|
|
|
|
if let Some(old_diagnostics) = self.diagnostics.get(&uri) {
|
|
|
|
// When using them later in the diagnostics picker, we calculate them on-demand.
|
|
|
|
if let Some(lang_conf) = doc.language_config() {
|
|
|
|
let diagnostics = match self.diagnostics.entry(uri) {
|
|
|
|
for source in &lang_conf.persistent_diagnostic_sources {
|
|
|
|
std::collections::btree_map::Entry::Occupied(o) => {
|
|
|
|
let new_diagnostics = diagnostics
|
|
|
|
let current_diagnostics = o.into_mut();
|
|
|
|
.iter()
|
|
|
|
// there may entries of other language servers, which is why we can't overwrite the whole entry
|
|
|
|
.filter(|d| d.0.source.as_ref() == Some(source));
|
|
|
|
current_diagnostics.retain(|(_, lsp_id)| *lsp_id != server_id);
|
|
|
|
let old_diagnostics = old_diagnostics
|
|
|
|
current_diagnostics.extend(diagnostics);
|
|
|
|
.iter()
|
|
|
|
current_diagnostics
|
|
|
|
.filter(|(d, d_server)| {
|
|
|
|
// Sort diagnostics first by severity and then by line numbers.
|
|
|
|
*d_server == server_id && d.source.as_ref() == Some(source)
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
.map(|(d, _)| d);
|
|
|
|
|
|
|
|
if new_diagnostics.map(|x| &x.0).eq(old_diagnostics) {
|
|
|
|
|
|
|
|
unchanged_diag_sources.push(source.clone())
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::collections::btree_map::Entry::Vacant(v) => v.insert(diagnostics),
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Sort diagnostics first by severity and then by line numbers.
|
|
|
|
// Insert the original lsp::Diagnostics here because we may have no open document
|
|
|
|
// Note: The `lsp::DiagnosticSeverity` enum is already defined in decreasing order
|
|
|
|
// for diagnosic message and so we can't calculate the exact position.
|
|
|
|
diagnostics.sort_by_key(|(d, server_id)| (d.severity, d.range.start, *server_id));
|
|
|
|
// When using them later in the diagnostics picker, we calculate them on-demand.
|
|
|
|
|
|
|
|
let diagnostics = match self.diagnostics.entry(uri) {
|
|
|
|
let diagnostic_of_language_server_and_not_in_unchanged_sources =
|
|
|
|
std::collections::btree_map::Entry::Occupied(o) => {
|
|
|
|
|diagnostic: &lsp::Diagnostic, ls_id| {
|
|
|
|
let current_diagnostics = o.into_mut();
|
|
|
|
ls_id == server_id
|
|
|
|
// there may entries of other language servers, which is why we can't overwrite the whole entry
|
|
|
|
&& diagnostic
|
|
|
|
current_diagnostics.retain(|(_, lsp_id)| *lsp_id != server_id);
|
|
|
|
.source
|
|
|
|
current_diagnostics.extend(diagnostics);
|
|
|
|
.as_ref()
|
|
|
|
current_diagnostics
|
|
|
|
.map_or(true, |source| !unchanged_diag_sources.contains(source))
|
|
|
|
// Sort diagnostics first by severity and then by line numbers.
|
|
|
|
};
|
|
|
|
|
|
|
|
let diagnostics = Editor::doc_diagnostics_with_filter(
|
|
|
|
|
|
|
|
&self.language_servers,
|
|
|
|
|
|
|
|
&self.diagnostics,
|
|
|
|
|
|
|
|
doc,
|
|
|
|
|
|
|
|
diagnostic_of_language_server_and_not_in_unchanged_sources,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
doc.replace_diagnostics(diagnostics, &unchanged_diag_sources, Some(server_id));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if result_id.is_some() {
|
|
|
|
|
|
|
|
doc.previous_diagnostic_id = result_id;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::collections::btree_map::Entry::Vacant(v) => v.insert(diagnostics),
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
let doc = doc.id();
|
|
|
|
// Sort diagnostics first by severity and then by line numbers.
|
|
|
|
|
|
|
|
// Note: The `lsp::DiagnosticSeverity` enum is already defined in decreasing order
|
|
|
|
|
|
|
|
diagnostics.sort_by_key(|(d, server_id)| (d.severity, d.range.start, *server_id));
|
|
|
|
|
|
|
|
|
|
|
|
helix_event::dispatch(crate::events::DiagnosticsDidChange { editor: self, doc });
|
|
|
|
let diagnostic_of_language_server_and_not_in_unchanged_sources =
|
|
|
|
|
|
|
|
|diagnostic: &lsp::Diagnostic, ls_id| {
|
|
|
|
|
|
|
|
ls_id == server_id
|
|
|
|
|
|
|
|
&& diagnostic
|
|
|
|
|
|
|
|
.source
|
|
|
|
|
|
|
|
.as_ref()
|
|
|
|
|
|
|
|
.map_or(true, |source| !unchanged_diag_sources.contains(source))
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
let diagnostics = Editor::doc_diagnostics_with_filter(
|
|
|
|
|
|
|
|
&self.language_servers,
|
|
|
|
|
|
|
|
&self.diagnostics,
|
|
|
|
|
|
|
|
doc,
|
|
|
|
|
|
|
|
diagnostic_of_language_server_and_not_in_unchanged_sources,
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
doc.replace_diagnostics(diagnostics, &unchanged_diag_sources, Some(server_id));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if result_id.is_some() {
|
|
|
|
|
|
|
|
doc.previous_diagnostic_id = result_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let doc = doc.id();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
helix_event::dispatch(crate::events::DiagnosticsDidChange { editor: self, doc });
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|