Group diagnostics by primary
Render primary message above the excerpt and supporting messages as block decorations with a `Below` disposition. This is still super rough. Co-Authored-By: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
e1a2897d53
commit
6c5b27af1d
13 changed files with 204 additions and 97 deletions
|
@ -8,7 +8,7 @@ use crate::{
|
|||
};
|
||||
use block_map::{BlockMap, BlockPoint};
|
||||
use fold_map::{FoldMap, ToFoldPoint as _};
|
||||
use gpui::{fonts::FontId, ElementBox, Entity, ModelContext, ModelHandle};
|
||||
use gpui::{fonts::FontId, Entity, ModelContext, ModelHandle};
|
||||
use language::{Point, Subscription as BufferSubscription};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
|
@ -21,7 +21,7 @@ use wrap_map::WrapMap;
|
|||
|
||||
pub use block_map::{
|
||||
AlignedBlock, BlockBufferRows as DisplayBufferRows, BlockChunks as DisplayChunks, BlockContext,
|
||||
BlockDisposition, BlockId, BlockProperties,
|
||||
BlockDisposition, BlockId, BlockProperties, RenderBlock,
|
||||
};
|
||||
|
||||
pub trait ToDisplayPoint {
|
||||
|
@ -146,10 +146,7 @@ impl DisplayMap {
|
|||
block_map.insert(blocks)
|
||||
}
|
||||
|
||||
pub fn replace_blocks<F>(&mut self, styles: HashMap<BlockId, F>)
|
||||
where
|
||||
F: 'static + Fn(&BlockContext) -> ElementBox,
|
||||
{
|
||||
pub fn replace_blocks(&mut self, styles: HashMap<BlockId, RenderBlock>) {
|
||||
self.block_map.replace(styles);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,11 +45,13 @@ struct BlockRow(u32);
|
|||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||
struct WrapRow(u32);
|
||||
|
||||
pub type RenderBlock = Arc<dyn Fn(&BlockContext) -> ElementBox>;
|
||||
|
||||
pub struct Block {
|
||||
id: BlockId,
|
||||
position: Anchor,
|
||||
height: u8,
|
||||
render: Mutex<Arc<dyn Fn(&BlockContext) -> ElementBox>>,
|
||||
render: Mutex<RenderBlock>,
|
||||
disposition: BlockDisposition,
|
||||
}
|
||||
|
||||
|
@ -306,13 +308,10 @@ impl BlockMap {
|
|||
*transforms = new_transforms;
|
||||
}
|
||||
|
||||
pub fn replace<F>(&mut self, mut element_builders: HashMap<BlockId, F>)
|
||||
where
|
||||
F: 'static + Fn(&BlockContext) -> ElementBox,
|
||||
{
|
||||
pub fn replace(&mut self, mut renderers: HashMap<BlockId, RenderBlock>) {
|
||||
for block in &self.blocks {
|
||||
if let Some(build_element) = element_builders.remove(&block.id) {
|
||||
*block.render.lock() = Arc::new(build_element);
|
||||
if let Some(render) = renderers.remove(&block.id) {
|
||||
*block.render.lock() = render;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -832,6 +831,14 @@ impl Deref for AlignedBlock {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for BlockContext<'a> {
|
||||
type Target = AppContext;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.cx
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Block {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Block")
|
||||
|
|
|
@ -27,16 +27,13 @@ use language::{
|
|||
BracketPair, Buffer, Diagnostic, DiagnosticSeverity, Language, Point, Selection, SelectionGoal,
|
||||
TransactionId,
|
||||
};
|
||||
use multi_buffer::{
|
||||
Anchor, AnchorRangeExt, MultiBufferChunks, MultiBufferSnapshot, ToOffset, ToPoint,
|
||||
};
|
||||
pub use multi_buffer::{ExcerptProperties, MultiBuffer};
|
||||
pub use multi_buffer::{Anchor, ExcerptProperties, MultiBuffer};
|
||||
use multi_buffer::{AnchorRangeExt, MultiBufferChunks, MultiBufferSnapshot, ToOffset, ToPoint};
|
||||
use postage::watch;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use smallvec::SmallVec;
|
||||
use smol::Timer;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
cmp,
|
||||
collections::HashMap,
|
||||
iter::{self, FromIterator},
|
||||
|
@ -359,6 +356,8 @@ pub enum SoftWrap {
|
|||
Column(u32),
|
||||
}
|
||||
|
||||
type BuildSettings = Rc<dyn Fn(&AppContext) -> EditorSettings>;
|
||||
|
||||
pub struct Editor {
|
||||
handle: WeakViewHandle<Self>,
|
||||
buffer: ModelHandle<MultiBuffer>,
|
||||
|
@ -377,7 +376,7 @@ pub struct Editor {
|
|||
scroll_position: Vector2F,
|
||||
scroll_top_anchor: Anchor,
|
||||
autoscroll_request: Option<Autoscroll>,
|
||||
build_settings: Rc<RefCell<dyn Fn(&AppContext) -> EditorSettings>>,
|
||||
build_settings: BuildSettings,
|
||||
focused: bool,
|
||||
show_local_cursors: bool,
|
||||
blink_epoch: usize,
|
||||
|
@ -433,10 +432,7 @@ struct ClipboardSelection {
|
|||
}
|
||||
|
||||
impl Editor {
|
||||
pub fn single_line(
|
||||
build_settings: impl 'static + Fn(&AppContext) -> EditorSettings,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
pub fn single_line(build_settings: BuildSettings, cx: &mut ViewContext<Self>) -> Self {
|
||||
let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
|
||||
let buffer = cx.add_model(|cx| MultiBuffer::singleton(buffer, cx));
|
||||
let mut view = Self::for_buffer(buffer, build_settings, cx);
|
||||
|
@ -446,7 +442,7 @@ impl Editor {
|
|||
|
||||
pub fn auto_height(
|
||||
max_lines: usize,
|
||||
build_settings: impl 'static + Fn(&AppContext) -> EditorSettings,
|
||||
build_settings: BuildSettings,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
let buffer = cx.add_model(|cx| Buffer::new(0, String::new(), cx));
|
||||
|
@ -458,10 +454,10 @@ impl Editor {
|
|||
|
||||
pub fn for_buffer(
|
||||
buffer: ModelHandle<MultiBuffer>,
|
||||
build_settings: impl 'static + Fn(&AppContext) -> EditorSettings,
|
||||
build_settings: BuildSettings,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
Self::new(buffer, Rc::new(RefCell::new(build_settings)), cx)
|
||||
Self::new(buffer, build_settings, cx)
|
||||
}
|
||||
|
||||
pub fn clone(&self, cx: &mut ViewContext<Self>) -> Self {
|
||||
|
@ -473,10 +469,10 @@ impl Editor {
|
|||
|
||||
pub fn new(
|
||||
buffer: ModelHandle<MultiBuffer>,
|
||||
build_settings: Rc<RefCell<dyn Fn(&AppContext) -> EditorSettings>>,
|
||||
build_settings: BuildSettings,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
let settings = build_settings.borrow_mut()(cx);
|
||||
let settings = build_settings(cx);
|
||||
let display_map = cx.add_model(|cx| {
|
||||
DisplayMap::new(
|
||||
buffer.clone(),
|
||||
|
@ -1440,7 +1436,7 @@ impl Editor {
|
|||
|
||||
pub fn tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
|
||||
self.start_transaction(cx);
|
||||
let tab_size = self.build_settings.borrow()(cx).tab_size;
|
||||
let tab_size = (self.build_settings)(cx).tab_size;
|
||||
let mut selections = self.local_selections::<Point>(cx);
|
||||
let mut last_indent = None;
|
||||
self.buffer.update(cx, |buffer, cx| {
|
||||
|
@ -1512,7 +1508,7 @@ impl Editor {
|
|||
|
||||
pub fn outdent(&mut self, _: &Outdent, cx: &mut ViewContext<Self>) {
|
||||
self.start_transaction(cx);
|
||||
let tab_size = self.build_settings.borrow()(cx).tab_size;
|
||||
let tab_size = (self.build_settings)(cx).tab_size;
|
||||
let selections = self.local_selections::<Point>(cx);
|
||||
let mut deletion_ranges = Vec::new();
|
||||
let mut last_outdent = None;
|
||||
|
@ -2900,13 +2896,14 @@ impl Editor {
|
|||
active_diagnostics.is_valid = is_valid;
|
||||
let mut new_styles = HashMap::new();
|
||||
for (block_id, diagnostic) in &active_diagnostics.blocks {
|
||||
let build_settings = self.build_settings.clone();
|
||||
let diagnostic = diagnostic.clone();
|
||||
new_styles.insert(*block_id, move |cx: &BlockContext| {
|
||||
let diagnostic = diagnostic.clone();
|
||||
let settings = build_settings.borrow()(cx.cx);
|
||||
render_diagnostic(diagnostic, &settings.style, is_valid, cx.anchor_x)
|
||||
});
|
||||
new_styles.insert(
|
||||
*block_id,
|
||||
diagnostic_block_renderer(
|
||||
diagnostic.clone(),
|
||||
is_valid,
|
||||
self.build_settings.clone(),
|
||||
),
|
||||
);
|
||||
}
|
||||
self.display_map
|
||||
.update(cx, |display_map, _| display_map.replace_blocks(new_styles));
|
||||
|
@ -2950,11 +2947,7 @@ impl Editor {
|
|||
BlockProperties {
|
||||
position: entry.range.start,
|
||||
height: message_height,
|
||||
render: Arc::new(move |cx| {
|
||||
let settings = build_settings.borrow()(cx.cx);
|
||||
let diagnostic = diagnostic.clone();
|
||||
render_diagnostic(diagnostic, &settings.style, true, cx.anchor_x)
|
||||
}),
|
||||
render: diagnostic_block_renderer(diagnostic, true, build_settings),
|
||||
disposition: BlockDisposition::Below,
|
||||
}
|
||||
}),
|
||||
|
@ -3431,6 +3424,18 @@ impl Editor {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn insert_blocks<P>(
|
||||
&mut self,
|
||||
blocks: impl IntoIterator<Item = BlockProperties<P>>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Vec<BlockId>
|
||||
where
|
||||
P: ToOffset + Clone,
|
||||
{
|
||||
self.display_map
|
||||
.update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx))
|
||||
}
|
||||
|
||||
pub fn longest_row(&self, cx: &mut MutableAppContext) -> u32 {
|
||||
self.display_map
|
||||
.update(cx, |map, cx| map.snapshot(cx))
|
||||
|
@ -3645,7 +3650,7 @@ impl Entity for Editor {
|
|||
|
||||
impl View for Editor {
|
||||
fn render(&mut self, cx: &mut RenderContext<Self>) -> ElementBox {
|
||||
let settings = self.build_settings.borrow_mut()(cx);
|
||||
let settings = (self.build_settings)(cx);
|
||||
self.display_map.update(cx, |map, cx| {
|
||||
map.set_font(
|
||||
settings.style.text.font_id,
|
||||
|
@ -3757,6 +3762,18 @@ impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn diagnostic_block_renderer(
|
||||
diagnostic: Diagnostic,
|
||||
is_valid: bool,
|
||||
build_settings: BuildSettings,
|
||||
) -> RenderBlock {
|
||||
Arc::new(move |cx: &BlockContext| {
|
||||
let diagnostic = diagnostic.clone();
|
||||
let settings = build_settings(cx);
|
||||
render_diagnostic(diagnostic, &settings.style, is_valid, cx.anchor_x)
|
||||
})
|
||||
}
|
||||
|
||||
fn render_diagnostic(
|
||||
diagnostic: Diagnostic,
|
||||
style: &EditorStyle,
|
||||
|
@ -3792,8 +3809,8 @@ pub fn diagnostic_style(
|
|||
pub fn settings_builder(
|
||||
buffer: WeakModelHandle<MultiBuffer>,
|
||||
settings: watch::Receiver<workspace::Settings>,
|
||||
) -> impl Fn(&AppContext) -> EditorSettings {
|
||||
move |cx| {
|
||||
) -> BuildSettings {
|
||||
Rc::new(move |cx| {
|
||||
let settings = settings.borrow();
|
||||
let font_cache = cx.font_cache();
|
||||
let font_family_id = settings.buffer_font_family;
|
||||
|
@ -3828,7 +3845,7 @@ pub fn settings_builder(
|
|||
soft_wrap,
|
||||
style: theme,
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -6086,7 +6103,7 @@ mod tests {
|
|||
settings: EditorSettings,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Editor {
|
||||
Editor::for_buffer(buffer, move |_| settings.clone(), cx)
|
||||
Editor::for_buffer(buffer, Rc::new(move |_| settings.clone()), cx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1179,6 +1179,7 @@ fn scale_horizontal_mouse_autoscroll_delta(delta: f32) -> f32 {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use crate::{Editor, EditorSettings, MultiBuffer};
|
||||
use std::rc::Rc;
|
||||
use util::test::sample_text;
|
||||
|
||||
#[gpui::test]
|
||||
|
@ -1190,7 +1191,7 @@ mod tests {
|
|||
buffer,
|
||||
{
|
||||
let settings = settings.clone();
|
||||
move |_| settings.clone()
|
||||
Rc::new(move |_| settings.clone())
|
||||
},
|
||||
cx,
|
||||
)
|
||||
|
|
|
@ -559,6 +559,8 @@ impl MultiBuffer {
|
|||
|
||||
self.subscriptions.publish_mut([edit]);
|
||||
|
||||
cx.notify();
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,13 @@ pub struct Anchor {
|
|||
}
|
||||
|
||||
impl Anchor {
|
||||
pub fn new(excerpt_id: ExcerptId, text_anchor: text::Anchor) -> Self {
|
||||
Self {
|
||||
excerpt_id,
|
||||
text_anchor,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn min() -> Self {
|
||||
Self {
|
||||
excerpt_id: ExcerptId::min(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue