diff --git a/crates/diagnostics2/src/diagnostics.rs b/crates/diagnostics2/src/diagnostics.rs index 1001ed880e0a8495c38aa497130f64c6802a1bd6..8103231ede627616cd0c47b3f74125704c6fa5bf 100644 --- a/crates/diagnostics2/src/diagnostics.rs +++ b/crates/diagnostics2/src/diagnostics.rs @@ -14,9 +14,9 @@ use editor::{ use futures::future::try_join_all; use gpui::{ actions, div, AnyElement, AnyView, AppContext, Context, Div, EventEmitter, FocusHandle, - Focusable, FocusableView, InteractiveElement, IntoElement, Model, ParentElement, Render, - SharedString, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView, - WindowContext, + Focusable, FocusableView, HighlightStyle, InteractiveElement, IntoElement, Model, + ParentElement, Render, SharedString, Styled, StyledText, Subscription, Task, View, ViewContext, + VisualContext, WeakView, WindowContext, }; use language::{ Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection, @@ -36,7 +36,7 @@ use std::{ }; use theme::ActiveTheme; pub use toolbar_controls::ToolbarControls; -use ui::{h_stack, prelude::*, HighlightedLabel, Icon, IconElement, Label}; +use ui::{h_stack, prelude::*, Icon, IconElement, Label}; use util::TryFutureExt; use workspace::{ item::{BreadcrumbText, Item, ItemEvent, ItemHandle}, @@ -785,8 +785,10 @@ impl Item for ProjectDiagnosticsEditor { } fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock { - let (message, highlights) = highlight_diagnostic_message(Vec::new(), &diagnostic.message); - Arc::new(move |_| { + let (message, code_ranges) = highlight_diagnostic_message(&diagnostic); + let message: SharedString = message.into(); + Arc::new(move |cx| { + let highlight_style: HighlightStyle = cx.theme().colors().text_accent.into(); h_stack() .id("diagnostic header") .py_2() @@ -809,7 +811,14 @@ fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock { .child( h_stack() .gap_1() - .child(HighlightedLabel::new(message.clone(), highlights.clone())) + .child( + StyledText::new(message.clone()).with_highlights( + &cx.text_style(), + code_ranges + .iter() + .map(|range| (range.clone(), highlight_style)), + ), + ) .when_some(diagnostic.code.as_ref(), |stack, code| { stack.child(Label::new(format!("({code})")).color(Color::Muted)) }), diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 379c66df5765af6ded325df600c4e6b8bc805e0c..58f8e857a9a167219b5e1cdeec5a2bbb1b5b62f9 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -9719,90 +9719,80 @@ impl InvalidationRegion for SnippetState { } } -// impl Deref for EditorStyle { -// type Target = theme::Editor; - -// fn deref(&self) -> &Self::Target { -// &self.theme -// } -// } - pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> RenderBlock { - let mut highlighted_lines = Vec::new(); - - for (index, line) in diagnostic.message.lines().enumerate() { - let line = match &diagnostic.source { - Some(source) if index == 0 => { - let source_highlight = Vec::from_iter(0..source.len()); - highlight_diagnostic_message(source_highlight, &format!("{source}: {line}")) - } + let (text_without_backticks, code_ranges) = highlight_diagnostic_message(&diagnostic); - _ => highlight_diagnostic_message(Vec::new(), line), - }; - highlighted_lines.push(line); - } Arc::new(move |cx: &mut BlockContext| { - let copy_id: SharedString = format!("copy-{}", cx.block_id.clone()).to_string().into(); + let color = Some(cx.theme().colors().text_accent); + let group_id: SharedString = cx.block_id.to_string().into(); // TODO: Nate: We should tint the background of the block with the severity color // We need to extend the theme before we can do this - v_stack() + h_stack() .id(cx.block_id) + .group(group_id.clone()) .relative() + .pl(cx.anchor_x) .size_full() - .bg(gpui::red()) - .children(highlighted_lines.iter().map(|(line, highlights)| { - let group_id = cx.block_id.to_string(); - h_stack() - .group(group_id.clone()) - .gap_2() - .absolute() - .left(cx.anchor_x) - .px_1p5() - .child(HighlightedLabel::new(line.clone(), highlights.clone())) - .child( - div().z_index(1).child( - IconButton::new(copy_id.clone(), Icon::Copy) - .icon_color(Color::Muted) - .size(ButtonSize::Compact) - .style(ButtonStyle::Transparent) - .visible_on_hover(group_id) - .on_click(cx.listener({ - let message = diagnostic.message.clone(); - move |_, _, cx| { - cx.write_to_clipboard(ClipboardItem::new(message.clone())) - } - })) - .tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)), - ), - ) - })) + .gap_2() + .child( + StyledText::new(text_without_backticks.clone()).with_highlights( + &cx.text_style(), + code_ranges.iter().map(|range| { + ( + range.clone(), + HighlightStyle { + color, + ..Default::default() + }, + ) + }), + ), + ) + .child( + IconButton::new(("copy-block", cx.block_id), Icon::Copy) + .icon_color(Color::Muted) + .size(ButtonSize::Compact) + .style(ButtonStyle::Transparent) + .visible_on_hover(group_id) + .on_click(cx.listener({ + let message = diagnostic.message.clone(); + move |_, _, cx| cx.write_to_clipboard(ClipboardItem::new(message.clone())) + })) + .tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)), + ) .into_any_element() }) } -pub fn highlight_diagnostic_message( - initial_highlights: Vec, - message: &str, -) -> (String, Vec) { - let mut message_without_backticks = String::new(); +pub fn highlight_diagnostic_message(diagnostic: &Diagnostic) -> (SharedString, Vec>) { + let mut text_without_backticks = String::new(); + let mut code_ranges = Vec::new(); + + if let Some(source) = &diagnostic.source { + text_without_backticks.push_str(&source); + code_ranges.push(0..source.len()); + text_without_backticks.push_str(": "); + } + let mut prev_offset = 0; - let mut inside_block = false; - let mut highlights = initial_highlights; - for (match_ix, (offset, _)) in message + let mut in_code_block = false; + for (ix, _) in diagnostic + .message .match_indices('`') - .chain([(message.len(), "")]) - .enumerate() + .chain([(diagnostic.message.len(), "")]) { - message_without_backticks.push_str(&message[prev_offset..offset]); - if inside_block { - highlights.extend(prev_offset - match_ix..offset - match_ix); + let prev_len = text_without_backticks.len(); + text_without_backticks.push_str(&diagnostic.message[prev_offset..ix]); + prev_offset = ix + 1; + if in_code_block { + code_ranges.push(prev_len..text_without_backticks.len()); + in_code_block = false; + } else { + in_code_block = true; } - - inside_block = !inside_block; - prev_offset = offset + 1; } - (message_without_backticks, highlights) + (text_without_backticks.into(), code_ranges) } pub fn diagnostic_style(