Detailed changes
@@ -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" }