mirror of https://github.com/helix-editor/helix
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
parent
d053886fe3
commit
f240d896a4
|
@ -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)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
push_diagnostic(vec, scope, diagnostic.range);
|
||||||
|
}
|
||||||
|
|
||||||
// If any diagnostic overlaps ranges with the prior diagnostic,
|
for tag in &diagnostic.tags {
|
||||||
// merge the two together. Otherwise push a new span.
|
match tag {
|
||||||
match vec.last_mut() {
|
DiagnosticTag::Unnecessary => {
|
||||||
Some((_, range)) if diagnostic.range.start <= range.end => {
|
if let Some(scope) = unnecessary {
|
||||||
// This branch merges overlapping diagnostics, assuming that the current
|
push_diagnostic(&mut unnecessary_vec, scope, diagnostic.range)
|
||||||
// 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`.
|
DiagnosticTag::Deprecated => {
|
||||||
debug_assert!(range.start <= diagnostic.range.start);
|
if let Some(scope) = deprecated {
|
||||||
range.end = diagnostic.range.end.max(range.end)
|
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…
Reference in New Issue