Implement chunks of the InlayMap

Co-Authored-By: Antonio Scandurra <antonio@zed.dev>
This commit is contained in:
Kirill Bulatov 2023-06-08 16:44:01 +03:00
parent 3028767d12
commit 5ad85b44d6
2 changed files with 112 additions and 16 deletions

View file

@ -2,7 +2,7 @@
// TODO kb // TODO kb
use std::{ use std::{
cmp::Reverse, cmp::{self, Reverse},
ops::{Add, AddAssign, Range, Sub}, ops::{Add, AddAssign, Range, Sub},
sync::atomic::{self, AtomicUsize}, sync::atomic::{self, AtomicUsize},
}; };
@ -22,7 +22,7 @@ use language::{Chunk, Edit, Point, Rope, TextSummary};
use parking_lot::Mutex; use parking_lot::Mutex;
use project::InlayHint; use project::InlayHint;
use rand::Rng; use rand::Rng;
use sum_tree::{Bias, SumTree}; use sum_tree::{Bias, Cursor, SumTree};
use util::post_inc; use util::post_inc;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
@ -42,7 +42,7 @@ pub struct InlaySnapshot {
pub version: usize, pub version: usize,
} }
#[derive(Clone)] #[derive(Clone, Debug)]
enum Transform { enum Transform {
Isomorphic(TextSummary), Isomorphic(TextSummary),
Inlay(Inlay), Inlay(Inlay),
@ -107,6 +107,18 @@ impl AddAssign for InlayOffset {
} }
} }
impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayOffset {
fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
self.0 += &summary.output.len;
}
}
impl<'a> sum_tree::Dimension<'a, TransformSummary> for SuggestionOffset {
fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
self.0 += &summary.input.len;
}
}
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)] #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
pub struct InlayPoint(pub Point); pub struct InlayPoint(pub Point);
@ -128,7 +140,12 @@ pub struct InlayBufferRows<'a> {
} }
pub struct InlayChunks<'a> { pub struct InlayChunks<'a> {
transforms: Cursor<'a, Transform, (InlayOffset, SuggestionOffset)>,
suggestion_chunks: SuggestionChunks<'a>, suggestion_chunks: SuggestionChunks<'a>,
suggestion_chunk: Option<Chunk<'a>>,
inlay_chunks: Option<text::Chunks<'a>>,
output_offset: InlayOffset,
max_output_offset: InlayOffset,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -147,7 +164,49 @@ impl<'a> Iterator for InlayChunks<'a> {
type Item = Chunk<'a>; type Item = Chunk<'a>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
self.suggestion_chunks.next() if self.output_offset == self.max_output_offset {
return None;
}
let chunk = match self.transforms.item()? {
Transform::Isomorphic(transform) => {
let chunk = self
.suggestion_chunk
.get_or_insert_with(|| self.suggestion_chunks.next().unwrap());
if chunk.text.is_empty() {
*chunk = self.suggestion_chunks.next().unwrap();
}
let (prefix, suffix) = chunk.text.split_at(transform.len);
chunk.text = suffix;
self.output_offset.0 += prefix.len();
Chunk {
text: prefix,
..chunk.clone()
}
}
Transform::Inlay(inlay) => {
let inlay_chunks = self.inlay_chunks.get_or_insert_with(|| {
let start = self.output_offset - self.transforms.start().0;
let end = cmp::min(self.max_output_offset, self.transforms.end(&()).0)
- self.transforms.start().0;
inlay.properties.text.chunks_in_range(start.0..end.0)
});
let chunk = inlay_chunks.next().unwrap();
self.output_offset.0 += chunk.len();
Chunk {
text: chunk,
..Default::default()
}
}
};
if self.output_offset == self.transforms.end(&()).0 {
self.transforms.next(&());
}
Some(chunk)
} }
} }
@ -178,7 +237,10 @@ impl InlayMap {
let snapshot = InlaySnapshot { let snapshot = InlaySnapshot {
suggestion_snapshot: suggestion_snapshot.clone(), suggestion_snapshot: suggestion_snapshot.clone(),
version: 0, version: 0,
transforms: SumTree::new(), transforms: SumTree::from_item(
Transform::Isomorphic(suggestion_snapshot.text_summary()),
&(),
),
}; };
( (
@ -348,9 +410,12 @@ impl InlaySnapshot {
) )
} }
pub fn len(&self) -> InlayOffset {
InlayOffset(self.transforms.summary().output.len)
}
pub fn max_point(&self) -> InlayPoint { pub fn max_point(&self) -> InlayPoint {
// TODO kb copied from suggestion_map InlayPoint(self.transforms.summary().output.lines)
self.to_inlay_point(self.suggestion_snapshot.max_point())
} }
pub fn to_offset(&self, point: InlayPoint) -> InlayOffset { pub fn to_offset(&self, point: InlayPoint) -> InlayOffset {
@ -372,6 +437,19 @@ impl InlaySnapshot {
SuggestionPoint(point.0) SuggestionPoint(point.0)
} }
pub fn to_suggestion_offset(&self, offset: InlayOffset) -> SuggestionOffset {
let mut cursor = self.transforms.cursor::<(InlayOffset, SuggestionOffset)>();
cursor.seek(&offset, Bias::Right, &());
match cursor.item() {
Some(Transform::Isomorphic(transform)) => {
let overshoot = offset - cursor.start().0;
cursor.start().1 + SuggestionOffset(overshoot.0)
}
Some(Transform::Inlay(inlay)) => cursor.start().1,
None => self.suggestion_snapshot.len(),
}
}
pub fn to_inlay_point(&self, point: SuggestionPoint) -> InlayPoint { pub fn to_inlay_point(&self, point: SuggestionPoint) -> InlayPoint {
InlayPoint(point.0) InlayPoint(point.0)
} }
@ -410,21 +488,35 @@ impl InlaySnapshot {
text_highlights: Option<&'a TextHighlights>, text_highlights: Option<&'a TextHighlights>,
suggestion_highlight: Option<HighlightStyle>, suggestion_highlight: Option<HighlightStyle>,
) -> InlayChunks<'a> { ) -> InlayChunks<'a> {
// TODO kb copied from suggestion_map dbg!(self.transforms.items(&()));
let mut cursor = self.transforms.cursor::<(InlayOffset, SuggestionOffset)>();
cursor.seek(&range.start, Bias::Right, &());
let suggestion_range =
self.to_suggestion_offset(range.start)..self.to_suggestion_offset(range.end);
let suggestion_chunks = self.suggestion_snapshot.chunks(
suggestion_range,
language_aware,
text_highlights,
suggestion_highlight,
);
InlayChunks { InlayChunks {
suggestion_chunks: self.suggestion_snapshot.chunks( transforms: cursor,
SuggestionOffset(range.start.0)..SuggestionOffset(range.end.0), suggestion_chunks,
language_aware, inlay_chunks: None,
text_highlights, suggestion_chunk: None,
suggestion_highlight, output_offset: range.start,
), max_output_offset: range.end,
} }
} }
#[cfg(test)] #[cfg(test)]
pub fn text(&self) -> String { pub fn text(&self) -> String {
// TODO kb copied from suggestion_map self.chunks(Default::default()..self.len(), false, None, None)
self.suggestion_snapshot.text() .map(|chunk| chunk.text)
.collect()
} }
} }

View file

@ -358,6 +358,10 @@ impl SuggestionSnapshot {
} }
} }
pub fn text_summary(&self) -> TextSummary {
self.text_summary_for_range(Default::default()..self.max_point())
}
pub fn text_summary_for_range(&self, range: Range<SuggestionPoint>) -> TextSummary { pub fn text_summary_for_range(&self, range: Range<SuggestionPoint>) -> TextSummary {
if let Some(suggestion) = self.suggestion.as_ref() { if let Some(suggestion) = self.suggestion.as_ref() {
let suggestion_start = suggestion.position.to_point(&self.fold_snapshot).0; let suggestion_start = suggestion.position.to_point(&self.fold_snapshot).0;