Detailed changes
@@ -10,7 +10,10 @@ use buffer::Rope;
use fold_map::{FoldMap, ToFoldPoint as _};
use gpui::{fonts::FontId, AppContext, Entity, ModelContext, ModelHandle};
use language::{Anchor, Buffer, Point, ToOffset, ToPoint};
-use std::{collections::HashSet, ops::Range};
+use std::{
+ collections::{HashMap, HashSet},
+ ops::Range,
+};
use sum_tree::Bias;
use tab_map::TabMap;
use theme::{BlockStyle, SyntaxTheme};
@@ -128,6 +131,13 @@ impl DisplayMap {
block_map.insert(blocks, cx)
}
+ pub fn restyle_blocks<F>(&mut self, styles: HashMap<BlockId, Option<F>>)
+ where
+ F: 'static + Fn(&AppContext) -> BlockStyle,
+ {
+ self.block_map.restyle(styles);
+ }
+
pub fn remove_blocks(&mut self, ids: HashSet<BlockId>, cx: &mut ModelContext<Self>) {
let (snapshot, edits) = self.fold_map.read(cx);
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
@@ -8,7 +8,7 @@ use language::{Buffer, Chunk};
use parking_lot::Mutex;
use std::{
cmp::{self, Ordering},
- collections::HashSet,
+ collections::{HashMap, HashSet},
fmt::Debug,
iter,
ops::{Deref, Range},
@@ -53,7 +53,7 @@ pub struct Block {
position: Anchor,
text: Rope,
build_runs: Option<Arc<dyn Fn(&AppContext) -> Vec<(usize, HighlightStyle)>>>,
- build_style: Option<Arc<dyn Fn(&AppContext) -> BlockStyle>>,
+ build_style: Mutex<Option<Arc<dyn Fn(&AppContext) -> BlockStyle>>>,
disposition: BlockDisposition,
}
@@ -332,6 +332,19 @@ impl BlockMap {
drop(cursor);
*transforms = new_transforms;
}
+
+ pub fn restyle<F>(&mut self, mut styles: HashMap<BlockId, Option<F>>)
+ where
+ F: 'static + Fn(&AppContext) -> BlockStyle,
+ {
+ for block in &self.blocks {
+ if let Some(build_style) = styles.remove(&block.id) {
+ *block.build_style.lock() = build_style.map(|build_style| {
+ Arc::new(build_style) as Arc<dyn Fn(&AppContext) -> BlockStyle>
+ });
+ }
+ }
+ }
}
fn push_isomorphic(tree: &mut SumTree<Transform>, rows: u32) {
@@ -421,7 +434,7 @@ impl<'a> BlockMapWriter<'a> {
position,
text: block.text.into(),
build_runs: block.build_runs,
- build_style: block.build_style,
+ build_style: Mutex::new(block.build_style),
disposition: block.disposition,
}),
);
@@ -896,7 +909,7 @@ impl<'a> Iterator for BufferRows<'a> {
if let Some(block) = &transform.block {
let style = self
.cx
- .and_then(|cx| block.build_style.as_ref().map(|f| f(cx)));
+ .and_then(|cx| block.build_style.lock().as_ref().map(|f| f(cx)));
Some(DisplayRow::Block(block.id, style))
} else {
Some(self.input_buffer_rows.next().unwrap())
@@ -1017,7 +1030,7 @@ mod tests {
id: BlockId(0),
position: Anchor::min(),
text: "one!\ntwo three\nfour".into(),
- build_style: None,
+ build_style: Mutex::new(None),
build_runs: Some(Arc::new(move |_| {
vec![(3, red.into()), (6, Default::default()), (5, blue.into())]
})),
@@ -24,7 +24,7 @@ use smol::Timer;
use std::{
cell::RefCell,
cmp::{self, Ordering},
- collections::HashSet,
+ collections::{HashMap, HashSet},
iter, mem,
ops::{Range, RangeInclusive},
rc::Rc,
@@ -341,8 +341,10 @@ struct BracketPairState {
#[derive(Debug)]
struct ActiveDiagnosticGroup {
primary_range: Range<Anchor>,
+ primary_message: String,
+ blocks: HashMap<BlockId, Diagnostic>,
group_range: Range<Anchor>,
- block_ids: HashSet<BlockId>,
+ is_valid: bool,
}
#[derive(Serialize, Deserialize)]
@@ -2268,13 +2270,17 @@ impl Editor {
..buffer.anchor_before(group_end);
let primary_range = buffer.anchor_after(primary_range.start)
..buffer.anchor_before(primary_range.end);
+ let mut primary_message = None;
- let block_ids = display_map
+ let blocks = display_map
.insert_blocks(
diagnostic_group.iter().map(|(range, diagnostic)| {
let build_settings = self.build_settings.clone();
let message_len = diagnostic.message.len();
let severity = diagnostic.severity;
+ if diagnostic.is_primary {
+ primary_message = Some(diagnostic.message.clone());
+ }
BlockProperties {
position: range.start,
text: diagnostic.message.as_str(),
@@ -2303,12 +2309,19 @@ impl Editor {
cx,
)
.into_iter()
+ .zip(
+ diagnostic_group
+ .into_iter()
+ .map(|(_, diagnostic)| diagnostic),
+ )
.collect();
Some(ActiveDiagnosticGroup {
primary_range,
+ primary_message: primary_message.unwrap(),
group_range,
- block_ids,
+ blocks,
+ is_valid: true,
})
});
@@ -2333,10 +2346,46 @@ impl Editor {
}
}
+ fn refresh_active_diagnostics(&mut self, cx: &mut ViewContext<Editor>) {
+ if let Some(active_diagnostics) = self.active_diagnostics.as_mut() {
+ let buffer = self.buffer.read(cx);
+ let primary_range_start = active_diagnostics.primary_range.start.to_offset(buffer);
+ let matching_diagnostic = buffer
+ .diagnostics_in_range::<_, usize>(active_diagnostics.primary_range.clone())
+ .find_map(|(range, diagnostic)| {
+ if diagnostic.is_primary
+ && range.start == primary_range_start
+ && diagnostic.message == active_diagnostics.primary_message
+ {
+ Some(diagnostic.group_id)
+ } else {
+ None
+ }
+ });
+ if let Some(matching_diagnostic) = matching_diagnostic {
+ } else if active_diagnostics.is_valid {
+ let mut new_styles = HashMap::new();
+ for (block_id, diagnostic) in &active_diagnostics.blocks {
+ let build_settings = self.build_settings.clone();
+ let severity = diagnostic.severity;
+ new_styles.insert(
+ *block_id,
+ Some(move |cx: &AppContext| {
+ let settings = build_settings.borrow()(cx);
+ diagnostic_style(severity, false, &settings.style).block
+ }),
+ );
+ }
+ self.display_map
+ .update(cx, |display_map, _| display_map.restyle_blocks(new_styles));
+ }
+ }
+ }
+
fn dismiss_diagnostics(&mut self, cx: &mut ViewContext<Self>) {
if let Some(active_diagnostic_group) = self.active_diagnostics.take() {
self.display_map.update(cx, |display_map, cx| {
- display_map.remove_blocks(active_diagnostic_group.block_ids, cx);
+ display_map.remove_blocks(active_diagnostic_group.blocks.into_keys().collect(), cx);
});
cx.notify();
}
@@ -2799,6 +2848,7 @@ impl Editor {
}
fn on_buffer_changed(&mut self, _: ModelHandle<Buffer>, cx: &mut ViewContext<Self>) {
+ self.refresh_active_diagnostics(cx);
cx.notify();
}