mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-27 12:54:42 +00:00
WIP
Co-Authored-By: Antonio Scandurra <me@as-cii.com> Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
7b453beebc
commit
e3ecd87081
6 changed files with 156 additions and 58 deletions
|
@ -77,7 +77,7 @@ pub struct Buffer {
|
||||||
pub struct BufferSnapshot {
|
pub struct BufferSnapshot {
|
||||||
text: text::BufferSnapshot,
|
text: text::BufferSnapshot,
|
||||||
tree: Option<Tree>,
|
tree: Option<Tree>,
|
||||||
diagnostics: DiagnosticSet,
|
diagnostics: HashMap<&'static str, DiagnosticSet>,
|
||||||
remote_selections: TreeMap<ReplicaId, Arc<[Selection<Anchor>]>>,
|
remote_selections: TreeMap<ReplicaId, Arc<[Selection<Anchor>]>>,
|
||||||
diagnostics_update_count: usize,
|
diagnostics_update_count: usize,
|
||||||
is_parsing: bool,
|
is_parsing: bool,
|
||||||
|
@ -115,7 +115,7 @@ struct LanguageServerSnapshot {
|
||||||
pub enum Operation {
|
pub enum Operation {
|
||||||
Buffer(text::Operation),
|
Buffer(text::Operation),
|
||||||
UpdateDiagnostics {
|
UpdateDiagnostics {
|
||||||
diagnostics: Arc<[DiagnosticEntry<Anchor>]>,
|
diagnostic_set: Arc<DiagnosticSet>,
|
||||||
lamport_timestamp: clock::Lamport,
|
lamport_timestamp: clock::Lamport,
|
||||||
},
|
},
|
||||||
UpdateSelections {
|
UpdateSelections {
|
||||||
|
@ -298,10 +298,12 @@ impl Buffer {
|
||||||
proto::deserialize_selections(selection_set.selections),
|
proto::deserialize_selections(selection_set.selections),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.apply_diagnostic_update(
|
for diagnostic_set in message.diagnostic_sets {
|
||||||
Arc::from(proto::deserialize_diagnostics(message.diagnostics)),
|
this.apply_diagnostic_update(
|
||||||
cx,
|
Arc::from(proto::deserialize_diagnostics(diagnostic_set)),
|
||||||
);
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(this)
|
Ok(this)
|
||||||
}
|
}
|
||||||
|
@ -323,7 +325,7 @@ impl Buffer {
|
||||||
selections: proto::serialize_selections(selections),
|
selections: proto::serialize_selections(selections),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
diagnostics: proto::serialize_diagnostics(self.diagnostics.iter()),
|
diagnostics: proto::serialize_diagnostic_set(self.diagnostics.iter()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,9 @@ use std::{
|
||||||
use sum_tree::{self, Bias, SumTree};
|
use sum_tree::{self, Bias, SumTree};
|
||||||
use text::{Anchor, FromAnchor, PointUtf16, ToOffset};
|
use text::{Anchor, FromAnchor, PointUtf16, ToOffset};
|
||||||
|
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct DiagnosticSet {
|
pub struct DiagnosticSet {
|
||||||
|
provider_name: String,
|
||||||
diagnostics: SumTree<DiagnosticEntry<Anchor>>,
|
diagnostics: SumTree<DiagnosticEntry<Anchor>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,22 +35,32 @@ pub struct Summary {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiagnosticSet {
|
impl DiagnosticSet {
|
||||||
pub fn from_sorted_entries<I>(iter: I, buffer: &text::BufferSnapshot) -> Self
|
pub fn provider_name(&self) -> &str {
|
||||||
|
&self.provider_name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_sorted_entries<I>(
|
||||||
|
provider_name: String,
|
||||||
|
iter: I,
|
||||||
|
buffer: &text::BufferSnapshot,
|
||||||
|
) -> Self
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = DiagnosticEntry<Anchor>>,
|
I: IntoIterator<Item = DiagnosticEntry<Anchor>>,
|
||||||
{
|
{
|
||||||
Self {
|
Self {
|
||||||
|
provider_name,
|
||||||
diagnostics: SumTree::from_iter(iter, buffer),
|
diagnostics: SumTree::from_iter(iter, buffer),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new<I>(iter: I, buffer: &text::BufferSnapshot) -> Self
|
pub fn new<I>(provider_name: &'static str, iter: I, buffer: &text::BufferSnapshot) -> Self
|
||||||
where
|
where
|
||||||
I: IntoIterator<Item = DiagnosticEntry<PointUtf16>>,
|
I: IntoIterator<Item = DiagnosticEntry<PointUtf16>>,
|
||||||
{
|
{
|
||||||
let mut entries = iter.into_iter().collect::<Vec<_>>();
|
let mut entries = iter.into_iter().collect::<Vec<_>>();
|
||||||
entries.sort_unstable_by_key(|entry| (entry.range.start, Reverse(entry.range.end)));
|
entries.sort_unstable_by_key(|entry| (entry.range.start, Reverse(entry.range.end)));
|
||||||
Self {
|
Self {
|
||||||
|
provider_name,
|
||||||
diagnostics: SumTree::from_iter(
|
diagnostics: SumTree::from_iter(
|
||||||
entries.into_iter().map(|entry| DiagnosticEntry {
|
entries.into_iter().map(|entry| DiagnosticEntry {
|
||||||
range: buffer.anchor_before(entry.range.start)
|
range: buffer.anchor_before(entry.range.start)
|
||||||
|
|
|
@ -66,6 +66,8 @@ pub struct BracketPair {
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait DiagnosticSource: 'static + Send + Sync {
|
pub trait DiagnosticSource: 'static + Send + Sync {
|
||||||
|
fn name(&self) -> &'static str;
|
||||||
|
|
||||||
async fn diagnose(
|
async fn diagnose(
|
||||||
&self,
|
&self,
|
||||||
path: Arc<Path>,
|
path: Arc<Path>,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{diagnostic_set::DiagnosticEntry, Diagnostic, Operation};
|
use crate::{diagnostic_set::DiagnosticEntry, Diagnostic, DiagnosticSet, Operation};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use clock::ReplicaId;
|
use clock::ReplicaId;
|
||||||
use lsp::DiagnosticSeverity;
|
use lsp::DiagnosticSeverity;
|
||||||
|
@ -57,12 +57,12 @@ pub fn serialize_operation(operation: &Operation) -> proto::Operation {
|
||||||
lamport_timestamp: lamport_timestamp.value,
|
lamport_timestamp: lamport_timestamp.value,
|
||||||
}),
|
}),
|
||||||
Operation::UpdateDiagnostics {
|
Operation::UpdateDiagnostics {
|
||||||
diagnostics,
|
diagnostic_set,
|
||||||
lamport_timestamp,
|
lamport_timestamp,
|
||||||
} => proto::operation::Variant::UpdateDiagnostics(proto::UpdateDiagnostics {
|
} => proto::operation::Variant::UpdateDiagnosticSet(proto::UpdateDiagnosticSet {
|
||||||
replica_id: lamport_timestamp.replica_id as u32,
|
replica_id: lamport_timestamp.replica_id as u32,
|
||||||
lamport_timestamp: lamport_timestamp.value,
|
lamport_timestamp: lamport_timestamp.value,
|
||||||
diagnostics: serialize_diagnostics(diagnostics.iter()),
|
diagnostic_set: Some(serialize_diagnostic_set(&diagnostic_set)),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
@ -99,29 +99,30 @@ pub fn serialize_selections(selections: &Arc<[Selection<Anchor>]>) -> Vec<proto:
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize_diagnostics<'a>(
|
pub fn serialize_diagnostic_set(set: &DiagnosticSet) -> proto::DiagnosticSet {
|
||||||
diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<Anchor>>,
|
proto::DiagnosticSet {
|
||||||
) -> Vec<proto::Diagnostic> {
|
provider_name: set.provider_name().to_string(),
|
||||||
diagnostics
|
diagnostics: set
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|entry| proto::Diagnostic {
|
.map(|entry| proto::Diagnostic {
|
||||||
start: Some(serialize_anchor(&entry.range.start)),
|
start: Some(serialize_anchor(&entry.range.start)),
|
||||||
end: Some(serialize_anchor(&entry.range.end)),
|
end: Some(serialize_anchor(&entry.range.end)),
|
||||||
message: entry.diagnostic.message.clone(),
|
message: entry.diagnostic.message.clone(),
|
||||||
severity: match entry.diagnostic.severity {
|
severity: match entry.diagnostic.severity {
|
||||||
DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
|
DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
|
||||||
DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
|
DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
|
||||||
DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
|
DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
|
||||||
DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
|
DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
|
||||||
_ => proto::diagnostic::Severity::None,
|
_ => proto::diagnostic::Severity::None,
|
||||||
} as i32,
|
} as i32,
|
||||||
group_id: entry.diagnostic.group_id as u64,
|
group_id: entry.diagnostic.group_id as u64,
|
||||||
is_primary: entry.diagnostic.is_primary,
|
is_primary: entry.diagnostic.is_primary,
|
||||||
is_valid: entry.diagnostic.is_valid,
|
is_valid: entry.diagnostic.is_valid,
|
||||||
code: entry.diagnostic.code.clone(),
|
code: entry.diagnostic.code.clone(),
|
||||||
is_disk_based: entry.diagnostic.is_disk_based,
|
is_disk_based: entry.diagnostic.is_disk_based,
|
||||||
})
|
})
|
||||||
.collect()
|
.collect(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
|
fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
|
||||||
|
@ -207,13 +208,15 @@ pub fn deserialize_operation(message: proto::Operation) -> Result<Operation> {
|
||||||
value: message.lamport_timestamp,
|
value: message.lamport_timestamp,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
proto::operation::Variant::UpdateDiagnostics(message) => Operation::UpdateDiagnostics {
|
proto::operation::Variant::UpdateDiagnosticSet(message) => {
|
||||||
diagnostics: Arc::from(deserialize_diagnostics(message.diagnostics)),
|
Operation::UpdateDiagnostics {
|
||||||
lamport_timestamp: clock::Lamport {
|
diagnostics: Arc::from(deserialize_diagnostic_set(message.diagnostic_set?)),
|
||||||
replica_id: message.replica_id as ReplicaId,
|
lamport_timestamp: clock::Lamport {
|
||||||
value: message.lamport_timestamp,
|
replica_id: message.replica_id as ReplicaId,
|
||||||
},
|
value: message.lamport_timestamp,
|
||||||
},
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -253,12 +256,13 @@ pub fn deserialize_selections(selections: Vec<proto::Selection>) -> Arc<[Selecti
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deserialize_diagnostics(
|
pub fn deserialize_diagnostic_set(
|
||||||
diagnostics: Vec<proto::Diagnostic>,
|
message: proto::DiagnosticSet,
|
||||||
) -> Vec<DiagnosticEntry<Anchor>> {
|
buffer: &BufferSnapshot,
|
||||||
diagnostics
|
) -> DiagnosticSet {
|
||||||
.into_iter()
|
DiagnosticSet::from_sorted_entries(
|
||||||
.filter_map(|diagnostic| {
|
message.provider_name,
|
||||||
|
message.diagnostics.into_iter().filter_map(|diagnostic| {
|
||||||
Some(DiagnosticEntry {
|
Some(DiagnosticEntry {
|
||||||
range: deserialize_anchor(diagnostic.start?)?..deserialize_anchor(diagnostic.end?)?,
|
range: deserialize_anchor(diagnostic.start?)?..deserialize_anchor(diagnostic.end?)?,
|
||||||
diagnostic: Diagnostic {
|
diagnostic: Diagnostic {
|
||||||
|
@ -277,8 +281,9 @@ pub fn deserialize_diagnostics(
|
||||||
is_disk_based: diagnostic.is_disk_based,
|
is_disk_based: diagnostic.is_disk_based,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
}),
|
||||||
.collect()
|
buffer,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
|
fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {
|
||||||
|
|
|
@ -672,6 +672,79 @@ impl Worktree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_lsp_diagnostics(
|
||||||
|
&mut self,
|
||||||
|
mut params: lsp::PublishDiagnosticsParams,
|
||||||
|
disk_based_sources: &HashSet<String>,
|
||||||
|
cx: &mut ModelContext<Worktree>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let this = self.as_local_mut().ok_or_else(|| anyhow!("not local"))?;
|
||||||
|
let abs_path = params
|
||||||
|
.uri
|
||||||
|
.to_file_path()
|
||||||
|
.map_err(|_| anyhow!("URI is not a file"))?;
|
||||||
|
let worktree_path = Arc::from(
|
||||||
|
abs_path
|
||||||
|
.strip_prefix(&this.abs_path)
|
||||||
|
.context("path is not within worktree")?,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut group_ids_by_diagnostic_range = HashMap::default();
|
||||||
|
let mut diagnostics_by_group_id = HashMap::default();
|
||||||
|
let mut next_group_id = 0;
|
||||||
|
for diagnostic in &mut params.diagnostics {
|
||||||
|
let source = diagnostic.source.as_ref();
|
||||||
|
let code = diagnostic.code.as_ref();
|
||||||
|
let group_id = diagnostic_ranges(&diagnostic, &abs_path)
|
||||||
|
.find_map(|range| group_ids_by_diagnostic_range.get(&(source, code, range)))
|
||||||
|
.copied()
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
let group_id = post_inc(&mut next_group_id);
|
||||||
|
for range in diagnostic_ranges(&diagnostic, &abs_path) {
|
||||||
|
group_ids_by_diagnostic_range.insert((source, code, range), group_id);
|
||||||
|
}
|
||||||
|
group_id
|
||||||
|
});
|
||||||
|
|
||||||
|
diagnostics_by_group_id
|
||||||
|
.entry(group_id)
|
||||||
|
.or_insert(Vec::new())
|
||||||
|
.push(DiagnosticEntry {
|
||||||
|
range: diagnostic.range.start.to_point_utf16()
|
||||||
|
..diagnostic.range.end.to_point_utf16(),
|
||||||
|
diagnostic: Diagnostic {
|
||||||
|
code: diagnostic.code.clone().map(|code| match code {
|
||||||
|
lsp::NumberOrString::Number(code) => code.to_string(),
|
||||||
|
lsp::NumberOrString::String(code) => code,
|
||||||
|
}),
|
||||||
|
severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
|
||||||
|
message: mem::take(&mut diagnostic.message),
|
||||||
|
group_id,
|
||||||
|
is_primary: false,
|
||||||
|
is_valid: true,
|
||||||
|
is_disk_based: diagnostic
|
||||||
|
.source
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |source| disk_based_sources.contains(source)),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let diagnostics = diagnostics_by_group_id
|
||||||
|
.into_values()
|
||||||
|
.flat_map(|mut diagnostics| {
|
||||||
|
let primary = diagnostics
|
||||||
|
.iter_mut()
|
||||||
|
.min_by_key(|entry| entry.diagnostic.severity)
|
||||||
|
.unwrap();
|
||||||
|
primary.diagnostic.is_primary = true;
|
||||||
|
diagnostics
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
self.update_diagnostic_entries(worktree_path, params.version, diagnostics, cx)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update_diagnostics(
|
pub fn update_diagnostics(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut params: lsp::PublishDiagnosticsParams,
|
mut params: lsp::PublishDiagnosticsParams,
|
||||||
|
@ -1046,7 +1119,7 @@ impl LocalWorktree {
|
||||||
while let Ok(diagnostics) = diagnostics_rx.recv().await {
|
while let Ok(diagnostics) = diagnostics_rx.recv().await {
|
||||||
if let Some(handle) = cx.read(|cx| this.upgrade(cx)) {
|
if let Some(handle) = cx.read(|cx| this.upgrade(cx)) {
|
||||||
handle.update(&mut cx, |this, cx| {
|
handle.update(&mut cx, |this, cx| {
|
||||||
this.update_diagnostics(diagnostics, &disk_based_sources, cx)
|
this.update_lsp_diagnostics(diagnostics, &disk_based_sources, cx)
|
||||||
.log_err();
|
.log_err();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -3835,7 +3908,7 @@ mod tests {
|
||||||
|
|
||||||
worktree
|
worktree
|
||||||
.update(&mut cx, |tree, cx| {
|
.update(&mut cx, |tree, cx| {
|
||||||
tree.update_diagnostics(message, &Default::default(), cx)
|
tree.update_lsp_diagnostics(message, &Default::default(), cx)
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let buffer = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
|
let buffer = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
|
||||||
|
|
|
@ -265,7 +265,7 @@ message Buffer {
|
||||||
string content = 2;
|
string content = 2;
|
||||||
repeated Operation.Edit history = 3;
|
repeated Operation.Edit history = 3;
|
||||||
repeated SelectionSet selections = 4;
|
repeated SelectionSet selections = 4;
|
||||||
repeated Diagnostic diagnostics = 5;
|
repeated DiagnosticSet diagnostic_sets = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message SelectionSet {
|
message SelectionSet {
|
||||||
|
@ -292,10 +292,15 @@ enum Bias {
|
||||||
Right = 1;
|
Right = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message UpdateDiagnostics {
|
message UpdateDiagnosticSet {
|
||||||
uint32 replica_id = 1;
|
uint32 replica_id = 1;
|
||||||
uint32 lamport_timestamp = 2;
|
uint32 lamport_timestamp = 2;
|
||||||
repeated Diagnostic diagnostics = 3;
|
DiagnosticSet diagnostic_set = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DiagnosticSet {
|
||||||
|
string provider_name = 1;
|
||||||
|
repeated Diagnostic diagnostics = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Diagnostic {
|
message Diagnostic {
|
||||||
|
@ -324,7 +329,7 @@ message Operation {
|
||||||
Undo undo = 2;
|
Undo undo = 2;
|
||||||
UpdateSelections update_selections = 3;
|
UpdateSelections update_selections = 3;
|
||||||
RemoveSelections remove_selections = 4;
|
RemoveSelections remove_selections = 4;
|
||||||
UpdateDiagnostics update_diagnostics = 5;
|
UpdateDiagnosticSet update_diagnostic_set = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Edit {
|
message Edit {
|
||||||
|
|
Loading…
Reference in a new issue