mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-07 02:57:34 +00:00
Move inlay map to be the first one
Co-Authored-By: Antonio Scandurra <antonio@zed.dev>
This commit is contained in:
parent
e744fb8842
commit
10765d69f4
8 changed files with 783 additions and 1635 deletions
|
@ -72,8 +72,8 @@ impl DisplayMap {
|
|||
let buffer_subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
|
||||
|
||||
let tab_size = Self::tab_size(&buffer, cx);
|
||||
let (fold_map, snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx));
|
||||
let (inlay_map, snapshot) = InlayMap::new(snapshot);
|
||||
let (inlay_map, snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx));
|
||||
let (fold_map, snapshot) = FoldMap::new(snapshot);
|
||||
let (tab_map, snapshot) = TabMap::new(snapshot, tab_size);
|
||||
let (wrap_map, snapshot) = WrapMap::new(snapshot, font_id, font_size, wrap_width, cx);
|
||||
let block_map = BlockMap::new(snapshot, buffer_header_height, excerpt_header_height);
|
||||
|
@ -94,10 +94,10 @@ impl DisplayMap {
|
|||
pub fn snapshot(&mut self, cx: &mut ModelContext<Self>) -> DisplaySnapshot {
|
||||
let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let edits = self.buffer_subscription.consume().into_inner();
|
||||
let (fold_snapshot, edits) = self.fold_map.read(buffer_snapshot, edits);
|
||||
let (inlay_snapshot, edits) = self.inlay_map.sync(fold_snapshot.clone(), edits);
|
||||
let (inlay_snapshot, edits) = self.inlay_map.sync(buffer_snapshot, edits);
|
||||
let (fold_snapshot, edits) = self.fold_map.read(inlay_snapshot.clone(), edits);
|
||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||
let (tab_snapshot, edits) = self.tab_map.sync(inlay_snapshot.clone(), edits, tab_size);
|
||||
let (tab_snapshot, edits) = self.tab_map.sync(fold_snapshot.clone(), edits, tab_size);
|
||||
let (wrap_snapshot, edits) = self
|
||||
.wrap_map
|
||||
.update(cx, |map, cx| map.sync(tab_snapshot.clone(), edits, cx));
|
||||
|
@ -132,15 +132,14 @@ impl DisplayMap {
|
|||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let edits = self.buffer_subscription.consume().into_inner();
|
||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||
let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
let (snapshot, edits) = self
|
||||
.wrap_map
|
||||
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
|
||||
self.block_map.read(snapshot, edits);
|
||||
let (snapshot, edits) = fold_map.fold(ranges);
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
let (snapshot, edits) = self
|
||||
.wrap_map
|
||||
|
@ -157,15 +156,14 @@ impl DisplayMap {
|
|||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let edits = self.buffer_subscription.consume().into_inner();
|
||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||
let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
let (snapshot, edits) = self
|
||||
.wrap_map
|
||||
.update(cx, |map, cx| map.sync(snapshot, edits, cx));
|
||||
self.block_map.read(snapshot, edits);
|
||||
let (snapshot, edits) = fold_map.unfold(ranges, inclusive);
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
let (snapshot, edits) = self
|
||||
.wrap_map
|
||||
|
@ -181,8 +179,8 @@ impl DisplayMap {
|
|||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let edits = self.buffer_subscription.consume().into_inner();
|
||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
let (snapshot, edits) = self
|
||||
.wrap_map
|
||||
|
@ -199,8 +197,8 @@ impl DisplayMap {
|
|||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let edits = self.buffer_subscription.consume().into_inner();
|
||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
let (snapshot, edits) = self
|
||||
.wrap_map
|
||||
|
@ -253,9 +251,9 @@ impl DisplayMap {
|
|||
) {
|
||||
let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let edits = self.buffer_subscription.consume().into_inner();
|
||||
let (snapshot, edits) = self.inlay_map.sync(buffer_snapshot, edits);
|
||||
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||
let tab_size = Self::tab_size(&self.buffer, cx);
|
||||
let (snapshot, edits) = self.fold_map.read(buffer_snapshot.clone(), edits);
|
||||
let (snapshot, edits) = self.inlay_map.sync(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
let (snapshot, edits) = self
|
||||
.wrap_map
|
||||
|
@ -263,6 +261,7 @@ impl DisplayMap {
|
|||
self.block_map.read(snapshot, edits);
|
||||
|
||||
let (snapshot, edits) = self.inlay_map.splice(to_remove, to_insert);
|
||||
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits, tab_size);
|
||||
let (snapshot, edits) = self
|
||||
.wrap_map
|
||||
|
@ -315,9 +314,9 @@ impl DisplaySnapshot {
|
|||
|
||||
pub fn prev_line_boundary(&self, mut point: Point) -> (Point, DisplayPoint) {
|
||||
loop {
|
||||
let mut fold_point = self.fold_snapshot.to_fold_point(point, Bias::Left);
|
||||
*fold_point.column_mut() = 0;
|
||||
point = fold_point.to_buffer_point(&self.fold_snapshot);
|
||||
let mut inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
||||
inlay_point.0.column = 0;
|
||||
point = self.inlay_snapshot.to_buffer_point(inlay_point);
|
||||
|
||||
let mut display_point = self.point_to_display_point(point, Bias::Left);
|
||||
*display_point.column_mut() = 0;
|
||||
|
@ -331,9 +330,9 @@ impl DisplaySnapshot {
|
|||
|
||||
pub fn next_line_boundary(&self, mut point: Point) -> (Point, DisplayPoint) {
|
||||
loop {
|
||||
let mut fold_point = self.fold_snapshot.to_fold_point(point, Bias::Right);
|
||||
*fold_point.column_mut() = self.fold_snapshot.line_len(fold_point.row());
|
||||
point = fold_point.to_buffer_point(&self.fold_snapshot);
|
||||
let mut inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
||||
inlay_point.0.column = self.inlay_snapshot.line_len(inlay_point.row());
|
||||
point = self.inlay_snapshot.to_buffer_point(inlay_point);
|
||||
|
||||
let mut display_point = self.point_to_display_point(point, Bias::Right);
|
||||
*display_point.column_mut() = self.line_len(display_point.row());
|
||||
|
@ -363,9 +362,9 @@ impl DisplaySnapshot {
|
|||
}
|
||||
|
||||
fn point_to_display_point(&self, point: Point, bias: Bias) -> DisplayPoint {
|
||||
let fold_point = self.fold_snapshot.to_fold_point(point, bias);
|
||||
let inlay_point = self.inlay_snapshot.to_inlay_point(fold_point);
|
||||
let tab_point = self.tab_snapshot.to_tab_point(inlay_point);
|
||||
let inlay_point = self.inlay_snapshot.to_inlay_point(point);
|
||||
let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias);
|
||||
let tab_point = self.tab_snapshot.to_tab_point(fold_point);
|
||||
let wrap_point = self.wrap_snapshot.tab_point_to_wrap_point(tab_point);
|
||||
let block_point = self.block_snapshot.to_block_point(wrap_point);
|
||||
DisplayPoint(block_point)
|
||||
|
@ -375,9 +374,9 @@ impl DisplaySnapshot {
|
|||
let block_point = point.0;
|
||||
let wrap_point = self.block_snapshot.to_wrap_point(block_point);
|
||||
let tab_point = self.wrap_snapshot.to_tab_point(wrap_point);
|
||||
let inlay_point = self.tab_snapshot.to_inlay_point(tab_point, bias).0;
|
||||
let fold_point = self.inlay_snapshot.to_fold_point(inlay_point);
|
||||
fold_point.to_buffer_point(&self.fold_snapshot)
|
||||
let fold_point = self.tab_snapshot.to_fold_point(tab_point, bias).0;
|
||||
let inlay_point = fold_point.to_inlay_point(&self.fold_snapshot);
|
||||
self.inlay_snapshot.to_buffer_point(inlay_point)
|
||||
}
|
||||
|
||||
pub fn max_point(&self) -> DisplayPoint {
|
||||
|
@ -407,13 +406,13 @@ impl DisplaySnapshot {
|
|||
&self,
|
||||
display_rows: Range<u32>,
|
||||
language_aware: bool,
|
||||
suggestion_highlight: Option<HighlightStyle>,
|
||||
inlay_highlights: Option<HighlightStyle>,
|
||||
) -> DisplayChunks<'_> {
|
||||
self.block_snapshot.chunks(
|
||||
display_rows,
|
||||
language_aware,
|
||||
Some(&self.text_highlights),
|
||||
suggestion_highlight,
|
||||
inlay_highlights,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -789,9 +788,10 @@ impl DisplayPoint {
|
|||
pub fn to_offset(self, map: &DisplaySnapshot, bias: Bias) -> usize {
|
||||
let wrap_point = map.block_snapshot.to_wrap_point(self.0);
|
||||
let tab_point = map.wrap_snapshot.to_tab_point(wrap_point);
|
||||
let inlay_point = map.tab_snapshot.to_inlay_point(tab_point, bias).0;
|
||||
let fold_point = map.inlay_snapshot.to_fold_point(inlay_point);
|
||||
fold_point.to_buffer_offset(&map.fold_snapshot)
|
||||
let fold_point = map.tab_snapshot.to_fold_point(tab_point, bias).0;
|
||||
let inlay_point = fold_point.to_inlay_point(&map.fold_snapshot);
|
||||
map.inlay_snapshot
|
||||
.to_buffer_offset(map.inlay_snapshot.to_offset(inlay_point))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -583,7 +583,7 @@ impl BlockSnapshot {
|
|||
rows: Range<u32>,
|
||||
language_aware: bool,
|
||||
text_highlights: Option<&'a TextHighlights>,
|
||||
suggestion_highlight: Option<HighlightStyle>,
|
||||
inlay_highlights: Option<HighlightStyle>,
|
||||
) -> BlockChunks<'a> {
|
||||
let max_output_row = cmp::min(rows.end, self.transforms.summary().output_rows);
|
||||
let mut cursor = self.transforms.cursor::<(BlockRow, WrapRow)>();
|
||||
|
@ -616,7 +616,7 @@ impl BlockSnapshot {
|
|||
input_start..input_end,
|
||||
language_aware,
|
||||
text_highlights,
|
||||
suggestion_highlight,
|
||||
inlay_highlights,
|
||||
),
|
||||
input_chunk: Default::default(),
|
||||
transforms: cursor,
|
||||
|
@ -1030,9 +1030,9 @@ mod tests {
|
|||
let buffer = MultiBuffer::build_simple(text, cx);
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
|
||||
let (fold_map, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(fold_snapshot);
|
||||
let (tab_map, tab_snapshot) = TabMap::new(inlay_snapshot, 1.try_into().unwrap());
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (tab_map, tab_snapshot) = TabMap::new(fold_snapshot, 1.try_into().unwrap());
|
||||
let (wrap_map, wraps_snapshot) = WrapMap::new(tab_snapshot, font_id, 14.0, None, cx);
|
||||
let mut block_map = BlockMap::new(wraps_snapshot.clone(), 1, 1);
|
||||
|
||||
|
@ -1175,11 +1175,11 @@ mod tests {
|
|||
buffer.snapshot(cx)
|
||||
});
|
||||
|
||||
let (fold_snapshot, fold_edits) =
|
||||
fold_map.read(buffer_snapshot, subscription.consume().into_inner());
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(fold_snapshot, fold_edits);
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot, subscription.consume().into_inner());
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
|
||||
let (tab_snapshot, tab_edits) =
|
||||
tab_map.sync(inlay_snapshot, inlay_edits, 4.try_into().unwrap());
|
||||
tab_map.sync(fold_snapshot, fold_edits, 4.try_into().unwrap());
|
||||
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
||||
wrap_map.sync(tab_snapshot, tab_edits, cx)
|
||||
});
|
||||
|
@ -1204,9 +1204,9 @@ mod tests {
|
|||
|
||||
let buffer = MultiBuffer::build_simple(text, cx);
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (_, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
|
||||
let (_, inlay_snapshot) = InlayMap::new(fold_snapshot);
|
||||
let (_, tab_snapshot) = TabMap::new(inlay_snapshot, 4.try_into().unwrap());
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
let (_, wraps_snapshot) = WrapMap::new(tab_snapshot, font_id, 14.0, Some(60.), cx);
|
||||
let mut block_map = BlockMap::new(wraps_snapshot.clone(), 1, 1);
|
||||
|
||||
|
@ -1276,9 +1276,9 @@ mod tests {
|
|||
};
|
||||
|
||||
let mut buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (fold_map, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(fold_snapshot);
|
||||
let (tab_map, tab_snapshot) = TabMap::new(inlay_snapshot, 4.try_into().unwrap());
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (tab_map, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
let (wrap_map, wraps_snapshot) =
|
||||
WrapMap::new(tab_snapshot, font_id, font_size, wrap_width, cx);
|
||||
let mut block_map = BlockMap::new(
|
||||
|
@ -1331,11 +1331,11 @@ mod tests {
|
|||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let (fold_snapshot, fold_edits) =
|
||||
fold_map.read(buffer_snapshot.clone(), vec![]);
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(fold_snapshot, fold_edits);
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot.clone(), vec![]);
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
|
||||
let (tab_snapshot, tab_edits) =
|
||||
tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
|
||||
tab_map.sync(fold_snapshot, fold_edits, tab_size);
|
||||
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
||||
wrap_map.sync(tab_snapshot, tab_edits, cx)
|
||||
});
|
||||
|
@ -1355,11 +1355,11 @@ mod tests {
|
|||
})
|
||||
.collect();
|
||||
|
||||
let (fold_snapshot, fold_edits) =
|
||||
fold_map.read(buffer_snapshot.clone(), vec![]);
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(fold_snapshot, fold_edits);
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot.clone(), vec![]);
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
|
||||
let (tab_snapshot, tab_edits) =
|
||||
tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
|
||||
tab_map.sync(fold_snapshot, fold_edits, tab_size);
|
||||
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
||||
wrap_map.sync(tab_snapshot, tab_edits, cx)
|
||||
});
|
||||
|
@ -1378,9 +1378,10 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(buffer_snapshot.clone(), buffer_edits);
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(fold_snapshot, fold_edits);
|
||||
let (tab_snapshot, tab_edits) = tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot.clone(), buffer_edits);
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
|
||||
let (tab_snapshot, tab_edits) = tab_map.sync(fold_snapshot, fold_edits, tab_size);
|
||||
let (wraps_snapshot, wrap_edits) = wrap_map.update(cx, |wrap_map, cx| {
|
||||
wrap_map.sync(tab_snapshot, tab_edits, cx)
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,9 +1,6 @@
|
|||
use super::{
|
||||
fold_map::{FoldBufferRows, FoldChunks, FoldEdit, FoldOffset, FoldPoint, FoldSnapshot},
|
||||
TextHighlights,
|
||||
};
|
||||
use crate::{
|
||||
inlay_cache::{Inlay, InlayId, InlayProperties},
|
||||
multi_buffer::{MultiBufferChunks, MultiBufferRows},
|
||||
MultiBufferSnapshot, ToPoint,
|
||||
};
|
||||
use collections::{BTreeSet, HashMap};
|
||||
|
@ -16,17 +13,19 @@ use std::{
|
|||
};
|
||||
use sum_tree::{Bias, Cursor, SumTree};
|
||||
use text::Patch;
|
||||
use util::post_inc;
|
||||
|
||||
pub struct InlayMap {
|
||||
snapshot: Mutex<InlaySnapshot>,
|
||||
buffer: Mutex<MultiBufferSnapshot>,
|
||||
transforms: SumTree<Transform>,
|
||||
inlays_by_id: HashMap<InlayId, Inlay>,
|
||||
inlays: Vec<Inlay>,
|
||||
version: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct InlaySnapshot {
|
||||
// TODO kb merge these two together
|
||||
pub fold_snapshot: FoldSnapshot,
|
||||
pub buffer: MultiBufferSnapshot,
|
||||
transforms: SumTree<Transform>,
|
||||
pub version: usize,
|
||||
}
|
||||
|
@ -102,12 +101,6 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayOffset {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> sum_tree::Dimension<'a, TransformSummary> for FoldOffset {
|
||||
fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
|
||||
self.0 += &summary.input.len;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||
pub struct InlayPoint(pub Point);
|
||||
|
||||
|
@ -117,23 +110,29 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayPoint {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> sum_tree::Dimension<'a, TransformSummary> for FoldPoint {
|
||||
impl<'a> sum_tree::Dimension<'a, TransformSummary> for usize {
|
||||
fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
|
||||
self.0 += &summary.input.lines;
|
||||
*self += &summary.input.len;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> sum_tree::Dimension<'a, TransformSummary> for Point {
|
||||
fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
|
||||
*self += &summary.input.lines;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct InlayBufferRows<'a> {
|
||||
transforms: Cursor<'a, Transform, (InlayPoint, FoldPoint)>,
|
||||
fold_rows: FoldBufferRows<'a>,
|
||||
transforms: Cursor<'a, Transform, (InlayPoint, Point)>,
|
||||
buffer_rows: MultiBufferRows<'a>,
|
||||
inlay_row: u32,
|
||||
}
|
||||
|
||||
pub struct InlayChunks<'a> {
|
||||
transforms: Cursor<'a, Transform, (InlayOffset, FoldOffset)>,
|
||||
fold_chunks: FoldChunks<'a>,
|
||||
fold_chunk: Option<Chunk<'a>>,
|
||||
transforms: Cursor<'a, Transform, (InlayOffset, usize)>,
|
||||
buffer_chunks: MultiBufferChunks<'a>,
|
||||
buffer_chunk: Option<Chunk<'a>>,
|
||||
inlay_chunks: Option<text::Chunks<'a>>,
|
||||
output_offset: InlayOffset,
|
||||
max_output_offset: InlayOffset,
|
||||
|
@ -151,10 +150,10 @@ impl<'a> Iterator for InlayChunks<'a> {
|
|||
let chunk = match self.transforms.item()? {
|
||||
Transform::Isomorphic(_) => {
|
||||
let chunk = self
|
||||
.fold_chunk
|
||||
.get_or_insert_with(|| self.fold_chunks.next().unwrap());
|
||||
.buffer_chunk
|
||||
.get_or_insert_with(|| self.buffer_chunks.next().unwrap());
|
||||
if chunk.text.is_empty() {
|
||||
*chunk = self.fold_chunks.next().unwrap();
|
||||
*chunk = self.buffer_chunks.next().unwrap();
|
||||
}
|
||||
|
||||
let (prefix, suffix) = chunk.text.split_at(cmp::min(
|
||||
|
@ -201,11 +200,11 @@ impl<'a> Iterator for InlayBufferRows<'a> {
|
|||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let buffer_row = if self.inlay_row == 0 {
|
||||
self.fold_rows.next().unwrap()
|
||||
self.buffer_rows.next().unwrap()
|
||||
} else {
|
||||
match self.transforms.item()? {
|
||||
Transform::Inlay(_) => None,
|
||||
Transform::Isomorphic(_) => self.fold_rows.next().unwrap(),
|
||||
Transform::Isomorphic(_) => self.buffer_rows.next().unwrap(),
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -232,21 +231,21 @@ impl InlayPoint {
|
|||
}
|
||||
|
||||
impl InlayMap {
|
||||
pub fn new(fold_snapshot: FoldSnapshot) -> (Self, InlaySnapshot) {
|
||||
pub fn new(buffer: MultiBufferSnapshot) -> (Self, InlaySnapshot) {
|
||||
let version = 0;
|
||||
let snapshot = InlaySnapshot {
|
||||
fold_snapshot: fold_snapshot.clone(),
|
||||
version: 0,
|
||||
transforms: SumTree::from_item(
|
||||
Transform::Isomorphic(fold_snapshot.text_summary()),
|
||||
&(),
|
||||
),
|
||||
buffer: buffer.clone(),
|
||||
transforms: SumTree::from_item(Transform::Isomorphic(buffer.text_summary()), &()),
|
||||
version,
|
||||
};
|
||||
|
||||
(
|
||||
Self {
|
||||
snapshot: Mutex::new(snapshot.clone()),
|
||||
buffer: Mutex::new(buffer),
|
||||
transforms: snapshot.transforms.clone(),
|
||||
inlays_by_id: Default::default(),
|
||||
inlays: Default::default(),
|
||||
version,
|
||||
},
|
||||
snapshot,
|
||||
)
|
||||
|
@ -254,144 +253,140 @@ impl InlayMap {
|
|||
|
||||
pub fn sync(
|
||||
&mut self,
|
||||
fold_snapshot: FoldSnapshot,
|
||||
mut fold_edits: Vec<FoldEdit>,
|
||||
buffer_snapshot: MultiBufferSnapshot,
|
||||
buffer_edits: Vec<text::Edit<usize>>,
|
||||
) -> (InlaySnapshot, Vec<InlayEdit>) {
|
||||
let mut snapshot = self.snapshot.lock();
|
||||
let mut buffer = self.buffer.lock();
|
||||
if buffer_edits.is_empty() {
|
||||
let new_version = if buffer.edit_count() != buffer_snapshot.edit_count()
|
||||
|| buffer.parse_count() != buffer_snapshot.parse_count()
|
||||
|| buffer.diagnostics_update_count() != buffer_snapshot.diagnostics_update_count()
|
||||
|| buffer.git_diff_update_count() != buffer_snapshot.git_diff_update_count()
|
||||
|| buffer.trailing_excerpt_update_count()
|
||||
!= buffer_snapshot.trailing_excerpt_update_count()
|
||||
{
|
||||
post_inc(&mut self.version)
|
||||
} else {
|
||||
self.version
|
||||
};
|
||||
|
||||
let mut new_snapshot = snapshot.clone();
|
||||
if new_snapshot.fold_snapshot.version != fold_snapshot.version {
|
||||
new_snapshot.version += 1;
|
||||
}
|
||||
*buffer = buffer_snapshot.clone();
|
||||
(
|
||||
InlaySnapshot {
|
||||
buffer: buffer_snapshot,
|
||||
transforms: SumTree::default(),
|
||||
version: new_version,
|
||||
},
|
||||
Vec::new(),
|
||||
)
|
||||
} else {
|
||||
let mut inlay_edits = Patch::default();
|
||||
let mut new_transforms = SumTree::new();
|
||||
// TODO kb something is wrong with how we store it?
|
||||
let mut transforms = self.transforms;
|
||||
let mut cursor = transforms.cursor::<(usize, InlayOffset)>();
|
||||
let mut buffer_edits_iter = buffer_edits.iter().peekable();
|
||||
while let Some(buffer_edit) = buffer_edits_iter.next() {
|
||||
new_transforms
|
||||
.push_tree(cursor.slice(&buffer_edit.old.start, Bias::Left, &()), &());
|
||||
if let Some(Transform::Isomorphic(transform)) = cursor.item() {
|
||||
if cursor.end(&()).0 == buffer_edit.old.start {
|
||||
new_transforms.push(Transform::Isomorphic(transform.clone()), &());
|
||||
cursor.next(&());
|
||||
}
|
||||
}
|
||||
|
||||
if fold_snapshot
|
||||
.buffer_snapshot()
|
||||
.trailing_excerpt_update_count()
|
||||
!= snapshot
|
||||
.fold_snapshot
|
||||
.buffer_snapshot()
|
||||
.trailing_excerpt_update_count()
|
||||
{
|
||||
if fold_edits.is_empty() {
|
||||
fold_edits.push(Edit {
|
||||
old: snapshot.fold_snapshot.len()..snapshot.fold_snapshot.len(),
|
||||
new: fold_snapshot.len()..fold_snapshot.len(),
|
||||
// Remove all the inlays and transforms contained by the edit.
|
||||
let old_start =
|
||||
cursor.start().1 + InlayOffset(buffer_edit.old.start - cursor.start().0);
|
||||
cursor.seek(&buffer_edit.old.end, Bias::Right, &());
|
||||
let old_end =
|
||||
cursor.start().1 + InlayOffset(buffer_edit.old.end - cursor.start().0);
|
||||
|
||||
// Push the unchanged prefix.
|
||||
let prefix_start = new_transforms.summary().input.len;
|
||||
let prefix_end = buffer_edit.new.start;
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
buffer_snapshot.text_summary_for_range(prefix_start..prefix_end),
|
||||
);
|
||||
let new_start = InlayOffset(new_transforms.summary().output.len);
|
||||
|
||||
let start_point = buffer_edit.new.start.to_point(&buffer_snapshot);
|
||||
let start_ix = match self.inlays.binary_search_by(|probe| {
|
||||
probe
|
||||
.position
|
||||
.to_point(&buffer_snapshot)
|
||||
.cmp(&start_point)
|
||||
.then(std::cmp::Ordering::Greater)
|
||||
}) {
|
||||
Ok(ix) | Err(ix) => ix,
|
||||
};
|
||||
|
||||
for inlay in &self.inlays[start_ix..] {
|
||||
let buffer_point = inlay.position.to_point(&buffer_snapshot);
|
||||
let buffer_offset = buffer_snapshot.point_to_offset(buffer_point);
|
||||
if buffer_offset > buffer_edit.new.end {
|
||||
break;
|
||||
}
|
||||
|
||||
let prefix_start = new_transforms.summary().input.len;
|
||||
let prefix_end = buffer_offset;
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
buffer_snapshot.text_summary_for_range(prefix_start..prefix_end),
|
||||
);
|
||||
|
||||
if inlay.position.is_valid(&buffer_snapshot) {
|
||||
new_transforms.push(Transform::Inlay(inlay.clone()), &());
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the rest of the edit.
|
||||
let transform_start = new_transforms.summary().input.len;
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
buffer_snapshot.text_summary_for_range(transform_start..buffer_edit.new.end),
|
||||
);
|
||||
let new_end = InlayOffset(new_transforms.summary().output.len);
|
||||
inlay_edits.push(Edit {
|
||||
old: old_start..old_end,
|
||||
new: new_start..new_end,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let mut inlay_edits = Patch::default();
|
||||
let mut new_transforms = SumTree::new();
|
||||
let mut cursor = snapshot.transforms.cursor::<(FoldOffset, InlayOffset)>();
|
||||
let mut fold_edits_iter = fold_edits.iter().peekable();
|
||||
while let Some(fold_edit) = fold_edits_iter.next() {
|
||||
new_transforms.push_tree(cursor.slice(&fold_edit.old.start, Bias::Left, &()), &());
|
||||
if let Some(Transform::Isomorphic(transform)) = cursor.item() {
|
||||
if cursor.end(&()).0 == fold_edit.old.start {
|
||||
new_transforms.push(Transform::Isomorphic(transform.clone()), &());
|
||||
// If the next edit doesn't intersect the current isomorphic transform, then
|
||||
// we can push its remainder.
|
||||
if buffer_edits_iter
|
||||
.peek()
|
||||
.map_or(true, |edit| edit.old.start >= cursor.end(&()).0)
|
||||
{
|
||||
let transform_start = new_transforms.summary().input.len;
|
||||
let transform_end =
|
||||
buffer_edit.new.end + (cursor.end(&()).0 - buffer_edit.old.end);
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
buffer_snapshot.text_summary_for_range(transform_start..transform_end),
|
||||
);
|
||||
cursor.next(&());
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all the inlays and transforms contained by the edit.
|
||||
let old_start =
|
||||
cursor.start().1 + InlayOffset(fold_edit.old.start.0 - cursor.start().0 .0);
|
||||
cursor.seek(&fold_edit.old.end, Bias::Right, &());
|
||||
let old_end = cursor.start().1 + InlayOffset(fold_edit.old.end.0 - cursor.start().0 .0);
|
||||
new_transforms.push_tree(cursor.suffix(&()), &());
|
||||
if new_transforms.first().is_none() {
|
||||
new_transforms.push(Transform::Isomorphic(Default::default()), &());
|
||||
}
|
||||
|
||||
// Push the unchanged prefix.
|
||||
let prefix_start = FoldOffset(new_transforms.summary().input.len);
|
||||
let prefix_end = fold_edit.new.start;
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
fold_snapshot.text_summary_for_range(
|
||||
prefix_start.to_point(&fold_snapshot)..prefix_end.to_point(&fold_snapshot),
|
||||
),
|
||||
);
|
||||
let new_start = InlayOffset(new_transforms.summary().output.len);
|
||||
|
||||
let start_point = fold_edit
|
||||
.new
|
||||
.start
|
||||
.to_point(&fold_snapshot)
|
||||
.to_buffer_point(&fold_snapshot);
|
||||
let start_ix = match self.inlays.binary_search_by(|probe| {
|
||||
probe
|
||||
.position
|
||||
.to_point(&fold_snapshot.buffer_snapshot())
|
||||
.cmp(&start_point)
|
||||
.then(std::cmp::Ordering::Greater)
|
||||
}) {
|
||||
Ok(ix) | Err(ix) => ix,
|
||||
let new_snapshot = InlaySnapshot {
|
||||
buffer: buffer_snapshot,
|
||||
transforms: new_transforms,
|
||||
version: post_inc(&mut self.version),
|
||||
};
|
||||
new_snapshot.check_invariants();
|
||||
drop(cursor);
|
||||
|
||||
for inlay in &self.inlays[start_ix..] {
|
||||
let buffer_point = inlay.position.to_point(fold_snapshot.buffer_snapshot());
|
||||
let fold_point = fold_snapshot.to_fold_point(buffer_point, Bias::Left);
|
||||
let fold_offset = fold_point.to_offset(&fold_snapshot);
|
||||
if fold_offset > fold_edit.new.end {
|
||||
break;
|
||||
}
|
||||
|
||||
let prefix_start = FoldOffset(new_transforms.summary().input.len);
|
||||
let prefix_end = fold_offset;
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
fold_snapshot.text_summary_for_range(
|
||||
prefix_start.to_point(&fold_snapshot)..prefix_end.to_point(&fold_snapshot),
|
||||
),
|
||||
);
|
||||
|
||||
if inlay.position.is_valid(fold_snapshot.buffer_snapshot()) {
|
||||
new_transforms.push(Transform::Inlay(inlay.clone()), &());
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the rest of the edit.
|
||||
let transform_start = FoldOffset(new_transforms.summary().input.len);
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
fold_snapshot.text_summary_for_range(
|
||||
transform_start.to_point(&fold_snapshot)
|
||||
..fold_edit.new.end.to_point(&fold_snapshot),
|
||||
),
|
||||
);
|
||||
let new_end = InlayOffset(new_transforms.summary().output.len);
|
||||
inlay_edits.push(Edit {
|
||||
old: old_start..old_end,
|
||||
new: new_start..new_end,
|
||||
});
|
||||
|
||||
// If the next edit doesn't intersect the current isomorphic transform, then
|
||||
// we can push its remainder.
|
||||
if fold_edits_iter
|
||||
.peek()
|
||||
.map_or(true, |edit| edit.old.start >= cursor.end(&()).0)
|
||||
{
|
||||
let transform_start = FoldOffset(new_transforms.summary().input.len);
|
||||
let transform_end = fold_edit.new.end + (cursor.end(&()).0 - fold_edit.old.end);
|
||||
push_isomorphic(
|
||||
&mut new_transforms,
|
||||
fold_snapshot.text_summary_for_range(
|
||||
transform_start.to_point(&fold_snapshot)
|
||||
..transform_end.to_point(&fold_snapshot),
|
||||
),
|
||||
);
|
||||
cursor.next(&());
|
||||
}
|
||||
*buffer = buffer_snapshot.clone();
|
||||
(new_snapshot, inlay_edits.into_inner())
|
||||
}
|
||||
|
||||
new_transforms.push_tree(cursor.suffix(&()), &());
|
||||
if new_transforms.first().is_none() {
|
||||
new_transforms.push(Transform::Isomorphic(Default::default()), &());
|
||||
}
|
||||
new_snapshot.transforms = new_transforms;
|
||||
new_snapshot.fold_snapshot = fold_snapshot;
|
||||
new_snapshot.check_invariants();
|
||||
drop(cursor);
|
||||
|
||||
*snapshot = new_snapshot.clone();
|
||||
(new_snapshot, inlay_edits.into_inner())
|
||||
}
|
||||
|
||||
pub fn splice<T: Into<Rope>>(
|
||||
|
@ -399,20 +394,15 @@ impl InlayMap {
|
|||
to_remove: Vec<InlayId>,
|
||||
to_insert: Vec<(InlayId, InlayProperties<T>)>,
|
||||
) -> (InlaySnapshot, Vec<InlayEdit>) {
|
||||
let mut snapshot = self.snapshot.lock();
|
||||
snapshot.version += 1;
|
||||
|
||||
let mut buffer_snapshot = self.buffer.lock();
|
||||
let mut edits = BTreeSet::new();
|
||||
|
||||
self.inlays.retain(|inlay| !to_remove.contains(&inlay.id));
|
||||
for inlay_id in to_remove {
|
||||
if let Some(inlay) = self.inlays_by_id.remove(&inlay_id) {
|
||||
let buffer_point = inlay.position.to_point(snapshot.buffer_snapshot());
|
||||
let fold_point = snapshot
|
||||
.fold_snapshot
|
||||
.to_fold_point(buffer_point, Bias::Left);
|
||||
let fold_offset = fold_point.to_offset(&snapshot.fold_snapshot);
|
||||
edits.insert(fold_offset);
|
||||
let buffer_point = inlay.position.to_point(&buffer_snapshot);
|
||||
let buffer_offset = buffer_snapshot.point_to_offset(buffer_point);
|
||||
edits.insert(buffer_offset);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,34 +413,28 @@ impl InlayMap {
|
|||
text: properties.text.into(),
|
||||
};
|
||||
self.inlays_by_id.insert(inlay.id, inlay.clone());
|
||||
match self.inlays.binary_search_by(|probe| {
|
||||
probe
|
||||
.position
|
||||
.cmp(&inlay.position, snapshot.buffer_snapshot())
|
||||
}) {
|
||||
match self
|
||||
.inlays
|
||||
.binary_search_by(|probe| probe.position.cmp(&inlay.position, &buffer_snapshot))
|
||||
{
|
||||
Ok(ix) | Err(ix) => {
|
||||
self.inlays.insert(ix, inlay.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let buffer_point = inlay.position.to_point(snapshot.buffer_snapshot());
|
||||
let fold_point = snapshot
|
||||
.fold_snapshot
|
||||
.to_fold_point(buffer_point, Bias::Left);
|
||||
let fold_offset = fold_point.to_offset(&snapshot.fold_snapshot);
|
||||
edits.insert(fold_offset);
|
||||
let buffer_point = inlay.position.to_point(&buffer_snapshot);
|
||||
let buffer_offset = buffer_snapshot.point_to_offset(buffer_point);
|
||||
edits.insert(buffer_offset);
|
||||
}
|
||||
|
||||
let fold_snapshot = snapshot.fold_snapshot.clone();
|
||||
let fold_edits = edits
|
||||
let buffer_edits = edits
|
||||
.into_iter()
|
||||
.map(|offset| Edit {
|
||||
old: offset..offset,
|
||||
new: offset..offset,
|
||||
})
|
||||
.collect();
|
||||
drop(snapshot);
|
||||
self.sync(fold_snapshot, fold_edits)
|
||||
self.sync(buffer_snapshot.clone(), buffer_edits)
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
|
@ -460,14 +444,12 @@ impl InlayMap {
|
|||
rng: &mut rand::rngs::StdRng,
|
||||
) -> (InlaySnapshot, Vec<InlayEdit>) {
|
||||
use rand::prelude::*;
|
||||
use util::post_inc;
|
||||
|
||||
let mut to_remove = Vec::new();
|
||||
let mut to_insert = Vec::new();
|
||||
let snapshot = self.snapshot.lock();
|
||||
let buffer_snapshot = self.buffer.lock();
|
||||
for _ in 0..rng.gen_range(1..=5) {
|
||||
if self.inlays.is_empty() || rng.gen() {
|
||||
let buffer_snapshot = snapshot.buffer_snapshot();
|
||||
let position = buffer_snapshot.random_byte_range(0, rng).start;
|
||||
let bias = if rng.gen() { Bias::Left } else { Bias::Right };
|
||||
let len = rng.gen_range(1..=5);
|
||||
|
@ -494,29 +476,25 @@ impl InlayMap {
|
|||
}
|
||||
log::info!("removing inlays: {:?}", to_remove);
|
||||
|
||||
drop(snapshot);
|
||||
drop(buffer_snapshot);
|
||||
self.splice(to_remove, to_insert)
|
||||
}
|
||||
}
|
||||
|
||||
impl InlaySnapshot {
|
||||
pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot {
|
||||
self.fold_snapshot.buffer_snapshot()
|
||||
}
|
||||
|
||||
pub fn to_point(&self, offset: InlayOffset) -> InlayPoint {
|
||||
let mut cursor = self
|
||||
.transforms
|
||||
.cursor::<(InlayOffset, (InlayPoint, FoldOffset))>();
|
||||
.cursor::<(InlayOffset, (InlayPoint, usize))>();
|
||||
cursor.seek(&offset, Bias::Right, &());
|
||||
let overshoot = offset.0 - cursor.start().0 .0;
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let fold_offset_start = cursor.start().1 .1;
|
||||
let fold_offset_end = FoldOffset(fold_offset_start.0 + overshoot);
|
||||
let fold_start = fold_offset_start.to_point(&self.fold_snapshot);
|
||||
let fold_end = fold_offset_end.to_point(&self.fold_snapshot);
|
||||
InlayPoint(cursor.start().1 .0 .0 + (fold_end.0 - fold_start.0))
|
||||
let buffer_offset_start = cursor.start().1 .1;
|
||||
let buffer_offset_end = buffer_offset_start + overshoot;
|
||||
let buffer_start = self.buffer.offset_to_point(buffer_offset_start);
|
||||
let buffer_end = self.buffer.offset_to_point(buffer_offset_end);
|
||||
InlayPoint(cursor.start().1 .0 .0 + (buffer_end - buffer_start))
|
||||
}
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
let overshoot = inlay.text.offset_to_point(overshoot);
|
||||
|
@ -537,16 +515,16 @@ impl InlaySnapshot {
|
|||
pub fn to_offset(&self, point: InlayPoint) -> InlayOffset {
|
||||
let mut cursor = self
|
||||
.transforms
|
||||
.cursor::<(InlayPoint, (InlayOffset, FoldPoint))>();
|
||||
.cursor::<(InlayPoint, (InlayOffset, Point))>();
|
||||
cursor.seek(&point, Bias::Right, &());
|
||||
let overshoot = point.0 - cursor.start().0 .0;
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let fold_point_start = cursor.start().1 .1;
|
||||
let fold_point_end = FoldPoint(fold_point_start.0 + overshoot);
|
||||
let fold_start = fold_point_start.to_offset(&self.fold_snapshot);
|
||||
let fold_end = fold_point_end.to_offset(&self.fold_snapshot);
|
||||
InlayOffset(cursor.start().1 .0 .0 + (fold_end.0 - fold_start.0))
|
||||
let buffer_point_start = cursor.start().1 .1;
|
||||
let buffer_point_end = buffer_point_start + overshoot;
|
||||
let buffer_offset_start = self.buffer.point_to_offset(buffer_point_start);
|
||||
let buffer_offset_end = self.buffer.point_to_offset(buffer_point_end);
|
||||
InlayOffset(cursor.start().1 .0 .0 + (buffer_offset_end - buffer_offset_start))
|
||||
}
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
let overshoot = inlay.text.point_to_offset(overshoot);
|
||||
|
@ -557,42 +535,55 @@ impl InlaySnapshot {
|
|||
}
|
||||
|
||||
pub fn chars_at(&self, start: InlayPoint) -> impl '_ + Iterator<Item = char> {
|
||||
self.chunks(self.to_offset(start)..self.len(), false, None, None)
|
||||
self.chunks(self.to_offset(start)..self.len(), false, None)
|
||||
.flat_map(|chunk| chunk.text.chars())
|
||||
}
|
||||
|
||||
pub fn to_fold_point(&self, point: InlayPoint) -> FoldPoint {
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, FoldPoint)>();
|
||||
pub fn to_buffer_point(&self, point: InlayPoint) -> Point {
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, Point)>();
|
||||
cursor.seek(&point, Bias::Right, &());
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let overshoot = point.0 - cursor.start().0 .0;
|
||||
FoldPoint(cursor.start().1 .0 + overshoot)
|
||||
cursor.start().1 + overshoot
|
||||
}
|
||||
Some(Transform::Inlay(_)) => cursor.start().1,
|
||||
None => self.fold_snapshot.max_point(),
|
||||
None => self.buffer.max_point(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_fold_offset(&self, offset: InlayOffset) -> FoldOffset {
|
||||
let mut cursor = self.transforms.cursor::<(InlayOffset, FoldOffset)>();
|
||||
pub fn to_buffer_offset(&self, offset: InlayOffset) -> usize {
|
||||
let mut cursor = self.transforms.cursor::<(InlayOffset, usize)>();
|
||||
cursor.seek(&offset, Bias::Right, &());
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let overshoot = offset - cursor.start().0;
|
||||
cursor.start().1 + FoldOffset(overshoot.0)
|
||||
cursor.start().1 + overshoot.0
|
||||
}
|
||||
Some(Transform::Inlay(_)) => cursor.start().1,
|
||||
None => self.fold_snapshot.len(),
|
||||
None => self.buffer.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_inlay_point(&self, point: FoldPoint) -> InlayPoint {
|
||||
let mut cursor = self.transforms.cursor::<(FoldPoint, InlayPoint)>();
|
||||
pub fn to_inlay_offset(&self, offset: usize) -> InlayOffset {
|
||||
let mut cursor = self.transforms.cursor::<(Point, InlayOffset)>();
|
||||
cursor.seek(&offset, Bias::Left, &());
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let overshoot = offset - cursor.start().0;
|
||||
InlayOffset(cursor.start().1 .0 + overshoot)
|
||||
}
|
||||
Some(Transform::Inlay(_)) => cursor.start().1,
|
||||
None => self.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_inlay_point(&self, point: Point) -> InlayPoint {
|
||||
let mut cursor = self.transforms.cursor::<(Point, InlayPoint)>();
|
||||
cursor.seek(&point, Bias::Left, &());
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let overshoot = point.0 - cursor.start().0 .0;
|
||||
let overshoot = point - cursor.start().0;
|
||||
InlayPoint(cursor.start().1 .0 + overshoot)
|
||||
}
|
||||
Some(Transform::Inlay(_)) => cursor.start().1,
|
||||
|
@ -601,7 +592,7 @@ impl InlaySnapshot {
|
|||
}
|
||||
|
||||
pub fn clip_point(&self, point: InlayPoint, bias: Bias) -> InlayPoint {
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, FoldPoint)>();
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, Point)>();
|
||||
cursor.seek(&point, Bias::Left, &());
|
||||
|
||||
let mut bias = bias;
|
||||
|
@ -623,9 +614,9 @@ impl InlaySnapshot {
|
|||
} else {
|
||||
point.0 - cursor.start().0 .0
|
||||
};
|
||||
let fold_point = FoldPoint(cursor.start().1 .0 + overshoot);
|
||||
let clipped_fold_point = self.fold_snapshot.clip_point(fold_point, bias);
|
||||
let clipped_overshoot = clipped_fold_point.0 - cursor.start().1 .0;
|
||||
let buffer_point = cursor.start().1 + overshoot;
|
||||
let clipped_buffer_point = self.buffer.clip_point(buffer_point, bias);
|
||||
let clipped_overshoot = clipped_buffer_point - cursor.start().1;
|
||||
return InlayPoint(cursor.start().0 .0 + clipped_overshoot);
|
||||
}
|
||||
Some(Transform::Inlay(_)) => skipped_inlay = true,
|
||||
|
@ -643,23 +634,24 @@ impl InlaySnapshot {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn text_summary(&self) -> TextSummary {
|
||||
self.transforms.summary().output
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range(&self, range: Range<InlayPoint>) -> TextSummary {
|
||||
let mut summary = TextSummary::default();
|
||||
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, FoldPoint)>();
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, Point)>();
|
||||
cursor.seek(&range.start, Bias::Right, &());
|
||||
|
||||
let overshoot = range.start.0 - cursor.start().0 .0;
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let fold_start = cursor.start().1 .0;
|
||||
let suffix_start = FoldPoint(fold_start + overshoot);
|
||||
let suffix_end = FoldPoint(
|
||||
fold_start + (cmp::min(cursor.end(&()).0, range.end).0 - cursor.start().0 .0),
|
||||
);
|
||||
summary = self
|
||||
.fold_snapshot
|
||||
.text_summary_for_range(suffix_start..suffix_end);
|
||||
let buffer_start = cursor.start().1;
|
||||
let suffix_start = buffer_start + overshoot;
|
||||
let suffix_end =
|
||||
buffer_start + (cmp::min(cursor.end(&()).0, range.end).0 - cursor.start().0 .0);
|
||||
summary = self.buffer.text_summary_for_range(suffix_start..suffix_end);
|
||||
cursor.next(&());
|
||||
}
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
|
@ -682,10 +674,10 @@ impl InlaySnapshot {
|
|||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let prefix_start = cursor.start().1;
|
||||
let prefix_end = FoldPoint(prefix_start.0 + overshoot);
|
||||
let prefix_end = prefix_start + overshoot;
|
||||
summary += self
|
||||
.fold_snapshot
|
||||
.text_summary_for_range(prefix_start..prefix_end);
|
||||
.buffer
|
||||
.text_summary_for_range::<TextSummary, Point>(prefix_start..prefix_end);
|
||||
}
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
let prefix_end = inlay.text.point_to_offset(overshoot);
|
||||
|
@ -699,27 +691,27 @@ impl InlaySnapshot {
|
|||
}
|
||||
|
||||
pub fn buffer_rows<'a>(&'a self, row: u32) -> InlayBufferRows<'a> {
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, FoldPoint)>();
|
||||
let mut cursor = self.transforms.cursor::<(InlayPoint, Point)>();
|
||||
let inlay_point = InlayPoint::new(row, 0);
|
||||
cursor.seek(&inlay_point, Bias::Left, &());
|
||||
|
||||
let mut fold_point = cursor.start().1;
|
||||
let fold_row = if row == 0 {
|
||||
let mut buffer_point = cursor.start().1;
|
||||
let buffer_row = if row == 0 {
|
||||
0
|
||||
} else {
|
||||
match cursor.item() {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
fold_point.0 += inlay_point.0 - cursor.start().0 .0;
|
||||
fold_point.row()
|
||||
buffer_point += inlay_point.0 - cursor.start().0 .0;
|
||||
buffer_point.row
|
||||
}
|
||||
_ => cmp::min(fold_point.row() + 1, self.fold_snapshot.max_point().row()),
|
||||
_ => cmp::min(buffer_point.row + 1, self.buffer.max_point().row),
|
||||
}
|
||||
};
|
||||
|
||||
InlayBufferRows {
|
||||
transforms: cursor,
|
||||
inlay_row: inlay_point.row(),
|
||||
fold_rows: self.fold_snapshot.buffer_rows(fold_row),
|
||||
buffer_rows: self.buffer.buffer_rows(buffer_row),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -737,22 +729,19 @@ impl InlaySnapshot {
|
|||
&'a self,
|
||||
range: Range<InlayOffset>,
|
||||
language_aware: bool,
|
||||
text_highlights: Option<&'a TextHighlights>,
|
||||
inlay_highlight_style: Option<HighlightStyle>,
|
||||
) -> InlayChunks<'a> {
|
||||
let mut cursor = self.transforms.cursor::<(InlayOffset, FoldOffset)>();
|
||||
let mut cursor = self.transforms.cursor::<(InlayOffset, usize)>();
|
||||
cursor.seek(&range.start, Bias::Right, &());
|
||||
|
||||
let fold_range = self.to_fold_offset(range.start)..self.to_fold_offset(range.end);
|
||||
let fold_chunks = self
|
||||
.fold_snapshot
|
||||
.chunks(fold_range, language_aware, text_highlights);
|
||||
let buffer_range = self.to_buffer_offset(range.start)..self.to_buffer_offset(range.end);
|
||||
let buffer_chunks = self.buffer.chunks(buffer_range, language_aware);
|
||||
|
||||
InlayChunks {
|
||||
transforms: cursor,
|
||||
fold_chunks,
|
||||
buffer_chunks,
|
||||
inlay_chunks: None,
|
||||
fold_chunk: None,
|
||||
buffer_chunk: None,
|
||||
output_offset: range.start,
|
||||
max_output_offset: range.end,
|
||||
highlight_style: inlay_highlight_style,
|
||||
|
@ -761,7 +750,7 @@ impl InlaySnapshot {
|
|||
|
||||
#[cfg(test)]
|
||||
pub fn text(&self) -> String {
|
||||
self.chunks(Default::default()..self.len(), false, None, None)
|
||||
self.chunks(Default::default()..self.len(), false, None)
|
||||
.map(|chunk| chunk.text)
|
||||
.collect()
|
||||
}
|
||||
|
@ -769,10 +758,7 @@ impl InlaySnapshot {
|
|||
fn check_invariants(&self) {
|
||||
#[cfg(any(debug_assertions, feature = "test-support"))]
|
||||
{
|
||||
assert_eq!(
|
||||
self.transforms.summary().input,
|
||||
self.fold_snapshot.text_summary()
|
||||
);
|
||||
assert_eq!(self.transforms.summary().input, self.buffer.text_summary());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -800,7 +786,7 @@ fn push_isomorphic(sum_tree: &mut SumTree<Transform>, summary: TextSummary) {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{display_map::fold_map::FoldMap, MultiBuffer};
|
||||
use crate::MultiBuffer;
|
||||
use gpui::AppContext;
|
||||
use rand::prelude::*;
|
||||
use settings::SettingsStore;
|
||||
|
@ -812,8 +798,7 @@ mod tests {
|
|||
fn test_basic_inlays(cx: &mut AppContext) {
|
||||
let buffer = MultiBuffer::build_simple("abcdefghi", cx);
|
||||
let buffer_edits = buffer.update(cx, |buffer, _| buffer.subscribe());
|
||||
let (fold_map, fold_snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx));
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(fold_snapshot.clone());
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx));
|
||||
assert_eq!(inlay_snapshot.text(), "abcdefghi");
|
||||
let mut next_inlay_id = 0;
|
||||
|
||||
|
@ -829,27 +814,27 @@ mod tests {
|
|||
);
|
||||
assert_eq!(inlay_snapshot.text(), "abc|123|defghi");
|
||||
assert_eq!(
|
||||
inlay_snapshot.to_inlay_point(FoldPoint::new(0, 0)),
|
||||
inlay_snapshot.to_inlay_point(Point::new(0, 0)),
|
||||
InlayPoint::new(0, 0)
|
||||
);
|
||||
assert_eq!(
|
||||
inlay_snapshot.to_inlay_point(FoldPoint::new(0, 1)),
|
||||
inlay_snapshot.to_inlay_point(Point::new(0, 1)),
|
||||
InlayPoint::new(0, 1)
|
||||
);
|
||||
assert_eq!(
|
||||
inlay_snapshot.to_inlay_point(FoldPoint::new(0, 2)),
|
||||
inlay_snapshot.to_inlay_point(Point::new(0, 2)),
|
||||
InlayPoint::new(0, 2)
|
||||
);
|
||||
assert_eq!(
|
||||
inlay_snapshot.to_inlay_point(FoldPoint::new(0, 3)),
|
||||
inlay_snapshot.to_inlay_point(Point::new(0, 3)),
|
||||
InlayPoint::new(0, 3)
|
||||
);
|
||||
assert_eq!(
|
||||
inlay_snapshot.to_inlay_point(FoldPoint::new(0, 4)),
|
||||
inlay_snapshot.to_inlay_point(Point::new(0, 4)),
|
||||
InlayPoint::new(0, 9)
|
||||
);
|
||||
assert_eq!(
|
||||
inlay_snapshot.to_inlay_point(FoldPoint::new(0, 5)),
|
||||
inlay_snapshot.to_inlay_point(Point::new(0, 5)),
|
||||
InlayPoint::new(0, 10)
|
||||
);
|
||||
assert_eq!(
|
||||
|
@ -881,20 +866,18 @@ mod tests {
|
|||
buffer.update(cx, |buffer, cx| {
|
||||
buffer.edit([(2..3, "x"), (3..3, "y"), (4..4, "z")], None, cx)
|
||||
});
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(
|
||||
let (inlay_snapshot, _) = inlay_map.sync(
|
||||
buffer.read(cx).snapshot(cx),
|
||||
buffer_edits.consume().into_inner(),
|
||||
);
|
||||
let (inlay_snapshot, _) = inlay_map.sync(fold_snapshot.clone(), fold_edits);
|
||||
assert_eq!(inlay_snapshot.text(), "abxy|123|dzefghi");
|
||||
|
||||
// An edit surrounding the inlay should invalidate it.
|
||||
buffer.update(cx, |buffer, cx| buffer.edit([(4..5, "D")], None, cx));
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(
|
||||
let (inlay_snapshot, _) = inlay_map.sync(
|
||||
buffer.read(cx).snapshot(cx),
|
||||
buffer_edits.consume().into_inner(),
|
||||
);
|
||||
let (inlay_snapshot, _) = inlay_map.sync(fold_snapshot.clone(), fold_edits);
|
||||
assert_eq!(inlay_snapshot.text(), "abxyDzefghi");
|
||||
|
||||
let (inlay_snapshot, _) = inlay_map.splice(
|
||||
|
@ -920,11 +903,10 @@ mod tests {
|
|||
|
||||
// Edits ending where the inlay starts should not move it if it has a left bias.
|
||||
buffer.update(cx, |buffer, cx| buffer.edit([(3..3, "JKL")], None, cx));
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(
|
||||
let (inlay_snapshot, _) = inlay_map.sync(
|
||||
buffer.read(cx).snapshot(cx),
|
||||
buffer_edits.consume().into_inner(),
|
||||
);
|
||||
let (inlay_snapshot, _) = inlay_map.sync(fold_snapshot.clone(), fold_edits);
|
||||
assert_eq!(inlay_snapshot.text(), "abx|123|JKL|456|yDzefghi");
|
||||
|
||||
// The inlays can be manually removed.
|
||||
|
@ -936,8 +918,7 @@ mod tests {
|
|||
#[gpui::test]
|
||||
fn test_buffer_rows(cx: &mut AppContext) {
|
||||
let buffer = MultiBuffer::build_simple("abc\ndef\nghi", cx);
|
||||
let (_, fold_snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx));
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(fold_snapshot.clone());
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer.read(cx).snapshot(cx));
|
||||
assert_eq!(inlay_snapshot.text(), "abc\ndef\nghi");
|
||||
|
||||
let (inlay_snapshot, _) = inlay_map.splice(
|
||||
|
@ -993,27 +974,20 @@ mod tests {
|
|||
let mut buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
log::info!("buffer text: {:?}", buffer_snapshot.text());
|
||||
|
||||
let (mut fold_map, mut fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
|
||||
let (mut inlay_map, mut inlay_snapshot) = InlayMap::new(fold_snapshot.clone());
|
||||
let (mut inlay_map, mut inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let mut next_inlay_id = 0;
|
||||
|
||||
for _ in 0..operations {
|
||||
let mut fold_edits = Patch::default();
|
||||
let mut inlay_edits = Patch::default();
|
||||
|
||||
let mut prev_inlay_text = inlay_snapshot.text();
|
||||
let mut buffer_edits = Vec::new();
|
||||
match rng.gen_range(0..=100) {
|
||||
0..=29 => {
|
||||
0..=50 => {
|
||||
let (snapshot, edits) = inlay_map.randomly_mutate(&mut next_inlay_id, &mut rng);
|
||||
log::info!("mutated text: {:?}", snapshot.text());
|
||||
inlay_edits = Patch::new(edits);
|
||||
}
|
||||
30..=59 => {
|
||||
for (_, edits) in fold_map.randomly_mutate(&mut rng) {
|
||||
fold_edits = fold_edits.compose(edits);
|
||||
}
|
||||
}
|
||||
_ => buffer.update(cx, |buffer, cx| {
|
||||
let subscription = buffer.subscribe();
|
||||
let edit_count = rng.gen_range(1..=5);
|
||||
|
@ -1025,17 +999,12 @@ mod tests {
|
|||
}),
|
||||
};
|
||||
|
||||
let (new_fold_snapshot, new_fold_edits) =
|
||||
fold_map.read(buffer_snapshot.clone(), buffer_edits);
|
||||
fold_snapshot = new_fold_snapshot;
|
||||
fold_edits = fold_edits.compose(new_fold_edits);
|
||||
let (new_inlay_snapshot, new_inlay_edits) =
|
||||
inlay_map.sync(fold_snapshot.clone(), fold_edits.into_inner());
|
||||
inlay_map.sync(buffer_snapshot.clone(), buffer_edits);
|
||||
inlay_snapshot = new_inlay_snapshot;
|
||||
inlay_edits = inlay_edits.compose(new_inlay_edits);
|
||||
|
||||
log::info!("buffer text: {:?}", buffer_snapshot.text());
|
||||
log::info!("folds text: {:?}", fold_snapshot.text());
|
||||
log::info!("inlay text: {:?}", inlay_snapshot.text());
|
||||
|
||||
let inlays = inlay_map
|
||||
|
@ -1044,14 +1013,13 @@ mod tests {
|
|||
.filter(|inlay| inlay.position.is_valid(&buffer_snapshot))
|
||||
.map(|inlay| {
|
||||
let buffer_point = inlay.position.to_point(&buffer_snapshot);
|
||||
let fold_point = fold_snapshot.to_fold_point(buffer_point, Bias::Left);
|
||||
let fold_offset = fold_point.to_offset(&fold_snapshot);
|
||||
(fold_offset, inlay.clone())
|
||||
let buffer_offset = buffer_snapshot.point_to_offset(buffer_point);
|
||||
(buffer_offset, inlay.clone())
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let mut expected_text = Rope::from(fold_snapshot.text().as_str());
|
||||
let mut expected_text = Rope::from(buffer_snapshot.text().as_str());
|
||||
for (offset, inlay) in inlays.into_iter().rev() {
|
||||
expected_text.replace(offset.0..offset.0, &inlay.text.to_string());
|
||||
expected_text.replace(offset..offset, &inlay.text.to_string());
|
||||
}
|
||||
assert_eq!(inlay_snapshot.text(), expected_text.to_string());
|
||||
|
||||
|
@ -1078,7 +1046,7 @@ mod tests {
|
|||
start = expected_text.clip_offset(start, Bias::Right);
|
||||
|
||||
let actual_text = inlay_snapshot
|
||||
.chunks(InlayOffset(start)..InlayOffset(end), false, None, None)
|
||||
.chunks(InlayOffset(start)..InlayOffset(end), false, None)
|
||||
.map(|chunk| chunk.text)
|
||||
.collect::<String>();
|
||||
assert_eq!(
|
||||
|
@ -1123,11 +1091,11 @@ mod tests {
|
|||
inlay_offset
|
||||
);
|
||||
assert_eq!(
|
||||
inlay_snapshot.to_inlay_point(inlay_snapshot.to_fold_point(inlay_point)),
|
||||
inlay_snapshot.to_inlay_point(inlay_snapshot.to_buffer_point(inlay_point)),
|
||||
inlay_snapshot.clip_point(inlay_point, Bias::Left),
|
||||
"to_fold_point({:?}) = {:?}",
|
||||
"to_buffer_point({:?}) = {:?}",
|
||||
inlay_point,
|
||||
inlay_snapshot.to_fold_point(inlay_point),
|
||||
inlay_snapshot.to_buffer_point(inlay_point),
|
||||
);
|
||||
|
||||
let mut bytes = [0; 4];
|
||||
|
|
|
@ -1,875 +0,0 @@
|
|||
use super::{
|
||||
fold_map::{FoldBufferRows, FoldChunks, FoldEdit, FoldOffset, FoldPoint, FoldSnapshot},
|
||||
TextHighlights,
|
||||
};
|
||||
use crate::{MultiBufferSnapshot, ToPoint};
|
||||
use gpui::fonts::HighlightStyle;
|
||||
use language::{Bias, Chunk, Edit, Patch, Point, Rope, TextSummary};
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
cmp,
|
||||
ops::{Add, AddAssign, Range, Sub},
|
||||
};
|
||||
use util::post_inc;
|
||||
|
||||
pub type SuggestionEdit = Edit<SuggestionOffset>;
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||
pub struct SuggestionOffset(pub usize);
|
||||
|
||||
impl Add for SuggestionOffset {
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for SuggestionOffset {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for SuggestionOffset {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.0 += rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||
pub struct SuggestionPoint(pub Point);
|
||||
|
||||
impl SuggestionPoint {
|
||||
pub fn new(row: u32, column: u32) -> Self {
|
||||
Self(Point::new(row, column))
|
||||
}
|
||||
|
||||
pub fn row(self) -> u32 {
|
||||
self.0.row
|
||||
}
|
||||
|
||||
pub fn column(self) -> u32 {
|
||||
self.0.column
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Suggestion<T> {
|
||||
pub position: T,
|
||||
pub text: Rope,
|
||||
}
|
||||
|
||||
pub struct SuggestionMap(Mutex<SuggestionSnapshot>);
|
||||
|
||||
impl SuggestionMap {
|
||||
pub fn new(fold_snapshot: FoldSnapshot) -> (Self, SuggestionSnapshot) {
|
||||
let snapshot = SuggestionSnapshot {
|
||||
fold_snapshot,
|
||||
suggestion: None,
|
||||
version: 0,
|
||||
};
|
||||
(Self(Mutex::new(snapshot.clone())), snapshot)
|
||||
}
|
||||
|
||||
pub fn replace<T>(
|
||||
&self,
|
||||
new_suggestion: Option<Suggestion<T>>,
|
||||
fold_snapshot: FoldSnapshot,
|
||||
fold_edits: Vec<FoldEdit>,
|
||||
) -> (
|
||||
SuggestionSnapshot,
|
||||
Vec<SuggestionEdit>,
|
||||
Option<Suggestion<FoldOffset>>,
|
||||
)
|
||||
where
|
||||
T: ToPoint,
|
||||
{
|
||||
let new_suggestion = new_suggestion.map(|new_suggestion| {
|
||||
let buffer_point = new_suggestion
|
||||
.position
|
||||
.to_point(fold_snapshot.buffer_snapshot());
|
||||
let fold_point = fold_snapshot.to_fold_point(buffer_point, Bias::Left);
|
||||
let fold_offset = fold_point.to_offset(&fold_snapshot);
|
||||
Suggestion {
|
||||
position: fold_offset,
|
||||
text: new_suggestion.text,
|
||||
}
|
||||
});
|
||||
|
||||
let (_, edits) = self.sync(fold_snapshot, fold_edits);
|
||||
let mut snapshot = self.0.lock();
|
||||
|
||||
let mut patch = Patch::new(edits);
|
||||
let old_suggestion = snapshot.suggestion.take();
|
||||
if let Some(suggestion) = &old_suggestion {
|
||||
patch = patch.compose([SuggestionEdit {
|
||||
old: SuggestionOffset(suggestion.position.0)
|
||||
..SuggestionOffset(suggestion.position.0 + suggestion.text.len()),
|
||||
new: SuggestionOffset(suggestion.position.0)
|
||||
..SuggestionOffset(suggestion.position.0),
|
||||
}]);
|
||||
}
|
||||
|
||||
if let Some(suggestion) = new_suggestion.as_ref() {
|
||||
patch = patch.compose([SuggestionEdit {
|
||||
old: SuggestionOffset(suggestion.position.0)
|
||||
..SuggestionOffset(suggestion.position.0),
|
||||
new: SuggestionOffset(suggestion.position.0)
|
||||
..SuggestionOffset(suggestion.position.0 + suggestion.text.len()),
|
||||
}]);
|
||||
}
|
||||
|
||||
snapshot.suggestion = new_suggestion;
|
||||
snapshot.version += 1;
|
||||
(snapshot.clone(), patch.into_inner(), old_suggestion)
|
||||
}
|
||||
|
||||
pub fn sync(
|
||||
&self,
|
||||
fold_snapshot: FoldSnapshot,
|
||||
fold_edits: Vec<FoldEdit>,
|
||||
) -> (SuggestionSnapshot, Vec<SuggestionEdit>) {
|
||||
let mut snapshot = self.0.lock();
|
||||
|
||||
if snapshot.fold_snapshot.version != fold_snapshot.version {
|
||||
snapshot.version += 1;
|
||||
}
|
||||
|
||||
let mut suggestion_edits = Vec::new();
|
||||
|
||||
let mut suggestion_old_len = 0;
|
||||
let mut suggestion_new_len = 0;
|
||||
for fold_edit in fold_edits {
|
||||
let start = fold_edit.new.start;
|
||||
let end = FoldOffset(start.0 + fold_edit.old_len().0);
|
||||
if let Some(suggestion) = snapshot.suggestion.as_mut() {
|
||||
if end <= suggestion.position {
|
||||
suggestion.position.0 += fold_edit.new_len().0;
|
||||
suggestion.position.0 -= fold_edit.old_len().0;
|
||||
} else if start > suggestion.position {
|
||||
suggestion_old_len = suggestion.text.len();
|
||||
suggestion_new_len = suggestion_old_len;
|
||||
} else {
|
||||
suggestion_old_len = suggestion.text.len();
|
||||
snapshot.suggestion.take();
|
||||
suggestion_edits.push(SuggestionEdit {
|
||||
old: SuggestionOffset(fold_edit.old.start.0)
|
||||
..SuggestionOffset(fold_edit.old.end.0 + suggestion_old_len),
|
||||
new: SuggestionOffset(fold_edit.new.start.0)
|
||||
..SuggestionOffset(fold_edit.new.end.0),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
suggestion_edits.push(SuggestionEdit {
|
||||
old: SuggestionOffset(fold_edit.old.start.0 + suggestion_old_len)
|
||||
..SuggestionOffset(fold_edit.old.end.0 + suggestion_old_len),
|
||||
new: SuggestionOffset(fold_edit.new.start.0 + suggestion_new_len)
|
||||
..SuggestionOffset(fold_edit.new.end.0 + suggestion_new_len),
|
||||
});
|
||||
}
|
||||
snapshot.fold_snapshot = fold_snapshot;
|
||||
|
||||
(snapshot.clone(), suggestion_edits)
|
||||
}
|
||||
|
||||
pub fn has_suggestion(&self) -> bool {
|
||||
let snapshot = self.0.lock();
|
||||
snapshot.suggestion.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SuggestionSnapshot {
|
||||
pub fold_snapshot: FoldSnapshot,
|
||||
pub suggestion: Option<Suggestion<FoldOffset>>,
|
||||
pub version: usize,
|
||||
}
|
||||
|
||||
impl SuggestionSnapshot {
|
||||
pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot {
|
||||
self.fold_snapshot.buffer_snapshot()
|
||||
}
|
||||
|
||||
pub fn max_point(&self) -> SuggestionPoint {
|
||||
if let Some(suggestion) = self.suggestion.as_ref() {
|
||||
let suggestion_point = suggestion.position.to_point(&self.fold_snapshot);
|
||||
let mut max_point = suggestion_point.0;
|
||||
max_point += suggestion.text.max_point();
|
||||
max_point += self.fold_snapshot.max_point().0 - suggestion_point.0;
|
||||
SuggestionPoint(max_point)
|
||||
} else {
|
||||
SuggestionPoint(self.fold_snapshot.max_point().0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn len(&self) -> SuggestionOffset {
|
||||
if let Some(suggestion) = self.suggestion.as_ref() {
|
||||
let mut len = suggestion.position.0;
|
||||
len += suggestion.text.len();
|
||||
len += self.fold_snapshot.len().0 - suggestion.position.0;
|
||||
SuggestionOffset(len)
|
||||
} else {
|
||||
SuggestionOffset(self.fold_snapshot.len().0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn line_len(&self, row: u32) -> u32 {
|
||||
if let Some(suggestion) = &self.suggestion {
|
||||
let suggestion_start = suggestion.position.to_point(&self.fold_snapshot).0;
|
||||
let suggestion_end = suggestion_start + suggestion.text.max_point();
|
||||
|
||||
if row < suggestion_start.row {
|
||||
self.fold_snapshot.line_len(row)
|
||||
} else if row > suggestion_end.row {
|
||||
self.fold_snapshot
|
||||
.line_len(suggestion_start.row + (row - suggestion_end.row))
|
||||
} else {
|
||||
let mut result = suggestion.text.line_len(row - suggestion_start.row);
|
||||
if row == suggestion_start.row {
|
||||
result += suggestion_start.column;
|
||||
}
|
||||
if row == suggestion_end.row {
|
||||
result +=
|
||||
self.fold_snapshot.line_len(suggestion_start.row) - suggestion_start.column;
|
||||
}
|
||||
result
|
||||
}
|
||||
} else {
|
||||
self.fold_snapshot.line_len(row)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clip_point(&self, point: SuggestionPoint, bias: Bias) -> SuggestionPoint {
|
||||
if let Some(suggestion) = self.suggestion.as_ref() {
|
||||
let suggestion_start = suggestion.position.to_point(&self.fold_snapshot).0;
|
||||
let suggestion_end = suggestion_start + suggestion.text.max_point();
|
||||
if point.0 <= suggestion_start {
|
||||
SuggestionPoint(self.fold_snapshot.clip_point(FoldPoint(point.0), bias).0)
|
||||
} else if point.0 > suggestion_end {
|
||||
let fold_point = self.fold_snapshot.clip_point(
|
||||
FoldPoint(suggestion_start + (point.0 - suggestion_end)),
|
||||
bias,
|
||||
);
|
||||
let suggestion_point = suggestion_end + (fold_point.0 - suggestion_start);
|
||||
if bias == Bias::Left && suggestion_point == suggestion_end {
|
||||
SuggestionPoint(suggestion_start)
|
||||
} else {
|
||||
SuggestionPoint(suggestion_point)
|
||||
}
|
||||
} else if bias == Bias::Left || suggestion_start == self.fold_snapshot.max_point().0 {
|
||||
SuggestionPoint(suggestion_start)
|
||||
} else {
|
||||
let fold_point = if self.fold_snapshot.line_len(suggestion_start.row)
|
||||
> suggestion_start.column
|
||||
{
|
||||
FoldPoint(suggestion_start + Point::new(0, 1))
|
||||
} else {
|
||||
FoldPoint(suggestion_start + Point::new(1, 0))
|
||||
};
|
||||
let clipped_fold_point = self.fold_snapshot.clip_point(fold_point, bias);
|
||||
SuggestionPoint(suggestion_end + (clipped_fold_point.0 - suggestion_start))
|
||||
}
|
||||
} else {
|
||||
SuggestionPoint(self.fold_snapshot.clip_point(FoldPoint(point.0), bias).0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_offset(&self, point: SuggestionPoint) -> SuggestionOffset {
|
||||
if let Some(suggestion) = self.suggestion.as_ref() {
|
||||
let suggestion_start = suggestion.position.to_point(&self.fold_snapshot).0;
|
||||
let suggestion_end = suggestion_start + suggestion.text.max_point();
|
||||
|
||||
if point.0 <= suggestion_start {
|
||||
SuggestionOffset(FoldPoint(point.0).to_offset(&self.fold_snapshot).0)
|
||||
} else if point.0 > suggestion_end {
|
||||
let fold_offset = FoldPoint(suggestion_start + (point.0 - suggestion_end))
|
||||
.to_offset(&self.fold_snapshot);
|
||||
SuggestionOffset(fold_offset.0 + suggestion.text.len())
|
||||
} else {
|
||||
let offset_in_suggestion =
|
||||
suggestion.text.point_to_offset(point.0 - suggestion_start);
|
||||
SuggestionOffset(suggestion.position.0 + offset_in_suggestion)
|
||||
}
|
||||
} else {
|
||||
SuggestionOffset(FoldPoint(point.0).to_offset(&self.fold_snapshot).0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_point(&self, offset: SuggestionOffset) -> SuggestionPoint {
|
||||
if let Some(suggestion) = self.suggestion.as_ref() {
|
||||
let suggestion_point_start = suggestion.position.to_point(&self.fold_snapshot).0;
|
||||
if offset.0 <= suggestion.position.0 {
|
||||
SuggestionPoint(FoldOffset(offset.0).to_point(&self.fold_snapshot).0)
|
||||
} else if offset.0 > (suggestion.position.0 + suggestion.text.len()) {
|
||||
let fold_point = FoldOffset(offset.0 - suggestion.text.len())
|
||||
.to_point(&self.fold_snapshot)
|
||||
.0;
|
||||
|
||||
SuggestionPoint(
|
||||
suggestion_point_start
|
||||
+ suggestion.text.max_point()
|
||||
+ (fold_point - suggestion_point_start),
|
||||
)
|
||||
} else {
|
||||
let point_in_suggestion = suggestion
|
||||
.text
|
||||
.offset_to_point(offset.0 - suggestion.position.0);
|
||||
SuggestionPoint(suggestion_point_start + point_in_suggestion)
|
||||
}
|
||||
} else {
|
||||
SuggestionPoint(FoldOffset(offset.0).to_point(&self.fold_snapshot).0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_fold_point(&self, point: SuggestionPoint) -> FoldPoint {
|
||||
if let Some(suggestion) = self.suggestion.as_ref() {
|
||||
let suggestion_start = suggestion.position.to_point(&self.fold_snapshot).0;
|
||||
let suggestion_end = suggestion_start + suggestion.text.max_point();
|
||||
|
||||
if point.0 <= suggestion_start {
|
||||
FoldPoint(point.0)
|
||||
} else if point.0 > suggestion_end {
|
||||
FoldPoint(suggestion_start + (point.0 - suggestion_end))
|
||||
} else {
|
||||
FoldPoint(suggestion_start)
|
||||
}
|
||||
} else {
|
||||
FoldPoint(point.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_suggestion_point(&self, point: FoldPoint) -> SuggestionPoint {
|
||||
if let Some(suggestion) = self.suggestion.as_ref() {
|
||||
let suggestion_start = suggestion.position.to_point(&self.fold_snapshot).0;
|
||||
|
||||
if point.0 <= suggestion_start {
|
||||
SuggestionPoint(point.0)
|
||||
} else {
|
||||
let suggestion_end = suggestion_start + suggestion.text.max_point();
|
||||
SuggestionPoint(suggestion_end + (point.0 - suggestion_start))
|
||||
}
|
||||
} else {
|
||||
SuggestionPoint(point.0)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
if let Some(suggestion) = self.suggestion.as_ref() {
|
||||
let suggestion_start = suggestion.position.to_point(&self.fold_snapshot).0;
|
||||
let suggestion_end = suggestion_start + suggestion.text.max_point();
|
||||
let mut summary = TextSummary::default();
|
||||
|
||||
let prefix_range =
|
||||
cmp::min(range.start.0, suggestion_start)..cmp::min(range.end.0, suggestion_start);
|
||||
if prefix_range.start < prefix_range.end {
|
||||
summary += self.fold_snapshot.text_summary_for_range(
|
||||
FoldPoint(prefix_range.start)..FoldPoint(prefix_range.end),
|
||||
);
|
||||
}
|
||||
|
||||
let suggestion_range =
|
||||
cmp::max(range.start.0, suggestion_start)..cmp::min(range.end.0, suggestion_end);
|
||||
if suggestion_range.start < suggestion_range.end {
|
||||
let point_range = suggestion_range.start - suggestion_start
|
||||
..suggestion_range.end - suggestion_start;
|
||||
let offset_range = suggestion.text.point_to_offset(point_range.start)
|
||||
..suggestion.text.point_to_offset(point_range.end);
|
||||
summary += suggestion
|
||||
.text
|
||||
.cursor(offset_range.start)
|
||||
.summary::<TextSummary>(offset_range.end);
|
||||
}
|
||||
|
||||
let suffix_range = cmp::max(range.start.0, suggestion_end)..range.end.0;
|
||||
if suffix_range.start < suffix_range.end {
|
||||
let start = suggestion_start + (suffix_range.start - suggestion_end);
|
||||
let end = suggestion_start + (suffix_range.end - suggestion_end);
|
||||
summary += self
|
||||
.fold_snapshot
|
||||
.text_summary_for_range(FoldPoint(start)..FoldPoint(end));
|
||||
}
|
||||
|
||||
summary
|
||||
} else {
|
||||
self.fold_snapshot
|
||||
.text_summary_for_range(FoldPoint(range.start.0)..FoldPoint(range.end.0))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chars_at(&self, start: SuggestionPoint) -> impl '_ + Iterator<Item = char> {
|
||||
let start = self.to_offset(start);
|
||||
self.chunks(start..self.len(), false, None, None)
|
||||
.flat_map(|chunk| chunk.text.chars())
|
||||
}
|
||||
|
||||
pub fn chunks<'a>(
|
||||
&'a self,
|
||||
range: Range<SuggestionOffset>,
|
||||
language_aware: bool,
|
||||
text_highlights: Option<&'a TextHighlights>,
|
||||
suggestion_highlight: Option<HighlightStyle>,
|
||||
) -> SuggestionChunks<'a> {
|
||||
if let Some(suggestion) = self.suggestion.as_ref() {
|
||||
let suggestion_range =
|
||||
suggestion.position.0..suggestion.position.0 + suggestion.text.len();
|
||||
|
||||
let prefix_chunks = if range.start.0 < suggestion_range.start {
|
||||
Some(self.fold_snapshot.chunks(
|
||||
FoldOffset(range.start.0)
|
||||
..cmp::min(FoldOffset(suggestion_range.start), FoldOffset(range.end.0)),
|
||||
language_aware,
|
||||
text_highlights,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let clipped_suggestion_range = cmp::max(range.start.0, suggestion_range.start)
|
||||
..cmp::min(range.end.0, suggestion_range.end);
|
||||
let suggestion_chunks = if clipped_suggestion_range.start < clipped_suggestion_range.end
|
||||
{
|
||||
let start = clipped_suggestion_range.start - suggestion_range.start;
|
||||
let end = clipped_suggestion_range.end - suggestion_range.start;
|
||||
Some(suggestion.text.chunks_in_range(start..end))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let suffix_chunks = if range.end.0 > suggestion_range.end {
|
||||
let start = cmp::max(suggestion_range.end, range.start.0) - suggestion_range.len();
|
||||
let end = range.end.0 - suggestion_range.len();
|
||||
Some(self.fold_snapshot.chunks(
|
||||
FoldOffset(start)..FoldOffset(end),
|
||||
language_aware,
|
||||
text_highlights,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
SuggestionChunks {
|
||||
prefix_chunks,
|
||||
suggestion_chunks,
|
||||
suffix_chunks,
|
||||
highlight_style: suggestion_highlight,
|
||||
}
|
||||
} else {
|
||||
SuggestionChunks {
|
||||
prefix_chunks: Some(self.fold_snapshot.chunks(
|
||||
FoldOffset(range.start.0)..FoldOffset(range.end.0),
|
||||
language_aware,
|
||||
text_highlights,
|
||||
)),
|
||||
suggestion_chunks: None,
|
||||
suffix_chunks: None,
|
||||
highlight_style: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer_rows<'a>(&'a self, row: u32) -> SuggestionBufferRows<'a> {
|
||||
let suggestion_range = if let Some(suggestion) = self.suggestion.as_ref() {
|
||||
let start = suggestion.position.to_point(&self.fold_snapshot).0;
|
||||
let end = start + suggestion.text.max_point();
|
||||
start.row..end.row
|
||||
} else {
|
||||
u32::MAX..u32::MAX
|
||||
};
|
||||
|
||||
let fold_buffer_rows = if row <= suggestion_range.start {
|
||||
self.fold_snapshot.buffer_rows(row)
|
||||
} else if row > suggestion_range.end {
|
||||
self.fold_snapshot
|
||||
.buffer_rows(row - (suggestion_range.end - suggestion_range.start))
|
||||
} else {
|
||||
let mut rows = self.fold_snapshot.buffer_rows(suggestion_range.start);
|
||||
rows.next();
|
||||
rows
|
||||
};
|
||||
|
||||
SuggestionBufferRows {
|
||||
current_row: row,
|
||||
suggestion_row_start: suggestion_range.start,
|
||||
suggestion_row_end: suggestion_range.end,
|
||||
fold_buffer_rows,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn text(&self) -> String {
|
||||
self.chunks(Default::default()..self.len(), false, None, None)
|
||||
.map(|chunk| chunk.text)
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SuggestionChunks<'a> {
|
||||
prefix_chunks: Option<FoldChunks<'a>>,
|
||||
suggestion_chunks: Option<text::Chunks<'a>>,
|
||||
suffix_chunks: Option<FoldChunks<'a>>,
|
||||
highlight_style: Option<HighlightStyle>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for SuggestionChunks<'a> {
|
||||
type Item = Chunk<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if let Some(chunks) = self.prefix_chunks.as_mut() {
|
||||
if let Some(chunk) = chunks.next() {
|
||||
return Some(chunk);
|
||||
} else {
|
||||
self.prefix_chunks = None;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(chunks) = self.suggestion_chunks.as_mut() {
|
||||
if let Some(chunk) = chunks.next() {
|
||||
return Some(Chunk {
|
||||
text: chunk,
|
||||
highlight_style: self.highlight_style,
|
||||
..Default::default()
|
||||
});
|
||||
} else {
|
||||
self.suggestion_chunks = None;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(chunks) = self.suffix_chunks.as_mut() {
|
||||
if let Some(chunk) = chunks.next() {
|
||||
return Some(chunk);
|
||||
} else {
|
||||
self.suffix_chunks = None;
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SuggestionBufferRows<'a> {
|
||||
current_row: u32,
|
||||
suggestion_row_start: u32,
|
||||
suggestion_row_end: u32,
|
||||
fold_buffer_rows: FoldBufferRows<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for SuggestionBufferRows<'a> {
|
||||
type Item = Option<u32>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let row = post_inc(&mut self.current_row);
|
||||
if row <= self.suggestion_row_start || row > self.suggestion_row_end {
|
||||
self.fold_buffer_rows.next()
|
||||
} else {
|
||||
Some(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{display_map::fold_map::FoldMap, MultiBuffer};
|
||||
use gpui::AppContext;
|
||||
use rand::{prelude::StdRng, Rng};
|
||||
use settings::SettingsStore;
|
||||
use std::{
|
||||
env,
|
||||
ops::{Bound, RangeBounds},
|
||||
};
|
||||
|
||||
#[gpui::test]
|
||||
fn test_basic(cx: &mut AppContext) {
|
||||
let buffer = MultiBuffer::build_simple("abcdefghi", cx);
|
||||
let buffer_edits = buffer.update(cx, |buffer, _| buffer.subscribe());
|
||||
let (mut fold_map, fold_snapshot) = FoldMap::new(buffer.read(cx).snapshot(cx));
|
||||
let (suggestion_map, suggestion_snapshot) = SuggestionMap::new(fold_snapshot.clone());
|
||||
assert_eq!(suggestion_snapshot.text(), "abcdefghi");
|
||||
|
||||
let (suggestion_snapshot, _, _) = suggestion_map.replace(
|
||||
Some(Suggestion {
|
||||
position: 3,
|
||||
text: "123\n456".into(),
|
||||
}),
|
||||
fold_snapshot,
|
||||
Default::default(),
|
||||
);
|
||||
assert_eq!(suggestion_snapshot.text(), "abc123\n456defghi");
|
||||
|
||||
buffer.update(cx, |buffer, cx| {
|
||||
buffer.edit(
|
||||
[(0..0, "ABC"), (3..3, "DEF"), (4..4, "GHI"), (9..9, "JKL")],
|
||||
None,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(
|
||||
buffer.read(cx).snapshot(cx),
|
||||
buffer_edits.consume().into_inner(),
|
||||
);
|
||||
let (suggestion_snapshot, _) = suggestion_map.sync(fold_snapshot.clone(), fold_edits);
|
||||
assert_eq!(suggestion_snapshot.text(), "ABCabcDEF123\n456dGHIefghiJKL");
|
||||
|
||||
let (mut fold_map_writer, _, _) =
|
||||
fold_map.write(buffer.read(cx).snapshot(cx), Default::default());
|
||||
let (fold_snapshot, fold_edits) = fold_map_writer.fold([0..3]);
|
||||
let (suggestion_snapshot, _) = suggestion_map.sync(fold_snapshot, fold_edits);
|
||||
assert_eq!(suggestion_snapshot.text(), "⋯abcDEF123\n456dGHIefghiJKL");
|
||||
|
||||
let (mut fold_map_writer, _, _) =
|
||||
fold_map.write(buffer.read(cx).snapshot(cx), Default::default());
|
||||
let (fold_snapshot, fold_edits) = fold_map_writer.fold([6..10]);
|
||||
let (suggestion_snapshot, _) = suggestion_map.sync(fold_snapshot, fold_edits);
|
||||
assert_eq!(suggestion_snapshot.text(), "⋯abc⋯GHIefghiJKL");
|
||||
}
|
||||
|
||||
#[gpui::test(iterations = 100)]
|
||||
fn test_random_suggestions(cx: &mut AppContext, mut rng: StdRng) {
|
||||
init_test(cx);
|
||||
|
||||
let operations = env::var("OPERATIONS")
|
||||
.map(|i| i.parse().expect("invalid `OPERATIONS` variable"))
|
||||
.unwrap_or(10);
|
||||
|
||||
let len = rng.gen_range(0..30);
|
||||
let buffer = if rng.gen() {
|
||||
let text = util::RandomCharIter::new(&mut rng)
|
||||
.take(len)
|
||||
.collect::<String>();
|
||||
MultiBuffer::build_simple(&text, cx)
|
||||
} else {
|
||||
MultiBuffer::build_random(&mut rng, cx)
|
||||
};
|
||||
let mut buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
log::info!("buffer text: {:?}", buffer_snapshot.text());
|
||||
|
||||
let (mut fold_map, mut fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
|
||||
let (suggestion_map, mut suggestion_snapshot) = SuggestionMap::new(fold_snapshot.clone());
|
||||
|
||||
for _ in 0..operations {
|
||||
let mut suggestion_edits = Patch::default();
|
||||
|
||||
let mut prev_suggestion_text = suggestion_snapshot.text();
|
||||
let mut buffer_edits = Vec::new();
|
||||
match rng.gen_range(0..=100) {
|
||||
0..=29 => {
|
||||
let (_, edits) = suggestion_map.randomly_mutate(&mut rng);
|
||||
suggestion_edits = suggestion_edits.compose(edits);
|
||||
}
|
||||
30..=59 => {
|
||||
for (new_fold_snapshot, fold_edits) in fold_map.randomly_mutate(&mut rng) {
|
||||
fold_snapshot = new_fold_snapshot;
|
||||
let (_, edits) = suggestion_map.sync(fold_snapshot.clone(), fold_edits);
|
||||
suggestion_edits = suggestion_edits.compose(edits);
|
||||
}
|
||||
}
|
||||
_ => buffer.update(cx, |buffer, cx| {
|
||||
let subscription = buffer.subscribe();
|
||||
let edit_count = rng.gen_range(1..=5);
|
||||
buffer.randomly_mutate(&mut rng, edit_count, cx);
|
||||
buffer_snapshot = buffer.snapshot(cx);
|
||||
let edits = subscription.consume().into_inner();
|
||||
log::info!("editing {:?}", edits);
|
||||
buffer_edits.extend(edits);
|
||||
}),
|
||||
};
|
||||
|
||||
let (new_fold_snapshot, fold_edits) =
|
||||
fold_map.read(buffer_snapshot.clone(), buffer_edits);
|
||||
fold_snapshot = new_fold_snapshot;
|
||||
let (new_suggestion_snapshot, edits) =
|
||||
suggestion_map.sync(fold_snapshot.clone(), fold_edits);
|
||||
suggestion_snapshot = new_suggestion_snapshot;
|
||||
suggestion_edits = suggestion_edits.compose(edits);
|
||||
|
||||
log::info!("buffer text: {:?}", buffer_snapshot.text());
|
||||
log::info!("folds text: {:?}", fold_snapshot.text());
|
||||
log::info!("suggestions text: {:?}", suggestion_snapshot.text());
|
||||
|
||||
let mut expected_text = Rope::from(fold_snapshot.text().as_str());
|
||||
let mut expected_buffer_rows = fold_snapshot.buffer_rows(0).collect::<Vec<_>>();
|
||||
if let Some(suggestion) = suggestion_snapshot.suggestion.as_ref() {
|
||||
expected_text.replace(
|
||||
suggestion.position.0..suggestion.position.0,
|
||||
&suggestion.text.to_string(),
|
||||
);
|
||||
let suggestion_start = suggestion.position.to_point(&fold_snapshot).0;
|
||||
let suggestion_end = suggestion_start + suggestion.text.max_point();
|
||||
expected_buffer_rows.splice(
|
||||
(suggestion_start.row + 1) as usize..(suggestion_start.row + 1) as usize,
|
||||
(0..suggestion_end.row - suggestion_start.row).map(|_| None),
|
||||
);
|
||||
}
|
||||
assert_eq!(suggestion_snapshot.text(), expected_text.to_string());
|
||||
for row_start in 0..expected_buffer_rows.len() {
|
||||
assert_eq!(
|
||||
suggestion_snapshot
|
||||
.buffer_rows(row_start as u32)
|
||||
.collect::<Vec<_>>(),
|
||||
&expected_buffer_rows[row_start..],
|
||||
"incorrect buffer rows starting at {}",
|
||||
row_start
|
||||
);
|
||||
}
|
||||
|
||||
for _ in 0..5 {
|
||||
let mut end = rng.gen_range(0..=suggestion_snapshot.len().0);
|
||||
end = expected_text.clip_offset(end, Bias::Right);
|
||||
let mut start = rng.gen_range(0..=end);
|
||||
start = expected_text.clip_offset(start, Bias::Right);
|
||||
|
||||
let actual_text = suggestion_snapshot
|
||||
.chunks(
|
||||
SuggestionOffset(start)..SuggestionOffset(end),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.map(|chunk| chunk.text)
|
||||
.collect::<String>();
|
||||
assert_eq!(
|
||||
actual_text,
|
||||
expected_text.slice(start..end).to_string(),
|
||||
"incorrect text in range {:?}",
|
||||
start..end
|
||||
);
|
||||
|
||||
let start_point = SuggestionPoint(expected_text.offset_to_point(start));
|
||||
let end_point = SuggestionPoint(expected_text.offset_to_point(end));
|
||||
assert_eq!(
|
||||
suggestion_snapshot.text_summary_for_range(start_point..end_point),
|
||||
expected_text.slice(start..end).summary()
|
||||
);
|
||||
}
|
||||
|
||||
for edit in suggestion_edits.into_inner() {
|
||||
prev_suggestion_text.replace_range(
|
||||
edit.new.start.0..edit.new.start.0 + edit.old_len().0,
|
||||
&suggestion_snapshot.text()[edit.new.start.0..edit.new.end.0],
|
||||
);
|
||||
}
|
||||
assert_eq!(prev_suggestion_text, suggestion_snapshot.text());
|
||||
|
||||
assert_eq!(expected_text.max_point(), suggestion_snapshot.max_point().0);
|
||||
assert_eq!(expected_text.len(), suggestion_snapshot.len().0);
|
||||
|
||||
let mut suggestion_point = SuggestionPoint::default();
|
||||
let mut suggestion_offset = SuggestionOffset::default();
|
||||
for ch in expected_text.chars() {
|
||||
assert_eq!(
|
||||
suggestion_snapshot.to_offset(suggestion_point),
|
||||
suggestion_offset,
|
||||
"invalid to_offset({:?})",
|
||||
suggestion_point
|
||||
);
|
||||
assert_eq!(
|
||||
suggestion_snapshot.to_point(suggestion_offset),
|
||||
suggestion_point,
|
||||
"invalid to_point({:?})",
|
||||
suggestion_offset
|
||||
);
|
||||
assert_eq!(
|
||||
suggestion_snapshot
|
||||
.to_suggestion_point(suggestion_snapshot.to_fold_point(suggestion_point)),
|
||||
suggestion_snapshot.clip_point(suggestion_point, Bias::Left),
|
||||
);
|
||||
|
||||
let mut bytes = [0; 4];
|
||||
for byte in ch.encode_utf8(&mut bytes).as_bytes() {
|
||||
suggestion_offset.0 += 1;
|
||||
if *byte == b'\n' {
|
||||
suggestion_point.0 += Point::new(1, 0);
|
||||
} else {
|
||||
suggestion_point.0 += Point::new(0, 1);
|
||||
}
|
||||
|
||||
let clipped_left_point =
|
||||
suggestion_snapshot.clip_point(suggestion_point, Bias::Left);
|
||||
let clipped_right_point =
|
||||
suggestion_snapshot.clip_point(suggestion_point, Bias::Right);
|
||||
assert!(
|
||||
clipped_left_point <= clipped_right_point,
|
||||
"clipped left point {:?} is greater than clipped right point {:?}",
|
||||
clipped_left_point,
|
||||
clipped_right_point
|
||||
);
|
||||
assert_eq!(
|
||||
clipped_left_point.0,
|
||||
expected_text.clip_point(clipped_left_point.0, Bias::Left)
|
||||
);
|
||||
assert_eq!(
|
||||
clipped_right_point.0,
|
||||
expected_text.clip_point(clipped_right_point.0, Bias::Right)
|
||||
);
|
||||
assert!(clipped_left_point <= suggestion_snapshot.max_point());
|
||||
assert!(clipped_right_point <= suggestion_snapshot.max_point());
|
||||
|
||||
if let Some(suggestion) = suggestion_snapshot.suggestion.as_ref() {
|
||||
let suggestion_start = suggestion.position.to_point(&fold_snapshot).0;
|
||||
let suggestion_end = suggestion_start + suggestion.text.max_point();
|
||||
let invalid_range = (
|
||||
Bound::Excluded(suggestion_start),
|
||||
Bound::Included(suggestion_end),
|
||||
);
|
||||
assert!(
|
||||
!invalid_range.contains(&clipped_left_point.0),
|
||||
"clipped left point {:?} is inside invalid suggestion range {:?}",
|
||||
clipped_left_point,
|
||||
invalid_range
|
||||
);
|
||||
assert!(
|
||||
!invalid_range.contains(&clipped_right_point.0),
|
||||
"clipped right point {:?} is inside invalid suggestion range {:?}",
|
||||
clipped_right_point,
|
||||
invalid_range
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init_test(cx: &mut AppContext) {
|
||||
cx.set_global(SettingsStore::test(cx));
|
||||
theme::init((), cx);
|
||||
}
|
||||
|
||||
impl SuggestionMap {
|
||||
pub fn randomly_mutate(
|
||||
&self,
|
||||
rng: &mut impl Rng,
|
||||
) -> (SuggestionSnapshot, Vec<SuggestionEdit>) {
|
||||
let fold_snapshot = self.0.lock().fold_snapshot.clone();
|
||||
let new_suggestion = if rng.gen_bool(0.3) {
|
||||
None
|
||||
} else {
|
||||
let index = rng.gen_range(0..=fold_snapshot.buffer_snapshot().len());
|
||||
let len = rng.gen_range(0..30);
|
||||
Some(Suggestion {
|
||||
position: index,
|
||||
text: util::RandomCharIter::new(rng)
|
||||
.take(len)
|
||||
.filter(|ch| *ch != '\r')
|
||||
.collect::<String>()
|
||||
.as_str()
|
||||
.into(),
|
||||
})
|
||||
};
|
||||
|
||||
log::info!("replacing suggestion with {:?}", new_suggestion);
|
||||
let (snapshot, edits, _) =
|
||||
self.replace(new_suggestion, fold_snapshot, Default::default());
|
||||
(snapshot, edits)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
use super::{
|
||||
inlay_map::{self, InlayChunks, InlayEdit, InlayPoint, InlaySnapshot},
|
||||
fold_map::{self, FoldChunks, FoldEdit, FoldPoint, FoldSnapshot},
|
||||
TextHighlights,
|
||||
};
|
||||
use crate::MultiBufferSnapshot;
|
||||
|
@ -14,9 +14,9 @@ const MAX_EXPANSION_COLUMN: u32 = 256;
|
|||
pub struct TabMap(Mutex<TabSnapshot>);
|
||||
|
||||
impl TabMap {
|
||||
pub fn new(input: InlaySnapshot, tab_size: NonZeroU32) -> (Self, TabSnapshot) {
|
||||
pub fn new(fold_snapshot: FoldSnapshot, tab_size: NonZeroU32) -> (Self, TabSnapshot) {
|
||||
let snapshot = TabSnapshot {
|
||||
inlay_snapshot: input,
|
||||
fold_snapshot,
|
||||
tab_size,
|
||||
max_expansion_column: MAX_EXPANSION_COLUMN,
|
||||
version: 0,
|
||||
|
@ -32,45 +32,42 @@ impl TabMap {
|
|||
|
||||
pub fn sync(
|
||||
&self,
|
||||
inlay_snapshot: InlaySnapshot,
|
||||
mut suggestion_edits: Vec<InlayEdit>,
|
||||
fold_snapshot: FoldSnapshot,
|
||||
mut fold_edits: Vec<FoldEdit>,
|
||||
tab_size: NonZeroU32,
|
||||
) -> (TabSnapshot, Vec<TabEdit>) {
|
||||
let mut old_snapshot = self.0.lock();
|
||||
let mut new_snapshot = TabSnapshot {
|
||||
inlay_snapshot,
|
||||
fold_snapshot,
|
||||
tab_size,
|
||||
max_expansion_column: old_snapshot.max_expansion_column,
|
||||
version: old_snapshot.version,
|
||||
};
|
||||
|
||||
if old_snapshot.inlay_snapshot.version != new_snapshot.inlay_snapshot.version {
|
||||
if old_snapshot.fold_snapshot.version != new_snapshot.fold_snapshot.version {
|
||||
new_snapshot.version += 1;
|
||||
}
|
||||
|
||||
let mut tab_edits = Vec::with_capacity(suggestion_edits.len());
|
||||
let mut tab_edits = Vec::with_capacity(fold_edits.len());
|
||||
|
||||
if old_snapshot.tab_size == new_snapshot.tab_size {
|
||||
// Expand each edit to include the next tab on the same line as the edit,
|
||||
// and any subsequent tabs on that line that moved across the tab expansion
|
||||
// boundary.
|
||||
for suggestion_edit in &mut suggestion_edits {
|
||||
let old_end = old_snapshot
|
||||
.inlay_snapshot
|
||||
.to_point(suggestion_edit.old.end);
|
||||
let old_end_row_successor_offset = old_snapshot.inlay_snapshot.to_offset(cmp::min(
|
||||
InlayPoint::new(old_end.row() + 1, 0),
|
||||
old_snapshot.inlay_snapshot.max_point(),
|
||||
));
|
||||
let new_end = new_snapshot
|
||||
.inlay_snapshot
|
||||
.to_point(suggestion_edit.new.end);
|
||||
for fold_edit in &mut fold_edits {
|
||||
let old_end = fold_edit.old.end.to_point(&old_snapshot.fold_snapshot);
|
||||
let old_end_row_successor_offset = cmp::min(
|
||||
FoldPoint::new(old_end.row() + 1, 0),
|
||||
old_snapshot.fold_snapshot.max_point(),
|
||||
)
|
||||
.to_offset(&old_snapshot.fold_snapshot);
|
||||
let new_end = fold_edit.new.end.to_point(&new_snapshot.fold_snapshot);
|
||||
|
||||
let mut offset_from_edit = 0;
|
||||
let mut first_tab_offset = None;
|
||||
let mut last_tab_with_changed_expansion_offset = None;
|
||||
'outer: for chunk in old_snapshot.inlay_snapshot.chunks(
|
||||
suggestion_edit.old.end..old_end_row_successor_offset,
|
||||
'outer: for chunk in old_snapshot.fold_snapshot.chunks(
|
||||
fold_edit.old.end..old_end_row_successor_offset,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
|
@ -101,39 +98,31 @@ impl TabMap {
|
|||
}
|
||||
|
||||
if let Some(offset) = last_tab_with_changed_expansion_offset.or(first_tab_offset) {
|
||||
suggestion_edit.old.end.0 += offset as usize + 1;
|
||||
suggestion_edit.new.end.0 += offset as usize + 1;
|
||||
fold_edit.old.end.0 += offset as usize + 1;
|
||||
fold_edit.new.end.0 += offset as usize + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Combine any edits that overlap due to the expansion.
|
||||
let mut ix = 1;
|
||||
while ix < suggestion_edits.len() {
|
||||
let (prev_edits, next_edits) = suggestion_edits.split_at_mut(ix);
|
||||
while ix < fold_edits.len() {
|
||||
let (prev_edits, next_edits) = fold_edits.split_at_mut(ix);
|
||||
let prev_edit = prev_edits.last_mut().unwrap();
|
||||
let edit = &next_edits[0];
|
||||
if prev_edit.old.end >= edit.old.start {
|
||||
prev_edit.old.end = edit.old.end;
|
||||
prev_edit.new.end = edit.new.end;
|
||||
suggestion_edits.remove(ix);
|
||||
fold_edits.remove(ix);
|
||||
} else {
|
||||
ix += 1;
|
||||
}
|
||||
}
|
||||
|
||||
for suggestion_edit in suggestion_edits {
|
||||
let old_start = old_snapshot
|
||||
.inlay_snapshot
|
||||
.to_point(suggestion_edit.old.start);
|
||||
let old_end = old_snapshot
|
||||
.inlay_snapshot
|
||||
.to_point(suggestion_edit.old.end);
|
||||
let new_start = new_snapshot
|
||||
.inlay_snapshot
|
||||
.to_point(suggestion_edit.new.start);
|
||||
let new_end = new_snapshot
|
||||
.inlay_snapshot
|
||||
.to_point(suggestion_edit.new.end);
|
||||
for fold_edit in fold_edits {
|
||||
let old_start = fold_edit.old.start.to_point(&old_snapshot.fold_snapshot);
|
||||
let old_end = fold_edit.old.end.to_point(&old_snapshot.fold_snapshot);
|
||||
let new_start = fold_edit.new.start.to_point(&new_snapshot.fold_snapshot);
|
||||
let new_end = fold_edit.new.end.to_point(&new_snapshot.fold_snapshot);
|
||||
tab_edits.push(TabEdit {
|
||||
old: old_snapshot.to_tab_point(old_start)..old_snapshot.to_tab_point(old_end),
|
||||
new: new_snapshot.to_tab_point(new_start)..new_snapshot.to_tab_point(new_end),
|
||||
|
@ -154,7 +143,7 @@ impl TabMap {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct TabSnapshot {
|
||||
pub inlay_snapshot: InlaySnapshot,
|
||||
pub fold_snapshot: FoldSnapshot,
|
||||
pub tab_size: NonZeroU32,
|
||||
pub max_expansion_column: u32,
|
||||
pub version: usize,
|
||||
|
@ -162,13 +151,13 @@ pub struct TabSnapshot {
|
|||
|
||||
impl TabSnapshot {
|
||||
pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot {
|
||||
self.inlay_snapshot.buffer_snapshot()
|
||||
&self.fold_snapshot.inlay_snapshot.buffer
|
||||
}
|
||||
|
||||
pub fn line_len(&self, row: u32) -> u32 {
|
||||
let max_point = self.max_point();
|
||||
if row < max_point.row() {
|
||||
self.to_tab_point(InlayPoint::new(row, self.inlay_snapshot.line_len(row)))
|
||||
self.to_tab_point(FoldPoint::new(row, self.fold_snapshot.line_len(row)))
|
||||
.0
|
||||
.column
|
||||
} else {
|
||||
|
@ -181,10 +170,10 @@ impl TabSnapshot {
|
|||
}
|
||||
|
||||
pub fn text_summary_for_range(&self, range: Range<TabPoint>) -> TextSummary {
|
||||
let input_start = self.to_inlay_point(range.start, Bias::Left).0;
|
||||
let input_end = self.to_inlay_point(range.end, Bias::Right).0;
|
||||
let input_start = self.to_fold_point(range.start, Bias::Left).0;
|
||||
let input_end = self.to_fold_point(range.end, Bias::Right).0;
|
||||
let input_summary = self
|
||||
.inlay_snapshot
|
||||
.fold_snapshot
|
||||
.text_summary_for_range(input_start..input_end);
|
||||
|
||||
let mut first_line_chars = 0;
|
||||
|
@ -234,15 +223,16 @@ impl TabSnapshot {
|
|||
range: Range<TabPoint>,
|
||||
language_aware: bool,
|
||||
text_highlights: Option<&'a TextHighlights>,
|
||||
suggestion_highlight: Option<HighlightStyle>,
|
||||
inlay_highlights: Option<HighlightStyle>,
|
||||
) -> TabChunks<'a> {
|
||||
let (input_start, expanded_char_column, to_next_stop) =
|
||||
self.to_inlay_point(range.start, Bias::Left);
|
||||
self.to_fold_point(range.start, Bias::Left);
|
||||
let input_column = input_start.column();
|
||||
let input_start = self.inlay_snapshot.to_offset(input_start);
|
||||
let input_start = input_start.to_offset(&self.fold_snapshot);
|
||||
let input_end = self
|
||||
.inlay_snapshot
|
||||
.to_offset(self.to_inlay_point(range.end, Bias::Right).0);
|
||||
.to_fold_point(range.end, Bias::Right)
|
||||
.0
|
||||
.to_offset(&self.fold_snapshot);
|
||||
let to_next_stop = if range.start.0 + Point::new(0, to_next_stop) > range.end.0 {
|
||||
range.end.column() - range.start.column()
|
||||
} else {
|
||||
|
@ -250,11 +240,11 @@ impl TabSnapshot {
|
|||
};
|
||||
|
||||
TabChunks {
|
||||
inlay_chunks: self.inlay_snapshot.chunks(
|
||||
fold_chunks: self.fold_snapshot.chunks(
|
||||
input_start..input_end,
|
||||
language_aware,
|
||||
text_highlights,
|
||||
suggestion_highlight,
|
||||
inlay_highlights,
|
||||
),
|
||||
input_column,
|
||||
column: expanded_char_column,
|
||||
|
@ -271,8 +261,8 @@ impl TabSnapshot {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn buffer_rows(&self, row: u32) -> inlay_map::InlayBufferRows<'_> {
|
||||
self.inlay_snapshot.buffer_rows(row)
|
||||
pub fn buffer_rows(&self, row: u32) -> fold_map::FoldBufferRows<'_> {
|
||||
self.fold_snapshot.buffer_rows(row)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -283,48 +273,46 @@ impl TabSnapshot {
|
|||
}
|
||||
|
||||
pub fn max_point(&self) -> TabPoint {
|
||||
self.to_tab_point(self.inlay_snapshot.max_point())
|
||||
self.to_tab_point(self.fold_snapshot.max_point())
|
||||
}
|
||||
|
||||
pub fn clip_point(&self, point: TabPoint, bias: Bias) -> TabPoint {
|
||||
self.to_tab_point(
|
||||
self.inlay_snapshot
|
||||
.clip_point(self.to_inlay_point(point, bias).0, bias),
|
||||
self.fold_snapshot
|
||||
.clip_point(self.to_fold_point(point, bias).0, bias),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_tab_point(&self, input: InlayPoint) -> TabPoint {
|
||||
let chars = self
|
||||
.inlay_snapshot
|
||||
.chars_at(InlayPoint::new(input.row(), 0));
|
||||
pub fn to_tab_point(&self, input: FoldPoint) -> TabPoint {
|
||||
let chars = self.fold_snapshot.chars_at(FoldPoint::new(input.row(), 0));
|
||||
let expanded = self.expand_tabs(chars, input.column());
|
||||
TabPoint::new(input.row(), expanded)
|
||||
}
|
||||
|
||||
pub fn to_inlay_point(&self, output: TabPoint, bias: Bias) -> (InlayPoint, u32, u32) {
|
||||
let chars = self
|
||||
.inlay_snapshot
|
||||
.chars_at(InlayPoint::new(output.row(), 0));
|
||||
pub fn to_fold_point(&self, output: TabPoint, bias: Bias) -> (FoldPoint, u32, u32) {
|
||||
let chars = self.fold_snapshot.chars_at(FoldPoint::new(output.row(), 0));
|
||||
let expanded = output.column();
|
||||
let (collapsed, expanded_char_column, to_next_stop) =
|
||||
self.collapse_tabs(chars, expanded, bias);
|
||||
(
|
||||
InlayPoint::new(output.row(), collapsed as u32),
|
||||
FoldPoint::new(output.row(), collapsed as u32),
|
||||
expanded_char_column,
|
||||
to_next_stop,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn make_tab_point(&self, point: Point, bias: Bias) -> TabPoint {
|
||||
let fold_point = self.inlay_snapshot.fold_snapshot.to_fold_point(point, bias);
|
||||
let inlay_point = self.inlay_snapshot.to_inlay_point(fold_point);
|
||||
self.to_tab_point(inlay_point)
|
||||
let inlay_point = self.fold_snapshot.inlay_snapshot.to_inlay_point(point);
|
||||
let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias);
|
||||
self.to_tab_point(fold_point)
|
||||
}
|
||||
|
||||
pub fn to_point(&self, point: TabPoint, bias: Bias) -> Point {
|
||||
let inlay_point = self.to_inlay_point(point, bias).0;
|
||||
let fold_point = self.inlay_snapshot.to_fold_point(inlay_point);
|
||||
fold_point.to_buffer_point(&self.inlay_snapshot.fold_snapshot)
|
||||
let fold_point = self.to_fold_point(point, bias).0;
|
||||
let inlay_point = fold_point.to_inlay_point(&self.fold_snapshot);
|
||||
self.fold_snapshot
|
||||
.inlay_snapshot
|
||||
.to_buffer_point(inlay_point)
|
||||
}
|
||||
|
||||
fn expand_tabs(&self, chars: impl Iterator<Item = char>, column: u32) -> u32 {
|
||||
|
@ -483,7 +471,7 @@ impl<'a> std::ops::AddAssign<&'a Self> for TextSummary {
|
|||
const SPACES: &str = " ";
|
||||
|
||||
pub struct TabChunks<'a> {
|
||||
inlay_chunks: InlayChunks<'a>,
|
||||
fold_chunks: FoldChunks<'a>,
|
||||
chunk: Chunk<'a>,
|
||||
column: u32,
|
||||
max_expansion_column: u32,
|
||||
|
@ -499,7 +487,7 @@ impl<'a> Iterator for TabChunks<'a> {
|
|||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.chunk.text.is_empty() {
|
||||
if let Some(chunk) = self.inlay_chunks.next() {
|
||||
if let Some(chunk) = self.fold_chunks.next() {
|
||||
self.chunk = chunk;
|
||||
if self.inside_leading_tab {
|
||||
self.chunk.text = &self.chunk.text[1..];
|
||||
|
@ -576,9 +564,9 @@ mod tests {
|
|||
fn test_expand_tabs(cx: &mut gpui::AppContext) {
|
||||
let buffer = MultiBuffer::build_simple("", cx);
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (_, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
|
||||
let (_, inlay_snapshot) = InlayMap::new(fold_snapshot);
|
||||
let (_, tab_snapshot) = TabMap::new(inlay_snapshot, 4.try_into().unwrap());
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
|
||||
assert_eq!(tab_snapshot.expand_tabs("\t".chars(), 0), 0);
|
||||
assert_eq!(tab_snapshot.expand_tabs("\t".chars(), 1), 4);
|
||||
|
@ -593,9 +581,9 @@ mod tests {
|
|||
|
||||
let buffer = MultiBuffer::build_simple(input, cx);
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (_, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
|
||||
let (_, inlay_snapshot) = InlayMap::new(fold_snapshot);
|
||||
let (_, mut tab_snapshot) = TabMap::new(inlay_snapshot, 4.try_into().unwrap());
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (_, mut tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
|
||||
tab_snapshot.max_expansion_column = max_expansion_column;
|
||||
assert_eq!(tab_snapshot.text(), output);
|
||||
|
@ -619,16 +607,16 @@ mod tests {
|
|||
let input_point = Point::new(0, ix as u32);
|
||||
let output_point = Point::new(0, output.find(c).unwrap() as u32);
|
||||
assert_eq!(
|
||||
tab_snapshot.to_tab_point(InlayPoint(input_point)),
|
||||
tab_snapshot.to_tab_point(FoldPoint(input_point)),
|
||||
TabPoint(output_point),
|
||||
"to_tab_point({input_point:?})"
|
||||
);
|
||||
assert_eq!(
|
||||
tab_snapshot
|
||||
.to_inlay_point(TabPoint(output_point), Bias::Left)
|
||||
.to_fold_point(TabPoint(output_point), Bias::Left)
|
||||
.0,
|
||||
InlayPoint(input_point),
|
||||
"to_suggestion_point({output_point:?})"
|
||||
FoldPoint(input_point),
|
||||
"to_fold_point({output_point:?})"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -641,9 +629,9 @@ mod tests {
|
|||
|
||||
let buffer = MultiBuffer::build_simple(input, cx);
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (_, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
|
||||
let (_, inlay_snapshot) = InlayMap::new(fold_snapshot);
|
||||
let (_, mut tab_snapshot) = TabMap::new(inlay_snapshot, 4.try_into().unwrap());
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (_, mut tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
|
||||
tab_snapshot.max_expansion_column = max_expansion_column;
|
||||
assert_eq!(tab_snapshot.text(), input);
|
||||
|
@ -655,9 +643,9 @@ mod tests {
|
|||
|
||||
let buffer = MultiBuffer::build_simple(&input, cx);
|
||||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
let (_, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
|
||||
let (_, inlay_snapshot) = InlayMap::new(fold_snapshot);
|
||||
let (_, tab_snapshot) = TabMap::new(inlay_snapshot, 4.try_into().unwrap());
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let (_, tab_snapshot) = TabMap::new(fold_snapshot, 4.try_into().unwrap());
|
||||
|
||||
assert_eq!(
|
||||
chunks(&tab_snapshot, TabPoint::zero()),
|
||||
|
@ -714,15 +702,16 @@ mod tests {
|
|||
let buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
log::info!("Buffer text: {:?}", buffer_snapshot.text());
|
||||
|
||||
let (mut fold_map, _) = FoldMap::new(buffer_snapshot.clone());
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
log::info!("InlayMap text: {:?}", inlay_snapshot.text());
|
||||
let (mut fold_map, _) = FoldMap::new(inlay_snapshot.clone());
|
||||
fold_map.randomly_mutate(&mut rng);
|
||||
let (fold_snapshot, _) = fold_map.read(buffer_snapshot, vec![]);
|
||||
let (fold_snapshot, _) = fold_map.read(inlay_snapshot, vec![]);
|
||||
log::info!("FoldMap text: {:?}", fold_snapshot.text());
|
||||
let (mut inlay_map, _) = InlayMap::new(fold_snapshot.clone());
|
||||
let (inlay_snapshot, _) = inlay_map.randomly_mutate(&mut 0, &mut rng);
|
||||
log::info!("InlayMap text: {:?}", inlay_snapshot.text());
|
||||
|
||||
let (tab_map, _) = TabMap::new(inlay_snapshot.clone(), tab_size);
|
||||
let (tab_map, _) = TabMap::new(fold_snapshot.clone(), tab_size);
|
||||
let tabs_snapshot = tab_map.set_max_expansion_column(32);
|
||||
|
||||
let text = text::Rope::from(tabs_snapshot.text().as_str());
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use super::{
|
||||
inlay_map::InlayBufferRows,
|
||||
fold_map::FoldBufferRows,
|
||||
tab_map::{self, TabEdit, TabPoint, TabSnapshot},
|
||||
TextHighlights,
|
||||
};
|
||||
|
@ -65,7 +65,7 @@ pub struct WrapChunks<'a> {
|
|||
|
||||
#[derive(Clone)]
|
||||
pub struct WrapBufferRows<'a> {
|
||||
input_buffer_rows: InlayBufferRows<'a>,
|
||||
input_buffer_rows: FoldBufferRows<'a>,
|
||||
input_buffer_row: Option<u32>,
|
||||
output_row: u32,
|
||||
soft_wrapped: bool,
|
||||
|
@ -575,7 +575,7 @@ impl WrapSnapshot {
|
|||
rows: Range<u32>,
|
||||
language_aware: bool,
|
||||
text_highlights: Option<&'a TextHighlights>,
|
||||
suggestion_highlight: Option<HighlightStyle>,
|
||||
inlay_highlights: Option<HighlightStyle>,
|
||||
) -> WrapChunks<'a> {
|
||||
let output_start = WrapPoint::new(rows.start, 0);
|
||||
let output_end = WrapPoint::new(rows.end, 0);
|
||||
|
@ -593,7 +593,7 @@ impl WrapSnapshot {
|
|||
input_start..input_end,
|
||||
language_aware,
|
||||
text_highlights,
|
||||
suggestion_highlight,
|
||||
inlay_highlights,
|
||||
),
|
||||
input_chunk: Default::default(),
|
||||
output_position: output_start,
|
||||
|
@ -762,13 +762,16 @@ impl WrapSnapshot {
|
|||
let mut prev_fold_row = 0;
|
||||
for display_row in 0..=self.max_point().row() {
|
||||
let tab_point = self.to_tab_point(WrapPoint::new(display_row, 0));
|
||||
let inlay_point = self.tab_snapshot.to_inlay_point(tab_point, Bias::Left).0;
|
||||
let fold_point = self.tab_snapshot.inlay_snapshot.to_fold_point(inlay_point);
|
||||
let fold_point = self.tab_snapshot.to_fold_point(tab_point, Bias::Left).0;
|
||||
if fold_point.row() == prev_fold_row && display_row != 0 {
|
||||
expected_buffer_rows.push(None);
|
||||
} else {
|
||||
let buffer_point =
|
||||
fold_point.to_buffer_point(&self.tab_snapshot.inlay_snapshot.fold_snapshot);
|
||||
let inlay_point = fold_point.to_inlay_point(&self.tab_snapshot.fold_snapshot);
|
||||
let buffer_point = self
|
||||
.tab_snapshot
|
||||
.fold_snapshot
|
||||
.inlay_snapshot
|
||||
.to_buffer_point(inlay_point);
|
||||
expected_buffer_rows.push(input_buffer_rows[buffer_point.row as usize]);
|
||||
prev_fold_row = fold_point.row();
|
||||
}
|
||||
|
@ -1083,11 +1086,11 @@ mod tests {
|
|||
});
|
||||
let mut buffer_snapshot = buffer.read_with(cx, |buffer, cx| buffer.snapshot(cx));
|
||||
log::info!("Buffer text: {:?}", buffer_snapshot.text());
|
||||
let (mut fold_map, fold_snapshot) = FoldMap::new(buffer_snapshot.clone());
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone());
|
||||
log::info!("InlayMap text: {:?}", inlay_snapshot.text());
|
||||
let (mut fold_map, fold_snapshot) = FoldMap::new(inlay_snapshot.clone());
|
||||
log::info!("FoldMap text: {:?}", fold_snapshot.text());
|
||||
let (mut inlay_map, inlay_snapshot) = InlayMap::new(fold_snapshot.clone());
|
||||
log::info!("InlaysMap text: {:?}", inlay_snapshot.text());
|
||||
let (tab_map, _) = TabMap::new(inlay_snapshot.clone(), tab_size);
|
||||
let (tab_map, _) = TabMap::new(fold_snapshot.clone(), tab_size);
|
||||
let tabs_snapshot = tab_map.set_max_expansion_column(32);
|
||||
log::info!("TabMap text: {:?}", tabs_snapshot.text());
|
||||
|
||||
|
@ -1134,10 +1137,8 @@ mod tests {
|
|||
}
|
||||
20..=39 => {
|
||||
for (fold_snapshot, fold_edits) in fold_map.randomly_mutate(&mut rng) {
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(fold_snapshot, fold_edits);
|
||||
let (tabs_snapshot, tab_edits) =
|
||||
tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
|
||||
tab_map.sync(fold_snapshot, fold_edits, tab_size);
|
||||
let (mut snapshot, wrap_edits) =
|
||||
wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot, tab_edits, cx));
|
||||
snapshot.check_invariants();
|
||||
|
@ -1148,8 +1149,9 @@ mod tests {
|
|||
40..=59 => {
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.randomly_mutate(&mut next_inlay_id, &mut rng);
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
|
||||
let (tabs_snapshot, tab_edits) =
|
||||
tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
|
||||
tab_map.sync(fold_snapshot, fold_edits, tab_size);
|
||||
let (mut snapshot, wrap_edits) =
|
||||
wrap_map.update(cx, |map, cx| map.sync(tabs_snapshot, tab_edits, cx));
|
||||
snapshot.check_invariants();
|
||||
|
@ -1168,11 +1170,12 @@ mod tests {
|
|||
}
|
||||
|
||||
log::info!("Buffer text: {:?}", buffer_snapshot.text());
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(buffer_snapshot.clone(), buffer_edits);
|
||||
log::info!("FoldMap text: {:?}", fold_snapshot.text());
|
||||
let (inlay_snapshot, inlay_edits) = inlay_map.sync(fold_snapshot, fold_edits);
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
inlay_map.sync(buffer_snapshot.clone(), buffer_edits);
|
||||
log::info!("InlayMap text: {:?}", inlay_snapshot.text());
|
||||
let (tabs_snapshot, tab_edits) = tab_map.sync(inlay_snapshot, inlay_edits, tab_size);
|
||||
let (fold_snapshot, fold_edits) = fold_map.read(inlay_snapshot, inlay_edits);
|
||||
log::info!("FoldMap text: {:?}", fold_snapshot.text());
|
||||
let (tabs_snapshot, tab_edits) = tab_map.sync(fold_snapshot, fold_edits, tab_size);
|
||||
log::info!("TabMap text: {:?}", tabs_snapshot.text());
|
||||
|
||||
let unwrapped_text = tabs_snapshot.text();
|
||||
|
@ -1220,7 +1223,7 @@ mod tests {
|
|||
if tab_size.get() == 1
|
||||
|| !wrapped_snapshot
|
||||
.tab_snapshot
|
||||
.inlay_snapshot
|
||||
.fold_snapshot
|
||||
.text()
|
||||
.contains('\t')
|
||||
{
|
||||
|
|
|
@ -70,11 +70,11 @@ use link_go_to_definition::{
|
|||
hide_link_definition, show_link_definition, LinkDefinitionKind, LinkGoToDefinitionState,
|
||||
};
|
||||
use log::error;
|
||||
use multi_buffer::ToOffsetUtf16;
|
||||
pub use multi_buffer::{
|
||||
Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
|
||||
ToPoint,
|
||||
};
|
||||
use multi_buffer::{MultiBufferChunks, ToOffsetUtf16};
|
||||
use ordered_float::OrderedFloat;
|
||||
use project::{FormatTrigger, Location, LocationLink, Project, ProjectPath, ProjectTransaction};
|
||||
use scroll::{
|
||||
|
|
Loading…
Reference in a new issue