Merge unnecessary/deprecated diagnostic highlights separately (#10084)

Previously unnecessary/deprecated diagnostic tags replaced the highlight
for the severity of a diagnostic. This could cause either the severity
or unnecessary/deprecated scopes to disappear when diagnostic ranges
overlapped though. Plus the severity highlight can be interesting in
addition to the unnecessary/deprecated highlight.

So this change separates the unnecessary and deprecated highlights from
the severity highlights, so each is merged separately and when they
overlap, the highlights are combined.
pull/10102/head
Michael Davis 3 months ago committed by GitHub
parent d053886fe3
commit f240d896a4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -359,8 +359,8 @@ impl EditorView {
pub fn doc_diagnostics_highlights( pub fn doc_diagnostics_highlights(
doc: &Document, doc: &Document,
theme: &Theme, theme: &Theme,
) -> [Vec<(usize, std::ops::Range<usize>)>; 5] { ) -> [Vec<(usize, std::ops::Range<usize>)>; 7] {
use helix_core::diagnostic::{DiagnosticTag, Severity}; use helix_core::diagnostic::{DiagnosticTag, Range, Severity};
let get_scope_of = |scope| { let get_scope_of = |scope| {
theme theme
.find_scope_index_exact(scope) .find_scope_index_exact(scope)
@ -389,6 +389,25 @@ impl EditorView {
let mut hint_vec = Vec::new(); let mut hint_vec = Vec::new();
let mut warning_vec = Vec::new(); let mut warning_vec = Vec::new();
let mut error_vec = Vec::new(); let mut error_vec = Vec::new();
let mut unnecessary_vec = Vec::new();
let mut deprecated_vec = Vec::new();
let push_diagnostic =
|vec: &mut Vec<(usize, std::ops::Range<usize>)>, scope, range: Range| {
// If any diagnostic overlaps ranges with the prior diagnostic,
// merge the two together. Otherwise push a new span.
match vec.last_mut() {
Some((_, existing_range)) if range.start <= existing_range.end => {
// This branch merges overlapping diagnostics, assuming that the current
// diagnostic starts on range.start or later. If this assertion fails,
// we will discard some part of `diagnostic`. This implies that
// `doc.diagnostics()` is not sorted by `diagnostic.range`.
debug_assert!(existing_range.start <= range.start);
existing_range.end = range.end.max(existing_range.end)
}
_ => vec.push((scope, range.start..range.end)),
}
};
for diagnostic in doc.diagnostics() { for diagnostic in doc.diagnostics() {
// Separate diagnostics into different Vecs by severity. // Separate diagnostics into different Vecs by severity.
@ -400,31 +419,44 @@ impl EditorView {
_ => (&mut default_vec, r#default), _ => (&mut default_vec, r#default),
}; };
let scope = diagnostic // If the diagnostic has tags and a non-warning/error severity, skip rendering
.tags // the diagnostic as info/hint/default and only render it as unnecessary/deprecated
.first() // instead. For warning/error diagnostics, render both the severity highlight and
.and_then(|tag| match tag { // the tag highlight.
DiagnosticTag::Unnecessary => unnecessary, if diagnostic.tags.is_empty()
DiagnosticTag::Deprecated => deprecated, || matches!(
}) diagnostic.severity,
.unwrap_or(scope); Some(Severity::Warning | Severity::Error)
)
// If any diagnostic overlaps ranges with the prior diagnostic, {
// merge the two together. Otherwise push a new span. push_diagnostic(vec, scope, diagnostic.range);
match vec.last_mut() { }
Some((_, range)) if diagnostic.range.start <= range.end => {
// This branch merges overlapping diagnostics, assuming that the current for tag in &diagnostic.tags {
// diagnostic starts on range.start or later. If this assertion fails, match tag {
// we will discard some part of `diagnostic`. This implies that DiagnosticTag::Unnecessary => {
// `doc.diagnostics()` is not sorted by `diagnostic.range`. if let Some(scope) = unnecessary {
debug_assert!(range.start <= diagnostic.range.start); push_diagnostic(&mut unnecessary_vec, scope, diagnostic.range)
range.end = diagnostic.range.end.max(range.end) }
}
DiagnosticTag::Deprecated => {
if let Some(scope) = deprecated {
push_diagnostic(&mut deprecated_vec, scope, diagnostic.range)
}
}
} }
_ => vec.push((scope, diagnostic.range.start..diagnostic.range.end)),
} }
} }
[default_vec, info_vec, hint_vec, warning_vec, error_vec] [
default_vec,
unnecessary_vec,
deprecated_vec,
info_vec,
hint_vec,
warning_vec,
error_vec,
]
} }
/// Get highlight spans for selections in a document view. /// Get highlight spans for selections in a document view.

Loading…
Cancel
Save