diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index f7660ad2b3..cddc10fba7 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -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) -> 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, language_aware: bool, - suggestion_highlight: Option, + inlay_highlights: Option, ) -> 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)) } } diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index 3bb8ccc2ac..a745fddce7 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -583,7 +583,7 @@ impl BlockSnapshot { rows: Range, language_aware: bool, text_highlights: Option<&'a TextHighlights>, - suggestion_highlight: Option, + inlay_highlights: Option, ) -> 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::>(); - 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) }); diff --git a/crates/editor/src/display_map/fold_map.rs b/crates/editor/src/display_map/fold_map.rs index 5e4eeca454..0cd3817814 100644 --- a/crates/editor/src/display_map/fold_map.rs +++ b/crates/editor/src/display_map/fold_map.rs @@ -1,7 +1,10 @@ -use super::TextHighlights; +use super::{ + inlay_map::{InlayEdit, InlayOffset, InlayPoint, InlaySnapshot}, + TextHighlights, +}; use crate::{ - multi_buffer::MultiBufferRows, Anchor, AnchorRangeExt, MultiBufferChunks, MultiBufferSnapshot, - ToOffset, + multi_buffer::{MultiBufferChunks, MultiBufferRows}, + Anchor, AnchorRangeExt, MultiBufferSnapshot, ToOffset, }; use collections::BTreeMap; use gpui::{color::Color, fonts::HighlightStyle}; @@ -29,6 +32,10 @@ impl FoldPoint { self.0.row } + pub fn column(self) -> u32 { + self.0.column + } + pub fn row_mut(&mut self) -> &mut u32 { &mut self.0.row } @@ -37,20 +44,20 @@ impl FoldPoint { &mut self.0.column } - pub fn to_buffer_point(self, snapshot: &FoldSnapshot) -> Point { - let mut cursor = snapshot.transforms.cursor::<(FoldPoint, Point)>(); + pub fn to_inlay_point(self, snapshot: &FoldSnapshot) -> InlayPoint { + let mut cursor = snapshot.transforms.cursor::<(FoldPoint, InlayPoint)>(); cursor.seek(&self, Bias::Right, &()); let overshoot = self.0 - cursor.start().0 .0; - cursor.start().1 + overshoot + InlayPoint(cursor.start().1 .0 + overshoot) } - pub fn to_buffer_offset(self, snapshot: &FoldSnapshot) -> usize { - let mut cursor = snapshot.transforms.cursor::<(FoldPoint, Point)>(); + pub fn to_inlay_offset(self, snapshot: &FoldSnapshot) -> InlayOffset { + let mut cursor = snapshot.transforms.cursor::<(FoldPoint, InlayPoint)>(); cursor.seek(&self, Bias::Right, &()); let overshoot = self.0 - cursor.start().0 .0; snapshot - .buffer_snapshot - .point_to_offset(cursor.start().1 + overshoot) + .inlay_snapshot + .to_offset(InlayPoint(cursor.start().1 .0 + overshoot)) } pub fn to_offset(self, snapshot: &FoldSnapshot) -> FoldOffset { @@ -58,17 +65,25 @@ impl FoldPoint { .transforms .cursor::<(FoldPoint, TransformSummary)>(); cursor.seek(&self, Bias::Right, &()); + let inlay_snapshot = &snapshot.inlay_snapshot; + let to_inlay_offset = |buffer_offset: usize| { + let buffer_point = inlay_snapshot.buffer.offset_to_point(buffer_offset); + inlay_snapshot.to_offset(inlay_snapshot.to_inlay_point(buffer_point)) + }; + let mut inlay_offset = to_inlay_offset(cursor.start().1.output.len); let overshoot = self.0 - cursor.start().1.output.lines; - let mut offset = cursor.start().1.output.len; if !overshoot.is_zero() { let transform = cursor.item().expect("display point out of range"); assert!(transform.output_text.is_none()); - let end_buffer_offset = snapshot - .buffer_snapshot - .point_to_offset(cursor.start().1.input.lines + overshoot); - offset += end_buffer_offset - cursor.start().1.input.len; + let end_snapshot_offset = snapshot + .inlay_snapshot + .to_offset(InlayPoint(cursor.start().1.input.lines + overshoot)); + inlay_offset += end_snapshot_offset - to_inlay_offset(cursor.start().1.input.len); } - FoldOffset(offset) + + snapshot + .to_fold_point(inlay_snapshot.to_point(inlay_offset), Bias::Right) + .to_offset(snapshot) } } @@ -87,8 +102,9 @@ impl<'a> FoldMapWriter<'a> { ) -> (FoldSnapshot, Vec) { let mut edits = Vec::new(); let mut folds = Vec::new(); - let buffer = self.0.buffer.lock().clone(); + let snapshot = self.0.inlay_snapshot.lock().clone(); for range in ranges.into_iter() { + let buffer = &snapshot.buffer; let range = range.start.to_offset(&buffer)..range.end.to_offset(&buffer); // Ignore any empty ranges. @@ -103,31 +119,35 @@ impl<'a> FoldMapWriter<'a> { } folds.push(fold); - edits.push(text::Edit { - old: range.clone(), - new: range, + + let inlay_range = + snapshot.to_inlay_offset(range.start)..snapshot.to_inlay_offset(range.end); + edits.push(InlayEdit { + old: inlay_range.clone(), + new: inlay_range, }); } - folds.sort_unstable_by(|a, b| sum_tree::SeekTarget::cmp(a, b, &buffer)); + let buffer = &snapshot.buffer; + folds.sort_unstable_by(|a, b| sum_tree::SeekTarget::cmp(a, b, buffer)); self.0.folds = { let mut new_tree = SumTree::new(); let mut cursor = self.0.folds.cursor::(); for fold in folds { - new_tree.append(cursor.slice(&fold, Bias::Right, &buffer), &buffer); - new_tree.push(fold, &buffer); + new_tree.append(cursor.slice(&fold, Bias::Right, buffer), buffer); + new_tree.push(fold, buffer); } - new_tree.append(cursor.suffix(&buffer), &buffer); + new_tree.append(cursor.suffix(buffer), buffer); new_tree }; - consolidate_buffer_edits(&mut edits); - let edits = self.0.sync(buffer.clone(), edits); + consolidate_inlay_edits(&mut edits); + let edits = self.0.sync(snapshot.clone(), edits); let snapshot = FoldSnapshot { transforms: self.0.transforms.lock().clone(), folds: self.0.folds.clone(), - buffer_snapshot: buffer, + inlay_snapshot: snapshot, version: self.0.version.load(SeqCst), ellipses_color: self.0.ellipses_color, }; @@ -141,20 +161,23 @@ impl<'a> FoldMapWriter<'a> { ) -> (FoldSnapshot, Vec) { let mut edits = Vec::new(); let mut fold_ixs_to_delete = Vec::new(); - let buffer = self.0.buffer.lock().clone(); + let snapshot = self.0.inlay_snapshot.lock().clone(); + let buffer = &snapshot.buffer; for range in ranges.into_iter() { // Remove intersecting folds and add their ranges to edits that are passed to sync. - let mut folds_cursor = intersecting_folds(&buffer, &self.0.folds, range, inclusive); + let mut folds_cursor = intersecting_folds(&snapshot, &self.0.folds, range, inclusive); while let Some(fold) = folds_cursor.item() { - let offset_range = fold.0.start.to_offset(&buffer)..fold.0.end.to_offset(&buffer); + let offset_range = fold.0.start.to_offset(buffer)..fold.0.end.to_offset(buffer); if offset_range.end > offset_range.start { - edits.push(text::Edit { - old: offset_range.clone(), - new: offset_range, + let inlay_range = snapshot.to_inlay_offset(offset_range.start) + ..snapshot.to_inlay_offset(offset_range.end); + edits.push(InlayEdit { + old: inlay_range.clone(), + new: inlay_range, }); } fold_ixs_to_delete.push(*folds_cursor.start()); - folds_cursor.next(&buffer); + folds_cursor.next(buffer); } } @@ -165,19 +188,19 @@ impl<'a> FoldMapWriter<'a> { let mut cursor = self.0.folds.cursor::(); let mut folds = SumTree::new(); for fold_ix in fold_ixs_to_delete { - folds.append(cursor.slice(&fold_ix, Bias::Right, &buffer), &buffer); - cursor.next(&buffer); + folds.append(cursor.slice(&fold_ix, Bias::Right, buffer), buffer); + cursor.next(buffer); } - folds.append(cursor.suffix(&buffer), &buffer); + folds.append(cursor.suffix(buffer), buffer); folds }; - consolidate_buffer_edits(&mut edits); - let edits = self.0.sync(buffer.clone(), edits); + consolidate_inlay_edits(&mut edits); + let edits = self.0.sync(snapshot.clone(), edits); let snapshot = FoldSnapshot { transforms: self.0.transforms.lock().clone(), folds: self.0.folds.clone(), - buffer_snapshot: buffer, + inlay_snapshot: snapshot, version: self.0.version.load(SeqCst), ellipses_color: self.0.ellipses_color, }; @@ -186,7 +209,7 @@ impl<'a> FoldMapWriter<'a> { } pub struct FoldMap { - buffer: Mutex, + inlay_snapshot: Mutex, transforms: Mutex>, folds: SumTree, version: AtomicUsize, @@ -194,15 +217,15 @@ pub struct FoldMap { } impl FoldMap { - pub fn new(buffer: MultiBufferSnapshot) -> (Self, FoldSnapshot) { + pub fn new(inlay_snapshot: InlaySnapshot) -> (Self, FoldSnapshot) { let this = Self { - buffer: Mutex::new(buffer.clone()), + inlay_snapshot: Mutex::new(inlay_snapshot.clone()), folds: Default::default(), transforms: Mutex::new(SumTree::from_item( Transform { summary: TransformSummary { - input: buffer.text_summary(), - output: buffer.text_summary(), + input: inlay_snapshot.text_summary(), + output: inlay_snapshot.text_summary(), }, output_text: None, }, @@ -215,7 +238,7 @@ impl FoldMap { let snapshot = FoldSnapshot { transforms: this.transforms.lock().clone(), folds: this.folds.clone(), - buffer_snapshot: this.buffer.lock().clone(), + inlay_snapshot: inlay_snapshot.clone(), version: this.version.load(SeqCst), ellipses_color: None, }; @@ -224,15 +247,15 @@ impl FoldMap { pub fn read( &self, - buffer: MultiBufferSnapshot, - edits: Vec>, + inlay_snapshot: InlaySnapshot, + edits: Vec, ) -> (FoldSnapshot, Vec) { - let edits = self.sync(buffer, edits); + let edits = self.sync(inlay_snapshot, edits); self.check_invariants(); let snapshot = FoldSnapshot { transforms: self.transforms.lock().clone(), folds: self.folds.clone(), - buffer_snapshot: self.buffer.lock().clone(), + inlay_snapshot: self.inlay_snapshot.lock().clone(), version: self.version.load(SeqCst), ellipses_color: self.ellipses_color, }; @@ -241,10 +264,10 @@ impl FoldMap { pub fn write( &mut self, - buffer: MultiBufferSnapshot, - edits: Vec>, + inlay_snapshot: InlaySnapshot, + edits: Vec, ) -> (FoldMapWriter, FoldSnapshot, Vec) { - let (snapshot, edits) = self.read(buffer, edits); + let (snapshot, edits) = self.read(inlay_snapshot, edits); (FoldMapWriter(self), snapshot, edits) } @@ -259,146 +282,109 @@ impl FoldMap { fn check_invariants(&self) { if cfg!(test) { + let inlay_snapshot = self.inlay_snapshot.lock(); assert_eq!( self.transforms.lock().summary().input.len, - self.buffer.lock().len(), - "transform tree does not match buffer's length" + inlay_snapshot.to_buffer_offset(inlay_snapshot.len()), + "transform tree does not match inlay snapshot's length" ); let mut folds = self.folds.iter().peekable(); while let Some(fold) = folds.next() { if let Some(next_fold) = folds.peek() { - let comparison = fold.0.cmp(&next_fold.0, &self.buffer.lock()); + let comparison = fold.0.cmp(&next_fold.0, &self.inlay_snapshot.lock().buffer); assert!(comparison.is_le()); } } } } - fn sync( - &self, - new_buffer: MultiBufferSnapshot, - buffer_edits: Vec>, - ) -> Vec { - if buffer_edits.is_empty() { - let mut buffer = self.buffer.lock(); - if buffer.edit_count() != new_buffer.edit_count() - || buffer.parse_count() != new_buffer.parse_count() - || buffer.diagnostics_update_count() != new_buffer.diagnostics_update_count() - || buffer.git_diff_update_count() != new_buffer.git_diff_update_count() - || buffer.trailing_excerpt_update_count() - != new_buffer.trailing_excerpt_update_count() - { - self.version.fetch_add(1, SeqCst); - } - *buffer = new_buffer; - Vec::new() - } else { - let mut buffer_edits_iter = buffer_edits.iter().cloned().peekable(); + fn sync(&self, inlay_snapshot: InlaySnapshot, inlay_edits: Vec) -> Vec { + let buffer = &inlay_snapshot.buffer; + let mut snapshot = self.inlay_snapshot.lock(); - let mut new_transforms = SumTree::new(); - let mut transforms = self.transforms.lock(); - let mut cursor = transforms.cursor::(); - cursor.seek(&0, Bias::Right, &()); + let mut new_snapshot = snapshot.clone(); + if new_snapshot.version != inlay_snapshot.version { + new_snapshot.version += 1; + } - while let Some(mut edit) = buffer_edits_iter.next() { - new_transforms.append(cursor.slice(&edit.old.start, Bias::Left, &()), &()); - edit.new.start -= edit.old.start - cursor.start(); - edit.old.start = *cursor.start(); + let mut inlay_edits_iter = inlay_edits.iter().cloned().peekable(); - cursor.seek(&edit.old.end, Bias::Right, &()); - cursor.next(&()); + let mut new_transforms = SumTree::new(); + let mut transforms = self.transforms.lock(); + let mut cursor = transforms.cursor::(); + cursor.seek(&0, Bias::Right, &()); - let mut delta = edit.new.len() as isize - edit.old.len() as isize; - loop { - edit.old.end = *cursor.start(); + while let Some(mut edit) = inlay_edits_iter.next() { + new_transforms.append(cursor.slice(&edit.old.start, Bias::Left, &()), &()); + edit.new.start -= edit.old.start - cursor.start(); + edit.old.start = *cursor.start(); - if let Some(next_edit) = buffer_edits_iter.peek() { - if next_edit.old.start > edit.old.end { - break; - } + cursor.seek(&edit.old.end, Bias::Right, &()); + cursor.next(&()); - let next_edit = buffer_edits_iter.next().unwrap(); - delta += next_edit.new.len() as isize - next_edit.old.len() as isize; + let mut delta = edit.new.len() as isize - edit.old.len() as isize; + loop { + edit.old.end = *cursor.start(); - if next_edit.old.end >= edit.old.end { - edit.old.end = next_edit.old.end; - cursor.seek(&edit.old.end, Bias::Right, &()); - cursor.next(&()); - } - } else { + if let Some(next_edit) = inlay_edits_iter.peek() { + if next_edit.old.start > edit.old.end { break; } + + let next_edit = inlay_edits_iter.next().unwrap(); + delta += next_edit.new.len() as isize - next_edit.old.len() as isize; + + if next_edit.old.end >= edit.old.end { + edit.old.end = next_edit.old.end; + cursor.seek(&edit.old.end, Bias::Right, &()); + cursor.next(&()); + } + } else { + break; } + } - edit.new.end = ((edit.new.start + edit.old.len()) as isize + delta) as usize; + edit.new.end = ((edit.new.start + edit.old.len()) as isize + delta) as usize; - let anchor = new_buffer.anchor_before(edit.new.start); - let mut folds_cursor = self.folds.cursor::(); - folds_cursor.seek(&Fold(anchor..Anchor::max()), Bias::Left, &new_buffer); + let anchor = buffer.anchor_before(inlay_snapshot.to_buffer_offset(edit.new.start)); + let mut folds_cursor = self.folds.cursor::(); + folds_cursor.seek(&Fold(anchor..Anchor::max()), Bias::Left, &buffer); - let mut folds = iter::from_fn({ - let buffer = &new_buffer; - move || { - let item = folds_cursor - .item() - .map(|f| f.0.start.to_offset(buffer)..f.0.end.to_offset(buffer)); - folds_cursor.next(buffer); - item - } - }) - .peekable(); + let mut folds = iter::from_fn({ + move || { + let item = folds_cursor.item().map(|f| { + let fold_buffer_start = f.0.start.to_offset(buffer); + let fold_buffer_end = f.0.end.to_offset(buffer); - while folds.peek().map_or(false, |fold| fold.start < edit.new.end) { - let mut fold = folds.next().unwrap(); - let sum = new_transforms.summary(); - - assert!(fold.start >= sum.input.len); - - while folds - .peek() - .map_or(false, |next_fold| next_fold.start <= fold.end) - { - let next_fold = folds.next().unwrap(); - if next_fold.end > fold.end { - fold.end = next_fold.end; - } - } - - if fold.start > sum.input.len { - let text_summary = new_buffer - .text_summary_for_range::(sum.input.len..fold.start); - new_transforms.push( - Transform { - summary: TransformSummary { - output: text_summary.clone(), - input: text_summary, - }, - output_text: None, - }, - &(), - ); - } - - if fold.end > fold.start { - let output_text = "⋯"; - new_transforms.push( - Transform { - summary: TransformSummary { - output: TextSummary::from(output_text), - input: new_buffer.text_summary_for_range(fold.start..fold.end), - }, - output_text: Some(output_text), - }, - &(), - ); - } + inlay_snapshot.to_inlay_offset(fold_buffer_start) + ..inlay_snapshot.to_inlay_offset(fold_buffer_end) + }); + folds_cursor.next(buffer); + item } + }) + .peekable(); + while folds.peek().map_or(false, |fold| fold.start < edit.new.end) { + let mut fold = folds.next().unwrap(); let sum = new_transforms.summary(); - if sum.input.len < edit.new.end { - let text_summary = new_buffer - .text_summary_for_range::(sum.input.len..edit.new.end); + + assert!(fold.start >= sum.input.len); + + while folds + .peek() + .map_or(false, |next_fold| next_fold.start <= fold.end) + { + let next_fold = folds.next().unwrap(); + if next_fold.end > fold.end { + fold.end = next_fold.end; + } + } + + if fold.start > sum.input.len { + let text_summary = + buffer.text_summary_for_range::(sum.input.len..fold.start); new_transforms.push( Transform { summary: TransformSummary { @@ -410,11 +396,25 @@ impl FoldMap { &(), ); } + + if fold.end > fold.start { + let output_text = "⋯"; + new_transforms.push( + Transform { + summary: TransformSummary { + output: TextSummary::from(output_text), + input: buffer.text_summary_for_range(fold.start..fold.end), + }, + output_text: Some(output_text), + }, + &(), + ); + } } - new_transforms.append(cursor.suffix(&()), &()); - if new_transforms.is_empty() { - let text_summary = new_buffer.text_summary(); + let sum = new_transforms.summary(); + if sum.input.len < edit.new.end { + let text_summary = buffer.text_summary_for_range(sum.input.len..edit.new.end); new_transforms.push( Transform { summary: TransformSummary { @@ -426,59 +426,74 @@ impl FoldMap { &(), ); } + } - drop(cursor); + new_transforms.append(cursor.suffix(&()), &()); + if new_transforms.is_empty() { + let text_summary = inlay_snapshot.text_summary(); + new_transforms.push( + Transform { + summary: TransformSummary { + output: text_summary.clone(), + input: text_summary, + }, + output_text: None, + }, + &(), + ); + } - let mut fold_edits = Vec::with_capacity(buffer_edits.len()); - { - let mut old_transforms = transforms.cursor::<(usize, FoldOffset)>(); - let mut new_transforms = new_transforms.cursor::<(usize, FoldOffset)>(); + drop(cursor); - for mut edit in buffer_edits { - old_transforms.seek(&edit.old.start, Bias::Left, &()); - if old_transforms.item().map_or(false, |t| t.is_fold()) { - edit.old.start = old_transforms.start().0; - } - let old_start = - old_transforms.start().1 .0 + (edit.old.start - old_transforms.start().0); + let mut fold_edits = Vec::with_capacity(inlay_edits.len()); + { + let mut old_transforms = transforms.cursor::<(usize, FoldOffset)>(); + let mut new_transforms = new_transforms.cursor::<(usize, FoldOffset)>(); - old_transforms.seek_forward(&edit.old.end, Bias::Right, &()); - if old_transforms.item().map_or(false, |t| t.is_fold()) { - old_transforms.next(&()); - edit.old.end = old_transforms.start().0; - } - let old_end = - old_transforms.start().1 .0 + (edit.old.end - old_transforms.start().0); - - new_transforms.seek(&edit.new.start, Bias::Left, &()); - if new_transforms.item().map_or(false, |t| t.is_fold()) { - edit.new.start = new_transforms.start().0; - } - let new_start = - new_transforms.start().1 .0 + (edit.new.start - new_transforms.start().0); - - new_transforms.seek_forward(&edit.new.end, Bias::Right, &()); - if new_transforms.item().map_or(false, |t| t.is_fold()) { - new_transforms.next(&()); - edit.new.end = new_transforms.start().0; - } - let new_end = - new_transforms.start().1 .0 + (edit.new.end - new_transforms.start().0); - - fold_edits.push(FoldEdit { - old: FoldOffset(old_start)..FoldOffset(old_end), - new: FoldOffset(new_start)..FoldOffset(new_end), - }); + for mut edit in inlay_edits { + old_transforms.seek(&edit.old.start, Bias::Left, &()); + if old_transforms.item().map_or(false, |t| t.is_fold()) { + edit.old.start = old_transforms.start().0; } + let old_start = + old_transforms.start().1 .0 + (edit.old.start - old_transforms.start().0); - consolidate_fold_edits(&mut fold_edits); + old_transforms.seek_forward(&edit.old.end, Bias::Right, &()); + if old_transforms.item().map_or(false, |t| t.is_fold()) { + old_transforms.next(&()); + edit.old.end = old_transforms.start().0; + } + let old_end = + old_transforms.start().1 .0 + (edit.old.end - old_transforms.start().0); + + new_transforms.seek(&edit.new.start, Bias::Left, &()); + if new_transforms.item().map_or(false, |t| t.is_fold()) { + edit.new.start = new_transforms.start().0; + } + let new_start = + new_transforms.start().1 .0 + (edit.new.start - new_transforms.start().0); + + new_transforms.seek_forward(&edit.new.end, Bias::Right, &()); + if new_transforms.item().map_or(false, |t| t.is_fold()) { + new_transforms.next(&()); + edit.new.end = new_transforms.start().0; + } + let new_end = + new_transforms.start().1 .0 + (edit.new.end - new_transforms.start().0); + + fold_edits.push(FoldEdit { + old: FoldOffset(old_start)..FoldOffset(old_end), + new: FoldOffset(new_start)..FoldOffset(new_end), + }); } - *transforms = new_transforms; - *self.buffer.lock() = new_buffer; - self.version.fetch_add(1, SeqCst); - fold_edits + consolidate_fold_edits(&mut fold_edits); } + + *transforms = new_transforms; + *self.inlay_snapshot.lock() = inlay_snapshot; + self.version.fetch_add(1, SeqCst); + fold_edits } } @@ -486,26 +501,22 @@ impl FoldMap { pub struct FoldSnapshot { transforms: SumTree, folds: SumTree, - buffer_snapshot: MultiBufferSnapshot, + pub inlay_snapshot: InlaySnapshot, pub version: usize, pub ellipses_color: Option, } impl FoldSnapshot { - pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot { - &self.buffer_snapshot - } - #[cfg(test)] pub fn text(&self) -> String { - self.chunks(FoldOffset(0)..self.len(), false, None) + self.chunks(FoldOffset(0)..self.len(), false, None, None) .map(|c| c.text) .collect() } #[cfg(test)] pub fn fold_count(&self) -> usize { - self.folds.items(&self.buffer_snapshot).len() + self.folds.items(&self.inlay_snapshot.buffer).len() } pub fn text_summary(&self) -> TextSummary { @@ -529,7 +540,8 @@ impl FoldSnapshot { let buffer_start = cursor.start().1 + start_in_transform; let buffer_end = cursor.start().1 + end_in_transform; summary = self - .buffer_snapshot + .inlay_snapshot + .buffer .text_summary_for_range(buffer_start..buffer_end); } } @@ -547,7 +559,8 @@ impl FoldSnapshot { let buffer_start = cursor.start().1; let buffer_end = cursor.start().1 + end_in_transform; summary += self - .buffer_snapshot + .inlay_snapshot + .buffer .text_summary_for_range::(buffer_start..buffer_end); } } @@ -556,8 +569,8 @@ impl FoldSnapshot { summary } - pub fn to_fold_point(&self, point: Point, bias: Bias) -> FoldPoint { - let mut cursor = self.transforms.cursor::<(Point, FoldPoint)>(); + pub fn to_fold_point(&self, point: InlayPoint, bias: Bias) -> FoldPoint { + let mut cursor = self.transforms.cursor::<(InlayPoint, FoldPoint)>(); cursor.seek(&point, Bias::Right, &()); if cursor.item().map_or(false, |t| t.is_fold()) { if bias == Bias::Left || point == cursor.start().0 { @@ -566,7 +579,7 @@ impl FoldSnapshot { cursor.end(&()).1 } } else { - let overshoot = point - cursor.start().0; + let overshoot = InlayPoint(point.0 - cursor.start().0 .0); FoldPoint(cmp::min( cursor.start().1 .0 + overshoot, cursor.end(&()).1 .0, @@ -599,7 +612,7 @@ impl FoldSnapshot { let overshoot = fold_point.0 - cursor.start().0 .0; let buffer_point = cursor.start().1 + overshoot; - let input_buffer_rows = self.buffer_snapshot.buffer_rows(buffer_point.row); + let input_buffer_rows = self.inlay_snapshot.buffer.buffer_rows(buffer_point.row); FoldBufferRows { fold_point, @@ -621,10 +634,10 @@ impl FoldSnapshot { where T: ToOffset, { - let mut folds = intersecting_folds(&self.buffer_snapshot, &self.folds, range, false); + let mut folds = intersecting_folds(&self.inlay_snapshot, &self.folds, range, false); iter::from_fn(move || { let item = folds.item().map(|f| &f.0); - folds.next(&self.buffer_snapshot); + folds.next(&self.inlay_snapshot.buffer); item }) } @@ -633,7 +646,7 @@ impl FoldSnapshot { where T: ToOffset, { - let offset = offset.to_offset(&self.buffer_snapshot); + let offset = offset.to_offset(&self.inlay_snapshot.buffer); let mut cursor = self.transforms.cursor::(); cursor.seek(&offset, Bias::Right, &()); cursor.item().map_or(false, |t| t.output_text.is_some()) @@ -641,6 +654,7 @@ impl FoldSnapshot { pub fn is_line_folded(&self, buffer_row: u32) -> bool { let mut cursor = self.transforms.cursor::(); + // TODO kb is this right? cursor.seek(&Point::new(buffer_row, 0), Bias::Right, &()); while let Some(transform) = cursor.item() { if transform.output_text.is_some() { @@ -660,6 +674,7 @@ impl FoldSnapshot { range: Range, language_aware: bool, text_highlights: Option<&'a TextHighlights>, + inlay_highlights: Option, ) -> FoldChunks<'a> { let mut highlight_endpoints = Vec::new(); let mut transform_cursor = self.transforms.cursor::<(FoldOffset, usize)>(); @@ -681,12 +696,13 @@ impl FoldSnapshot { while transform_cursor.start().0 < range.end { if !transform_cursor.item().unwrap().is_fold() { let transform_start = self - .buffer_snapshot + .inlay_snapshot + .buffer .anchor_after(cmp::max(buffer_start, transform_cursor.start().1)); let transform_end = { let overshoot = range.end.0 - transform_cursor.start().0 .0; - self.buffer_snapshot.anchor_before(cmp::min( + self.inlay_snapshot.buffer.anchor_before(cmp::min( transform_cursor.end(&()).1, transform_cursor.start().1 + overshoot, )) @@ -697,7 +713,8 @@ impl FoldSnapshot { let ranges = &highlights.1; let start_ix = match ranges.binary_search_by(|probe| { - let cmp = probe.end.cmp(&transform_start, self.buffer_snapshot()); + let cmp = + probe.end.cmp(&transform_start, &self.inlay_snapshot.buffer); if cmp.is_gt() { Ordering::Greater } else { @@ -709,20 +726,20 @@ impl FoldSnapshot { for range in &ranges[start_ix..] { if range .start - .cmp(&transform_end, &self.buffer_snapshot) + .cmp(&transform_end, &self.inlay_snapshot.buffer) .is_ge() { break; } highlight_endpoints.push(HighlightEndpoint { - offset: range.start.to_offset(&self.buffer_snapshot), + offset: range.start.to_offset(&self.inlay_snapshot.buffer), is_start: true, tag: *tag, style, }); highlight_endpoints.push(HighlightEndpoint { - offset: range.end.to_offset(&self.buffer_snapshot), + offset: range.end.to_offset(&self.inlay_snapshot.buffer), is_start: false, tag: *tag, style, @@ -741,9 +758,10 @@ impl FoldSnapshot { FoldChunks { transform_cursor, buffer_chunks: self - .buffer_snapshot + .inlay_snapshot + .buffer .chunks(buffer_start..buffer_end, language_aware), - buffer_chunk: None, + inlay_chunk: None, buffer_offset: buffer_start, output_offset: range.start.0, max_output_offset: range.end.0, @@ -753,6 +771,11 @@ impl FoldSnapshot { } } + pub fn chars_at(&self, start: FoldPoint) -> impl '_ + Iterator { + self.chunks(start.to_offset(self)..self.len(), false, None, None) + .flat_map(|chunk| chunk.text.chars()) + } + #[cfg(test)] pub fn clip_offset(&self, offset: FoldOffset, bias: Bias) -> FoldOffset { let mut cursor = self.transforms.cursor::<(FoldOffset, usize)>(); @@ -768,7 +791,8 @@ impl FoldSnapshot { } else { let overshoot = offset.0 - transform_start; let buffer_offset = cursor.start().1 + overshoot; - let clipped_buffer_offset = self.buffer_snapshot.clip_offset(buffer_offset, bias); + let clipped_buffer_offset = + self.inlay_snapshot.buffer.clip_offset(buffer_offset, bias); FoldOffset( (offset.0 as isize + (clipped_buffer_offset as isize - buffer_offset as isize)) as usize, @@ -794,7 +818,7 @@ impl FoldSnapshot { let overshoot = point.0 - transform_start; let buffer_position = cursor.start().1 + overshoot; let clipped_buffer_position = - self.buffer_snapshot.clip_point(buffer_position, bias); + self.inlay_snapshot.buffer.clip_point(buffer_position, bias); FoldPoint(cursor.start().0 .0 + (clipped_buffer_position - cursor.start().1)) } } else { @@ -804,7 +828,7 @@ impl FoldSnapshot { } fn intersecting_folds<'a, T>( - buffer: &'a MultiBufferSnapshot, + inlay_snapshot: &'a InlaySnapshot, folds: &'a SumTree, range: Range, inclusive: bool, @@ -812,6 +836,7 @@ fn intersecting_folds<'a, T>( where T: ToOffset, { + let buffer = &inlay_snapshot.buffer; let start = buffer.anchor_before(range.start.to_offset(buffer)); let end = buffer.anchor_after(range.end.to_offset(buffer)); let mut cursor = folds.filter::<_, usize>(move |summary| { @@ -828,7 +853,7 @@ where cursor } -fn consolidate_buffer_edits(edits: &mut Vec>) { +fn consolidate_inlay_edits(edits: &mut Vec) { edits.sort_unstable_by(|a, b| { a.old .start @@ -956,7 +981,7 @@ impl Default for FoldSummary { impl sum_tree::Summary for FoldSummary { type Context = MultiBufferSnapshot; - fn add_summary(&mut self, other: &Self, buffer: &MultiBufferSnapshot) { + fn add_summary(&mut self, other: &Self, buffer: &Self::Context) { if other.min_start.cmp(&self.min_start, buffer) == Ordering::Less { self.min_start = other.min_start.clone(); } @@ -1034,7 +1059,7 @@ impl<'a> Iterator for FoldBufferRows<'a> { pub struct FoldChunks<'a> { transform_cursor: Cursor<'a, Transform, (FoldOffset, usize)>, buffer_chunks: MultiBufferChunks<'a>, - buffer_chunk: Option<(usize, Chunk<'a>)>, + inlay_chunk: Option<(usize, Chunk<'a>)>, buffer_offset: usize, output_offset: usize, max_output_offset: usize, @@ -1056,7 +1081,7 @@ impl<'a> Iterator for FoldChunks<'a> { // If we're in a fold, then return the fold's display text and // advance the transform and buffer cursors to the end of the fold. if let Some(output_text) = transform.output_text { - self.buffer_chunk.take(); + self.inlay_chunk.take(); self.buffer_offset += transform.summary.input.len; self.buffer_chunks.seek(self.buffer_offset); @@ -1093,13 +1118,13 @@ impl<'a> Iterator for FoldChunks<'a> { } // Retrieve a chunk from the current location in the buffer. - if self.buffer_chunk.is_none() { + if self.inlay_chunk.is_none() { let chunk_offset = self.buffer_chunks.offset(); - self.buffer_chunk = self.buffer_chunks.next().map(|chunk| (chunk_offset, chunk)); + self.inlay_chunk = self.buffer_chunks.next().map(|chunk| (chunk_offset, chunk)); } // Otherwise, take a chunk from the buffer's text. - if let Some((buffer_chunk_start, mut chunk)) = self.buffer_chunk { + if let Some((buffer_chunk_start, mut chunk)) = self.inlay_chunk { let buffer_chunk_end = buffer_chunk_start + chunk.text.len(); let transform_end = self.transform_cursor.end(&()).1; let chunk_end = buffer_chunk_end @@ -1120,7 +1145,7 @@ impl<'a> Iterator for FoldChunks<'a> { if chunk_end == transform_end { self.transform_cursor.next(&()); } else if chunk_end == buffer_chunk_end { - self.buffer_chunk.take(); + self.inlay_chunk.take(); } self.buffer_offset = chunk_end; @@ -1163,11 +1188,15 @@ impl FoldOffset { .transforms .cursor::<(FoldOffset, TransformSummary)>(); cursor.seek(&self, Bias::Right, &()); + // TODO kb seems wrong to use buffer points? let overshoot = if cursor.item().map_or(true, |t| t.is_fold()) { Point::new(0, (self.0 - cursor.start().0 .0) as u32) } else { let buffer_offset = cursor.start().1.input.len + self.0 - cursor.start().0 .0; - let buffer_point = snapshot.buffer_snapshot.offset_to_point(buffer_offset); + let buffer_point = snapshot + .inlay_snapshot + .buffer + .offset_to_point(buffer_offset); buffer_point - cursor.start().1.input.lines }; FoldPoint(cursor.start().1.output.lines + overshoot) @@ -1202,6 +1231,18 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for FoldOffset { } } +impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayPoint { + fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) { + self.0 += &summary.input.lines; + } +} + +impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayOffset { + fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) { + self.0 += &summary.input.len; + } +} + impl<'a> sum_tree::Dimension<'a, TransformSummary> for Point { fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) { *self += &summary.input.lines; @@ -1219,7 +1260,7 @@ pub type FoldEdit = Edit; #[cfg(test)] mod tests { use super::*; - use crate::{MultiBuffer, ToPoint}; + use crate::{display_map::inlay_map::InlayMap, MultiBuffer, ToPoint}; use collections::HashSet; use rand::prelude::*; use settings::SettingsStore; @@ -1235,9 +1276,10 @@ mod tests { let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx); let subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); let buffer_snapshot = buffer.read(cx).snapshot(cx); - let mut map = FoldMap::new(buffer_snapshot.clone()).0; + let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); + let mut map = FoldMap::new(inlay_snapshot.clone()).0; - let (mut writer, _, _) = map.write(buffer_snapshot, vec![]); + let (mut writer, _, _) = map.write(inlay_snapshot, vec![]); let (snapshot2, edits) = writer.fold(vec![ Point::new(0, 2)..Point::new(2, 2), Point::new(2, 4)..Point::new(4, 1), @@ -1268,7 +1310,10 @@ mod tests { ); buffer.snapshot(cx) }); - let (snapshot3, edits) = map.read(buffer_snapshot, subscription.consume().into_inner()); + + let (inlay_snapshot, inlay_edits) = + inlay_map.sync(buffer_snapshot, subscription.consume().into_inner()); + let (snapshot3, edits) = map.read(inlay_snapshot, inlay_edits); assert_eq!(snapshot3.text(), "123a⋯c123c⋯eeeee"); assert_eq!( edits, @@ -1288,17 +1333,19 @@ mod tests { buffer.edit([(Point::new(2, 6)..Point::new(4, 3), "456")], None, cx); buffer.snapshot(cx) }); - let (snapshot4, _) = map.read(buffer_snapshot.clone(), subscription.consume().into_inner()); + let (inlay_snapshot, inlay_edits) = + inlay_map.sync(buffer_snapshot, subscription.consume().into_inner()); + let (snapshot4, _) = map.read(inlay_snapshot.clone(), inlay_edits); assert_eq!(snapshot4.text(), "123a⋯c123456eee"); - let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); + let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]); writer.unfold(Some(Point::new(0, 4)..Point::new(0, 4)), false); - let (snapshot5, _) = map.read(buffer_snapshot.clone(), vec![]); + let (snapshot5, _) = map.read(inlay_snapshot.clone(), vec![]); assert_eq!(snapshot5.text(), "123a⋯c123456eee"); - let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); + let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]); writer.unfold(Some(Point::new(0, 4)..Point::new(0, 4)), true); - let (snapshot6, _) = map.read(buffer_snapshot, vec![]); + let (snapshot6, _) = map.read(inlay_snapshot, vec![]); assert_eq!(snapshot6.text(), "123aaaaa\nbbbbbb\nccc123456eee"); } @@ -1308,35 +1355,36 @@ mod tests { let buffer = MultiBuffer::build_simple("abcdefghijkl", cx); let subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); let buffer_snapshot = buffer.read(cx).snapshot(cx); + let (inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); { - let mut map = FoldMap::new(buffer_snapshot.clone()).0; + let mut map = FoldMap::new(inlay_snapshot.clone()).0; - let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); + let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]); writer.fold(vec![5..8]); - let (snapshot, _) = map.read(buffer_snapshot.clone(), vec![]); + let (snapshot, _) = map.read(inlay_snapshot.clone(), vec![]); assert_eq!(snapshot.text(), "abcde⋯ijkl"); // Create an fold adjacent to the start of the first fold. - let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); + let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]); writer.fold(vec![0..1, 2..5]); - let (snapshot, _) = map.read(buffer_snapshot.clone(), vec![]); + let (snapshot, _) = map.read(inlay_snapshot.clone(), vec![]); assert_eq!(snapshot.text(), "⋯b⋯ijkl"); // Create an fold adjacent to the end of the first fold. - let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); + let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]); writer.fold(vec![11..11, 8..10]); - let (snapshot, _) = map.read(buffer_snapshot.clone(), vec![]); + let (snapshot, _) = map.read(inlay_snapshot.clone(), vec![]); assert_eq!(snapshot.text(), "⋯b⋯kl"); } { - let mut map = FoldMap::new(buffer_snapshot.clone()).0; + let mut map = FoldMap::new(inlay_snapshot.clone()).0; // Create two adjacent folds. - let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); + let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]); writer.fold(vec![0..2, 2..5]); - let (snapshot, _) = map.read(buffer_snapshot, vec![]); + let (snapshot, _) = map.read(inlay_snapshot, vec![]); assert_eq!(snapshot.text(), "⋯fghijkl"); // Edit within one of the folds. @@ -1344,7 +1392,9 @@ mod tests { buffer.edit([(0..1, "12345")], None, cx); buffer.snapshot(cx) }); - let (snapshot, _) = map.read(buffer_snapshot, subscription.consume().into_inner()); + let (inlay_snapshot, inlay_edits) = + inlay_map.sync(buffer_snapshot, subscription.consume().into_inner()); + let (snapshot, _) = map.read(inlay_snapshot, inlay_edits); assert_eq!(snapshot.text(), "12345⋯fghijkl"); } } @@ -1353,15 +1403,16 @@ mod tests { fn test_overlapping_folds(cx: &mut gpui::AppContext) { let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx); let buffer_snapshot = buffer.read(cx).snapshot(cx); - let mut map = FoldMap::new(buffer_snapshot.clone()).0; - let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); + let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot); + let mut map = FoldMap::new(inlay_snapshot.clone()).0; + let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]); writer.fold(vec![ Point::new(0, 2)..Point::new(2, 2), Point::new(0, 4)..Point::new(1, 0), Point::new(1, 2)..Point::new(3, 2), Point::new(3, 1)..Point::new(4, 1), ]); - let (snapshot, _) = map.read(buffer_snapshot, vec![]); + let (snapshot, _) = map.read(inlay_snapshot, vec![]); assert_eq!(snapshot.text(), "aa⋯eeeee"); } @@ -1371,21 +1422,24 @@ mod tests { let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx); let subscription = buffer.update(cx, |buffer, _| buffer.subscribe()); let buffer_snapshot = buffer.read(cx).snapshot(cx); - let mut map = FoldMap::new(buffer_snapshot.clone()).0; + let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); + let mut map = FoldMap::new(inlay_snapshot.clone()).0; - let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); + let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]); writer.fold(vec![ Point::new(0, 2)..Point::new(2, 2), Point::new(3, 1)..Point::new(4, 1), ]); - let (snapshot, _) = map.read(buffer_snapshot, vec![]); + let (snapshot, _) = map.read(inlay_snapshot.clone(), vec![]); assert_eq!(snapshot.text(), "aa⋯cccc\nd⋯eeeee"); let buffer_snapshot = buffer.update(cx, |buffer, cx| { buffer.edit([(Point::new(2, 2)..Point::new(3, 1), "")], None, cx); buffer.snapshot(cx) }); - let (snapshot, _) = map.read(buffer_snapshot, subscription.consume().into_inner()); + let (inlay_snapshot, inlay_edits) = + inlay_map.sync(buffer_snapshot, subscription.consume().into_inner()); + let (snapshot, _) = map.read(inlay_snapshot, inlay_edits); assert_eq!(snapshot.text(), "aa⋯eeeee"); } @@ -1393,16 +1447,17 @@ mod tests { fn test_folds_in_range(cx: &mut gpui::AppContext) { let buffer = MultiBuffer::build_simple(&sample_text(5, 6, 'a'), cx); let buffer_snapshot = buffer.read(cx).snapshot(cx); - let mut map = FoldMap::new(buffer_snapshot.clone()).0; + let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); + let mut map = FoldMap::new(inlay_snapshot.clone()).0; - let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); + let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]); writer.fold(vec![ Point::new(0, 2)..Point::new(2, 2), Point::new(0, 4)..Point::new(1, 0), Point::new(1, 2)..Point::new(3, 2), Point::new(3, 1)..Point::new(4, 1), ]); - let (snapshot, _) = map.read(buffer_snapshot.clone(), vec![]); + let (snapshot, _) = map.read(inlay_snapshot.clone(), vec![]); let fold_ranges = snapshot .folds_in_range(Point::new(1, 0)..Point::new(1, 3)) .map(|fold| fold.start.to_point(&buffer_snapshot)..fold.end.to_point(&buffer_snapshot)) @@ -1431,9 +1486,10 @@ mod tests { MultiBuffer::build_random(&mut rng, cx) }; let mut buffer_snapshot = buffer.read(cx).snapshot(cx); - let mut map = FoldMap::new(buffer_snapshot.clone()).0; + let (mut inlay_map, inlay_snapshot) = InlayMap::new(buffer_snapshot.clone()); + let mut map = FoldMap::new(inlay_snapshot.clone()).0; - let (mut initial_snapshot, _) = map.read(buffer_snapshot.clone(), vec![]); + let (mut initial_snapshot, _) = map.read(inlay_snapshot.clone(), vec![]); let mut snapshot_edits = Vec::new(); let mut highlights = TreeMap::default(); @@ -1473,7 +1529,8 @@ mod tests { }), }; - let (snapshot, edits) = map.read(buffer_snapshot.clone(), buffer_edits); + let (inlay_snapshot, inlay_edits) = inlay_map.sync(buffer_snapshot, buffer_edits); + let (snapshot, edits) = map.read(inlay_snapshot, inlay_edits); snapshot_edits.push((snapshot.clone(), edits)); let mut expected_text: String = buffer_snapshot.text().to_string(); @@ -1526,19 +1583,20 @@ mod tests { let mut fold_offset = FoldOffset(0); let mut char_column = 0; for c in expected_text.chars() { - let buffer_point = fold_point.to_buffer_point(&snapshot); - let buffer_offset = buffer_point.to_offset(&buffer_snapshot); + let inlay_point = fold_point.to_inlay_point(&snapshot); + let buffer_point = inlay_snapshot.to_buffer_point(inlay_point); + let buffer_offset = buffer_snapshot.point_to_offset(buffer_point); assert_eq!( - snapshot.to_fold_point(buffer_point, Right), + snapshot.to_fold_point(inlay_point, Right), fold_point, "{:?} -> fold point", buffer_point, ); assert_eq!( - fold_point.to_buffer_offset(&snapshot), + inlay_snapshot.to_buffer_offset(inlay_snapshot.to_offset(inlay_point)), buffer_offset, - "fold_point.to_buffer_offset({:?})", - fold_point, + "inlay_snapshot.to_buffer_offset(inlay_snapshot.to_offset(({:?}))", + inlay_point, ); assert_eq!( fold_point.to_offset(&snapshot), @@ -1579,7 +1637,7 @@ mod tests { let text = &expected_text[start.0..end.0]; assert_eq!( snapshot - .chunks(start..end, false, Some(&highlights)) + .chunks(start..end, false, Some(&highlights), None) .map(|c| c.text) .collect::(), text, @@ -1677,15 +1735,16 @@ mod tests { let buffer = MultiBuffer::build_simple(&text, cx); let buffer_snapshot = buffer.read(cx).snapshot(cx); - let mut map = FoldMap::new(buffer_snapshot.clone()).0; + let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot); + let mut map = FoldMap::new(inlay_snapshot.clone()).0; - let (mut writer, _, _) = map.write(buffer_snapshot.clone(), vec![]); + let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]); writer.fold(vec![ Point::new(0, 2)..Point::new(2, 2), Point::new(3, 1)..Point::new(4, 1), ]); - let (snapshot, _) = map.read(buffer_snapshot, vec![]); + let (snapshot, _) = map.read(inlay_snapshot, vec![]); assert_eq!(snapshot.text(), "aa⋯cccc\nd⋯eeeee\nffffff\n"); assert_eq!( snapshot.buffer_rows(0).collect::>(), @@ -1700,13 +1759,14 @@ mod tests { impl FoldMap { fn merged_fold_ranges(&self) -> Vec> { - let buffer = self.buffer.lock().clone(); - let mut folds = self.folds.items(&buffer); + let inlay_snapshot = self.inlay_snapshot.lock().clone(); + let buffer = &inlay_snapshot.buffer; + let mut folds = self.folds.items(buffer); // Ensure sorting doesn't change how folds get merged and displayed. - folds.sort_by(|a, b| a.0.cmp(&b.0, &buffer)); + folds.sort_by(|a, b| a.0.cmp(&b.0, buffer)); let mut fold_ranges = folds .iter() - .map(|fold| fold.0.start.to_offset(&buffer)..fold.0.end.to_offset(&buffer)) + .map(|fold| fold.0.start.to_offset(buffer)..fold.0.end.to_offset(buffer)) .peekable(); let mut merged_ranges = Vec::new(); @@ -1735,7 +1795,8 @@ mod tests { let mut snapshot_edits = Vec::new(); match rng.gen_range(0..=100) { 0..=39 if !self.folds.is_empty() => { - let buffer = self.buffer.lock().clone(); + let inlay_snapshot = self.inlay_snapshot.lock().clone(); + let buffer = &inlay_snapshot.buffer; let mut to_unfold = Vec::new(); for _ in 0..rng.gen_range(1..=3) { let end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right); @@ -1743,13 +1804,14 @@ mod tests { to_unfold.push(start..end); } log::info!("unfolding {:?}", to_unfold); - let (mut writer, snapshot, edits) = self.write(buffer, vec![]); + let (mut writer, snapshot, edits) = self.write(inlay_snapshot, vec![]); snapshot_edits.push((snapshot, edits)); let (snapshot, edits) = writer.fold(to_unfold); snapshot_edits.push((snapshot, edits)); } _ => { - let buffer = self.buffer.lock().clone(); + let inlay_snapshot = self.inlay_snapshot.lock().clone(); + let buffer = &inlay_snapshot.buffer; let mut to_fold = Vec::new(); for _ in 0..rng.gen_range(1..=2) { let end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right); @@ -1757,7 +1819,7 @@ mod tests { to_fold.push(start..end); } log::info!("folding {:?}", to_fold); - let (mut writer, snapshot, edits) = self.write(buffer, vec![]); + let (mut writer, snapshot, edits) = self.write(inlay_snapshot, vec![]); snapshot_edits.push((snapshot, edits)); let (snapshot, edits) = writer.fold(to_fold); snapshot_edits.push((snapshot, edits)); diff --git a/crates/editor/src/display_map/inlay_map.rs b/crates/editor/src/display_map/inlay_map.rs index c3ccaf161e..b9e7119fc9 100644 --- a/crates/editor/src/display_map/inlay_map.rs +++ b/crates/editor/src/display_map/inlay_map.rs @@ -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, + buffer: Mutex, + transforms: SumTree, inlays_by_id: HashMap, inlays: Vec, + version: usize, } #[derive(Clone)] pub struct InlaySnapshot { - // TODO kb merge these two together - pub fold_snapshot: FoldSnapshot, + pub buffer: MultiBufferSnapshot, transforms: SumTree, 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>, + transforms: Cursor<'a, Transform, (InlayOffset, usize)>, + buffer_chunks: MultiBufferChunks<'a>, + buffer_chunk: Option>, inlay_chunks: Option>, 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 { 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, + buffer_snapshot: MultiBufferSnapshot, + buffer_edits: Vec>, ) -> (InlaySnapshot, Vec) { - 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>( @@ -399,20 +394,15 @@ impl InlayMap { to_remove: Vec, to_insert: Vec<(InlayId, InlayProperties)>, ) -> (InlaySnapshot, Vec) { - 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) { 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 { - 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) -> 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::(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, language_aware: bool, - text_highlights: Option<&'a TextHighlights>, inlay_highlight_style: Option, ) -> 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, 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::>(); - 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::(); 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]; diff --git a/crates/editor/src/display_map/suggestion_map.rs b/crates/editor/src/display_map/suggestion_map.rs deleted file mode 100644 index b23f172bca..0000000000 --- a/crates/editor/src/display_map/suggestion_map.rs +++ /dev/null @@ -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; - -#[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 { - pub position: T, - pub text: Rope, -} - -pub struct SuggestionMap(Mutex); - -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( - &self, - new_suggestion: Option>, - fold_snapshot: FoldSnapshot, - fold_edits: Vec, - ) -> ( - SuggestionSnapshot, - Vec, - Option>, - ) - 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, - ) -> (SuggestionSnapshot, Vec) { - 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>, - 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) -> 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::(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 { - 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, - language_aware: bool, - text_highlights: Option<&'a TextHighlights>, - suggestion_highlight: Option, - ) -> 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>, - suggestion_chunks: Option>, - suffix_chunks: Option>, - highlight_style: Option, -} - -impl<'a> Iterator for SuggestionChunks<'a> { - type Item = Chunk<'a>; - - fn next(&mut self) -> Option { - 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; - - fn next(&mut self) -> Option { - 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::(); - 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::>(); - 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::>(), - &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::(); - 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) { - 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::() - .as_str() - .into(), - }) - }; - - log::info!("replacing suggestion with {:?}", new_suggestion); - let (snapshot, edits, _) = - self.replace(new_suggestion, fold_snapshot, Default::default()); - (snapshot, edits) - } - } -} diff --git a/crates/editor/src/display_map/tab_map.rs b/crates/editor/src/display_map/tab_map.rs index 0deb0f888f..9157caace4 100644 --- a/crates/editor/src/display_map/tab_map.rs +++ b/crates/editor/src/display_map/tab_map.rs @@ -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); 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, + fold_snapshot: FoldSnapshot, + mut fold_edits: Vec, tab_size: NonZeroU32, ) -> (TabSnapshot, Vec) { 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) -> 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, language_aware: bool, text_highlights: Option<&'a TextHighlights>, - suggestion_highlight: Option, + inlay_highlights: Option, ) -> 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, 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 { 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()); diff --git a/crates/editor/src/display_map/wrap_map.rs b/crates/editor/src/display_map/wrap_map.rs index 2e2fa449bd..5197a2e0de 100644 --- a/crates/editor/src/display_map/wrap_map.rs +++ b/crates/editor/src/display_map/wrap_map.rs @@ -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, output_row: u32, soft_wrapped: bool, @@ -575,7 +575,7 @@ impl WrapSnapshot { rows: Range, language_aware: bool, text_highlights: Option<&'a TextHighlights>, - suggestion_highlight: Option, + inlay_highlights: Option, ) -> 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') { diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 33bf89e452..10c86ceb29 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -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::{