Jump to primary diagnostic when clicking on header's jump icon
This commit is contained in:
parent
4f9c207425
commit
d180f7a2c3
2 changed files with 75 additions and 30 deletions
|
@ -8,12 +8,12 @@ use editor::{
|
||||||
highlight_diagnostic_message, Autoscroll, Editor, ExcerptId, MultiBuffer, ToOffset,
|
highlight_diagnostic_message, Autoscroll, Editor, ExcerptId, MultiBuffer, ToOffset,
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, elements::*, fonts::TextStyle, platform::CursorStyle, serde_json, AnyViewHandle,
|
actions, elements::*, fonts::TextStyle, impl_internal_actions, platform::CursorStyle,
|
||||||
AppContext, Entity, ModelHandle, MutableAppContext, RenderContext, Task, View, ViewContext,
|
serde_json, AnyViewHandle, AppContext, Entity, ModelHandle, MutableAppContext, RenderContext,
|
||||||
ViewHandle, WeakViewHandle,
|
Task, View, ViewContext, ViewHandle, WeakViewHandle,
|
||||||
};
|
};
|
||||||
use language::{
|
use language::{
|
||||||
Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection, SelectionGoal,
|
Bias, Buffer, DiagnosticEntry, DiagnosticSeverity, Point, Selection, SelectionGoal,
|
||||||
};
|
};
|
||||||
use project::{DiagnosticSummary, Project, ProjectPath};
|
use project::{DiagnosticSummary, Project, ProjectPath};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
@ -27,15 +27,18 @@ use std::{
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use util::TryFutureExt;
|
use util::{ResultExt, TryFutureExt};
|
||||||
use workspace::{ItemHandle as _, ItemNavHistory, Workspace};
|
use workspace::{ItemHandle as _, ItemNavHistory, Workspace};
|
||||||
|
|
||||||
actions!(diagnostics, [Deploy]);
|
actions!(diagnostics, [Deploy]);
|
||||||
|
|
||||||
|
impl_internal_actions!(diagnostics, [Jump]);
|
||||||
|
|
||||||
const CONTEXT_LINE_COUNT: u32 = 1;
|
const CONTEXT_LINE_COUNT: u32 = 1;
|
||||||
|
|
||||||
pub fn init(cx: &mut MutableAppContext) {
|
pub fn init(cx: &mut MutableAppContext) {
|
||||||
cx.add_action(ProjectDiagnosticsEditor::deploy);
|
cx.add_action(ProjectDiagnosticsEditor::deploy);
|
||||||
|
cx.add_action(ProjectDiagnosticsEditor::jump);
|
||||||
items::init(cx);
|
items::init(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +59,12 @@ struct PathState {
|
||||||
diagnostic_groups: Vec<DiagnosticGroupState>,
|
diagnostic_groups: Vec<DiagnosticGroupState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Jump {
|
||||||
|
path: ProjectPath,
|
||||||
|
range: Range<Point>,
|
||||||
|
}
|
||||||
|
|
||||||
struct DiagnosticGroupState {
|
struct DiagnosticGroupState {
|
||||||
primary_diagnostic: DiagnosticEntry<language::Anchor>,
|
primary_diagnostic: DiagnosticEntry<language::Anchor>,
|
||||||
primary_excerpt_ix: usize,
|
primary_excerpt_ix: usize,
|
||||||
|
@ -177,6 +186,24 @@ impl ProjectDiagnosticsEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn jump(workspace: &mut Workspace, action: &Jump, cx: &mut ViewContext<Workspace>) {
|
||||||
|
let editor = workspace.open_path(action.path.clone(), true, cx);
|
||||||
|
let range = action.range.clone();
|
||||||
|
cx.spawn_weak(|_, mut cx| async move {
|
||||||
|
let editor = editor.await.log_err()?.downcast::<Editor>()?;
|
||||||
|
editor.update(&mut cx, |editor, cx| {
|
||||||
|
let buffer = editor.buffer().read(cx).as_singleton()?;
|
||||||
|
let cursor = buffer.read(cx).clip_point(range.start, Bias::Left);
|
||||||
|
editor.change_selections(Some(Autoscroll::Newest), cx, |s| {
|
||||||
|
s.select_ranges([cursor..cursor]);
|
||||||
|
});
|
||||||
|
Some(())
|
||||||
|
})?;
|
||||||
|
Some(())
|
||||||
|
})
|
||||||
|
.detach()
|
||||||
|
}
|
||||||
|
|
||||||
fn update_excerpts(&mut self, cx: &mut ViewContext<Self>) {
|
fn update_excerpts(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
let paths = mem::take(&mut self.paths_to_update);
|
let paths = mem::take(&mut self.paths_to_update);
|
||||||
let project = self.project.clone();
|
let project = self.project.clone();
|
||||||
|
@ -311,14 +338,19 @@ 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].diagnostic.clone();
|
group.entries[group.primary_ix].resolve::<Point>(&snapshot);
|
||||||
primary.message =
|
primary.diagnostic.message = primary
|
||||||
primary.message.split('\n').next().unwrap().to_string();
|
.diagnostic
|
||||||
|
.message
|
||||||
|
.split('\n')
|
||||||
|
.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),
|
render: diagnostic_header_renderer(primary, path.clone()),
|
||||||
disposition: BlockDisposition::Above,
|
disposition: BlockDisposition::Above,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -575,17 +607,17 @@ impl workspace::Item for ProjectDiagnosticsEditor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock {
|
fn diagnostic_header_renderer(entry: DiagnosticEntry<Point>, path: ProjectPath) -> RenderBlock {
|
||||||
enum JumpIcon {}
|
enum JumpIcon {}
|
||||||
|
|
||||||
let (message, highlights) = highlight_diagnostic_message(&diagnostic.message);
|
let (message, highlights) = highlight_diagnostic_message(&entry.diagnostic.message);
|
||||||
Arc::new(move |cx| {
|
Arc::new(move |cx| {
|
||||||
let settings = cx.global::<Settings>();
|
let settings = cx.global::<Settings>();
|
||||||
let theme = &settings.theme.editor;
|
let theme = &settings.theme.editor;
|
||||||
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 diagnostic.severity == DiagnosticSeverity::ERROR {
|
let icon = if entry.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 {
|
||||||
|
@ -614,7 +646,7 @@ fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock {
|
||||||
.aligned()
|
.aligned()
|
||||||
.boxed(),
|
.boxed(),
|
||||||
)
|
)
|
||||||
.with_children(diagnostic.code.clone().map(|code| {
|
.with_children(entry.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)
|
||||||
|
@ -622,23 +654,34 @@ fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock {
|
||||||
.boxed()
|
.boxed()
|
||||||
}))
|
}))
|
||||||
.with_child(
|
.with_child(
|
||||||
MouseEventHandler::new::<JumpIcon, _, _>(0, cx, |state, _| {
|
MouseEventHandler::new::<JumpIcon, _, _>(
|
||||||
let style = style.jump_icon.style_for(state, false);
|
entry.diagnostic.group_id,
|
||||||
Svg::new("icons/jump.svg")
|
cx,
|
||||||
.with_color(style.color)
|
|state, _| {
|
||||||
.constrained()
|
let style = style.jump_icon.style_for(state, false);
|
||||||
.with_width(style.icon_width)
|
Svg::new("icons/jump.svg")
|
||||||
.aligned()
|
.with_color(style.color)
|
||||||
.contained()
|
.constrained()
|
||||||
.with_style(style.container)
|
.with_width(style.icon_width)
|
||||||
.constrained()
|
.aligned()
|
||||||
.with_width(style.button_width)
|
.contained()
|
||||||
.with_height(style.button_width)
|
.with_style(style.container)
|
||||||
.boxed()
|
.constrained()
|
||||||
})
|
.with_width(style.button_width)
|
||||||
|
.with_height(style.button_width)
|
||||||
|
.boxed()
|
||||||
|
},
|
||||||
|
)
|
||||||
.with_cursor_style(CursorStyle::PointingHand)
|
.with_cursor_style(CursorStyle::PointingHand)
|
||||||
.on_click(|_, _, cx| {
|
.on_click({
|
||||||
dbg!("click!");
|
let entry = entry.clone();
|
||||||
|
let path = path.clone();
|
||||||
|
move |_, _, cx| {
|
||||||
|
cx.dispatch_action(Jump {
|
||||||
|
path: path.clone(),
|
||||||
|
range: entry.range.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.aligned()
|
.aligned()
|
||||||
.flex_float()
|
.flex_float()
|
||||||
|
|
|
@ -299,7 +299,9 @@ impl Pane {
|
||||||
) -> Box<dyn ItemHandle> {
|
) -> Box<dyn ItemHandle> {
|
||||||
let existing_item = pane.update(cx, |pane, cx| {
|
let existing_item = pane.update(cx, |pane, cx| {
|
||||||
for (ix, item) in pane.items.iter().enumerate() {
|
for (ix, item) in pane.items.iter().enumerate() {
|
||||||
if item.project_entry_ids(cx).as_slice() == &[project_entry_id] {
|
if item.project_path(cx).is_some()
|
||||||
|
&& item.project_entry_ids(cx).as_slice() == &[project_entry_id]
|
||||||
|
{
|
||||||
let item = item.boxed_clone();
|
let item = item.boxed_clone();
|
||||||
pane.activate_item(ix, true, focus_item, cx);
|
pane.activate_item(ix, true, focus_item, cx);
|
||||||
return Some(item);
|
return Some(item);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue