Fix layout of diagnostic blocks
This commit is contained in:
parent
afd3bf7746
commit
3fccc648d6
2 changed files with 75 additions and 76 deletions
|
@ -14,9 +14,9 @@ use editor::{
|
||||||
use futures::future::try_join_all;
|
use futures::future::try_join_all;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, div, AnyElement, AnyView, AppContext, Context, Div, EventEmitter, FocusHandle,
|
actions, div, AnyElement, AnyView, AppContext, Context, Div, EventEmitter, FocusHandle,
|
||||||
Focusable, FocusableView, InteractiveElement, IntoElement, Model, ParentElement, Render,
|
Focusable, FocusableView, HighlightStyle, InteractiveElement, IntoElement, Model,
|
||||||
SharedString, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView,
|
ParentElement, Render, SharedString, Styled, StyledText, Subscription, Task, View, ViewContext,
|
||||||
WindowContext,
|
VisualContext, WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
use language::{
|
use language::{
|
||||||
Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection,
|
Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection,
|
||||||
|
@ -36,7 +36,7 @@ use std::{
|
||||||
};
|
};
|
||||||
use theme::ActiveTheme;
|
use theme::ActiveTheme;
|
||||||
pub use toolbar_controls::ToolbarControls;
|
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 util::TryFutureExt;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
item::{BreadcrumbText, Item, ItemEvent, ItemHandle},
|
item::{BreadcrumbText, Item, ItemEvent, ItemHandle},
|
||||||
|
@ -785,8 +785,10 @@ impl Item for ProjectDiagnosticsEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock {
|
fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock {
|
||||||
let (message, highlights) = highlight_diagnostic_message(Vec::new(), &diagnostic.message);
|
let (message, code_ranges) = highlight_diagnostic_message(&diagnostic);
|
||||||
Arc::new(move |_| {
|
let message: SharedString = message.into();
|
||||||
|
Arc::new(move |cx| {
|
||||||
|
let highlight_style: HighlightStyle = cx.theme().colors().text_accent.into();
|
||||||
h_stack()
|
h_stack()
|
||||||
.id("diagnostic header")
|
.id("diagnostic header")
|
||||||
.py_2()
|
.py_2()
|
||||||
|
@ -809,7 +811,14 @@ fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock {
|
||||||
.child(
|
.child(
|
||||||
h_stack()
|
h_stack()
|
||||||
.gap_1()
|
.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| {
|
.when_some(diagnostic.code.as_ref(), |stack, code| {
|
||||||
stack.child(Label::new(format!("({code})")).color(Color::Muted))
|
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 {
|
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| {
|
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
|
// 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
|
// We need to extend the theme before we can do this
|
||||||
v_stack()
|
h_stack()
|
||||||
.id(cx.block_id)
|
.id(cx.block_id)
|
||||||
|
.group(group_id.clone())
|
||||||
.relative()
|
.relative()
|
||||||
|
.pl(cx.anchor_x)
|
||||||
.size_full()
|
.size_full()
|
||||||
.bg(gpui::red())
|
.gap_2()
|
||||||
.children(highlighted_lines.iter().map(|(line, highlights)| {
|
.child(
|
||||||
let group_id = cx.block_id.to_string();
|
StyledText::new(text_without_backticks.clone()).with_highlights(
|
||||||
h_stack()
|
&cx.text_style(),
|
||||||
.group(group_id.clone())
|
code_ranges.iter().map(|range| {
|
||||||
.gap_2()
|
(
|
||||||
.absolute()
|
range.clone(),
|
||||||
.left(cx.anchor_x)
|
HighlightStyle {
|
||||||
.px_1p5()
|
color,
|
||||||
.child(HighlightedLabel::new(line.clone(), highlights.clone()))
|
..Default::default()
|
||||||
.child(
|
},
|
||||||
div().z_index(1).child(
|
)
|
||||||
IconButton::new(copy_id.clone(), Icon::Copy)
|
}),
|
||||||
.icon_color(Color::Muted)
|
),
|
||||||
.size(ButtonSize::Compact)
|
)
|
||||||
.style(ButtonStyle::Transparent)
|
.child(
|
||||||
.visible_on_hover(group_id)
|
IconButton::new(("copy-block", cx.block_id), Icon::Copy)
|
||||||
.on_click(cx.listener({
|
.icon_color(Color::Muted)
|
||||||
let message = diagnostic.message.clone();
|
.size(ButtonSize::Compact)
|
||||||
move |_, _, cx| {
|
.style(ButtonStyle::Transparent)
|
||||||
cx.write_to_clipboard(ClipboardItem::new(message.clone()))
|
.visible_on_hover(group_id)
|
||||||
}
|
.on_click(cx.listener({
|
||||||
}))
|
let message = diagnostic.message.clone();
|
||||||
.tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)),
|
move |_, _, cx| cx.write_to_clipboard(ClipboardItem::new(message.clone()))
|
||||||
),
|
}))
|
||||||
)
|
.tooltip(|cx| Tooltip::text("Copy diagnostic message", cx)),
|
||||||
}))
|
)
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn highlight_diagnostic_message(
|
pub fn highlight_diagnostic_message(diagnostic: &Diagnostic) -> (SharedString, Vec<Range<usize>>) {
|
||||||
initial_highlights: Vec<usize>,
|
let mut text_without_backticks = String::new();
|
||||||
message: &str,
|
let mut code_ranges = Vec::new();
|
||||||
) -> (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);
|
|
||||||
}
|
|
||||||
|
|
||||||
inside_block = !inside_block;
|
if let Some(source) = &diagnostic.source {
|
||||||
prev_offset = offset + 1;
|
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(
|
pub fn diagnostic_style(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue