Rip out "diagnostic providers"

Antonio Scandurra created

Change summary

crates/diagnostics/src/diagnostics.rs |  28 +-
crates/editor/src/editor.rs           |  19 -
crates/editor/src/items.rs            |   6 
crates/editor/src/multi_buffer.rs     |   5 
crates/language/src/buffer.rs         |  77 ++------
crates/language/src/diagnostic_set.rs |  17 -
crates/language/src/language.rs       |  22 --
crates/language/src/proto.rs          | 134 ++++++---------
crates/language/src/tests.rs          | 146 +++++++---------
crates/project/src/project.rs         |  37 ----
crates/project/src/worktree.rs        | 244 ++++++++++------------------
crates/rpc/proto/zed.proto            |  13 -
crates/rpc/src/peer.rs                |   8 
crates/server/src/rpc.rs              |   2 
crates/workspace/src/workspace.rs     |  14 -
crates/zed/src/language.rs            | 179 ---------------------
16 files changed, 265 insertions(+), 686 deletions(-)

Detailed changes

crates/diagnostics/src/diagnostics.rs 🔗

@@ -571,7 +571,7 @@ mod tests {
     use super::*;
     use client::{http::ServerResponse, test::FakeHttpClient, Client, UserStore};
     use gpui::TestAppContext;
-    use language::{Diagnostic, DiagnosticEntry, DiagnosticSeverity, LanguageRegistry};
+    use language::{Diagnostic, DiagnosticEntry, DiagnosticSeverity, LanguageRegistry, PointUtf16};
     use project::FakeFs;
     use serde_json::json;
     use std::sync::Arc;
@@ -629,11 +629,12 @@ mod tests {
 
         worktree.update(&mut cx, |worktree, cx| {
             worktree
-                .update_diagnostics_from_provider(
+                .update_diagnostic_entries(
                     Arc::from("/test/main.rs".as_ref()),
+                    None,
                     vec![
                         DiagnosticEntry {
-                            range: 20..21,
+                            range: PointUtf16::new(1, 8)..PointUtf16::new(1, 9),
                             diagnostic: Diagnostic {
                                 message:
                                     "move occurs because `x` has type `Vec<char>`, which does not implement the `Copy` trait"
@@ -646,7 +647,7 @@ mod tests {
                             },
                         },
                         DiagnosticEntry {
-                            range: 40..41,
+                            range: PointUtf16::new(2, 8)..PointUtf16::new(2, 9),
                             diagnostic: Diagnostic {
                                 message:
                                     "move occurs because `y` has type `Vec<char>`, which does not implement the `Copy` trait"
@@ -659,7 +660,7 @@ mod tests {
                             },
                         },
                         DiagnosticEntry {
-                            range: 58..59,
+                            range: PointUtf16::new(3, 6)..PointUtf16::new(3, 7),
                             diagnostic: Diagnostic {
                                 message: "value moved here".to_string(),
                                 severity: DiagnosticSeverity::INFORMATION,
@@ -670,7 +671,7 @@ mod tests {
                             },
                         },
                         DiagnosticEntry {
-                            range: 68..69,
+                            range: PointUtf16::new(4, 6)..PointUtf16::new(4, 7),
                             diagnostic: Diagnostic {
                                 message: "value moved here".to_string(),
                                 severity: DiagnosticSeverity::INFORMATION,
@@ -681,7 +682,7 @@ mod tests {
                             },
                         },
                         DiagnosticEntry {
-                            range: 112..113,
+                            range: PointUtf16::new(7, 6)..PointUtf16::new(7, 7),
                             diagnostic: Diagnostic {
                                 message: "use of moved value".to_string(),
                                 severity: DiagnosticSeverity::ERROR,
@@ -692,7 +693,7 @@ mod tests {
                             },
                         },
                         DiagnosticEntry {
-                            range: 112..113,
+                            range: PointUtf16::new(7, 6)..PointUtf16::new(7, 7),
                             diagnostic: Diagnostic {
                                 message: "value used here after move".to_string(),
                                 severity: DiagnosticSeverity::INFORMATION,
@@ -703,7 +704,7 @@ mod tests {
                             },
                         },
                         DiagnosticEntry {
-                            range: 122..123,
+                            range: PointUtf16::new(8, 6)..PointUtf16::new(8, 7),
                             diagnostic: Diagnostic {
                                 message: "use of moved value".to_string(),
                                 severity: DiagnosticSeverity::ERROR,
@@ -714,7 +715,7 @@ mod tests {
                             },
                         },
                         DiagnosticEntry {
-                            range: 122..123,
+                            range: PointUtf16::new(8, 6)..PointUtf16::new(8, 7),
                             diagnostic: Diagnostic {
                                 message: "value used here after move".to_string(),
                                 severity: DiagnosticSeverity::INFORMATION,
@@ -782,11 +783,12 @@ mod tests {
 
         worktree.update(&mut cx, |worktree, cx| {
             worktree
-                .update_diagnostics_from_provider(
+                .update_diagnostic_entries(
                     Arc::from("/test/a.rs".as_ref()),
+                    None,
                     vec![
                         DiagnosticEntry {
-                            range: 15..15,
+                            range: PointUtf16::new(0, 15)..PointUtf16::new(0, 15),
                             diagnostic: Diagnostic {
                                 message: "mismatched types".to_string(),
                                 severity: DiagnosticSeverity::ERROR,
@@ -797,7 +799,7 @@ mod tests {
                             },
                         },
                         DiagnosticEntry {
-                            range: 15..15,
+                            range: PointUtf16::new(0, 15)..PointUtf16::new(0, 15),
                             diagnostic: Diagnostic {
                                 message: "expected `usize`, found `char`".to_string(),
                                 severity: DiagnosticSeverity::INFORMATION,

crates/editor/src/editor.rs 🔗

@@ -2857,19 +2857,19 @@ impl Editor {
         loop {
             let next_group = buffer
                 .diagnostics_in_range::<_, usize>(search_start..buffer.len())
-                .find_map(|(provider_name, entry)| {
+                .find_map(|entry| {
                     if entry.diagnostic.is_primary
                         && !entry.range.is_empty()
                         && Some(entry.range.end) != active_primary_range.as_ref().map(|r| *r.end())
                     {
-                        Some((provider_name, entry.range, entry.diagnostic.group_id))
+                        Some((entry.range, entry.diagnostic.group_id))
                     } else {
                         None
                     }
                 });
 
-            if let Some((provider_name, primary_range, group_id)) = next_group {
-                self.activate_diagnostics(provider_name, group_id, cx);
+            if let Some((primary_range, group_id)) = next_group {
+                self.activate_diagnostics(group_id, cx);
                 self.update_selections(
                     vec![Selection {
                         id: selection.id,
@@ -2897,7 +2897,7 @@ impl Editor {
             let primary_range_start = active_diagnostics.primary_range.start.to_offset(&buffer);
             let is_valid = buffer
                 .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone())
-                .any(|(_, entry)| {
+                .any(|entry| {
                     entry.diagnostic.is_primary
                         && !entry.range.is_empty()
                         && entry.range.start == primary_range_start
@@ -2923,12 +2923,7 @@ impl Editor {
         }
     }
 
-    fn activate_diagnostics(
-        &mut self,
-        provider_name: &str,
-        group_id: usize,
-        cx: &mut ViewContext<Self>,
-    ) {
+    fn activate_diagnostics(&mut self, group_id: usize, cx: &mut ViewContext<Self>) {
         self.dismiss_diagnostics(cx);
         self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
             let buffer = self.buffer.read(cx).snapshot(cx);
@@ -2937,7 +2932,7 @@ impl Editor {
             let mut primary_message = None;
             let mut group_end = Point::zero();
             let diagnostic_group = buffer
-                .diagnostic_group::<Point>(provider_name, group_id)
+                .diagnostic_group::<Point>(group_id)
                 .map(|entry| {
                     if entry.range.end > group_end {
                         group_end = entry.range.end;

crates/editor/src/items.rs 🔗

@@ -298,9 +298,9 @@ impl DiagnosticMessage {
         let new_diagnostic = buffer
             .read(cx)
             .diagnostics_in_range::<_, usize>(cursor_position..cursor_position)
-            .filter(|(_, entry)| !entry.range.is_empty())
-            .min_by_key(|(_, entry)| (entry.diagnostic.severity, entry.range.len()))
-            .map(|(_, entry)| entry.diagnostic);
+            .filter(|entry| !entry.range.is_empty())
+            .min_by_key(|entry| (entry.diagnostic.severity, entry.range.len()))
+            .map(|entry| entry.diagnostic);
         if new_diagnostic != self.diagnostic {
             self.diagnostic = new_diagnostic;
             cx.notify();

crates/editor/src/multi_buffer.rs 🔗

@@ -1487,7 +1487,6 @@ impl MultiBufferSnapshot {
 
     pub fn diagnostic_group<'a, O>(
         &'a self,
-        provider_name: &'a str,
         group_id: usize,
     ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
     where
@@ -1495,13 +1494,13 @@ impl MultiBufferSnapshot {
     {
         self.as_singleton()
             .into_iter()
-            .flat_map(move |buffer| buffer.diagnostic_group(provider_name, group_id))
+            .flat_map(move |buffer| buffer.diagnostic_group(group_id))
     }
 
     pub fn diagnostics_in_range<'a, T, O>(
         &'a self,
         range: Range<T>,
-    ) -> impl Iterator<Item = (&'a str, DiagnosticEntry<O>)> + 'a
+    ) -> impl Iterator<Item = DiagnosticEntry<O>> + 'a
     where
         T: 'a + ToOffset,
         O: 'a + text::FromAnchor,

crates/language/src/buffer.rs 🔗

@@ -66,7 +66,7 @@ pub struct Buffer {
     parsing_in_background: bool,
     parse_count: usize,
     remote_selections: TreeMap<ReplicaId, Arc<[Selection<Anchor>]>>,
-    diagnostic_sets: Vec<DiagnosticSet>,
+    diagnostics: DiagnosticSet,
     diagnostics_update_count: usize,
     language_server: Option<LanguageServerState>,
     deferred_ops: OperationQueue<Operation>,
@@ -77,7 +77,7 @@ pub struct Buffer {
 pub struct BufferSnapshot {
     text: text::BufferSnapshot,
     tree: Option<Tree>,
-    diagnostic_sets: Vec<DiagnosticSet>,
+    diagnostics: DiagnosticSet,
     remote_selections: TreeMap<ReplicaId, Arc<[Selection<Anchor>]>>,
     diagnostics_update_count: usize,
     is_parsing: bool,
@@ -121,7 +121,6 @@ struct LanguageServerSnapshot {
 pub enum Operation {
     Buffer(text::Operation),
     UpdateDiagnostics {
-        provider_name: String,
         diagnostics: Arc<[DiagnosticEntry<Anchor>]>,
         lamport_timestamp: clock::Lamport,
     },
@@ -306,17 +305,11 @@ impl Buffer {
             );
         }
         let snapshot = this.snapshot();
-        for diagnostic_set in message.diagnostic_sets {
-            let (provider_name, entries) = proto::deserialize_diagnostic_set(diagnostic_set);
-            this.apply_diagnostic_update(
-                DiagnosticSet::from_sorted_entries(
-                    provider_name,
-                    entries.into_iter().cloned(),
-                    &snapshot,
-                ),
-                cx,
-            );
-        }
+        let entries = proto::deserialize_diagnostics(message.diagnostics);
+        this.apply_diagnostic_update(
+            DiagnosticSet::from_sorted_entries(entries.into_iter().cloned(), &snapshot),
+            cx,
+        );
 
         Ok(this)
     }
@@ -338,13 +331,7 @@ impl Buffer {
                     selections: proto::serialize_selections(selections),
                 })
                 .collect(),
-            diagnostic_sets: self
-                .diagnostic_sets
-                .iter()
-                .map(|set| {
-                    proto::serialize_diagnostic_set(set.provider_name().to_string(), set.iter())
-                })
-                .collect(),
+            diagnostics: proto::serialize_diagnostics(self.diagnostics.iter()),
         }
     }
 
@@ -379,7 +366,7 @@ impl Buffer {
             pending_autoindent: Default::default(),
             language: None,
             remote_selections: Default::default(),
-            diagnostic_sets: Default::default(),
+            diagnostics: Default::default(),
             diagnostics_update_count: 0,
             language_server: None,
             deferred_ops: OperationQueue::new(),
@@ -393,7 +380,7 @@ impl Buffer {
             text: self.text.snapshot(),
             tree: self.syntax_tree(),
             remote_selections: self.remote_selections.clone(),
-            diagnostic_sets: self.diagnostic_sets.clone(),
+            diagnostics: self.diagnostics.clone(),
             diagnostics_update_count: self.diagnostics_update_count,
             is_parsing: self.parsing_in_background,
             language: self.language.clone(),
@@ -743,7 +730,6 @@ impl Buffer {
 
     pub fn update_diagnostics<T>(
         &mut self,
-        provider_name: Arc<str>,
         version: Option<i32>,
         mut diagnostics: Vec<DiagnosticEntry<T>>,
         cx: &mut ModelContext<Self>,
@@ -833,10 +819,9 @@ impl Buffer {
         }
         drop(edits_since_save);
 
-        let set = DiagnosticSet::new(provider_name, sanitized_diagnostics, content);
+        let set = DiagnosticSet::new(sanitized_diagnostics, content);
         self.apply_diagnostic_update(set.clone(), cx);
         Ok(Operation::UpdateDiagnostics {
-            provider_name: set.provider_name().to_string(),
             diagnostics: set.iter().cloned().collect(),
             lamport_timestamp: self.text.lamport_clock.tick(),
         })
@@ -1347,17 +1332,12 @@ impl Buffer {
                 unreachable!("buffer operations should never be applied at this layer")
             }
             Operation::UpdateDiagnostics {
-                provider_name,
                 diagnostics: diagnostic_set,
                 ..
             } => {
                 let snapshot = self.snapshot();
                 self.apply_diagnostic_update(
-                    DiagnosticSet::from_sorted_entries(
-                        provider_name,
-                        diagnostic_set.iter().cloned(),
-                        &snapshot,
-                    ),
+                    DiagnosticSet::from_sorted_entries(diagnostic_set.iter().cloned(), &snapshot),
                     cx,
                 );
             }
@@ -1379,15 +1359,8 @@ impl Buffer {
         }
     }
 
-    fn apply_diagnostic_update(&mut self, set: DiagnosticSet, cx: &mut ModelContext<Self>) {
-        match self
-            .diagnostic_sets
-            .binary_search_by_key(&set.provider_name(), |set| set.provider_name())
-        {
-            Ok(ix) => self.diagnostic_sets[ix] = set.clone(),
-            Err(ix) => self.diagnostic_sets.insert(ix, set.clone()),
-        }
-
+    fn apply_diagnostic_update(&mut self, diagnostics: DiagnosticSet, cx: &mut ModelContext<Self>) {
+        self.diagnostics = diagnostics;
         self.diagnostics_update_count += 1;
         cx.notify();
         cx.emit(Event::DiagnosticsUpdated);
@@ -1625,7 +1598,7 @@ impl BufferSnapshot {
         let mut highlights = None;
         let mut diagnostic_endpoints = Vec::<DiagnosticEndpoint>::new();
         if let Some(theme) = theme {
-            for (_, entry) in self.diagnostics_in_range::<_, usize>(range.clone()) {
+            for entry in self.diagnostics_in_range::<_, usize>(range.clone()) {
                 diagnostic_endpoints.push(DiagnosticEndpoint {
                     offset: entry.range.start,
                     is_start: true,
@@ -1756,38 +1729,28 @@ impl BufferSnapshot {
     pub fn diagnostics_in_range<'a, T, O>(
         &'a self,
         search_range: Range<T>,
-    ) -> impl 'a + Iterator<Item = (&'a str, DiagnosticEntry<O>)>
+    ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
     where
         T: 'a + Clone + ToOffset,
         O: 'a + FromAnchor,
     {
-        self.diagnostic_sets.iter().flat_map(move |set| {
-            set.range(search_range.clone(), self, true)
-                .map(|e| (set.provider_name(), e))
-        })
+        self.diagnostics.range(search_range.clone(), self, true)
     }
 
     pub fn diagnostic_groups(&self) -> Vec<DiagnosticGroup<Anchor>> {
         let mut groups = Vec::new();
-        for set in &self.diagnostic_sets {
-            set.groups(&mut groups, self);
-        }
+        self.diagnostics.groups(&mut groups, self);
         groups
     }
 
     pub fn diagnostic_group<'a, O>(
         &'a self,
-        provider_name: &str,
         group_id: usize,
     ) -> impl 'a + Iterator<Item = DiagnosticEntry<O>>
     where
         O: 'a + FromAnchor,
     {
-        self.diagnostic_sets
-            .iter()
-            .find(|s| s.provider_name() == provider_name)
-            .into_iter()
-            .flat_map(move |s| s.group(group_id, self))
+        self.diagnostics.group(group_id, self)
     }
 
     pub fn diagnostics_update_count(&self) -> usize {
@@ -1805,7 +1768,7 @@ impl Clone for BufferSnapshot {
             text: self.text.clone(),
             tree: self.tree.clone(),
             remote_selections: self.remote_selections.clone(),
-            diagnostic_sets: self.diagnostic_sets.clone(),
+            diagnostics: self.diagnostics.clone(),
             diagnostics_update_count: self.diagnostics_update_count,
             is_parsing: self.is_parsing,
             language: self.language.clone(),

crates/language/src/diagnostic_set.rs 🔗

@@ -4,14 +4,12 @@ use std::{
     cmp::{Ordering, Reverse},
     iter,
     ops::Range,
-    sync::Arc,
 };
 use sum_tree::{self, Bias, SumTree};
 use text::{Anchor, FromAnchor, Point, ToOffset};
 
 #[derive(Clone, Debug)]
 pub struct DiagnosticSet {
-    provider_name: Arc<str>,
     diagnostics: SumTree<DiagnosticEntry<Anchor>>,
 }
 
@@ -36,32 +34,22 @@ pub struct Summary {
 }
 
 impl DiagnosticSet {
-    pub fn provider_name(&self) -> &str {
-        &self.provider_name
-    }
-
-    pub fn from_sorted_entries<I>(
-        provider_name: impl Into<Arc<str>>,
-        iter: I,
-        buffer: &text::BufferSnapshot,
-    ) -> Self
+    pub fn from_sorted_entries<I>(iter: I, buffer: &text::BufferSnapshot) -> Self
     where
         I: IntoIterator<Item = DiagnosticEntry<Anchor>>,
     {
         Self {
-            provider_name: provider_name.into(),
             diagnostics: SumTree::from_iter(iter, buffer),
         }
     }
 
-    pub fn new<I>(provider_name: Arc<str>, iter: I, buffer: &text::BufferSnapshot) -> Self
+    pub fn new<I>(iter: I, buffer: &text::BufferSnapshot) -> Self
     where
         I: IntoIterator<Item = DiagnosticEntry<Point>>,
     {
         let mut entries = iter.into_iter().collect::<Vec<_>>();
         entries.sort_unstable_by_key(|entry| (entry.range.start, Reverse(entry.range.end)));
         Self {
-            provider_name,
             diagnostics: SumTree::from_iter(
                 entries.into_iter().map(|entry| DiagnosticEntry {
                     range: buffer.anchor_before(entry.range.start)
@@ -159,7 +147,6 @@ impl DiagnosticSet {
 impl Default for DiagnosticSet {
     fn default() -> Self {
         Self {
-            provider_name: "".into(),
             diagnostics: Default::default(),
         }
     }

crates/language/src/language.rs 🔗

@@ -6,10 +6,9 @@ pub mod proto;
 mod tests;
 
 use anyhow::{anyhow, Result};
-use async_trait::async_trait;
 pub use buffer::Operation;
 pub use buffer::*;
-use collections::{HashMap, HashSet};
+use collections::HashSet;
 pub use diagnostic_set::DiagnosticEntry;
 use gpui::AppContext;
 use highlight_map::HighlightMap;
@@ -60,18 +59,9 @@ pub struct BracketPair {
     pub newline: bool,
 }
 
-#[async_trait]
-pub trait DiagnosticProvider: 'static + Send + Sync {
-    async fn diagnose(
-        &self,
-        path: Arc<Path>,
-    ) -> Result<HashMap<Arc<Path>, Vec<DiagnosticEntry<usize>>>>;
-}
-
 pub struct Language {
     pub(crate) config: LanguageConfig,
     pub(crate) grammar: Option<Arc<Grammar>>,
-    pub(crate) diagnostic_provider: Option<Arc<dyn DiagnosticProvider>>,
 }
 
 pub struct Grammar {
@@ -136,7 +126,6 @@ impl Language {
                     highlight_map: Default::default(),
                 })
             }),
-            diagnostic_provider: None,
         }
     }
 
@@ -170,11 +159,6 @@ impl Language {
         Ok(self)
     }
 
-    pub fn with_diagnostic_provider(mut self, source: impl DiagnosticProvider) -> Self {
-        self.diagnostic_provider = Some(Arc::new(source));
-        self
-    }
-
     pub fn name(&self) -> &str {
         self.config.name.as_str()
     }
@@ -208,10 +192,6 @@ impl Language {
         }
     }
 
-    pub fn diagnostic_provider(&self) -> Option<&Arc<dyn DiagnosticProvider>> {
-        self.diagnostic_provider.as_ref()
-    }
-
     pub fn disk_based_diagnostic_sources(&self) -> Option<&HashSet<String>> {
         self.config
             .language_server

crates/language/src/proto.rs 🔗

@@ -57,16 +57,12 @@ pub fn serialize_operation(operation: &Operation) -> proto::Operation {
                 lamport_timestamp: lamport_timestamp.value,
             }),
             Operation::UpdateDiagnostics {
-                provider_name,
                 diagnostics,
                 lamport_timestamp,
-            } => proto::operation::Variant::UpdateDiagnosticSet(proto::UpdateDiagnosticSet {
+            } => proto::operation::Variant::UpdateDiagnostics(proto::UpdateDiagnostics {
                 replica_id: lamport_timestamp.replica_id as u32,
                 lamport_timestamp: lamport_timestamp.value,
-                diagnostic_set: Some(serialize_diagnostic_set(
-                    provider_name.clone(),
-                    diagnostics.iter(),
-                )),
+                diagnostics: serialize_diagnostics(diagnostics.iter()),
             }),
         }),
     }
@@ -103,33 +99,29 @@ pub fn serialize_selections(selections: &Arc<[Selection<Anchor>]>) -> Vec<proto:
         .collect()
 }
 
-pub fn serialize_diagnostic_set<'a>(
-    provider_name: String,
+pub fn serialize_diagnostics<'a>(
     diagnostics: impl IntoIterator<Item = &'a DiagnosticEntry<Anchor>>,
-) -> proto::DiagnosticSet {
-    proto::DiagnosticSet {
-        provider_name,
-        diagnostics: diagnostics
-            .into_iter()
-            .map(|entry| proto::Diagnostic {
-                start: Some(serialize_anchor(&entry.range.start)),
-                end: Some(serialize_anchor(&entry.range.end)),
-                message: entry.diagnostic.message.clone(),
-                severity: match entry.diagnostic.severity {
-                    DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
-                    DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
-                    DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
-                    DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
-                    _ => proto::diagnostic::Severity::None,
-                } 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(),
-                is_disk_based: entry.diagnostic.is_disk_based,
-            })
-            .collect(),
-    }
+) -> Vec<proto::Diagnostic> {
+    diagnostics
+        .into_iter()
+        .map(|entry| proto::Diagnostic {
+            start: Some(serialize_anchor(&entry.range.start)),
+            end: Some(serialize_anchor(&entry.range.end)),
+            message: entry.diagnostic.message.clone(),
+            severity: match entry.diagnostic.severity {
+                DiagnosticSeverity::ERROR => proto::diagnostic::Severity::Error,
+                DiagnosticSeverity::WARNING => proto::diagnostic::Severity::Warning,
+                DiagnosticSeverity::INFORMATION => proto::diagnostic::Severity::Information,
+                DiagnosticSeverity::HINT => proto::diagnostic::Severity::Hint,
+                _ => proto::diagnostic::Severity::None,
+            } 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(),
+            is_disk_based: entry.diagnostic.is_disk_based,
+        })
+        .collect()
 }
 
 fn serialize_anchor(anchor: &Anchor) -> proto::Anchor {
@@ -215,21 +207,13 @@ pub fn deserialize_operation(message: proto::Operation) -> Result<Operation> {
                     value: message.lamport_timestamp,
                 },
             },
-            proto::operation::Variant::UpdateDiagnosticSet(message) => {
-                let (provider_name, diagnostics) = deserialize_diagnostic_set(
-                    message
-                        .diagnostic_set
-                        .ok_or_else(|| anyhow!("missing diagnostic set"))?,
-                );
-                Operation::UpdateDiagnostics {
-                    provider_name,
-                    diagnostics,
-                    lamport_timestamp: clock::Lamport {
-                        replica_id: message.replica_id as ReplicaId,
-                        value: message.lamport_timestamp,
-                    },
-                }
-            }
+            proto::operation::Variant::UpdateDiagnostics(message) => Operation::UpdateDiagnostics {
+                diagnostics: deserialize_diagnostics(message.diagnostics),
+                lamport_timestamp: clock::Lamport {
+                    replica_id: message.replica_id as ReplicaId,
+                    value: message.lamport_timestamp,
+                },
+            },
         },
     )
 }
@@ -269,40 +253,32 @@ pub fn deserialize_selections(selections: Vec<proto::Selection>) -> Arc<[Selecti
     )
 }
 
-pub fn deserialize_diagnostic_set(
-    message: proto::DiagnosticSet,
-) -> (String, Arc<[DiagnosticEntry<Anchor>]>) {
-    (
-        message.provider_name,
-        message
-            .diagnostics
-            .into_iter()
-            .filter_map(|diagnostic| {
-                Some(DiagnosticEntry {
-                    range: deserialize_anchor(diagnostic.start?)?
-                        ..deserialize_anchor(diagnostic.end?)?,
-                    diagnostic: Diagnostic {
-                        severity: match proto::diagnostic::Severity::from_i32(diagnostic.severity)?
-                        {
-                            proto::diagnostic::Severity::Error => DiagnosticSeverity::ERROR,
-                            proto::diagnostic::Severity::Warning => DiagnosticSeverity::WARNING,
-                            proto::diagnostic::Severity::Information => {
-                                DiagnosticSeverity::INFORMATION
-                            }
-                            proto::diagnostic::Severity::Hint => DiagnosticSeverity::HINT,
-                            proto::diagnostic::Severity::None => return None,
-                        },
-                        message: diagnostic.message,
-                        group_id: diagnostic.group_id as usize,
-                        code: diagnostic.code,
-                        is_valid: diagnostic.is_valid,
-                        is_primary: diagnostic.is_primary,
-                        is_disk_based: diagnostic.is_disk_based,
+pub fn deserialize_diagnostics(
+    diagnostics: Vec<proto::Diagnostic>,
+) -> Arc<[DiagnosticEntry<Anchor>]> {
+    diagnostics
+        .into_iter()
+        .filter_map(|diagnostic| {
+            Some(DiagnosticEntry {
+                range: deserialize_anchor(diagnostic.start?)?..deserialize_anchor(diagnostic.end?)?,
+                diagnostic: Diagnostic {
+                    severity: match proto::diagnostic::Severity::from_i32(diagnostic.severity)? {
+                        proto::diagnostic::Severity::Error => DiagnosticSeverity::ERROR,
+                        proto::diagnostic::Severity::Warning => DiagnosticSeverity::WARNING,
+                        proto::diagnostic::Severity::Information => DiagnosticSeverity::INFORMATION,
+                        proto::diagnostic::Severity::Hint => DiagnosticSeverity::HINT,
+                        proto::diagnostic::Severity::None => return None,
                     },
-                })
+                    message: diagnostic.message,
+                    group_id: diagnostic.group_id as usize,
+                    code: diagnostic.code,
+                    is_valid: diagnostic.is_valid,
+                    is_primary: diagnostic.is_primary,
+                    is_disk_based: diagnostic.is_disk_based,
+                },
             })
-            .collect(),
-    )
+        })
+        .collect()
 }
 
 fn deserialize_anchor(anchor: proto::Anchor) -> Option<Anchor> {

crates/language/src/tests.rs 🔗

@@ -455,7 +455,6 @@ async fn test_diagnostics(mut cx: gpui::TestAppContext) {
         // Receive diagnostics for an earlier version of the buffer.
         buffer
             .update_diagnostics(
-                "lsp".into(),
                 Some(open_notification.text_document.version),
                 vec![
                     DiagnosticEntry {
@@ -503,34 +502,28 @@ async fn test_diagnostics(mut cx: gpui::TestAppContext) {
                 .diagnostics_in_range::<_, Point>(Point::new(3, 0)..Point::new(5, 0))
                 .collect::<Vec<_>>(),
             &[
-                (
-                    "lsp",
-                    DiagnosticEntry {
-                        range: Point::new(3, 9)..Point::new(3, 11),
-                        diagnostic: Diagnostic {
-                            severity: DiagnosticSeverity::ERROR,
-                            message: "undefined variable 'BB'".to_string(),
-                            is_disk_based: true,
-                            group_id: 1,
-                            is_primary: true,
-                            ..Default::default()
-                        },
-                    }
-                ),
-                (
-                    "lsp",
-                    DiagnosticEntry {
-                        range: Point::new(4, 9)..Point::new(4, 12),
-                        diagnostic: Diagnostic {
-                            severity: DiagnosticSeverity::ERROR,
-                            message: "undefined variable 'CCC'".to_string(),
-                            is_disk_based: true,
-                            group_id: 2,
-                            is_primary: true,
-                            ..Default::default()
-                        }
+                DiagnosticEntry {
+                    range: Point::new(3, 9)..Point::new(3, 11),
+                    diagnostic: Diagnostic {
+                        severity: DiagnosticSeverity::ERROR,
+                        message: "undefined variable 'BB'".to_string(),
+                        is_disk_based: true,
+                        group_id: 1,
+                        is_primary: true,
+                        ..Default::default()
+                    },
+                },
+                DiagnosticEntry {
+                    range: Point::new(4, 9)..Point::new(4, 12),
+                    diagnostic: Diagnostic {
+                        severity: DiagnosticSeverity::ERROR,
+                        message: "undefined variable 'CCC'".to_string(),
+                        is_disk_based: true,
+                        group_id: 2,
+                        is_primary: true,
+                        ..Default::default()
                     }
-                )
+                }
             ]
         );
         assert_eq!(
@@ -557,7 +550,6 @@ async fn test_diagnostics(mut cx: gpui::TestAppContext) {
         // Ensure overlapping diagnostics are highlighted correctly.
         buffer
             .update_diagnostics(
-                "lsp".into(),
                 Some(open_notification.text_document.version),
                 vec![
                     DiagnosticEntry {
@@ -591,33 +583,27 @@ async fn test_diagnostics(mut cx: gpui::TestAppContext) {
                 .diagnostics_in_range::<_, Point>(Point::new(2, 0)..Point::new(3, 0))
                 .collect::<Vec<_>>(),
             &[
-                (
-                    "lsp",
-                    DiagnosticEntry {
-                        range: Point::new(2, 9)..Point::new(2, 12),
-                        diagnostic: Diagnostic {
-                            severity: DiagnosticSeverity::WARNING,
-                            message: "unreachable statement".to_string(),
-                            group_id: 1,
-                            is_primary: true,
-                            ..Default::default()
-                        }
-                    }
-                ),
-                (
-                    "lsp",
-                    DiagnosticEntry {
-                        range: Point::new(2, 9)..Point::new(2, 10),
-                        diagnostic: Diagnostic {
-                            severity: DiagnosticSeverity::ERROR,
-                            message: "undefined variable 'A'".to_string(),
-                            is_disk_based: true,
-                            group_id: 0,
-                            is_primary: true,
-                            ..Default::default()
-                        },
+                DiagnosticEntry {
+                    range: Point::new(2, 9)..Point::new(2, 12),
+                    diagnostic: Diagnostic {
+                        severity: DiagnosticSeverity::WARNING,
+                        message: "unreachable statement".to_string(),
+                        group_id: 1,
+                        is_primary: true,
+                        ..Default::default()
                     }
-                )
+                },
+                DiagnosticEntry {
+                    range: Point::new(2, 9)..Point::new(2, 10),
+                    diagnostic: Diagnostic {
+                        severity: DiagnosticSeverity::ERROR,
+                        message: "undefined variable 'A'".to_string(),
+                        is_disk_based: true,
+                        group_id: 0,
+                        is_primary: true,
+                        ..Default::default()
+                    },
+                }
             ]
         );
         assert_eq!(
@@ -654,7 +640,6 @@ async fn test_diagnostics(mut cx: gpui::TestAppContext) {
     buffer.update(&mut cx, |buffer, cx| {
         buffer
             .update_diagnostics(
-                "lsp".into(),
                 Some(change_notification_2.text_document.version),
                 vec![
                     DiagnosticEntry {
@@ -689,34 +674,28 @@ async fn test_diagnostics(mut cx: gpui::TestAppContext) {
                 .diagnostics_in_range::<_, Point>(0..buffer.len())
                 .collect::<Vec<_>>(),
             &[
-                (
-                    "lsp",
-                    DiagnosticEntry {
-                        range: Point::new(2, 21)..Point::new(2, 22),
-                        diagnostic: Diagnostic {
-                            severity: DiagnosticSeverity::ERROR,
-                            message: "undefined variable 'A'".to_string(),
-                            is_disk_based: true,
-                            group_id: 0,
-                            is_primary: true,
-                            ..Default::default()
-                        }
+                DiagnosticEntry {
+                    range: Point::new(2, 21)..Point::new(2, 22),
+                    diagnostic: Diagnostic {
+                        severity: DiagnosticSeverity::ERROR,
+                        message: "undefined variable 'A'".to_string(),
+                        is_disk_based: true,
+                        group_id: 0,
+                        is_primary: true,
+                        ..Default::default()
                     }
-                ),
-                (
-                    "lsp",
-                    DiagnosticEntry {
-                        range: Point::new(3, 9)..Point::new(3, 11),
-                        diagnostic: Diagnostic {
-                            severity: DiagnosticSeverity::ERROR,
-                            message: "undefined variable 'BB'".to_string(),
-                            is_disk_based: true,
-                            group_id: 1,
-                            is_primary: true,
-                            ..Default::default()
-                        },
-                    }
-                )
+                },
+                DiagnosticEntry {
+                    range: Point::new(3, 9)..Point::new(3, 11),
+                    diagnostic: Diagnostic {
+                        severity: DiagnosticSeverity::ERROR,
+                        message: "undefined variable 'BB'".to_string(),
+                        is_disk_based: true,
+                        group_id: 1,
+                        is_primary: true,
+                        ..Default::default()
+                    },
+                }
             ]
         );
     });
@@ -735,7 +714,6 @@ async fn test_empty_diagnostic_ranges(mut cx: gpui::TestAppContext) {
         buffer.set_language(Some(Arc::new(rust_lang())), None, cx);
         buffer
             .update_diagnostics(
-                "lsp".into(),
                 None,
                 vec![
                     DiagnosticEntry {

crates/project/src/project.rs 🔗

@@ -18,7 +18,7 @@ use std::{
     path::Path,
     sync::{atomic::AtomicBool, Arc},
 };
-use util::{ResultExt, TryFutureExt as _};
+use util::TryFutureExt as _;
 
 pub use fs::*;
 pub use worktree::*;
@@ -475,10 +475,7 @@ impl Project {
 
     fn add_worktree(&mut self, worktree: ModelHandle<Worktree>, cx: &mut ModelContext<Self>) {
         cx.observe(&worktree, |_, _, cx| cx.notify()).detach();
-        cx.subscribe(&worktree, |this, worktree, event, cx| match event {
-            worktree::Event::LanguageRegistered => {
-                this.diagnose(cx);
-            }
+        cx.subscribe(&worktree, |_, worktree, event, cx| match event {
             worktree::Event::DiagnosticsUpdated(path) => {
                 cx.emit(Event::DiagnosticsUpdated(ProjectPath {
                     worktree_id: worktree.id(),
@@ -506,36 +503,6 @@ impl Project {
         }
     }
 
-    pub fn diagnose(&self, cx: &mut ModelContext<Self>) {
-        for worktree_handle in &self.worktrees {
-            if let Some(worktree) = worktree_handle.read(cx).as_local() {
-                for language in worktree.languages() {
-                    if let Some(provider) = language.diagnostic_provider().cloned() {
-                        let worktree_path = worktree.abs_path().clone();
-                        let worktree_handle = worktree_handle.downgrade();
-                        cx.spawn_weak(|_, mut cx| async move {
-                            let diagnostics = provider.diagnose(worktree_path).await.log_err()?;
-                            let worktree_handle = worktree_handle.upgrade(&cx)?;
-                            worktree_handle.update(&mut cx, |worktree, cx| {
-                                for (path, diagnostics) in diagnostics {
-                                    worktree
-                                        .update_diagnostics_from_provider(
-                                            path.into(),
-                                            diagnostics,
-                                            cx,
-                                        )
-                                        .log_err()?;
-                                }
-                                Some(())
-                            })
-                        })
-                        .detach();
-                    }
-                }
-            }
-        }
-    }
-
     pub fn diagnostic_summaries<'a>(
         &'a self,
         cx: &'a AppContext,

crates/project/src/worktree.rs 🔗

@@ -50,8 +50,6 @@ use util::{post_inc, ResultExt, TryFutureExt};
 
 lazy_static! {
     static ref GITIGNORE: &'static OsStr = OsStr::new(".gitignore");
-    static ref DIAGNOSTIC_PROVIDER_NAME: Arc<str> = Arc::from("diagnostic_source");
-    static ref LSP_PROVIDER_NAME: Arc<str> = Arc::from("lsp");
 }
 
 #[derive(Clone, Debug)]
@@ -68,7 +66,6 @@ pub enum Worktree {
 
 #[derive(Debug)]
 pub enum Event {
-    LanguageRegistered,
     DiagnosticsUpdated(Arc<Path>),
 }
 
@@ -675,7 +672,7 @@ impl Worktree {
         }
     }
 
-    pub fn update_diagnostics_from_lsp(
+    pub fn update_diagnostics(
         &mut self,
         mut params: lsp::PublishDiagnosticsParams,
         disk_based_sources: &HashSet<String>,
@@ -745,45 +742,16 @@ impl Worktree {
             })
             .collect::<Vec<_>>();
 
-        let this = self.as_local_mut().unwrap();
-        for buffer in this.open_buffers.values() {
-            if let Some(buffer) = buffer.upgrade(cx) {
-                if buffer
-                    .read(cx)
-                    .file()
-                    .map_or(false, |file| *file.path() == worktree_path)
-                {
-                    let (remote_id, operation) = buffer.update(cx, |buffer, cx| {
-                        (
-                            buffer.remote_id(),
-                            buffer.update_diagnostics(
-                                LSP_PROVIDER_NAME.clone(),
-                                params.version,
-                                diagnostics.clone(),
-                                cx,
-                            ),
-                        )
-                    });
-                    self.send_buffer_update(remote_id, operation?, cx);
-                    break;
-                }
-            }
-        }
-
-        let this = self.as_local_mut().unwrap();
-        this.diagnostic_summaries
-            .insert(worktree_path.clone(), DiagnosticSummary::new(&diagnostics));
-        this.lsp_diagnostics
-            .insert(worktree_path.clone(), diagnostics);
-        cx.emit(Event::DiagnosticsUpdated(worktree_path.clone()));
+        self.update_diagnostic_entries(worktree_path, params.version, diagnostics, cx)?;
         Ok(())
     }
 
-    pub fn update_diagnostics_from_provider(
+    pub fn update_diagnostic_entries(
         &mut self,
-        path: Arc<Path>,
-        diagnostics: Vec<DiagnosticEntry<usize>>,
-        cx: &mut ModelContext<Worktree>,
+        worktree_path: Arc<Path>,
+        version: Option<i32>,
+        diagnostics: Vec<DiagnosticEntry<PointUtf16>>,
+        cx: &mut ModelContext<Self>,
     ) -> Result<()> {
         let this = self.as_local_mut().unwrap();
         for buffer in this.open_buffers.values() {
@@ -791,17 +759,12 @@ impl Worktree {
                 if buffer
                     .read(cx)
                     .file()
-                    .map_or(false, |file| *file.path() == path)
+                    .map_or(false, |file| *file.path() == worktree_path)
                 {
                     let (remote_id, operation) = buffer.update(cx, |buffer, cx| {
                         (
                             buffer.remote_id(),
-                            buffer.update_diagnostics(
-                                DIAGNOSTIC_PROVIDER_NAME.clone(),
-                                None,
-                                diagnostics.clone(),
-                                cx,
-                            ),
+                            buffer.update_diagnostics(version, diagnostics.clone(), cx),
                         )
                     });
                     self.send_buffer_update(remote_id, operation?, cx);
@@ -812,9 +775,9 @@ impl Worktree {
 
         let this = self.as_local_mut().unwrap();
         this.diagnostic_summaries
-            .insert(path.clone(), DiagnosticSummary::new(&diagnostics));
-        this.provider_diagnostics.insert(path.clone(), diagnostics);
-        cx.emit(Event::DiagnosticsUpdated(path.clone()));
+            .insert(worktree_path.clone(), DiagnosticSummary::new(&diagnostics));
+        this.diagnostics.insert(worktree_path.clone(), diagnostics);
+        cx.emit(Event::DiagnosticsUpdated(worktree_path.clone()));
         Ok(())
     }
 
@@ -888,8 +851,7 @@ pub struct LocalWorktree {
     loading_buffers: LoadingBuffers,
     open_buffers: HashMap<usize, WeakModelHandle<Buffer>>,
     shared_buffers: HashMap<PeerId, HashMap<u64, ModelHandle<Buffer>>>,
-    lsp_diagnostics: HashMap<Arc<Path>, Vec<DiagnosticEntry<PointUtf16>>>,
-    provider_diagnostics: HashMap<Arc<Path>, Vec<DiagnosticEntry<usize>>>,
+    diagnostics: HashMap<Arc<Path>, Vec<DiagnosticEntry<PointUtf16>>>,
     diagnostic_summaries: BTreeMap<Arc<Path>, DiagnosticSummary>,
     queued_operations: Vec<(u64, Operation)>,
     language_registry: Arc<LanguageRegistry>,
@@ -997,8 +959,7 @@ impl LocalWorktree {
                 loading_buffers: Default::default(),
                 open_buffers: Default::default(),
                 shared_buffers: Default::default(),
-                lsp_diagnostics: Default::default(),
-                provider_diagnostics: Default::default(),
+                diagnostics: Default::default(),
                 diagnostic_summaries: Default::default(),
                 queued_operations: Default::default(),
                 language_registry: languages,
@@ -1061,7 +1022,6 @@ impl LocalWorktree {
     ) -> Option<Arc<LanguageServer>> {
         if !self.languages.iter().any(|l| Arc::ptr_eq(l, language)) {
             self.languages.push(language.clone());
-            cx.emit(Event::LanguageRegistered);
         }
 
         if let Some(server) = self.language_servers.get(language.name()) {
@@ -1087,7 +1047,7 @@ impl LocalWorktree {
                 while let Ok(diagnostics) = diagnostics_rx.recv().await {
                     if let Some(handle) = cx.read(|cx| this.upgrade(cx)) {
                         handle.update(&mut cx, |this, cx| {
-                            this.update_diagnostics_from_lsp(diagnostics, &disk_based_sources, cx)
+                            this.update_diagnostics(diagnostics, &disk_based_sources, cx)
                                 .log_err();
                         });
                     } else {
@@ -1138,35 +1098,25 @@ impl LocalWorktree {
                 .update(&mut cx, |t, cx| t.as_local().unwrap().load(&path, cx))
                 .await?;
 
-            let (lsp_diagnostics, provider_diagnostics, language, language_server) =
-                this.update(&mut cx, |this, cx| {
-                    let this = this.as_local_mut().unwrap();
-                    let lsp_diagnostics = this.lsp_diagnostics.remove(&path);
-                    let provider_diagnostics = this.provider_diagnostics.remove(&path);
-                    let language = this
-                        .language_registry
-                        .select_language(file.full_path())
-                        .cloned();
-                    let server = language
-                        .as_ref()
-                        .and_then(|language| this.register_language(language, cx));
-                    (lsp_diagnostics, provider_diagnostics, language, server)
-                });
+            let (diagnostics, language, language_server) = this.update(&mut cx, |this, cx| {
+                let this = this.as_local_mut().unwrap();
+                let diagnostics = this.diagnostics.remove(&path);
+                let language = this
+                    .language_registry
+                    .select_language(file.full_path())
+                    .cloned();
+                let server = language
+                    .as_ref()
+                    .and_then(|language| this.register_language(language, cx));
+                (diagnostics, language, server)
+            });
 
             let mut buffer_operations = Vec::new();
             let buffer = cx.add_model(|cx| {
                 let mut buffer = Buffer::from_file(0, contents, Box::new(file), cx);
                 buffer.set_language(language, language_server, cx);
-                if let Some(diagnostics) = lsp_diagnostics {
-                    let op = buffer
-                        .update_diagnostics(LSP_PROVIDER_NAME.clone(), None, diagnostics, cx)
-                        .unwrap();
-                    buffer_operations.push(op);
-                }
-                if let Some(diagnostics) = provider_diagnostics {
-                    let op = buffer
-                        .update_diagnostics(DIAGNOSTIC_PROVIDER_NAME.clone(), None, diagnostics, cx)
-                        .unwrap();
+                if let Some(diagnostics) = diagnostics {
+                    let op = buffer.update_diagnostics(None, diagnostics, cx).unwrap();
                     buffer_operations.push(op);
                 }
                 buffer
@@ -3739,19 +3689,16 @@ mod tests {
                 .collect::<Vec<_>>();
             assert_eq!(
                 diagnostics,
-                &[(
-                    LSP_PROVIDER_NAME.as_ref(),
-                    DiagnosticEntry {
-                        range: Point::new(0, 9)..Point::new(0, 10),
-                        diagnostic: Diagnostic {
-                            severity: lsp::DiagnosticSeverity::ERROR,
-                            message: "undefined variable 'A'".to_string(),
-                            group_id: 0,
-                            is_primary: true,
-                            ..Default::default()
-                        }
+                &[DiagnosticEntry {
+                    range: Point::new(0, 9)..Point::new(0, 10),
+                    diagnostic: Diagnostic {
+                        severity: lsp::DiagnosticSeverity::ERROR,
+                        message: "undefined variable 'A'".to_string(),
+                        group_id: 0,
+                        is_primary: true,
+                        ..Default::default()
                     }
-                )]
+                }]
             )
         });
     }
@@ -3896,7 +3843,7 @@ mod tests {
 
         worktree
             .update(&mut cx, |tree, cx| {
-                tree.update_diagnostics_from_lsp(message, &Default::default(), cx)
+                tree.update_diagnostics(message, &Default::default(), cx)
             })
             .unwrap();
         let buffer = buffer.read_with(&cx, |buffer, _| buffer.snapshot());
@@ -3906,78 +3853,61 @@ mod tests {
                 .diagnostics_in_range::<_, Point>(0..buffer.len())
                 .collect::<Vec<_>>(),
             &[
-                (
-                    LSP_PROVIDER_NAME.as_ref(),
-                    DiagnosticEntry {
-                        range: Point::new(1, 8)..Point::new(1, 9),
-                        diagnostic: Diagnostic {
-                            severity: DiagnosticSeverity::WARNING,
-                            message: "error 1".to_string(),
-                            group_id: 0,
-                            is_primary: true,
-                            ..Default::default()
-                        }
+                DiagnosticEntry {
+                    range: Point::new(1, 8)..Point::new(1, 9),
+                    diagnostic: Diagnostic {
+                        severity: DiagnosticSeverity::WARNING,
+                        message: "error 1".to_string(),
+                        group_id: 0,
+                        is_primary: true,
+                        ..Default::default()
                     }
-                ),
-                (
-                    LSP_PROVIDER_NAME.as_ref(),
-                    DiagnosticEntry {
-                        range: Point::new(1, 8)..Point::new(1, 9),
-                        diagnostic: Diagnostic {
-                            severity: DiagnosticSeverity::HINT,
-                            message: "error 1 hint 1".to_string(),
-                            group_id: 0,
-                            is_primary: false,
-                            ..Default::default()
-                        }
+                },
+                DiagnosticEntry {
+                    range: Point::new(1, 8)..Point::new(1, 9),
+                    diagnostic: Diagnostic {
+                        severity: DiagnosticSeverity::HINT,
+                        message: "error 1 hint 1".to_string(),
+                        group_id: 0,
+                        is_primary: false,
+                        ..Default::default()
                     }
-                ),
-                (
-                    LSP_PROVIDER_NAME.as_ref(),
-                    DiagnosticEntry {
-                        range: Point::new(1, 13)..Point::new(1, 15),
-                        diagnostic: Diagnostic {
-                            severity: DiagnosticSeverity::HINT,
-                            message: "error 2 hint 1".to_string(),
-                            group_id: 1,
-                            is_primary: false,
-                            ..Default::default()
-                        }
+                },
+                DiagnosticEntry {
+                    range: Point::new(1, 13)..Point::new(1, 15),
+                    diagnostic: Diagnostic {
+                        severity: DiagnosticSeverity::HINT,
+                        message: "error 2 hint 1".to_string(),
+                        group_id: 1,
+                        is_primary: false,
+                        ..Default::default()
                     }
-                ),
-                (
-                    LSP_PROVIDER_NAME.as_ref(),
-                    DiagnosticEntry {
-                        range: Point::new(1, 13)..Point::new(1, 15),
-                        diagnostic: Diagnostic {
-                            severity: DiagnosticSeverity::HINT,
-                            message: "error 2 hint 2".to_string(),
-                            group_id: 1,
-                            is_primary: false,
-                            ..Default::default()
-                        }
+                },
+                DiagnosticEntry {
+                    range: Point::new(1, 13)..Point::new(1, 15),
+                    diagnostic: Diagnostic {
+                        severity: DiagnosticSeverity::HINT,
+                        message: "error 2 hint 2".to_string(),
+                        group_id: 1,
+                        is_primary: false,
+                        ..Default::default()
                     }
-                ),
-                (
-                    LSP_PROVIDER_NAME.as_ref(),
-                    DiagnosticEntry {
-                        range: Point::new(2, 8)..Point::new(2, 17),
-                        diagnostic: Diagnostic {
-                            severity: DiagnosticSeverity::ERROR,
-                            message: "error 2".to_string(),
-                            group_id: 1,
-                            is_primary: true,
-                            ..Default::default()
-                        }
+                },
+                DiagnosticEntry {
+                    range: Point::new(2, 8)..Point::new(2, 17),
+                    diagnostic: Diagnostic {
+                        severity: DiagnosticSeverity::ERROR,
+                        message: "error 2".to_string(),
+                        group_id: 1,
+                        is_primary: true,
+                        ..Default::default()
                     }
-                )
+                }
             ]
         );
 
         assert_eq!(
-            buffer
-                .diagnostic_group::<Point>(&LSP_PROVIDER_NAME, 0)
-                .collect::<Vec<_>>(),
+            buffer.diagnostic_group::<Point>(0).collect::<Vec<_>>(),
             &[
                 DiagnosticEntry {
                     range: Point::new(1, 8)..Point::new(1, 9),
@@ -4002,9 +3932,7 @@ mod tests {
             ]
         );
         assert_eq!(
-            buffer
-                .diagnostic_group::<Point>(&LSP_PROVIDER_NAME, 1)
-                .collect::<Vec<_>>(),
+            buffer.diagnostic_group::<Point>(1).collect::<Vec<_>>(),
             &[
                 DiagnosticEntry {
                     range: Point::new(1, 13)..Point::new(1, 15),

crates/rpc/proto/zed.proto 🔗

@@ -265,7 +265,7 @@ message Buffer {
     string content = 2;
     repeated Operation.Edit history = 3;
     repeated SelectionSet selections = 4;
-    repeated DiagnosticSet diagnostic_sets = 5;
+    repeated Diagnostic diagnostics = 5;
 }
 
 message SelectionSet {
@@ -292,15 +292,10 @@ enum Bias {
     Right = 1;
 }
 
-message UpdateDiagnosticSet {
+message UpdateDiagnostics {
     uint32 replica_id = 1;
     uint32 lamport_timestamp = 2;
-    DiagnosticSet diagnostic_set = 3;
-}
-
-message DiagnosticSet {
-    string provider_name = 1;
-    repeated Diagnostic diagnostics = 2;
+    repeated Diagnostic diagnostics = 3;
 }
 
 message Diagnostic {
@@ -329,7 +324,7 @@ message Operation {
         Undo undo = 2;
         UpdateSelections update_selections = 3;
         RemoveSelections remove_selections = 4;
-        UpdateDiagnosticSet update_diagnostic_set = 5;
+        UpdateDiagnostics update_diagnostics = 5;
     }
 
     message Edit {

crates/rpc/src/peer.rs 🔗

@@ -401,7 +401,7 @@ mod tests {
                         content: "path/one content".to_string(),
                         history: vec![],
                         selections: vec![],
-                        diagnostic_sets: vec![],
+                        diagnostics: vec![],
                     }),
                 }
             );
@@ -424,7 +424,7 @@ mod tests {
                         content: "path/two content".to_string(),
                         history: vec![],
                         selections: vec![],
-                        diagnostic_sets: vec![],
+                        diagnostics: vec![],
                     }),
                 }
             );
@@ -455,7 +455,7 @@ mod tests {
                                         content: "path/one content".to_string(),
                                         history: vec![],
                                         selections: vec![],
-                                        diagnostic_sets: vec![],
+                                        diagnostics: vec![],
                                     }),
                                 }
                             }
@@ -467,7 +467,7 @@ mod tests {
                                         content: "path/two content".to_string(),
                                         history: vec![],
                                         selections: vec![],
-                                        diagnostic_sets: vec![],
+                                        diagnostics: vec![],
                                     }),
                                 }
                             }

crates/server/src/rpc.rs 🔗

@@ -1831,7 +1831,7 @@ mod tests {
                 buffer
                     .snapshot()
                     .diagnostics_in_range::<_, Point>(0..buffer.len())
-                    .map(|(_, entry)| entry)
+                    .map(|entry| entry)
                     .collect::<Vec<_>>(),
                 &[
                     DiagnosticEntry {

crates/workspace/src/workspace.rs 🔗

@@ -791,24 +791,16 @@ impl Workspace {
                                     {
                                         error!("failed to save item: {:?}, ", error);
                                     }
-
-                                    handle.update(&mut cx, |this, cx| {
-                                        this.project.update(cx, |project, cx| project.diagnose(cx))
-                                    });
                                 })
                                 .detach();
                             }
                         },
                     );
                 } else {
-                    cx.spawn(|this, mut cx| async move {
+                    cx.spawn(|_, mut cx| async move {
                         if let Err(error) = cx.update(|cx| item.save(cx)).unwrap().await {
                             error!("failed to save item: {:?}, ", error);
                         }
-
-                        this.update(&mut cx, |this, cx| {
-                            this.project.update(cx, |project, cx| project.diagnose(cx))
-                        });
                     })
                     .detach();
                 }
@@ -840,10 +832,6 @@ impl Workspace {
                             if let Err(error) = result {
                                 error!("failed to save item: {:?}, ", error);
                             }
-
-                            handle.update(&mut cx, |this, cx| {
-                                this.project.update(cx, |project, cx| project.diagnose(cx))
-                            });
                         })
                         .detach()
                     }

crates/zed/src/language.rs 🔗

@@ -7,184 +7,6 @@ use std::{str, sync::Arc};
 #[folder = "languages"]
 struct LanguageDir;
 
-mod rust {
-    use anyhow::Result;
-    use async_trait::async_trait;
-    use collections::{HashMap, HashSet};
-    use language::{Diagnostic, DiagnosticEntry, DiagnosticSeverity};
-    use parking_lot::Mutex;
-    use serde::Deserialize;
-    use serde_json::Deserializer;
-    use smol::process::Command;
-    use std::path::{Path, PathBuf};
-    use std::sync::Arc;
-
-    #[derive(Default)]
-    pub struct DiagnosticProvider {
-        reported_paths: Mutex<HashSet<Arc<Path>>>,
-    }
-
-    #[derive(Debug, Deserialize)]
-    struct Check {
-        message: CompilerMessage,
-    }
-
-    #[derive(Debug, Deserialize)]
-    struct CompilerMessage {
-        code: Option<ErrorCode>,
-        spans: Vec<Span>,
-        message: String,
-        level: ErrorLevel,
-        children: Vec<CompilerMessage>,
-    }
-
-    #[derive(Debug, Deserialize)]
-    enum ErrorLevel {
-        #[serde(rename = "warning")]
-        Warning,
-        #[serde(rename = "error")]
-        Error,
-        #[serde(rename = "help")]
-        Help,
-        #[serde(rename = "note")]
-        Note,
-    }
-
-    #[derive(Debug, Deserialize)]
-    struct ErrorCode {
-        code: String,
-    }
-
-    #[derive(Clone, Debug, Deserialize)]
-    struct Span {
-        is_primary: bool,
-        file_name: PathBuf,
-        byte_start: usize,
-        byte_end: usize,
-        expansion: Option<Box<Expansion>>,
-    }
-
-    #[derive(Clone, Debug, Deserialize)]
-    struct Expansion {
-        span: Span,
-    }
-
-    #[async_trait]
-    impl language::DiagnosticProvider for DiagnosticProvider {
-        async fn diagnose(
-            &self,
-            root_path: Arc<Path>,
-        ) -> Result<HashMap<Arc<Path>, Vec<DiagnosticEntry<usize>>>> {
-            let output = Command::new("cargo")
-                .arg("check")
-                .args(["--message-format", "json"])
-                .current_dir(&root_path)
-                .output()
-                .await?;
-
-            let mut group_id = 0;
-            let mut diagnostics_by_path = HashMap::default();
-            let mut new_reported_paths = HashSet::default();
-            for value in
-                Deserializer::from_slice(&output.stdout).into_iter::<&serde_json::value::RawValue>()
-            {
-                if let Ok(check) = serde_json::from_str::<Check>(value?.get()) {
-                    let check_severity = match check.message.level {
-                        ErrorLevel::Warning => DiagnosticSeverity::WARNING,
-                        ErrorLevel::Error => DiagnosticSeverity::ERROR,
-                        ErrorLevel::Help => DiagnosticSeverity::HINT,
-                        ErrorLevel::Note => DiagnosticSeverity::INFORMATION,
-                    };
-
-                    let mut primary_span = None;
-                    for mut span in check.message.spans {
-                        if let Some(mut expansion) = span.expansion {
-                            expansion.span.is_primary = span.is_primary;
-                            span = expansion.span;
-                        }
-
-                        let span_path: Arc<Path> = span.file_name.as_path().into();
-                        new_reported_paths.insert(span_path.clone());
-                        diagnostics_by_path
-                            .entry(span_path)
-                            .or_insert(Vec::new())
-                            .push(DiagnosticEntry {
-                                range: span.byte_start..span.byte_end,
-                                diagnostic: Diagnostic {
-                                    code: check.message.code.as_ref().map(|c| c.code.clone()),
-                                    severity: check_severity,
-                                    message: check.message.message.clone(),
-                                    group_id,
-                                    is_valid: true,
-                                    is_primary: span.is_primary,
-                                    is_disk_based: true,
-                                },
-                            });
-
-                        if span.is_primary {
-                            primary_span = Some(span);
-                        }
-                    }
-
-                    for mut child in check.message.children {
-                        if child.spans.is_empty() {
-                            if let Some(primary_span) = primary_span.clone() {
-                                child.spans.push(primary_span);
-                            }
-                        } else {
-                            // TODO
-                            continue;
-                        }
-
-                        let child_severity = match child.level {
-                            ErrorLevel::Warning => DiagnosticSeverity::WARNING,
-                            ErrorLevel::Error => DiagnosticSeverity::ERROR,
-                            ErrorLevel::Help => DiagnosticSeverity::HINT,
-                            ErrorLevel::Note => DiagnosticSeverity::INFORMATION,
-                        };
-
-                        for mut span in child.spans {
-                            if let Some(expansion) = span.expansion {
-                                span = expansion.span;
-                            }
-
-                            let span_path: Arc<Path> = span.file_name.as_path().into();
-                            new_reported_paths.insert(span_path.clone());
-                            diagnostics_by_path
-                                .entry(span_path)
-                                .or_insert(Vec::new())
-                                .push(DiagnosticEntry {
-                                    range: span.byte_start..span.byte_end,
-                                    diagnostic: Diagnostic {
-                                        code: child.code.as_ref().map(|c| c.code.clone()),
-                                        severity: child_severity,
-                                        message: child.message.clone(),
-                                        group_id,
-                                        is_valid: true,
-                                        is_primary: false,
-                                        is_disk_based: true,
-                                    },
-                                });
-                        }
-                    }
-
-                    group_id += 1;
-                }
-            }
-
-            let reported_paths = &mut *self.reported_paths.lock();
-            for old_reported_path in reported_paths.iter() {
-                if !diagnostics_by_path.contains_key(old_reported_path) {
-                    diagnostics_by_path.insert(old_reported_path.clone(), Default::default());
-                }
-            }
-            *reported_paths = new_reported_paths;
-
-            Ok(diagnostics_by_path)
-        }
-    }
-}
-
 pub fn build_language_registry() -> LanguageRegistry {
     let mut languages = LanguageRegistry::default();
     languages.add(Arc::new(rust()));
@@ -202,7 +24,6 @@ fn rust() -> Language {
         .unwrap()
         .with_indents_query(load_query("rust/indents.scm").as_ref())
         .unwrap()
-        .with_diagnostic_provider(rust::DiagnosticProvider::default())
 }
 
 fn markdown() -> Language {