Render basic diagnostic messages in project diagnostics view
Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
ad05c0cc7a
commit
e1a2897d53
4 changed files with 145 additions and 98 deletions
|
@ -1,10 +1,10 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use editor::{Editor, ExcerptProperties, MultiBuffer};
|
use editor::{diagnostic_style, Editor, ExcerptProperties, MultiBuffer};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
action, elements::*, keymap::Binding, AppContext, Entity, ModelContext, ModelHandle,
|
action, elements::*, keymap::Binding, AppContext, Entity, ModelHandle, MutableAppContext,
|
||||||
MutableAppContext, RenderContext, View, ViewContext, ViewHandle,
|
RenderContext, View, ViewContext, ViewHandle,
|
||||||
};
|
};
|
||||||
use language::Point;
|
use language::Point;
|
||||||
use postage::watch;
|
use postage::watch;
|
||||||
|
@ -19,16 +19,63 @@ pub fn init(cx: &mut MutableAppContext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProjectDiagnostics {
|
struct ProjectDiagnostics {
|
||||||
excerpts: ModelHandle<MultiBuffer>,
|
|
||||||
project: ModelHandle<Project>,
|
project: ModelHandle<Project>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProjectDiagnosticsEditor {
|
struct ProjectDiagnosticsEditor {
|
||||||
editor: ViewHandle<Editor>,
|
editor: ViewHandle<Editor>,
|
||||||
|
excerpts: ModelHandle<MultiBuffer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProjectDiagnostics {
|
impl ProjectDiagnostics {
|
||||||
fn new(project: ModelHandle<Project>, cx: &mut ModelContext<Self>) -> Self {
|
fn new(project: ModelHandle<Project>) -> Self {
|
||||||
|
Self { project }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Entity for ProjectDiagnostics {
|
||||||
|
type Event = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Entity for ProjectDiagnosticsEditor {
|
||||||
|
type Event = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl View for ProjectDiagnosticsEditor {
|
||||||
|
fn ui_name() -> &'static str {
|
||||||
|
"ProjectDiagnosticsEditor"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&mut self, _: &mut RenderContext<Self>) -> ElementBox {
|
||||||
|
ChildView::new(self.editor.id()).boxed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProjectDiagnosticsEditor {
|
||||||
|
fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) {
|
||||||
|
let diagnostics = cx.add_model(|_| ProjectDiagnostics::new(workspace.project().clone()));
|
||||||
|
workspace.add_item(diagnostics, cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl workspace::Item for ProjectDiagnostics {
|
||||||
|
type View = ProjectDiagnosticsEditor;
|
||||||
|
|
||||||
|
fn build_view(
|
||||||
|
handle: ModelHandle<Self>,
|
||||||
|
settings: watch::Receiver<workspace::Settings>,
|
||||||
|
cx: &mut ViewContext<Self::View>,
|
||||||
|
) -> Self::View {
|
||||||
|
let project = handle.read(cx).project.clone();
|
||||||
|
let excerpts = cx.add_model(|cx| MultiBuffer::new(project.read(cx).replica_id(cx)));
|
||||||
|
let editor = cx.add_view(|cx| {
|
||||||
|
Editor::for_buffer(
|
||||||
|
excerpts.clone(),
|
||||||
|
editor::settings_builder(excerpts.downgrade(), settings.clone()),
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
let project_paths = project
|
let project_paths = project
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.diagnostic_summaries(cx)
|
.diagnostic_summaries(cx)
|
||||||
|
@ -58,19 +105,35 @@ impl ProjectDiagnostics {
|
||||||
grouped_diagnostics.into_values().collect::<Vec<_>>();
|
grouped_diagnostics.into_values().collect::<Vec<_>>();
|
||||||
sorted_diagnostic_groups.sort_by_key(|group| group.0);
|
sorted_diagnostic_groups.sort_by_key(|group| group.0);
|
||||||
|
|
||||||
for diagnostic in snapshot.all_diagnostics::<Point>() {
|
for entry in snapshot.all_diagnostics::<Point>() {
|
||||||
this.update(&mut cx, |this, cx| {
|
this.update(&mut cx, |this, cx| {
|
||||||
this.excerpts.update(cx, |excerpts, cx| {
|
this.excerpts.update(cx, |excerpts, cx| {
|
||||||
excerpts.push_excerpt(
|
excerpts.push_excerpt(
|
||||||
ExcerptProperties {
|
ExcerptProperties {
|
||||||
buffer: &buffer,
|
buffer: &buffer,
|
||||||
range: diagnostic.range,
|
range: entry.range,
|
||||||
header_height: 1,
|
header_height: entry
|
||||||
|
.diagnostic
|
||||||
|
.message
|
||||||
|
.matches('\n')
|
||||||
|
.count()
|
||||||
|
as u8
|
||||||
|
+ 1,
|
||||||
render_header: Some(Arc::new({
|
render_header: Some(Arc::new({
|
||||||
let message = diagnostic.diagnostic.message.clone();
|
let message = entry.diagnostic.message.clone();
|
||||||
|
let settings = settings.clone();
|
||||||
|
|
||||||
move |_| {
|
move |_| {
|
||||||
Text::new(message.clone(), Default::default())
|
let editor_style = &settings.borrow().theme.editor;
|
||||||
.boxed()
|
let mut text_style = editor_style.text.clone();
|
||||||
|
text_style.color = diagnostic_style(
|
||||||
|
entry.diagnostic.severity,
|
||||||
|
true,
|
||||||
|
&editor_style,
|
||||||
|
)
|
||||||
|
.text;
|
||||||
|
|
||||||
|
Text::new(message.clone(), text_style).boxed()
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
},
|
},
|
||||||
|
@ -86,56 +149,7 @@ impl ProjectDiagnostics {
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
|
|
||||||
Self {
|
ProjectDiagnosticsEditor { editor, excerpts }
|
||||||
excerpts: cx.add_model(|cx| MultiBuffer::new(project.read(cx).replica_id(cx))),
|
|
||||||
project,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Entity for ProjectDiagnostics {
|
|
||||||
type Event = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Entity for ProjectDiagnosticsEditor {
|
|
||||||
type Event = ();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl View for ProjectDiagnosticsEditor {
|
|
||||||
fn ui_name() -> &'static str {
|
|
||||||
"ProjectDiagnosticsEditor"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
|
|
||||||
ChildView::new(self.editor.id()).boxed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ProjectDiagnosticsEditor {
|
|
||||||
fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Workspace>) {
|
|
||||||
let diagnostics =
|
|
||||||
cx.add_model(|cx| ProjectDiagnostics::new(workspace.project().clone(), cx));
|
|
||||||
workspace.add_item(diagnostics, cx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl workspace::Item for ProjectDiagnostics {
|
|
||||||
type View = ProjectDiagnosticsEditor;
|
|
||||||
|
|
||||||
fn build_view(
|
|
||||||
handle: ModelHandle<Self>,
|
|
||||||
settings: watch::Receiver<workspace::Settings>,
|
|
||||||
cx: &mut ViewContext<Self::View>,
|
|
||||||
) -> Self::View {
|
|
||||||
let excerpts = handle.read(cx).excerpts.clone();
|
|
||||||
let editor = cx.add_view(|cx| {
|
|
||||||
Editor::for_buffer(
|
|
||||||
excerpts.clone(),
|
|
||||||
editor::settings_builder(excerpts.downgrade(), settings),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
});
|
|
||||||
ProjectDiagnosticsEditor { editor }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn project_path(&self) -> Option<project::ProjectPath> {
|
fn project_path(&self) -> Option<project::ProjectPath> {
|
||||||
|
@ -148,22 +162,22 @@ impl workspace::ItemView for ProjectDiagnosticsEditor {
|
||||||
"Project Diagnostics".to_string()
|
"Project Diagnostics".to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn project_path(&self, cx: &AppContext) -> Option<project::ProjectPath> {
|
fn project_path(&self, _: &AppContext) -> Option<project::ProjectPath> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save(
|
fn save(
|
||||||
&mut self,
|
&mut self,
|
||||||
cx: &mut ViewContext<Self>,
|
_: &mut ViewContext<Self>,
|
||||||
) -> anyhow::Result<gpui::Task<anyhow::Result<()>>> {
|
) -> anyhow::Result<gpui::Task<anyhow::Result<()>>> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_as(
|
fn save_as(
|
||||||
&mut self,
|
&mut self,
|
||||||
worktree: ModelHandle<project::Worktree>,
|
_: ModelHandle<project::Worktree>,
|
||||||
path: &std::path::Path,
|
_: &std::path::Path,
|
||||||
cx: &mut ViewContext<Self>,
|
_: &mut ViewContext<Self>,
|
||||||
) -> gpui::Task<anyhow::Result<()>> {
|
) -> gpui::Task<anyhow::Result<()>> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,9 @@ mod fold_map;
|
||||||
mod tab_map;
|
mod tab_map;
|
||||||
mod wrap_map;
|
mod wrap_map;
|
||||||
|
|
||||||
use crate::{Anchor, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint};
|
use crate::{
|
||||||
|
multi_buffer::RenderHeaderFn, Anchor, MultiBuffer, MultiBufferSnapshot, ToOffset, ToPoint,
|
||||||
|
};
|
||||||
use block_map::{BlockMap, BlockPoint};
|
use block_map::{BlockMap, BlockPoint};
|
||||||
use fold_map::{FoldMap, ToFoldPoint as _};
|
use fold_map::{FoldMap, ToFoldPoint as _};
|
||||||
use gpui::{fonts::FontId, ElementBox, Entity, ModelContext, ModelHandle};
|
use gpui::{fonts::FontId, ElementBox, Entity, ModelContext, ModelHandle};
|
||||||
|
@ -327,6 +329,21 @@ impl DisplaySnapshot {
|
||||||
self.blocks_snapshot.blocks_in_range(rows)
|
self.blocks_snapshot.blocks_in_range(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn excerpt_headers_in_range<'a>(
|
||||||
|
&'a self,
|
||||||
|
rows: Range<u32>,
|
||||||
|
) -> impl 'a + Iterator<Item = (Range<u32>, RenderHeaderFn)> {
|
||||||
|
let start_row = DisplayPoint::new(rows.start, 0).to_point(self).row;
|
||||||
|
let end_row = DisplayPoint::new(rows.end, 0).to_point(self).row;
|
||||||
|
self.buffer_snapshot
|
||||||
|
.excerpt_headers_in_range(start_row..end_row)
|
||||||
|
.map(move |(rows, render)| {
|
||||||
|
let start_row = Point::new(rows.start, 0).to_display_point(self).row();
|
||||||
|
let end_row = Point::new(rows.end, 0).to_display_point(self).row();
|
||||||
|
(start_row..end_row, render)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn intersects_fold<T: ToOffset>(&self, offset: T) -> bool {
|
pub fn intersects_fold<T: ToOffset>(&self, offset: T) -> bool {
|
||||||
self.folds_snapshot.intersects_fold(offset)
|
self.folds_snapshot.intersects_fold(offset)
|
||||||
}
|
}
|
||||||
|
|
|
@ -590,11 +590,6 @@ impl Editor {
|
||||||
scroll_position.y() - self.scroll_top_anchor.to_display_point(&map).row() as f32,
|
scroll_position.y() - self.scroll_top_anchor.to_display_point(&map).row() as f32,
|
||||||
);
|
);
|
||||||
|
|
||||||
debug_assert_eq!(
|
|
||||||
compute_scroll_position(&map, self.scroll_position, &self.scroll_top_anchor),
|
|
||||||
scroll_position
|
|
||||||
);
|
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -631,34 +631,55 @@ impl EditorElement {
|
||||||
line_layouts: &[text_layout::Line],
|
line_layouts: &[text_layout::Line],
|
||||||
cx: &mut LayoutContext,
|
cx: &mut LayoutContext,
|
||||||
) -> Vec<(u32, ElementBox)> {
|
) -> Vec<(u32, ElementBox)> {
|
||||||
snapshot
|
let mut blocks = Vec::new();
|
||||||
.blocks_in_range(rows.clone())
|
|
||||||
.map(|(start_row, block)| {
|
|
||||||
let anchor_row = block
|
|
||||||
.position()
|
|
||||||
.to_point(&snapshot.buffer_snapshot)
|
|
||||||
.to_display_point(snapshot)
|
|
||||||
.row();
|
|
||||||
|
|
||||||
let anchor_x = if rows.contains(&anchor_row) {
|
blocks.extend(
|
||||||
line_layouts[(anchor_row - rows.start) as usize]
|
snapshot
|
||||||
.x_for_index(block.column() as usize)
|
.blocks_in_range(rows.clone())
|
||||||
} else {
|
.map(|(start_row, block)| {
|
||||||
layout_line(anchor_row, snapshot, style, cx.text_layout_cache)
|
let anchor_row = block
|
||||||
.x_for_index(block.column() as usize)
|
.position()
|
||||||
};
|
.to_point(&snapshot.buffer_snapshot)
|
||||||
|
.to_display_point(snapshot)
|
||||||
|
.row();
|
||||||
|
|
||||||
let mut element = block.render(&BlockContext { cx, anchor_x });
|
let anchor_x = if rows.contains(&anchor_row) {
|
||||||
element.layout(
|
line_layouts[(anchor_row - rows.start) as usize]
|
||||||
SizeConstraint {
|
.x_for_index(block.column() as usize)
|
||||||
min: Vector2F::zero(),
|
} else {
|
||||||
max: vec2f(text_width, block.height() as f32 * line_height),
|
layout_line(anchor_row, snapshot, style, cx.text_layout_cache)
|
||||||
},
|
.x_for_index(block.column() as usize)
|
||||||
cx,
|
};
|
||||||
);
|
|
||||||
(start_row, element)
|
let mut element = block.render(&BlockContext { cx, anchor_x });
|
||||||
})
|
element.layout(
|
||||||
.collect()
|
SizeConstraint {
|
||||||
|
min: Vector2F::zero(),
|
||||||
|
max: vec2f(text_width, block.height() as f32 * line_height),
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
(start_row, element)
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
blocks.extend(
|
||||||
|
snapshot
|
||||||
|
.excerpt_headers_in_range(rows.clone())
|
||||||
|
.map(|(rows, render)| {
|
||||||
|
let mut element = render(cx);
|
||||||
|
element.layout(
|
||||||
|
SizeConstraint {
|
||||||
|
min: Vector2F::zero(),
|
||||||
|
max: vec2f(text_width, rows.len() as f32 * line_height),
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
(rows.start, element)
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
blocks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue