Show source of diagnostic hovers

Julia created

Change summary

crates/editor/src/hover_popover.rs   | 18 +++++++++++++++---
crates/language/src/buffer.rs        |  2 ++
crates/language/src/proto.rs         |  2 ++
crates/project/src/project.rs        |  2 ++
crates/rpc/proto/zed.proto           | 17 +++++++++--------
crates/rpc/src/rpc.rs                |  2 +-
crates/theme/src/theme.rs            |  1 +
crates/zed/src/languages.rs          | 23 +++++++++++++----------
styles/src/styleTree/hoverPopover.ts |  5 +++--
9 files changed, 48 insertions(+), 24 deletions(-)

Detailed changes

crates/editor/src/hover_popover.rs 🔗

@@ -1,7 +1,7 @@
 use futures::FutureExt;
 use gpui::{
     actions,
-    elements::{Flex, MouseEventHandler, Padding, Text},
+    elements::{Flex, MouseEventHandler, Padding, ParentElement, Text},
     impl_internal_actions,
     platform::{CursorStyle, MouseButton},
     AnyElement, AppContext, Axis, Element, ModelHandle, Task, ViewContext,
@@ -378,6 +378,8 @@ impl DiagnosticPopover {
 
         let mut text_style = style.hover_popover.prose.clone();
         text_style.font_size = style.text.font_size;
+        let mut diagnostic_source_style = style.hover_popover.diagnostic_source.clone();
+        diagnostic_source_style.font_size = style.text.font_size;
 
         let container_style = match self.local_diagnostic.diagnostic.severity {
             DiagnosticSeverity::HINT => style.hover_popover.info_container,
@@ -390,8 +392,18 @@ impl DiagnosticPopover {
         let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
 
         MouseEventHandler::<DiagnosticPopover, _>::new(0, cx, |_, _| {
-            Text::new(self.local_diagnostic.diagnostic.message.clone(), text_style)
-                .with_soft_wrap(true)
+            Flex::row()
+                .with_children(
+                    self.local_diagnostic
+                        .diagnostic
+                        .source
+                        .as_ref()
+                        .map(|source| Text::new(format!("{source}: "), diagnostic_source_style)),
+                )
+                .with_child(
+                    Text::new(self.local_diagnostic.diagnostic.message.clone(), text_style)
+                        .with_soft_wrap(true),
+                )
                 .contained()
                 .with_style(container_style)
         })

crates/language/src/buffer.rs 🔗

@@ -138,6 +138,7 @@ pub struct GroupId {
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct Diagnostic {
+    pub source: Option<String>,
     pub code: Option<String>,
     pub severity: DiagnosticSeverity,
     pub message: String,
@@ -2881,6 +2882,7 @@ impl operation_queue::Operation for Operation {
 impl Default for Diagnostic {
     fn default() -> Self {
         Self {
+            source: Default::default(),
             code: None,
             severity: DiagnosticSeverity::ERROR,
             message: Default::default(),

crates/language/src/proto.rs 🔗

@@ -173,6 +173,7 @@ pub fn serialize_diagnostics<'a>(
     diagnostics
         .into_iter()
         .map(|entry| proto::Diagnostic {
+            source: entry.diagnostic.source.clone(),
             start: Some(serialize_anchor(&entry.range.start)),
             end: Some(serialize_anchor(&entry.range.end)),
             message: entry.diagnostic.message.clone(),
@@ -359,6 +360,7 @@ pub fn deserialize_diagnostics(
             Some(DiagnosticEntry {
                 range: deserialize_anchor(diagnostic.start?)?..deserialize_anchor(diagnostic.end?)?,
                 diagnostic: Diagnostic {
+                    source: diagnostic.source,
                     severity: match proto::diagnostic::Severity::from_i32(diagnostic.severity)? {
                         proto::diagnostic::Severity::Error => DiagnosticSeverity::ERROR,
                         proto::diagnostic::Severity::Warning => DiagnosticSeverity::WARNING,

crates/project/src/project.rs 🔗

@@ -2954,6 +2954,7 @@ impl Project {
                 diagnostics.push(DiagnosticEntry {
                     range,
                     diagnostic: Diagnostic {
+                        source: diagnostic.source.clone(),
                         code: code.clone(),
                         severity: diagnostic.severity.unwrap_or(DiagnosticSeverity::ERROR),
                         message: diagnostic.message.clone(),
@@ -2971,6 +2972,7 @@ impl Project {
                             diagnostics.push(DiagnosticEntry {
                                 range,
                                 diagnostic: Diagnostic {
+                                    source: diagnostic.source.clone(),
                                     code: code.clone(),
                                     severity: DiagnosticSeverity::INFORMATION,
                                     message: info.message.clone(),

crates/rpc/proto/zed.proto 🔗

@@ -1049,14 +1049,15 @@ enum Bias {
 message Diagnostic {
     Anchor start = 1;
     Anchor end = 2;
-    Severity severity = 3;
-    string message = 4;
-    optional string code = 5;
-    uint64 group_id = 6;
-    bool is_primary = 7;
-    bool is_valid = 8;
-    bool is_disk_based = 9;
-    bool is_unnecessary = 10;
+    optional string source = 3;
+    Severity severity = 4;
+    string message = 5;
+    optional string code = 6;
+    uint64 group_id = 7;
+    bool is_primary = 8;
+    bool is_valid = 9;
+    bool is_disk_based = 10;
+    bool is_unnecessary = 11;
 
     enum Severity {
         None = 0;

crates/rpc/src/rpc.rs 🔗

@@ -6,4 +6,4 @@ pub use conn::Connection;
 pub use peer::*;
 mod macros;
 
-pub const PROTOCOL_VERSION: u32 = 52;
+pub const PROTOCOL_VERSION: u32 = 53;

crates/theme/src/theme.rs 🔗

@@ -887,6 +887,7 @@ pub struct HoverPopover {
     pub error_container: ContainerStyle,
     pub block_style: ContainerStyle,
     pub prose: TextStyle,
+    pub diagnostic_source: TextStyle,
     pub highlight: Color,
 }
 

crates/zed/src/languages.rs 🔗

@@ -89,23 +89,26 @@ pub fn init(
         (
             "tsx",
             tree_sitter_typescript::language_tsx(),
-            vec![adapter_arc(typescript::TypeScriptLspAdapter::new(
-                node_runtime.clone(),
-            ))],
+            vec![
+                adapter_arc(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
+                adapter_arc(typescript::EsLintLspAdapter::new(node_runtime.clone())),
+            ],
         ),
         (
             "typescript",
             tree_sitter_typescript::language_typescript(),
-            vec![adapter_arc(typescript::TypeScriptLspAdapter::new(
-                node_runtime.clone(),
-            ))],
+            vec![
+                adapter_arc(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
+                adapter_arc(typescript::EsLintLspAdapter::new(node_runtime.clone())),
+            ],
         ),
         (
             "javascript",
             tree_sitter_typescript::language_tsx(),
-            vec![adapter_arc(typescript::TypeScriptLspAdapter::new(
-                node_runtime.clone(),
-            ))],
+            vec![
+                adapter_arc(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
+                adapter_arc(typescript::EsLintLspAdapter::new(node_runtime.clone())),
+            ],
         ),
         (
             "html",
@@ -132,7 +135,7 @@ pub fn init(
         (
             "yaml",
             tree_sitter_yaml::language(),
-            vec![adapter_arc(yaml::YamlLspAdapter::new(node_runtime.clone()))],
+            vec![adapter_arc(yaml::YamlLspAdapter::new(node_runtime))],
         ),
     ];
 

styles/src/styleTree/hoverPopover.ts 🔗

@@ -1,5 +1,5 @@
 import { ColorScheme } from "../themes/common/colorScheme"
-import { background, border, text } from "./components"
+import { background, border, foreground, text } from "./components"
 
 export default function HoverPopover(colorScheme: ColorScheme) {
     let layer = colorScheme.middle
@@ -36,10 +36,11 @@ export default function HoverPopover(colorScheme: ColorScheme) {
             background: background(layer, "negative"),
             border: border(layer, "negative"),
         },
-        block_style: {
+        blockStyle: {
             padding: { top: 4 },
         },
         prose: text(layer, "sans", { size: "sm" }),
+        diagnosticSource: text(layer, "sans", { size: "sm", underline: true, color: foreground(layer, "accent") }),
         highlight: colorScheme.ramps.neutral(0.5).alpha(0.2).hex(), // TODO: blend was used here. Replace with something better
     }
 }