Fix layout of diagnostic blocks (#3729)
Previously, all of the lines in a multi-line error message were painted on top of each other. I also simplified the logic for highlighting backtick-enclosed ranges in a diagnostic message.
This commit is contained in:
commit
71d17e268d
2 changed files with 75 additions and 76 deletions
|
@ -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))
|
||||
}),
|
||||
|
|
|
@ -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();
|
||||
let (text_without_backticks, code_ranges) = highlight_diagnostic_message(&diagnostic);
|
||||
|
||||
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}"))
|
||||
}
|
||||
|
||||
_ => 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<usize>,
|
||||
message: &str,
|
||||
) -> (String, Vec<usize>) {
|
||||
let mut message_without_backticks = String::new();
|
||||
let mut prev_offset = 0;
|
||||
let mut inside_block = false;
|
||||
let mut highlights = initial_highlights;
|
||||
for (match_ix, (offset, _)) in message
|
||||
.match_indices('`')
|
||||
.chain([(message.len(), "")])
|
||||
.enumerate()
|
||||
{
|
||||
message_without_backticks.push_str(&message[prev_offset..offset]);
|
||||
if inside_block {
|
||||
highlights.extend(prev_offset - match_ix..offset - match_ix);
|
||||
}
|
||||
pub fn highlight_diagnostic_message(diagnostic: &Diagnostic) -> (SharedString, Vec<Range<usize>>) {
|
||||
let mut text_without_backticks = String::new();
|
||||
let mut code_ranges = Vec::new();
|
||||
|
||||
inside_block = !inside_block;
|
||||
prev_offset = offset + 1;
|
||||
if let Some(source) = &diagnostic.source {
|
||||
text_without_backticks.push_str(&source);
|
||||
code_ranges.push(0..source.len());
|
||||
text_without_backticks.push_str(": ");
|
||||
}
|
||||
|
||||
(message_without_backticks, highlights)
|
||||
let mut prev_offset = 0;
|
||||
let mut in_code_block = false;
|
||||
for (ix, _) in diagnostic
|
||||
.message
|
||||
.match_indices('`')
|
||||
.chain([(diagnostic.message.len(), "")])
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
(text_without_backticks.into(), code_ranges)
|
||||
}
|
||||
|
||||
pub fn diagnostic_style(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue