Include diagnostic info in HighlightedChunks iterator
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
f1db618be2
commit
c539069cbb
12 changed files with 248 additions and 90 deletions
|
@ -972,16 +972,16 @@ mod tests {
|
|||
) -> Vec<(String, Option<&'a str>)> {
|
||||
let mut snapshot = map.update(cx, |map, cx| map.snapshot(cx));
|
||||
let mut chunks: Vec<(String, Option<&str>)> = Vec::new();
|
||||
for (chunk, style_id) in snapshot.highlighted_chunks_for_rows(rows) {
|
||||
let style_name = style_id.name(theme);
|
||||
for chunk in snapshot.highlighted_chunks_for_rows(rows) {
|
||||
let style_name = chunk.highlight_id.name(theme);
|
||||
if let Some((last_chunk, last_style_name)) = chunks.last_mut() {
|
||||
if style_name == *last_style_name {
|
||||
last_chunk.push_str(chunk);
|
||||
last_chunk.push_str(chunk.text);
|
||||
} else {
|
||||
chunks.push((chunk.to_string(), style_name));
|
||||
chunks.push((chunk.text.to_string(), style_name));
|
||||
}
|
||||
} else {
|
||||
chunks.push((chunk.to_string(), style_name));
|
||||
chunks.push((chunk.text.to_string(), style_name));
|
||||
}
|
||||
}
|
||||
chunks
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
use gpui::{AppContext, ModelHandle};
|
||||
use language::{Anchor, AnchorRangeExt, Buffer, HighlightId, Point, TextSummary, ToOffset};
|
||||
use language::{
|
||||
Anchor, AnchorRangeExt, Buffer, HighlightId, HighlightedChunk, Point, TextSummary, ToOffset,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
cmp::{self, Ordering},
|
||||
|
@ -995,12 +997,12 @@ impl<'a> Iterator for Chunks<'a> {
|
|||
pub struct HighlightedChunks<'a> {
|
||||
transform_cursor: Cursor<'a, Transform, (FoldOffset, usize)>,
|
||||
buffer_chunks: language::HighlightedChunks<'a>,
|
||||
buffer_chunk: Option<(usize, &'a str, HighlightId)>,
|
||||
buffer_chunk: Option<(usize, HighlightedChunk<'a>)>,
|
||||
buffer_offset: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for HighlightedChunks<'a> {
|
||||
type Item = (&'a str, HighlightId);
|
||||
type Item = HighlightedChunk<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let transform = if let Some(item) = self.transform_cursor.item() {
|
||||
|
@ -1022,34 +1024,35 @@ impl<'a> Iterator for HighlightedChunks<'a> {
|
|||
self.transform_cursor.next(&());
|
||||
}
|
||||
|
||||
return Some((output_text, HighlightId::default()));
|
||||
return Some(HighlightedChunk {
|
||||
text: output_text,
|
||||
highlight_id: HighlightId::default(),
|
||||
diagnostic: None,
|
||||
});
|
||||
}
|
||||
|
||||
// Retrieve a chunk from the current location in the buffer.
|
||||
if self.buffer_chunk.is_none() {
|
||||
let chunk_offset = self.buffer_chunks.offset();
|
||||
self.buffer_chunk = self
|
||||
.buffer_chunks
|
||||
.next()
|
||||
.map(|(chunk, capture_ix)| (chunk_offset, chunk, capture_ix));
|
||||
self.buffer_chunk = self.buffer_chunks.next().map(|chunk| (chunk_offset, chunk));
|
||||
}
|
||||
|
||||
// Otherwise, take a chunk from the buffer's text.
|
||||
if let Some((chunk_offset, mut chunk, capture_ix)) = self.buffer_chunk {
|
||||
if let Some((chunk_offset, mut chunk)) = self.buffer_chunk {
|
||||
let offset_in_chunk = self.buffer_offset - chunk_offset;
|
||||
chunk = &chunk[offset_in_chunk..];
|
||||
chunk.text = &chunk.text[offset_in_chunk..];
|
||||
|
||||
// Truncate the chunk so that it ends at the next fold.
|
||||
let region_end = self.transform_cursor.end(&()).1 - self.buffer_offset;
|
||||
if chunk.len() >= region_end {
|
||||
chunk = &chunk[0..region_end];
|
||||
if chunk.text.len() >= region_end {
|
||||
chunk.text = &chunk.text[0..region_end];
|
||||
self.transform_cursor.next(&());
|
||||
} else {
|
||||
self.buffer_chunk.take();
|
||||
}
|
||||
|
||||
self.buffer_offset += chunk.len();
|
||||
return Some((chunk, capture_ix));
|
||||
self.buffer_offset += chunk.text.len();
|
||||
return Some(chunk);
|
||||
}
|
||||
|
||||
None
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::fold_map::{self, FoldEdit, FoldPoint, Snapshot as FoldSnapshot};
|
||||
use language::{rope, HighlightId};
|
||||
use language::{rope, HighlightedChunk};
|
||||
use parking_lot::Mutex;
|
||||
use std::{mem, ops::Range};
|
||||
use sum_tree::Bias;
|
||||
|
@ -173,9 +173,11 @@ impl Snapshot {
|
|||
.highlighted_chunks(input_start..input_end),
|
||||
column: expanded_char_column,
|
||||
tab_size: self.tab_size,
|
||||
chunk: &SPACES[0..to_next_stop],
|
||||
chunk: HighlightedChunk {
|
||||
text: &SPACES[0..to_next_stop],
|
||||
..Default::default()
|
||||
},
|
||||
skip_leading_tab: to_next_stop > 0,
|
||||
style_id: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -415,23 +417,21 @@ impl<'a> Iterator for Chunks<'a> {
|
|||
|
||||
pub struct HighlightedChunks<'a> {
|
||||
fold_chunks: fold_map::HighlightedChunks<'a>,
|
||||
chunk: &'a str,
|
||||
style_id: HighlightId,
|
||||
chunk: HighlightedChunk<'a>,
|
||||
column: usize,
|
||||
tab_size: usize,
|
||||
skip_leading_tab: bool,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for HighlightedChunks<'a> {
|
||||
type Item = (&'a str, HighlightId);
|
||||
type Item = HighlightedChunk<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.chunk.is_empty() {
|
||||
if let Some((chunk, style_id)) = self.fold_chunks.next() {
|
||||
if self.chunk.text.is_empty() {
|
||||
if let Some(chunk) = self.fold_chunks.next() {
|
||||
self.chunk = chunk;
|
||||
self.style_id = style_id;
|
||||
if self.skip_leading_tab {
|
||||
self.chunk = &self.chunk[1..];
|
||||
self.chunk.text = &self.chunk.text[1..];
|
||||
self.skip_leading_tab = false;
|
||||
}
|
||||
} else {
|
||||
|
@ -439,18 +439,24 @@ impl<'a> Iterator for HighlightedChunks<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
for (ix, c) in self.chunk.char_indices() {
|
||||
for (ix, c) in self.chunk.text.char_indices() {
|
||||
match c {
|
||||
'\t' => {
|
||||
if ix > 0 {
|
||||
let (prefix, suffix) = self.chunk.split_at(ix);
|
||||
self.chunk = suffix;
|
||||
return Some((prefix, self.style_id));
|
||||
let (prefix, suffix) = self.chunk.text.split_at(ix);
|
||||
self.chunk.text = suffix;
|
||||
return Some(HighlightedChunk {
|
||||
text: prefix,
|
||||
..self.chunk
|
||||
});
|
||||
} else {
|
||||
self.chunk = &self.chunk[1..];
|
||||
self.chunk.text = &self.chunk.text[1..];
|
||||
let len = self.tab_size - self.column % self.tab_size;
|
||||
self.column += len;
|
||||
return Some((&SPACES[0..len], self.style_id));
|
||||
return Some(HighlightedChunk {
|
||||
text: &SPACES[0..len],
|
||||
..self.chunk
|
||||
});
|
||||
}
|
||||
}
|
||||
'\n' => self.column = 0,
|
||||
|
@ -458,7 +464,7 @@ impl<'a> Iterator for HighlightedChunks<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
Some((mem::take(&mut self.chunk), mem::take(&mut self.style_id)))
|
||||
Some(mem::take(&mut self.chunk))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use super::{
|
|||
tab_map::{self, Edit as TabEdit, Snapshot as TabSnapshot, TabPoint, TextSummary},
|
||||
};
|
||||
use gpui::{fonts::FontId, text_layout::LineWrapper, Entity, ModelContext, Task};
|
||||
use language::{HighlightId, Point};
|
||||
use language::{HighlightedChunk, Point};
|
||||
use lazy_static::lazy_static;
|
||||
use smol::future::yield_now;
|
||||
use std::{collections::VecDeque, ops::Range, time::Duration};
|
||||
|
@ -52,8 +52,7 @@ pub struct Chunks<'a> {
|
|||
|
||||
pub struct HighlightedChunks<'a> {
|
||||
input_chunks: tab_map::HighlightedChunks<'a>,
|
||||
input_chunk: &'a str,
|
||||
style_id: HighlightId,
|
||||
input_chunk: HighlightedChunk<'a>,
|
||||
output_position: WrapPoint,
|
||||
max_output_row: u32,
|
||||
transforms: Cursor<'a, Transform, (WrapPoint, TabPoint)>,
|
||||
|
@ -490,8 +489,7 @@ impl Snapshot {
|
|||
.min(self.tab_snapshot.max_point());
|
||||
HighlightedChunks {
|
||||
input_chunks: self.tab_snapshot.highlighted_chunks(input_start..input_end),
|
||||
input_chunk: "",
|
||||
style_id: HighlightId::default(),
|
||||
input_chunk: Default::default(),
|
||||
output_position: output_start,
|
||||
max_output_row: rows.end,
|
||||
transforms,
|
||||
|
@ -674,7 +672,7 @@ impl<'a> Iterator for Chunks<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Iterator for HighlightedChunks<'a> {
|
||||
type Item = (&'a str, HighlightId);
|
||||
type Item = HighlightedChunk<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.output_position.row() >= self.max_output_row {
|
||||
|
@ -699,18 +697,19 @@ impl<'a> Iterator for HighlightedChunks<'a> {
|
|||
|
||||
self.output_position.0 += summary;
|
||||
self.transforms.next(&());
|
||||
return Some((&display_text[start_ix..end_ix], self.style_id));
|
||||
return Some(HighlightedChunk {
|
||||
text: &display_text[start_ix..end_ix],
|
||||
..self.input_chunk
|
||||
});
|
||||
}
|
||||
|
||||
if self.input_chunk.is_empty() {
|
||||
let (chunk, style_id) = self.input_chunks.next().unwrap();
|
||||
self.input_chunk = chunk;
|
||||
self.style_id = style_id;
|
||||
if self.input_chunk.text.is_empty() {
|
||||
self.input_chunk = self.input_chunks.next().unwrap();
|
||||
}
|
||||
|
||||
let mut input_len = 0;
|
||||
let transform_end = self.transforms.end(&()).0;
|
||||
for c in self.input_chunk.chars() {
|
||||
for c in self.input_chunk.text.chars() {
|
||||
let char_len = c.len_utf8();
|
||||
input_len += char_len;
|
||||
if c == '\n' {
|
||||
|
@ -726,9 +725,12 @@ impl<'a> Iterator for HighlightedChunks<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
let (prefix, suffix) = self.input_chunk.split_at(input_len);
|
||||
self.input_chunk = suffix;
|
||||
Some((prefix, self.style_id))
|
||||
let (prefix, suffix) = self.input_chunk.text.split_at(input_len);
|
||||
self.input_chunk.text = suffix;
|
||||
Some(HighlightedChunk {
|
||||
text: prefix,
|
||||
..self.input_chunk
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1090,7 +1092,7 @@ mod tests {
|
|||
|
||||
let actual_text = self
|
||||
.highlighted_chunks_for_rows(start_row..end_row)
|
||||
.map(|c| c.0)
|
||||
.map(|c| c.text)
|
||||
.collect::<String>();
|
||||
assert_eq!(
|
||||
expected_text,
|
||||
|
|
|
@ -17,7 +17,7 @@ use gpui::{
|
|||
MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle,
|
||||
};
|
||||
use json::json;
|
||||
use language::HighlightId;
|
||||
use language::{DiagnosticSeverity, HighlightedChunk};
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
cmp::{self, Ordering},
|
||||
|
@ -495,8 +495,12 @@ impl EditorElement {
|
|||
let mut line_exceeded_max_len = false;
|
||||
let chunks = snapshot.highlighted_chunks_for_rows(rows.clone());
|
||||
|
||||
'outer: for (chunk, style_ix) in chunks.chain(Some(("\n", HighlightId::default()))) {
|
||||
for (ix, mut line_chunk) in chunk.split('\n').enumerate() {
|
||||
let newline_chunk = HighlightedChunk {
|
||||
text: "\n",
|
||||
..Default::default()
|
||||
};
|
||||
'outer: for chunk in chunks.chain([newline_chunk]) {
|
||||
for (ix, mut line_chunk) in chunk.text.split('\n').enumerate() {
|
||||
if ix > 0 {
|
||||
layouts.push(cx.text_layout_cache.layout_str(
|
||||
&line,
|
||||
|
@ -513,7 +517,8 @@ impl EditorElement {
|
|||
}
|
||||
|
||||
if !line_chunk.is_empty() && !line_exceeded_max_len {
|
||||
let highlight_style = style_ix
|
||||
let highlight_style = chunk
|
||||
.highlight_id
|
||||
.style(&style.syntax)
|
||||
.unwrap_or(style.text.clone().into());
|
||||
// Avoid a lookup if the font properties match the previous ones.
|
||||
|
@ -537,13 +542,25 @@ impl EditorElement {
|
|||
line_exceeded_max_len = true;
|
||||
}
|
||||
|
||||
let underline = if let Some(severity) = chunk.diagnostic {
|
||||
match severity {
|
||||
DiagnosticSeverity::ERROR => Some(style.error_underline),
|
||||
DiagnosticSeverity::WARNING => Some(style.warning_underline),
|
||||
DiagnosticSeverity::INFORMATION => Some(style.information_underline),
|
||||
DiagnosticSeverity::HINT => Some(style.hint_underline),
|
||||
_ => highlight_style.underline,
|
||||
}
|
||||
} else {
|
||||
highlight_style.underline
|
||||
};
|
||||
|
||||
line.push_str(line_chunk);
|
||||
styles.push((
|
||||
line_chunk.len(),
|
||||
RunStyle {
|
||||
font_id,
|
||||
color: highlight_style.color,
|
||||
underline: highlight_style.underline,
|
||||
underline,
|
||||
},
|
||||
));
|
||||
prev_font_id = font_id;
|
||||
|
|
|
@ -2774,6 +2774,10 @@ impl EditorSettings {
|
|||
selection: Default::default(),
|
||||
guest_selections: Default::default(),
|
||||
syntax: Default::default(),
|
||||
error_underline: Default::default(),
|
||||
warning_underline: Default::default(),
|
||||
information_underline: Default::default(),
|
||||
hint_underline: Default::default(),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue