mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-28 04:33:13 +03:00
Start work on preserving continuity of disk-based diagnostics
This commit is contained in:
parent
e31205c95e
commit
1544da887e
@ -18,11 +18,11 @@ use smol::future::yield_now;
|
||||
use std::{
|
||||
any::Any,
|
||||
cell::RefCell,
|
||||
cmp,
|
||||
cmp::{self, Reverse},
|
||||
collections::{BTreeMap, HashMap, HashSet},
|
||||
ffi::OsString,
|
||||
future::Future,
|
||||
iter::{Iterator, Peekable},
|
||||
iter::{self, Iterator, Peekable},
|
||||
ops::{Deref, DerefMut, Range},
|
||||
path::{Path, PathBuf},
|
||||
str,
|
||||
@ -92,6 +92,7 @@ pub struct Diagnostic {
|
||||
pub severity: DiagnosticSeverity,
|
||||
pub message: String,
|
||||
pub group_id: usize,
|
||||
pub is_valid: bool,
|
||||
pub is_primary: bool,
|
||||
}
|
||||
|
||||
@ -725,7 +726,7 @@ impl Buffer {
|
||||
mut diagnostics: Vec<DiagnosticEntry<PointUtf16>>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Result<Operation> {
|
||||
diagnostics.sort_unstable_by_key(|d| (d.range.start, d.range.end));
|
||||
diagnostics.sort_unstable_by_key(|d| (d.range.start, Reverse(d.range.end)));
|
||||
|
||||
let version = version.map(|version| version as usize);
|
||||
let content = if let Some(version) = version {
|
||||
@ -754,6 +755,7 @@ impl Buffer {
|
||||
.peekable();
|
||||
let mut last_edit_old_end = PointUtf16::zero();
|
||||
let mut last_edit_new_end = PointUtf16::zero();
|
||||
let mut has_disk_based_diagnostics = false;
|
||||
let mut ix = 0;
|
||||
'outer: while ix < diagnostics.len() {
|
||||
let entry = &mut diagnostics[ix];
|
||||
@ -769,6 +771,7 @@ impl Buffer {
|
||||
.as_ref()
|
||||
.map_or(false, |source| disk_based_sources.contains(source))
|
||||
{
|
||||
has_disk_based_diagnostics = true;
|
||||
while let Some(edit) = edits_since_save.peek() {
|
||||
if edit.old.end <= start {
|
||||
last_edit_old_end = edit.old.end;
|
||||
@ -802,7 +805,62 @@ impl Buffer {
|
||||
}
|
||||
|
||||
drop(edits_since_save);
|
||||
self.diagnostics = DiagnosticSet::new(diagnostics, content);
|
||||
|
||||
let diagnostics = diagnostics.into_iter().map(|entry| DiagnosticEntry {
|
||||
range: content.anchor_before(entry.range.start)..content.anchor_after(entry.range.end),
|
||||
diagnostic: entry.diagnostic,
|
||||
});
|
||||
|
||||
// Some diagnostic sources are reported on a less frequent basis than others.
|
||||
// If those sources are absent from this message, then preserve the previous
|
||||
// diagnostics for those sources, but mark them as stale, and set a time to
|
||||
// clear them out.
|
||||
let mut merged_old_disk_based_diagnostics = false;
|
||||
self.diagnostics = if has_disk_based_diagnostics {
|
||||
DiagnosticSet::from_sorted_entries(diagnostics, content)
|
||||
} else {
|
||||
let mut new_diagnostics = diagnostics.peekable();
|
||||
let mut old_diagnostics = self
|
||||
.diagnostics
|
||||
.iter()
|
||||
.filter_map(|entry| {
|
||||
let is_disk_based = entry
|
||||
.diagnostic
|
||||
.source
|
||||
.as_ref()
|
||||
.map_or(false, |source| disk_based_sources.contains(source));
|
||||
if is_disk_based {
|
||||
merged_old_disk_based_diagnostics = true;
|
||||
let mut entry = entry.clone();
|
||||
entry.diagnostic.is_valid = false;
|
||||
Some(entry)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.peekable();
|
||||
let merged_diagnostics =
|
||||
iter::from_fn(|| match (old_diagnostics.peek(), new_diagnostics.peek()) {
|
||||
(None, None) => None,
|
||||
(Some(_), None) => old_diagnostics.next(),
|
||||
(None, Some(_)) => new_diagnostics.next(),
|
||||
(Some(old), Some(new)) => {
|
||||
let ordering = old
|
||||
.range
|
||||
.start
|
||||
.cmp(&new.range.start, content)
|
||||
.unwrap()
|
||||
.then_with(|| new.range.end.cmp(&old.range.end, content).unwrap());
|
||||
if ordering.is_lt() {
|
||||
old_diagnostics.next()
|
||||
} else {
|
||||
new_diagnostics.next()
|
||||
}
|
||||
}
|
||||
});
|
||||
DiagnosticSet::from_sorted_entries(merged_diagnostics, content)
|
||||
};
|
||||
|
||||
self.diagnostics_update_count += 1;
|
||||
cx.notify();
|
||||
cx.emit(Event::DiagnosticsUpdated);
|
||||
@ -2009,6 +2067,7 @@ impl Default for Diagnostic {
|
||||
message: Default::default(),
|
||||
group_id: Default::default(),
|
||||
is_primary: Default::default(),
|
||||
is_valid: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -117,6 +117,7 @@ pub fn serialize_diagnostics<'a>(
|
||||
} as i32,
|
||||
group_id: entry.diagnostic.group_id as u64,
|
||||
is_primary: entry.diagnostic.is_primary,
|
||||
is_valid: entry.diagnostic.is_valid,
|
||||
code: entry.diagnostic.code.clone(),
|
||||
source: entry.diagnostic.source.clone(),
|
||||
})
|
||||
@ -273,6 +274,7 @@ pub fn deserialize_diagnostics(
|
||||
is_primary: diagnostic.is_primary,
|
||||
code: diagnostic.code,
|
||||
source: diagnostic.source,
|
||||
is_valid: diagnostic.is_valid,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
@ -721,6 +721,7 @@ impl Worktree {
|
||||
message: mem::take(&mut diagnostic.message),
|
||||
group_id,
|
||||
is_primary: false,
|
||||
is_valid: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
@ -303,10 +303,12 @@ message Diagnostic {
|
||||
Anchor end = 2;
|
||||
Severity severity = 3;
|
||||
string message = 4;
|
||||
uint64 group_id = 5;
|
||||
bool is_primary = 6;
|
||||
optional string code = 7;
|
||||
optional string source = 8;
|
||||
optional string code = 5;
|
||||
optional string source = 6;
|
||||
uint64 group_id = 7;
|
||||
bool is_primary = 8;
|
||||
bool is_valid = 9;
|
||||
|
||||
enum Severity {
|
||||
None = 0;
|
||||
Error = 1;
|
||||
|
Loading…
Reference in New Issue
Block a user