Use anchors to jump to diagnostic whenever possible

This commit is contained in:
Antonio Scandurra 2022-06-02 09:30:07 +02:00
parent cc028cca78
commit 6979e67bed

View file

@ -13,7 +13,8 @@ use gpui::{
Task, View, ViewContext, ViewHandle, WeakViewHandle, Task, View, ViewContext, ViewHandle, WeakViewHandle,
}; };
use language::{ use language::{
Bias, Buffer, DiagnosticEntry, DiagnosticSeverity, Point, Selection, SelectionGoal, Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection,
SelectionGoal, ToPoint,
}; };
use project::{DiagnosticSummary, Project, ProjectPath}; use project::{DiagnosticSummary, Project, ProjectPath};
use serde_json::json; use serde_json::json;
@ -62,7 +63,8 @@ struct PathState {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct Jump { struct Jump {
path: ProjectPath, path: ProjectPath,
range: Range<Point>, position: Point,
anchor: Anchor,
} }
struct DiagnosticGroupState { struct DiagnosticGroupState {
@ -188,12 +190,18 @@ impl ProjectDiagnosticsEditor {
fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) { fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
let editor = workspace.open_path(action.path.clone(), true, cx); let editor = workspace.open_path(action.path.clone(), true, cx);
let range = action.range.clone(); let position = action.position;
let anchor = action.anchor;
cx.spawn_weak(|_, mut cx| async move { cx.spawn_weak(|_, mut cx| async move {
let editor = editor.await.log_err()?.downcast::<Editor>()?; let editor = editor.await.log_err()?.downcast::<Editor>()?;
editor.update(&mut cx, |editor, cx| { editor.update(&mut cx, |editor, cx| {
let buffer = editor.buffer().read(cx).as_singleton()?; let buffer = editor.buffer().read(cx).as_singleton()?;
let cursor = buffer.read(cx).clip_point(range.start, Bias::Left); let buffer = buffer.read(cx);
let cursor = if buffer.can_resolve(&anchor) {
anchor.to_point(buffer)
} else {
buffer.clip_point(position, Bias::Left)
};
editor.change_selections(Some(Autoscroll::Newest), cx, |s| { editor.change_selections(Some(Autoscroll::Newest), cx, |s| {
s.select_ranges([cursor..cursor]); s.select_ranges([cursor..cursor]);
}); });
@ -338,19 +346,21 @@ impl ProjectDiagnosticsEditor {
if is_first_excerpt_for_group { if is_first_excerpt_for_group {
is_first_excerpt_for_group = false; is_first_excerpt_for_group = false;
let mut primary = let mut primary =
group.entries[group.primary_ix].resolve::<Point>(&snapshot); group.entries[group.primary_ix].diagnostic.clone();
primary.diagnostic.message = primary let anchor = group.entries[group.primary_ix].range.start;
.diagnostic let position = anchor.to_point(&snapshot);
.message primary.message =
.split('\n') primary.message.split('\n').next().unwrap().to_string();
.next()
.unwrap()
.to_string();
group_state.block_count += 1; group_state.block_count += 1;
blocks_to_add.push(BlockProperties { blocks_to_add.push(BlockProperties {
position: header_position, position: header_position,
height: 2, height: 2,
render: diagnostic_header_renderer(primary, path.clone()), render: diagnostic_header_renderer(
primary,
path.clone(),
position,
anchor,
),
disposition: BlockDisposition::Above, disposition: BlockDisposition::Above,
}); });
} }
@ -607,10 +617,15 @@ impl workspace::Item for ProjectDiagnosticsEditor {
} }
} }
fn diagnostic_header_renderer(entry: DiagnosticEntry<Point>, path: ProjectPath) -> RenderBlock { fn diagnostic_header_renderer(
diagnostic: Diagnostic,
path: ProjectPath,
position: Point,
anchor: Anchor,
) -> RenderBlock {
enum JumpIcon {} enum JumpIcon {}
let (message, highlights) = highlight_diagnostic_message(&entry.diagnostic.message); let (message, highlights) = highlight_diagnostic_message(&diagnostic.message);
Arc::new(move |cx| { Arc::new(move |cx| {
let settings = cx.global::<Settings>(); let settings = cx.global::<Settings>();
let tooltip_style = settings.theme.tooltip.clone(); let tooltip_style = settings.theme.tooltip.clone();
@ -618,7 +633,7 @@ fn diagnostic_header_renderer(entry: DiagnosticEntry<Point>, path: ProjectPath)
let style = theme.diagnostic_header.clone(); let style = theme.diagnostic_header.clone();
let font_size = (style.text_scale_factor * settings.buffer_font_size).round(); let font_size = (style.text_scale_factor * settings.buffer_font_size).round();
let icon_width = cx.em_width * style.icon_width_factor; let icon_width = cx.em_width * style.icon_width_factor;
let icon = if entry.diagnostic.severity == DiagnosticSeverity::ERROR { let icon = if diagnostic.severity == DiagnosticSeverity::ERROR {
Svg::new("icons/diagnostic-error-10.svg") Svg::new("icons/diagnostic-error-10.svg")
.with_color(theme.error_diagnostic.message.text.color) .with_color(theme.error_diagnostic.message.text.color)
} else { } else {
@ -647,7 +662,7 @@ fn diagnostic_header_renderer(entry: DiagnosticEntry<Point>, path: ProjectPath)
.aligned() .aligned()
.boxed(), .boxed(),
) )
.with_children(entry.diagnostic.code.clone().map(|code| { .with_children(diagnostic.code.clone().map(|code| {
Label::new(code, style.code.text.clone().with_font_size(font_size)) Label::new(code, style.code.text.clone().with_font_size(font_size))
.contained() .contained()
.with_style(style.code.container) .with_style(style.code.container)
@ -655,37 +670,33 @@ fn diagnostic_header_renderer(entry: DiagnosticEntry<Point>, path: ProjectPath)
.boxed() .boxed()
})) }))
.with_child( .with_child(
MouseEventHandler::new::<JumpIcon, _, _>( MouseEventHandler::new::<JumpIcon, _, _>(diagnostic.group_id, cx, |state, _| {
entry.diagnostic.group_id, let style = style.jump_icon.style_for(state, false);
cx, Svg::new("icons/jump.svg")
|state, _| { .with_color(style.color)
let style = style.jump_icon.style_for(state, false); .constrained()
Svg::new("icons/jump.svg") .with_width(style.icon_width)
.with_color(style.color) .aligned()
.constrained() .contained()
.with_width(style.icon_width) .with_style(style.container)
.aligned() .constrained()
.contained() .with_width(style.button_width)
.with_style(style.container) .with_height(style.button_width)
.constrained() .boxed()
.with_width(style.button_width) })
.with_height(style.button_width)
.boxed()
},
)
.with_cursor_style(CursorStyle::PointingHand) .with_cursor_style(CursorStyle::PointingHand)
.on_click({ .on_click({
let entry = entry.clone();
let path = path.clone(); let path = path.clone();
move |_, _, cx| { move |_, _, cx| {
cx.dispatch_action(Jump { cx.dispatch_action(Jump {
path: path.clone(), path: path.clone(),
range: entry.range.clone(), position,
anchor,
}); });
} }
}) })
.with_tooltip( .with_tooltip(
entry.diagnostic.group_id, diagnostic.group_id,
"Jump to diagnostic".to_string(), "Jump to diagnostic".to_string(),
Some(Box::new(editor::OpenExcerpts)), Some(Box::new(editor::OpenExcerpts)),
tooltip_style, tooltip_style,