Start work on allowing blocks to be styled
This commit is contained in:
parent
c04151f999
commit
8d1a4a6a24
7 changed files with 232 additions and 96 deletions
|
@ -13,7 +13,7 @@ use language::{Anchor, Buffer, Point, ToOffset, ToPoint};
|
|||
use std::{collections::HashSet, ops::Range};
|
||||
use sum_tree::Bias;
|
||||
use tab_map::TabMap;
|
||||
use theme::SyntaxTheme;
|
||||
use theme::{BlockStyle, SyntaxTheme};
|
||||
use wrap_map::WrapMap;
|
||||
|
||||
pub trait ToDisplayPoint {
|
||||
|
@ -172,8 +172,8 @@ impl DisplayMapSnapshot {
|
|||
self.buffer_snapshot.len() == 0
|
||||
}
|
||||
|
||||
pub fn buffer_rows(&self, start_row: u32) -> BufferRows {
|
||||
self.blocks_snapshot.buffer_rows(start_row)
|
||||
pub fn buffer_rows<'a>(&'a self, start_row: u32, cx: Option<&'a AppContext>) -> BufferRows<'a> {
|
||||
self.blocks_snapshot.buffer_rows(start_row, cx)
|
||||
}
|
||||
|
||||
pub fn buffer_row_count(&self) -> u32 {
|
||||
|
@ -416,6 +416,13 @@ impl ToDisplayPoint for Anchor {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum DisplayRow {
|
||||
Buffer(u32),
|
||||
Block(BlockId, Option<BlockStyle>),
|
||||
Wrap,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use super::wrap_map::{self, Edit as WrapEdit, Snapshot as WrapSnapshot, WrapPoint};
|
||||
use super::{
|
||||
wrap_map::{self, Edit as WrapEdit, Snapshot as WrapSnapshot, WrapPoint},
|
||||
BlockStyle, DisplayRow,
|
||||
};
|
||||
use buffer::{rope, Anchor, Bias, Edit, Point, Rope, ToOffset, ToPoint as _};
|
||||
use gpui::{fonts::HighlightStyle, AppContext, ModelHandle};
|
||||
use language::{Buffer, Chunk};
|
||||
|
@ -45,11 +48,12 @@ struct BlockRow(u32);
|
|||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||
struct WrapRow(u32);
|
||||
|
||||
struct Block {
|
||||
pub struct Block {
|
||||
id: BlockId,
|
||||
position: Anchor,
|
||||
text: Rope,
|
||||
build_runs: Option<Arc<dyn Fn(&AppContext) -> Vec<(usize, HighlightStyle)>>>,
|
||||
build_style: Option<Arc<dyn Fn(&AppContext) -> BlockStyle>>,
|
||||
disposition: BlockDisposition,
|
||||
}
|
||||
|
||||
|
@ -62,6 +66,7 @@ where
|
|||
pub position: P,
|
||||
pub text: T,
|
||||
pub build_runs: Option<Arc<dyn Fn(&AppContext) -> Vec<(usize, HighlightStyle)>>>,
|
||||
pub build_style: Option<Arc<dyn Fn(&AppContext) -> BlockStyle>>,
|
||||
pub disposition: BlockDisposition,
|
||||
}
|
||||
|
||||
|
@ -115,6 +120,7 @@ pub struct BufferRows<'a> {
|
|||
transforms: sum_tree::Cursor<'a, Transform, (BlockRow, WrapRow)>,
|
||||
input_buffer_rows: wrap_map::BufferRows<'a>,
|
||||
output_row: u32,
|
||||
cx: Option<&'a AppContext>,
|
||||
started: bool,
|
||||
}
|
||||
|
||||
|
@ -415,6 +421,7 @@ impl<'a> BlockMapWriter<'a> {
|
|||
position,
|
||||
text: block.text.into(),
|
||||
build_runs: block.build_runs,
|
||||
build_style: block.build_style,
|
||||
disposition: block.disposition,
|
||||
}),
|
||||
);
|
||||
|
@ -519,7 +526,7 @@ impl BlockSnapshot {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn buffer_rows(&self, start_row: u32) -> BufferRows {
|
||||
pub fn buffer_rows<'a>(&'a self, start_row: u32, cx: Option<&'a AppContext>) -> BufferRows<'a> {
|
||||
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>();
|
||||
cursor.seek(&BlockRow(start_row), Bias::Right, &());
|
||||
let (output_start, input_start) = cursor.start();
|
||||
|
@ -530,6 +537,7 @@ impl BlockSnapshot {
|
|||
};
|
||||
let input_start_row = input_start.0 + overshoot;
|
||||
BufferRows {
|
||||
cx,
|
||||
transforms: cursor,
|
||||
input_buffer_rows: self.wrap_snapshot.buffer_rows(input_start_row),
|
||||
output_row: start_row,
|
||||
|
@ -871,7 +879,7 @@ impl<'a> Iterator for BlockChunks<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Iterator for BufferRows<'a> {
|
||||
type Item = Option<u32>;
|
||||
type Item = DisplayRow;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.started {
|
||||
|
@ -885,10 +893,13 @@ impl<'a> Iterator for BufferRows<'a> {
|
|||
}
|
||||
|
||||
let transform = self.transforms.item()?;
|
||||
if transform.is_isomorphic() {
|
||||
Some(self.input_buffer_rows.next().unwrap())
|
||||
if let Some(block) = &transform.block {
|
||||
let style = self
|
||||
.cx
|
||||
.and_then(|cx| block.build_style.as_ref().map(|f| f(cx)));
|
||||
Some(DisplayRow::Block(block.id, style))
|
||||
} else {
|
||||
Some(None)
|
||||
Some(self.input_buffer_rows.next().unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1006,6 +1017,7 @@ mod tests {
|
|||
id: BlockId(0),
|
||||
position: Anchor::min(),
|
||||
text: "one!\ntwo three\nfour".into(),
|
||||
build_style: None,
|
||||
build_runs: Some(Arc::new(move |_| {
|
||||
vec![(3, red.into()), (6, Default::default()), (5, blue.into())]
|
||||
})),
|
||||
|
@ -1080,25 +1092,28 @@ mod tests {
|
|||
let mut block_map = BlockMap::new(buffer.clone(), wraps_snapshot.clone());
|
||||
|
||||
let mut writer = block_map.write(wraps_snapshot.clone(), vec![], cx);
|
||||
writer.insert(
|
||||
let block_ids = writer.insert(
|
||||
vec![
|
||||
BlockProperties {
|
||||
position: Point::new(1, 0),
|
||||
text: "BLOCK 1",
|
||||
disposition: BlockDisposition::Above,
|
||||
build_runs: None,
|
||||
build_style: None,
|
||||
},
|
||||
BlockProperties {
|
||||
position: Point::new(1, 2),
|
||||
text: "BLOCK 2",
|
||||
disposition: BlockDisposition::Above,
|
||||
build_runs: None,
|
||||
build_style: None,
|
||||
},
|
||||
BlockProperties {
|
||||
position: Point::new(3, 2),
|
||||
text: "BLOCK 3",
|
||||
disposition: BlockDisposition::Below,
|
||||
build_runs: None,
|
||||
build_style: None,
|
||||
},
|
||||
],
|
||||
cx,
|
||||
|
@ -1181,8 +1196,16 @@ mod tests {
|
|||
);
|
||||
|
||||
assert_eq!(
|
||||
snapshot.buffer_rows(0).collect::<Vec<_>>(),
|
||||
&[Some(0), None, None, Some(1), Some(2), Some(3), None]
|
||||
snapshot.buffer_rows(0, None).collect::<Vec<_>>(),
|
||||
&[
|
||||
DisplayRow::Buffer(0),
|
||||
DisplayRow::Block(block_ids[0], None),
|
||||
DisplayRow::Block(block_ids[1], None),
|
||||
DisplayRow::Buffer(1),
|
||||
DisplayRow::Buffer(2),
|
||||
DisplayRow::Buffer(3),
|
||||
DisplayRow::Block(block_ids[2], None)
|
||||
]
|
||||
);
|
||||
|
||||
// Insert a line break, separating two block decorations into separate
|
||||
|
@ -1227,12 +1250,14 @@ mod tests {
|
|||
text: "<BLOCK 1",
|
||||
disposition: BlockDisposition::Above,
|
||||
build_runs: None,
|
||||
build_style: None,
|
||||
},
|
||||
BlockProperties {
|
||||
position: Point::new(1, 1),
|
||||
text: ">BLOCK 2",
|
||||
disposition: BlockDisposition::Below,
|
||||
build_runs: None,
|
||||
build_style: None,
|
||||
},
|
||||
],
|
||||
cx,
|
||||
|
@ -1325,8 +1350,9 @@ mod tests {
|
|||
BlockProperties {
|
||||
position,
|
||||
text,
|
||||
build_runs: None,
|
||||
disposition,
|
||||
build_runs: None,
|
||||
build_style: None,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
@ -1402,6 +1428,7 @@ mod tests {
|
|||
position: BlockPoint::new(row, column),
|
||||
text: block.text,
|
||||
build_runs: block.build_runs.clone(),
|
||||
build_style: None,
|
||||
disposition: block.disposition,
|
||||
},
|
||||
)
|
||||
|
@ -1424,7 +1451,7 @@ mod tests {
|
|||
.to_point(WrapPoint::new(row, 0), Bias::Left)
|
||||
.row;
|
||||
|
||||
while let Some((_, block)) = sorted_blocks.peek() {
|
||||
while let Some((block_id, block)) = sorted_blocks.peek() {
|
||||
if block.position.row == row && block.disposition == BlockDisposition::Above {
|
||||
let text = block.text.to_string();
|
||||
let padding = " ".repeat(block.position.column as usize);
|
||||
|
@ -1434,7 +1461,7 @@ mod tests {
|
|||
expected_text.push_str(line);
|
||||
}
|
||||
expected_text.push('\n');
|
||||
expected_buffer_rows.push(None);
|
||||
expected_buffer_rows.push(DisplayRow::Block(*block_id, None));
|
||||
}
|
||||
sorted_blocks.next();
|
||||
} else {
|
||||
|
@ -1443,10 +1470,14 @@ mod tests {
|
|||
}
|
||||
|
||||
let soft_wrapped = wraps_snapshot.to_tab_point(WrapPoint::new(row, 0)).column() > 0;
|
||||
expected_buffer_rows.push(if soft_wrapped { None } else { Some(buffer_row) });
|
||||
expected_buffer_rows.push(if soft_wrapped {
|
||||
DisplayRow::Wrap
|
||||
} else {
|
||||
DisplayRow::Buffer(buffer_row)
|
||||
});
|
||||
expected_text.push_str(input_line);
|
||||
|
||||
while let Some((_, block)) = sorted_blocks.peek() {
|
||||
while let Some((block_id, block)) = sorted_blocks.peek() {
|
||||
if block.position.row == row && block.disposition == BlockDisposition::Below {
|
||||
let text = block.text.to_string();
|
||||
let padding = " ".repeat(block.position.column as usize);
|
||||
|
@ -1456,7 +1487,7 @@ mod tests {
|
|||
expected_text.push_str(&padding);
|
||||
expected_text.push_str(line);
|
||||
}
|
||||
expected_buffer_rows.push(None);
|
||||
expected_buffer_rows.push(DisplayRow::Block(*block_id, None));
|
||||
}
|
||||
sorted_blocks.next();
|
||||
} else {
|
||||
|
@ -1480,7 +1511,7 @@ mod tests {
|
|||
);
|
||||
assert_eq!(
|
||||
blocks_snapshot
|
||||
.buffer_rows(start_row as u32)
|
||||
.buffer_rows(start_row as u32, None)
|
||||
.collect::<Vec<_>>(),
|
||||
&expected_buffer_rows[start_row..]
|
||||
);
|
||||
|
|
|
@ -2,6 +2,7 @@ use super::{
|
|||
fold_map,
|
||||
patch::Patch,
|
||||
tab_map::{self, Edit as TabEdit, Snapshot as TabSnapshot, TabPoint},
|
||||
DisplayRow,
|
||||
};
|
||||
use gpui::{
|
||||
fonts::FontId, text_layout::LineWrapper, Entity, ModelContext, ModelHandle, MutableAppContext,
|
||||
|
@ -712,7 +713,11 @@ impl Snapshot {
|
|||
prev_tab_row = tab_point.row();
|
||||
soft_wrapped = false;
|
||||
}
|
||||
expected_buffer_rows.push(if soft_wrapped { None } else { Some(buffer_row) });
|
||||
expected_buffer_rows.push(if soft_wrapped {
|
||||
DisplayRow::Wrap
|
||||
} else {
|
||||
DisplayRow::Buffer(buffer_row)
|
||||
});
|
||||
}
|
||||
|
||||
for start_display_row in 0..expected_buffer_rows.len() {
|
||||
|
@ -792,7 +797,7 @@ impl<'a> Iterator for Chunks<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Iterator for BufferRows<'a> {
|
||||
type Item = Option<u32>;
|
||||
type Item = DisplayRow;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.output_row > self.max_output_row {
|
||||
|
@ -812,7 +817,11 @@ impl<'a> Iterator for BufferRows<'a> {
|
|||
self.soft_wrapped = true;
|
||||
}
|
||||
|
||||
Some(if soft_wrapped { None } else { Some(buffer_row) })
|
||||
Some(if soft_wrapped {
|
||||
DisplayRow::Wrap
|
||||
} else {
|
||||
DisplayRow::Buffer(buffer_row)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::{
|
||||
DisplayPoint, Editor, EditorMode, EditorSettings, EditorStyle, Input, Scroll, Select,
|
||||
SelectPhase, Snapshot, MAX_LINE_LEN,
|
||||
DisplayPoint, DisplayRow, Editor, EditorMode, EditorSettings, EditorStyle, Input, Scroll,
|
||||
Select, SelectPhase, Snapshot, MAX_LINE_LEN,
|
||||
};
|
||||
use clock::ReplicaId;
|
||||
use gpui::{
|
||||
|
@ -25,6 +25,7 @@ use std::{
|
|||
fmt::Write,
|
||||
ops::Range,
|
||||
};
|
||||
use theme::BlockStyle;
|
||||
|
||||
pub struct EditorElement {
|
||||
view: WeakViewHandle<Editor>,
|
||||
|
@ -359,6 +360,30 @@ impl EditorElement {
|
|||
}
|
||||
|
||||
if let Some(visible_text_bounds) = bounds.intersection(visible_bounds) {
|
||||
// Draw blocks
|
||||
for (ixs, block_style) in &layout.block_layouts {
|
||||
let row = start_row + ixs.start;
|
||||
let origin = content_origin
|
||||
+ vec2f(-scroll_left, row as f32 * layout.line_height - scroll_top);
|
||||
let height = ixs.len() as f32 * layout.line_height;
|
||||
cx.scene.push_quad(Quad {
|
||||
bounds: RectF::new(origin, vec2f(visible_text_bounds.width(), height)),
|
||||
background: block_style.background,
|
||||
border: block_style
|
||||
.border
|
||||
.map_or(Default::default(), |color| Border {
|
||||
width: 1.,
|
||||
color,
|
||||
overlay: true,
|
||||
top: true,
|
||||
right: false,
|
||||
bottom: true,
|
||||
left: false,
|
||||
}),
|
||||
corner_radius: 0.,
|
||||
});
|
||||
}
|
||||
|
||||
// Draw glyphs
|
||||
for (ix, line) in layout.line_layouts.iter().enumerate() {
|
||||
let row = start_row + ix as u32;
|
||||
|
@ -401,18 +426,24 @@ impl EditorElement {
|
|||
.width()
|
||||
}
|
||||
|
||||
fn layout_line_numbers(
|
||||
fn layout_rows(
|
||||
&self,
|
||||
rows: Range<u32>,
|
||||
active_rows: &BTreeMap<u32, bool>,
|
||||
snapshot: &Snapshot,
|
||||
cx: &LayoutContext,
|
||||
) -> Vec<Option<text_layout::Line>> {
|
||||
) -> (
|
||||
Vec<Option<text_layout::Line>>,
|
||||
Vec<(Range<u32>, BlockStyle)>,
|
||||
) {
|
||||
let style = &self.settings.style;
|
||||
let mut layouts = Vec::with_capacity(rows.len());
|
||||
let include_line_numbers = snapshot.mode == EditorMode::Full;
|
||||
let mut last_block_id = None;
|
||||
let mut blocks = Vec::<(Range<u32>, BlockStyle)>::new();
|
||||
let mut line_number_layouts = Vec::with_capacity(rows.len());
|
||||
let mut line_number = String::new();
|
||||
for (ix, buffer_row) in snapshot
|
||||
.buffer_rows(rows.start)
|
||||
for (ix, row) in snapshot
|
||||
.buffer_rows(rows.start, cx)
|
||||
.take((rows.end - rows.start) as usize)
|
||||
.enumerate()
|
||||
{
|
||||
|
@ -422,27 +453,46 @@ impl EditorElement {
|
|||
} else {
|
||||
style.line_number
|
||||
};
|
||||
if let Some(buffer_row) = buffer_row {
|
||||
line_number.clear();
|
||||
write!(&mut line_number, "{}", buffer_row + 1).unwrap();
|
||||
layouts.push(Some(cx.text_layout_cache.layout_str(
|
||||
&line_number,
|
||||
style.text.font_size,
|
||||
&[(
|
||||
line_number.len(),
|
||||
RunStyle {
|
||||
font_id: style.text.font_id,
|
||||
color,
|
||||
underline: None,
|
||||
},
|
||||
)],
|
||||
)));
|
||||
} else {
|
||||
layouts.push(None);
|
||||
match row {
|
||||
DisplayRow::Buffer(buffer_row) => {
|
||||
if include_line_numbers {
|
||||
line_number.clear();
|
||||
write!(&mut line_number, "{}", buffer_row + 1).unwrap();
|
||||
line_number_layouts.push(Some(cx.text_layout_cache.layout_str(
|
||||
&line_number,
|
||||
style.text.font_size,
|
||||
&[(
|
||||
line_number.len(),
|
||||
RunStyle {
|
||||
font_id: style.text.font_id,
|
||||
color,
|
||||
underline: None,
|
||||
},
|
||||
)],
|
||||
)));
|
||||
}
|
||||
last_block_id = None;
|
||||
}
|
||||
DisplayRow::Block(block_id, style) => {
|
||||
let ix = ix as u32;
|
||||
if last_block_id == Some(block_id) {
|
||||
if let Some((row_range, _)) = blocks.last_mut() {
|
||||
row_range.end += 1;
|
||||
}
|
||||
} else if let Some(style) = style {
|
||||
blocks.push((ix..ix + 1, style));
|
||||
}
|
||||
line_number_layouts.push(None);
|
||||
last_block_id = Some(block_id);
|
||||
}
|
||||
DisplayRow::Wrap => {
|
||||
line_number_layouts.push(None);
|
||||
last_block_id = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
layouts
|
||||
(line_number_layouts, blocks)
|
||||
}
|
||||
|
||||
fn layout_lines(
|
||||
|
@ -541,7 +591,7 @@ impl EditorElement {
|
|||
}
|
||||
|
||||
let underline = if let Some(severity) = chunk.diagnostic {
|
||||
Some(super::diagnostic_color(severity, style))
|
||||
Some(super::diagnostic_style(severity, style).text)
|
||||
} else {
|
||||
highlight_style.underline
|
||||
};
|
||||
|
@ -669,11 +719,8 @@ impl Element for EditorElement {
|
|||
}
|
||||
});
|
||||
|
||||
let line_number_layouts = if snapshot.mode == EditorMode::Full {
|
||||
self.layout_line_numbers(start_row..end_row, &active_rows, &snapshot, cx)
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let (line_number_layouts, block_layouts) =
|
||||
self.layout_rows(start_row..end_row, &active_rows, &snapshot, cx);
|
||||
|
||||
let mut max_visible_line_width = 0.0;
|
||||
let line_layouts = self.layout_lines(start_row..end_row, &mut snapshot, cx);
|
||||
|
@ -695,6 +742,7 @@ impl Element for EditorElement {
|
|||
active_rows,
|
||||
line_layouts,
|
||||
line_number_layouts,
|
||||
block_layouts,
|
||||
line_height,
|
||||
em_width,
|
||||
selections,
|
||||
|
@ -817,6 +865,7 @@ pub struct LayoutState {
|
|||
active_rows: BTreeMap<u32, bool>,
|
||||
line_layouts: Vec<text_layout::Line>,
|
||||
line_number_layouts: Vec<Option<text_layout::Line>>,
|
||||
block_layouts: Vec<(Range<u32>, BlockStyle)>,
|
||||
line_height: f32,
|
||||
em_width: f32,
|
||||
selections: HashMap<ReplicaId, Vec<Range<DisplayPoint>>>,
|
||||
|
@ -1071,11 +1120,11 @@ mod tests {
|
|||
});
|
||||
let element = EditorElement::new(editor.downgrade(), settings);
|
||||
|
||||
let layouts = editor.update(cx, |editor, cx| {
|
||||
let (layouts, _) = editor.update(cx, |editor, cx| {
|
||||
let snapshot = editor.snapshot(cx);
|
||||
let mut presenter = cx.build_presenter(window_id, 30.);
|
||||
let mut layout_cx = presenter.build_layout_context(false, cx);
|
||||
element.layout_line_numbers(0..6, &Default::default(), &snapshot, &mut layout_cx)
|
||||
element.layout_rows(0..6, &Default::default(), &snapshot, &mut layout_cx)
|
||||
});
|
||||
assert_eq!(layouts.len(), 6);
|
||||
}
|
||||
|
|
|
@ -7,12 +7,11 @@ mod test;
|
|||
|
||||
use buffer::rope::TextDimension;
|
||||
use clock::ReplicaId;
|
||||
pub use display_map::DisplayPoint;
|
||||
use display_map::*;
|
||||
pub use display_map::{DisplayPoint, DisplayRow};
|
||||
pub use element::*;
|
||||
use gpui::{
|
||||
action,
|
||||
color::Color,
|
||||
geometry::vector::{vec2f, Vector2F},
|
||||
keymap::Binding,
|
||||
text_layout, AppContext, ClipboardItem, Element, ElementBox, Entity, ModelHandle,
|
||||
|
@ -33,7 +32,7 @@ use std::{
|
|||
time::Duration,
|
||||
};
|
||||
use sum_tree::Bias;
|
||||
use theme::{EditorStyle, SyntaxTheme};
|
||||
use theme::{DiagnosticStyle, EditorStyle, SyntaxTheme};
|
||||
use util::post_inc;
|
||||
|
||||
const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
|
||||
|
@ -342,6 +341,7 @@ struct BracketPairState {
|
|||
#[derive(Debug)]
|
||||
struct ActiveDiagnosticGroup {
|
||||
primary_range: Range<Anchor>,
|
||||
group_range: Range<Anchor>,
|
||||
block_ids: HashSet<BlockId>,
|
||||
}
|
||||
|
||||
|
@ -2238,21 +2238,34 @@ impl Editor {
|
|||
loop {
|
||||
let next_group = buffer
|
||||
.diagnostics_in_range::<_, usize>(search_start..buffer.len())
|
||||
.filter(|(_, diagnostic)| diagnostic.is_primary)
|
||||
.skip_while(|(range, _)| {
|
||||
Some(range.end) == active_primary_range.as_ref().map(|r| *r.end())
|
||||
})
|
||||
.next()
|
||||
.map(|(range, diagnostic)| (range, diagnostic.group_id));
|
||||
.find_map(|(range, diagnostic)| {
|
||||
if diagnostic.is_primary
|
||||
&& Some(range.end) != active_primary_range.as_ref().map(|r| *r.end())
|
||||
{
|
||||
Some((range, diagnostic.group_id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
if let Some((primary_range, group_id)) = next_group {
|
||||
self.dismiss_diagnostics(cx);
|
||||
self.active_diagnostics = self.display_map.update(cx, |display_map, cx| {
|
||||
let buffer = self.buffer.read(cx);
|
||||
|
||||
let mut group_end = Point::zero();
|
||||
let diagnostic_group = buffer
|
||||
.diagnostic_group::<Point>(group_id)
|
||||
.map(|(range, diagnostic)| (range, diagnostic.clone()))
|
||||
.map(|(range, diagnostic)| {
|
||||
if range.end > group_end {
|
||||
group_end = range.end;
|
||||
}
|
||||
(range, diagnostic.clone())
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let group_range = buffer.anchor_after(diagnostic_group[0].0.start)
|
||||
..buffer.anchor_before(group_end);
|
||||
let primary_range = buffer.anchor_after(primary_range.start)
|
||||
..buffer.anchor_before(primary_range.end);
|
||||
|
||||
|
@ -2265,12 +2278,24 @@ impl Editor {
|
|||
BlockProperties {
|
||||
position: range.start,
|
||||
text: diagnostic.message.as_str(),
|
||||
build_runs: Some(Arc::new(move |cx| {
|
||||
let settings = build_settings.borrow()(cx);
|
||||
vec![(
|
||||
message_len,
|
||||
diagnostic_color(severity, &settings.style).into(),
|
||||
)]
|
||||
build_runs: Some(Arc::new({
|
||||
let build_settings = build_settings.clone();
|
||||
move |cx| {
|
||||
let settings = build_settings.borrow()(cx);
|
||||
vec![(
|
||||
message_len,
|
||||
diagnostic_style(severity, &settings.style)
|
||||
.text
|
||||
.into(),
|
||||
)]
|
||||
}
|
||||
})),
|
||||
build_style: Some(Arc::new({
|
||||
let build_settings = build_settings.clone();
|
||||
move |cx| {
|
||||
let settings = build_settings.borrow()(cx);
|
||||
diagnostic_style(severity, &settings.style).block
|
||||
}
|
||||
})),
|
||||
disposition: BlockDisposition::Below,
|
||||
}
|
||||
|
@ -2282,6 +2307,7 @@ impl Editor {
|
|||
|
||||
Some(ActiveDiagnosticGroup {
|
||||
primary_range,
|
||||
group_range,
|
||||
block_ids,
|
||||
})
|
||||
});
|
||||
|
@ -2815,8 +2841,8 @@ impl Snapshot {
|
|||
self.display_snapshot.buffer_row_count()
|
||||
}
|
||||
|
||||
pub fn buffer_rows(&self, start_row: u32) -> BufferRows {
|
||||
self.display_snapshot.buffer_rows(start_row)
|
||||
pub fn buffer_rows<'a>(&'a self, start_row: u32, cx: &'a AppContext) -> BufferRows<'a> {
|
||||
self.display_snapshot.buffer_rows(start_row, Some(cx))
|
||||
}
|
||||
|
||||
pub fn chunks<'a>(
|
||||
|
@ -2893,10 +2919,10 @@ impl EditorSettings {
|
|||
selection: Default::default(),
|
||||
guest_selections: Default::default(),
|
||||
syntax: Default::default(),
|
||||
error_color: Default::default(),
|
||||
warning_color: Default::default(),
|
||||
information_color: Default::default(),
|
||||
hint_color: Default::default(),
|
||||
diagnostic_error: Default::default(),
|
||||
diagnostic_warning: Default::default(),
|
||||
diagnostic_information: Default::default(),
|
||||
diagnostic_hint: Default::default(),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
@ -3020,13 +3046,13 @@ impl SelectionExt for Selection<Point> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn diagnostic_color(severity: DiagnosticSeverity, style: &EditorStyle) -> Color {
|
||||
pub fn diagnostic_style(severity: DiagnosticSeverity, style: &EditorStyle) -> DiagnosticStyle {
|
||||
match severity {
|
||||
DiagnosticSeverity::ERROR => style.error_color,
|
||||
DiagnosticSeverity::WARNING => style.warning_color,
|
||||
DiagnosticSeverity::INFORMATION => style.information_color,
|
||||
DiagnosticSeverity::HINT => style.hint_color,
|
||||
_ => style.text.color,
|
||||
DiagnosticSeverity::ERROR => style.diagnostic_error,
|
||||
DiagnosticSeverity::WARNING => style.diagnostic_warning,
|
||||
DiagnosticSeverity::INFORMATION => style.diagnostic_information,
|
||||
DiagnosticSeverity::HINT => style.diagnostic_hint,
|
||||
_ => Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -227,12 +227,19 @@ pub struct EditorStyle {
|
|||
pub line_number_active: Color,
|
||||
pub guest_selections: Vec<SelectionStyle>,
|
||||
pub syntax: Arc<SyntaxTheme>,
|
||||
pub error_color: Color,
|
||||
pub warning_color: Color,
|
||||
pub diagnostic_error: DiagnosticStyle,
|
||||
pub diagnostic_warning: DiagnosticStyle,
|
||||
#[serde(default)]
|
||||
pub information_color: Color,
|
||||
pub diagnostic_information: DiagnosticStyle,
|
||||
#[serde(default)]
|
||||
pub hint_color: Color,
|
||||
pub diagnostic_hint: DiagnosticStyle,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Deserialize, Default)]
|
||||
pub struct DiagnosticStyle {
|
||||
pub text: Color,
|
||||
#[serde(flatten)]
|
||||
pub block: BlockStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Default, Deserialize)]
|
||||
|
@ -251,6 +258,12 @@ pub struct InputEditorStyle {
|
|||
pub selection: SelectionStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq)]
|
||||
pub struct BlockStyle {
|
||||
pub background: Option<Color>,
|
||||
pub border: Option<Color>,
|
||||
}
|
||||
|
||||
impl EditorStyle {
|
||||
pub fn placeholder_text(&self) -> &TextStyle {
|
||||
self.placeholder_text.as_ref().unwrap_or(&self.text)
|
||||
|
@ -273,10 +286,10 @@ impl InputEditorStyle {
|
|||
line_number_active: Default::default(),
|
||||
guest_selections: Default::default(),
|
||||
syntax: Default::default(),
|
||||
error_color: Default::default(),
|
||||
warning_color: Default::default(),
|
||||
information_color: Default::default(),
|
||||
hint_color: Default::default(),
|
||||
diagnostic_error: Default::default(),
|
||||
diagnostic_warning: Default::default(),
|
||||
diagnostic_information: Default::default(),
|
||||
diagnostic_hint: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,7 +173,7 @@ corner_radius = 6
|
|||
|
||||
[project_panel]
|
||||
extends = "$panel"
|
||||
padding.top = 6 # ($workspace.tab.height - $project_panel.entry.height) / 2
|
||||
padding.top = 6 # ($workspace.tab.height - $project_panel.entry.height) / 2
|
||||
|
||||
[project_panel.entry]
|
||||
text = "$text.1"
|
||||
|
@ -236,6 +236,7 @@ line_number_active = "$text.0.color"
|
|||
selection = "$selection.host"
|
||||
guest_selections = "$selection.guests"
|
||||
error_color = "$status.bad"
|
||||
warning_color = "$status.warn"
|
||||
info_color = "$status.info"
|
||||
hint_color = "$status.info"
|
||||
diagnostic_error = { text = "$status.bad", border = "#ff0000", background = "#ffdddd" }
|
||||
diagnostic_warning = { text = "$status.warn", border = "#ffff00", background = "#ffffdd" }
|
||||
diagnostic_info = { text = "$status.info" }
|
||||
diagnostic_hint = { text = "$status.info" }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue