use super::{ inlay_map::{InlayBufferRows, InlayChunks, InlayEdit, InlayOffset, InlayPoint, InlaySnapshot}, Highlights,};use gpui::{AnyElement, ElementId, WindowContext};use language::{Chunk, ChunkRenderer, Edit, Point, TextSummary};use multi_buffer::{Anchor, AnchorRangeExt, MultiBufferRow, MultiBufferSnapshot, ToOffset};use std::{ cmp::{self, Ordering}, fmt, iter, ops::{Add, AddAssign, Deref, DerefMut, Range, Sub}, sync::Arc,};use sum_tree::{Bias, Cursor, FilterCursor, SumTree, Summary};use util::post_inc; #[derive(Clone)]pub struct FoldPlaceholder { /// Creates an element to represent this fold's placeholder. pub render: Arc<dyn Send + Sync + Fn(FoldId, Range<Anchor>, &mut WindowContext) -> AnyElement>, /// If true, the element is constrained to the shaped width of an ellipsis. pub constrain_width: bool, /// If true, merges the fold with an adjacent one. pub merge_adjacent: bool,} impl FoldPlaceholder { #[cfg(any(test, feature = "test-support"))] pub fn test() -> Self { use gpui::IntoElement; Self { render: Arc::new(|_id, _range, _cx| gpui::Empty.into_any_element()), constrain_width: true, merge_adjacent: true, } }} impl fmt::Debug for FoldPlaceholder { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FoldPlaceholder") .field("constrain_width", &self.constrain_width) .finish() }} impl Eq for FoldPlaceholder {} impl PartialEq for FoldPlaceholder { fn eq(&self, other: &Self) -> bool { Arc::ptr_eq(&self.render, &other.render) && self.constrain_width == other.constrain_width }} #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]pub struct FoldPoint(pub Point); impl FoldPoint { 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 } pub fn row_mut(&mut self) -> &mut u32 { &mut self.0.row } #[cfg(test)] pub fn column_mut(&mut self) -> &mut u32 { &mut self.0.column } 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; InlayPoint(cursor.start().1 .0 + overshoot) } pub fn to_offset(self, snapshot: &FoldSnapshot) -> FoldOffset { let mut cursor = snapshot .transforms .cursor::<(FoldPoint, TransformSummary)>(); cursor.seek(&self, Bias::Right, &()); 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.placeholder.is_none()); let end_inlay_offset = snapshot .inlay_snapshot .to_offset(InlayPoint(cursor.start().1.input.lines + overshoot)); offset += end_inlay_offset.0 - cursor.start().1.input.len; } FoldOffset(offset) }} impl<'a> sum_tree::Dimension<'a, TransformSummary> for FoldPoint { fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) { self.0 += &summary.output.lines; }} pub(crate) struct FoldMapWriter<'a>(&'a mut FoldMap); impl<'a> FoldMapWriter<'a> { pub(crate) fn fold<T: ToOffset>( &mut self, ranges: impl IntoIterator<Item = (Range<T>, FoldPlaceholder)>, ) -> (FoldSnapshot, Vec<FoldEdit>) { let mut edits = Vec::new(); let mut folds = Vec::new(); let snapshot = self.0.snapshot.inlay_snapshot.clone(); for (range, fold_text) in ranges.into_iter() { let buffer = &snapshot.buffer; let range = range.start.to_offset(buffer)..range.end.to_offset(buffer); // Ignore any empty ranges. if range.start == range.end { continue; } // For now, ignore any ranges that span an excerpt boundary. let fold_range = FoldRange(buffer.anchor_after(range.start)..buffer.anchor_before(range.end)); if fold_range.0.start.excerpt_id != fold_range.0.end.excerpt_id { continue; } folds.push(Fold { id: FoldId(post_inc(&mut self.0.next_fold_id.0)), range: fold_range, placeholder: fold_text, }); 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, }); } let buffer = &snapshot.buffer; folds.sort_unstable_by(|a, b| sum_tree::SeekTarget::cmp(&a.range, &b.range, buffer)); self.0.snapshot.folds = { let mut new_tree = SumTree::new(); let mut cursor = self.0.snapshot.folds.cursor::<FoldRange>(); for fold in folds { new_tree.append(cursor.slice(&fold.range, Bias::Right, buffer), buffer); new_tree.push(fold, buffer); } new_tree.append(cursor.suffix(buffer), buffer); new_tree }; let edits = consolidate_inlay_edits(edits); let edits = self.0.sync(snapshot.clone(), edits); (self.0.snapshot.clone(), edits) } pub(crate) fn unfold<T: ToOffset>( &mut self, ranges: impl IntoIterator<Item = Range<T>>, inclusive: bool, ) -> (FoldSnapshot, Vec<FoldEdit>) { let mut edits = Vec::new(); let mut fold_ixs_to_delete = Vec::new(); let snapshot = self.0.snapshot.inlay_snapshot.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(&snapshot, &self.0.snapshot.folds, range, inclusive); while let Some(fold) = folds_cursor.item() { let offset_range = fold.range.start.to_offset(buffer)..fold.range.end.to_offset(buffer); if offset_range.end > offset_range.start { 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); } } fold_ixs_to_delete.sort_unstable(); fold_ixs_to_delete.dedup(); self.0.snapshot.folds = { let mut cursor = self.0.snapshot.folds.cursor::<usize>(); 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.suffix(buffer), buffer); folds }; let edits = consolidate_inlay_edits(edits); let edits = self.0.sync(snapshot.clone(), edits); (self.0.snapshot.clone(), edits) }} /// Decides where the fold indicators should be; also tracks parts of a source file that are currently folded.////// See the [`display_map` module documentation](crate::display_map) for more information.pub(crate) struct FoldMap { snapshot: FoldSnapshot, next_fold_id: FoldId,} impl FoldMap { pub(crate) fn new(inlay_snapshot: InlaySnapshot) -> (Self, FoldSnapshot) { let this = Self { snapshot: FoldSnapshot { folds: Default::default(), transforms: SumTree::from_item( Transform { summary: TransformSummary { input: inlay_snapshot.text_summary(), output: inlay_snapshot.text_summary(), }, placeholder: None, }, &(), ), inlay_snapshot: inlay_snapshot.clone(), version: 0, }, next_fold_id: FoldId::default(), }; let snapshot = this.snapshot.clone(); (this, snapshot) } pub fn read( &mut self, inlay_snapshot: InlaySnapshot, edits: Vec<InlayEdit>, ) -> (FoldSnapshot, Vec<FoldEdit>) { let edits = self.sync(inlay_snapshot, edits); self.check_invariants(); (self.snapshot.clone(), edits) } pub fn write( &mut self, inlay_snapshot: InlaySnapshot, edits: Vec<InlayEdit>, ) -> (FoldMapWriter, FoldSnapshot, Vec<FoldEdit>) { let (snapshot, edits) = self.read(inlay_snapshot, edits); (FoldMapWriter(self), snapshot, edits) } fn check_invariants(&self) { if cfg!(test) { assert_eq!( self.snapshot.transforms.summary().input.len, self.snapshot.inlay_snapshot.len().0, "transform tree does not match inlay snapshot's length" ); let mut prev_transform_isomorphic = false; for transform in self.snapshot.transforms.iter() { if !transform.is_fold() && prev_transform_isomorphic { panic!( "found adjacent isomorphic transforms: {:?}", self.snapshot.transforms.items(&()) ); } prev_transform_isomorphic = !transform.is_fold(); } let mut folds = self.snapshot.folds.iter().peekable(); while let Some(fold) = folds.next() { if let Some(next_fold) = folds.peek() { let comparison = fold .range .cmp(&next_fold.range, &self.snapshot.inlay_snapshot.buffer); assert!(comparison.is_le()); } } } } fn sync( &mut self, inlay_snapshot: InlaySnapshot, inlay_edits: Vec<InlayEdit>, ) -> Vec<FoldEdit> { if inlay_edits.is_empty() { if self.snapshot.inlay_snapshot.version != inlay_snapshot.version { self.snapshot.version += 1; } self.snapshot.inlay_snapshot = inlay_snapshot; Vec::new() } else { let mut inlay_edits_iter = inlay_edits.iter().cloned().peekable(); let mut new_transforms = SumTree::<Transform>::new(); let mut cursor = self.snapshot.transforms.cursor::<InlayOffset>(); cursor.seek(&InlayOffset(0), Bias::Right, &()); while let Some(mut edit) = inlay_edits_iter.next() { if let Some(item) = cursor.item() { if !item.is_fold() { new_transforms.update_last( |transform| { if !transform.is_fold() { transform.summary.add_summary(&item.summary, &()); cursor.next(&()); } }, &(), ); } } new_transforms.append(cursor.slice(&edit.old.start, Bias::Left, &()), &()); edit.new.start -= edit.old.start - *cursor.start(); edit.old.start = *cursor.start(); cursor.seek(&edit.old.end, Bias::Right, &()); cursor.next(&()); let mut delta = edit.new_len().0 as isize - edit.old_len().0 as isize; loop { edit.old.end = *cursor.start(); 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().0 as isize - next_edit.old_len().0 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 = InlayOffset(((edit.new.start + edit.old_len()).0 as isize + delta) as usize); let anchor = inlay_snapshot .buffer .anchor_before(inlay_snapshot.to_buffer_offset(edit.new.start)); let mut folds_cursor = self.snapshot.folds.cursor::<FoldRange>(); folds_cursor.seek( &FoldRange(anchor..Anchor::max()), Bias::Left, &inlay_snapshot.buffer, ); let mut folds = iter::from_fn({ let inlay_snapshot = &inlay_snapshot; move || { let item = folds_cursor.item().map(|fold| { let buffer_start = fold.range.start.to_offset(&inlay_snapshot.buffer); let buffer_end = fold.range.end.to_offset(&inlay_snapshot.buffer); ( fold.clone(), inlay_snapshot.to_inlay_offset(buffer_start) ..inlay_snapshot.to_inlay_offset(buffer_end), ) }); folds_cursor.next(&inlay_snapshot.buffer); item } }) .peekable(); while folds .peek() .map_or(false, |(_, fold_range)| fold_range.start < edit.new.end) { let (fold, mut fold_range) = folds.next().unwrap(); let sum = new_transforms.summary(); assert!(fold_range.start.0 >= sum.input.len); while folds.peek().map_or(false, |(next_fold, next_fold_range)| { next_fold_range.start < fold_range.end || (next_fold_range.start == fold_range.end && fold.placeholder.merge_adjacent && next_fold.placeholder.merge_adjacent) }) { let (_, next_fold_range) = folds.next().unwrap(); if next_fold_range.end > fold_range.end { fold_range.end = next_fold_range.end; } } if fold_range.start.0 > sum.input.len { let text_summary = inlay_snapshot .text_summary_for_range(InlayOffset(sum.input.len)..fold_range.start); push_isomorphic(&mut new_transforms, text_summary); } if fold_range.end > fold_range.start { const ELLIPSIS: &str = "⋯"; let fold_id = fold.id; new_transforms.push( Transform { summary: TransformSummary { output: TextSummary::from(ELLIPSIS), input: inlay_snapshot .text_summary_for_range(fold_range.start..fold_range.end), }, placeholder: Some(TransformPlaceholder { text: ELLIPSIS, renderer: ChunkRenderer { render: Arc::new(move |cx| { (fold.placeholder.render)( fold_id, fold.range.0.clone(), cx, ) }), constrain_width: fold.placeholder.constrain_width, }, }), }, &(), ); } } let sum = new_transforms.summary(); if sum.input.len < edit.new.end.0 { let text_summary = inlay_snapshot .text_summary_for_range(InlayOffset(sum.input.len)..edit.new.end); push_isomorphic(&mut new_transforms, text_summary); } } new_transforms.append(cursor.suffix(&()), &()); if new_transforms.is_empty() { let text_summary = inlay_snapshot.text_summary(); push_isomorphic(&mut new_transforms, text_summary); } drop(cursor); let mut fold_edits = Vec::with_capacity(inlay_edits.len()); { let mut old_transforms = self .snapshot .transforms .cursor::<(InlayOffset, FoldOffset)>(); let mut new_transforms = new_transforms.cursor::<(InlayOffset, FoldOffset)>(); 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).0; 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).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).0; new_transforms.seek_forward(&edit.new.end, Bias::Right, &()); if new_transforms.item().map_or(false, |t| t.is_fold()) {Lines 1–500 of 1860. Load more
use super::{ inlay_map::{InlayBufferRows, InlayChunks, InlayEdit, InlayOffset, InlayPoint, InlaySnapshot}, Highlights, }; use gpui::{AnyElement, ElementId, WindowContext}; use language::{Chunk, ChunkRenderer, Edit, Point, TextSummary}; use multi_buffer::{Anchor, AnchorRangeExt, MultiBufferRow, MultiBufferSnapshot, ToOffset}; use std::{ cmp::{self, Ordering}, fmt, iter, ops::{Add, AddAssign, Deref, DerefMut, Range, Sub}, sync::Arc, }; use sum_tree::{Bias, Cursor, FilterCursor, SumTree, Summary}; use util::post_inc; #[derive(Clone)] pub struct FoldPlaceholder { /// Creates an element to represent this fold's placeholder. pub render: Arc<dyn Send + Sync + Fn(FoldId, Range<Anchor>, &mut WindowContext) -> AnyElement>, /// If true, the element is constrained to the shaped width of an ellipsis. pub constrain_width: bool, /// If true, merges the fold with an adjacent one. pub merge_adjacent: bool, } impl FoldPlaceholder { #[cfg(any(test, feature = "test-support"))] pub fn test() -> Self { use gpui::IntoElement; Self { render: Arc::new(|_id, _range, _cx| gpui::Empty.into_any_element()), constrain_width: true, merge_adjacent: true, } } } impl fmt::Debug for FoldPlaceholder { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("FoldPlaceholder") .field("constrain_width", &self.constrain_width) .finish() } } impl Eq for FoldPlaceholder {} impl PartialEq for FoldPlaceholder { fn eq(&self, other: &Self) -> bool { Arc::ptr_eq(&self.render, &other.render) && self.constrain_width == other.constrain_width } } #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)] pub struct FoldPoint(pub Point); impl FoldPoint { 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 } pub fn row_mut(&mut self) -> &mut u32 { &mut self.0.row } #[cfg(test)] pub fn column_mut(&mut self) -> &mut u32 { &mut self.0.column } 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; InlayPoint(cursor.start().1 .0 + overshoot) } pub fn to_offset(self, snapshot: &FoldSnapshot) -> FoldOffset { let mut cursor = snapshot .transforms .cursor::<(FoldPoint, TransformSummary)>(); cursor.seek(&self, Bias::Right, &()); 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.placeholder.is_none()); let end_inlay_offset = snapshot .inlay_snapshot .to_offset(InlayPoint(cursor.start().1.input.lines + overshoot)); offset += end_inlay_offset.0 - cursor.start().1.input.len; } FoldOffset(offset) } } impl<'a> sum_tree::Dimension<'a, TransformSummary> for FoldPoint { fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) { self.0 += &summary.output.lines; } } pub(crate) struct FoldMapWriter<'a>(&'a mut FoldMap); impl<'a> FoldMapWriter<'a> { pub(crate) fn fold<T: ToOffset>( &mut self, ranges: impl IntoIterator<Item = (Range<T>, FoldPlaceholder)>, ) -> (FoldSnapshot, Vec<FoldEdit>) { let mut edits = Vec::new(); let mut folds = Vec::new(); let snapshot = self.0.snapshot.inlay_snapshot.clone(); for (range, fold_text) in ranges.into_iter() { let buffer = &snapshot.buffer; let range = range.start.to_offset(buffer)..range.end.to_offset(buffer); // Ignore any empty ranges. if range.start == range.end { continue; } // For now, ignore any ranges that span an excerpt boundary. let fold_range = FoldRange(buffer.anchor_after(range.start)..buffer.anchor_before(range.end)); if fold_range.0.start.excerpt_id != fold_range.0.end.excerpt_id { continue; } folds.push(Fold { id: FoldId(post_inc(&mut self.0.next_fold_id.0)), range: fold_range, placeholder: fold_text, }); 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, }); } let buffer = &snapshot.buffer; folds.sort_unstable_by(|a, b| sum_tree::SeekTarget::cmp(&a.range, &b.range, buffer)); self.0.snapshot.folds = { let mut new_tree = SumTree::new(); let mut cursor = self.0.snapshot.folds.cursor::<FoldRange>(); for fold in folds { new_tree.append(cursor.slice(&fold.range, Bias::Right, buffer), buffer); new_tree.push(fold, buffer); } new_tree.append(cursor.suffix(buffer), buffer); new_tree }; let edits = consolidate_inlay_edits(edits); let edits = self.0.sync(snapshot.clone(), edits); (self.0.snapshot.clone(), edits) } pub(crate) fn unfold<T: ToOffset>( &mut self, ranges: impl IntoIterator<Item = Range<T>>, inclusive: bool, ) -> (FoldSnapshot, Vec<FoldEdit>) { let mut edits = Vec::new(); let mut fold_ixs_to_delete = Vec::new(); let snapshot = self.0.snapshot.inlay_snapshot.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(&snapshot, &self.0.snapshot.folds, range, inclusive); while let Some(fold) = folds_cursor.item() { let offset_range = fold.range.start.to_offset(buffer)..fold.range.end.to_offset(buffer); if offset_range.end > offset_range.start { 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); } } fold_ixs_to_delete.sort_unstable(); fold_ixs_to_delete.dedup(); self.0.snapshot.folds = { let mut cursor = self.0.snapshot.folds.cursor::<usize>(); 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.suffix(buffer), buffer); folds }; let edits = consolidate_inlay_edits(edits); let edits = self.0.sync(snapshot.clone(), edits); (self.0.snapshot.clone(), edits) } } /// Decides where the fold indicators should be; also tracks parts of a source file that are currently folded. /// /// See the [`display_map` module documentation](crate::display_map) for more information. pub(crate) struct FoldMap { snapshot: FoldSnapshot, next_fold_id: FoldId, } impl FoldMap { pub(crate) fn new(inlay_snapshot: InlaySnapshot) -> (Self, FoldSnapshot) { let this = Self { snapshot: FoldSnapshot { folds: Default::default(), transforms: SumTree::from_item( Transform { summary: TransformSummary { input: inlay_snapshot.text_summary(), output: inlay_snapshot.text_summary(), }, placeholder: None, }, &(), ), inlay_snapshot: inlay_snapshot.clone(), version: 0, }, next_fold_id: FoldId::default(), }; let snapshot = this.snapshot.clone(); (this, snapshot) } pub fn read( &mut self, inlay_snapshot: InlaySnapshot, edits: Vec<InlayEdit>, ) -> (FoldSnapshot, Vec<FoldEdit>) { let edits = self.sync(inlay_snapshot, edits); self.check_invariants(); (self.snapshot.clone(), edits) } pub fn write( &mut self, inlay_snapshot: InlaySnapshot, edits: Vec<InlayEdit>, ) -> (FoldMapWriter, FoldSnapshot, Vec<FoldEdit>) { let (snapshot, edits) = self.read(inlay_snapshot, edits); (FoldMapWriter(self), snapshot, edits) } fn check_invariants(&self) { if cfg!(test) { assert_eq!( self.snapshot.transforms.summary().input.len, self.snapshot.inlay_snapshot.len().0, "transform tree does not match inlay snapshot's length" ); let mut prev_transform_isomorphic = false; for transform in self.snapshot.transforms.iter() { if !transform.is_fold() && prev_transform_isomorphic { panic!( "found adjacent isomorphic transforms: {:?}", self.snapshot.transforms.items(&()) ); } prev_transform_isomorphic = !transform.is_fold(); } let mut folds = self.snapshot.folds.iter().peekable(); while let Some(fold) = folds.next() { if let Some(next_fold) = folds.peek() { let comparison = fold .range .cmp(&next_fold.range, &self.snapshot.inlay_snapshot.buffer); assert!(comparison.is_le()); } } } } fn sync( &mut self, inlay_snapshot: InlaySnapshot, inlay_edits: Vec<InlayEdit>, ) -> Vec<FoldEdit> { if inlay_edits.is_empty() { if self.snapshot.inlay_snapshot.version != inlay_snapshot.version { self.snapshot.version += 1; } self.snapshot.inlay_snapshot = inlay_snapshot; Vec::new() } else { let mut inlay_edits_iter = inlay_edits.iter().cloned().peekable(); let mut new_transforms = SumTree::<Transform>::new(); let mut cursor = self.snapshot.transforms.cursor::<InlayOffset>(); cursor.seek(&InlayOffset(0), Bias::Right, &()); while let Some(mut edit) = inlay_edits_iter.next() { if let Some(item) = cursor.item() { if !item.is_fold() { new_transforms.update_last( |transform| { if !transform.is_fold() { transform.summary.add_summary(&item.summary, &()); cursor.next(&()); } }, &(), ); } } new_transforms.append(cursor.slice(&edit.old.start, Bias::Left, &()), &()); edit.new.start -= edit.old.start - *cursor.start(); edit.old.start = *cursor.start(); cursor.seek(&edit.old.end, Bias::Right, &()); cursor.next(&()); let mut delta = edit.new_len().0 as isize - edit.old_len().0 as isize; loop { edit.old.end = *cursor.start(); 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().0 as isize - next_edit.old_len().0 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 = InlayOffset(((edit.new.start + edit.old_len()).0 as isize + delta) as usize); let anchor = inlay_snapshot .buffer .anchor_before(inlay_snapshot.to_buffer_offset(edit.new.start)); let mut folds_cursor = self.snapshot.folds.cursor::<FoldRange>(); folds_cursor.seek( &FoldRange(anchor..Anchor::max()), Bias::Left, &inlay_snapshot.buffer, ); let mut folds = iter::from_fn({ let inlay_snapshot = &inlay_snapshot; move || { let item = folds_cursor.item().map(|fold| { let buffer_start = fold.range.start.to_offset(&inlay_snapshot.buffer); let buffer_end = fold.range.end.to_offset(&inlay_snapshot.buffer); ( fold.clone(), inlay_snapshot.to_inlay_offset(buffer_start) ..inlay_snapshot.to_inlay_offset(buffer_end), ) }); folds_cursor.next(&inlay_snapshot.buffer); item } }) .peekable(); while folds .peek() .map_or(false, |(_, fold_range)| fold_range.start < edit.new.end) { let (fold, mut fold_range) = folds.next().unwrap(); let sum = new_transforms.summary(); assert!(fold_range.start.0 >= sum.input.len); while folds.peek().map_or(false, |(next_fold, next_fold_range)| { next_fold_range.start < fold_range.end || (next_fold_range.start == fold_range.end && fold.placeholder.merge_adjacent && next_fold.placeholder.merge_adjacent) }) { let (_, next_fold_range) = folds.next().unwrap(); if next_fold_range.end > fold_range.end { fold_range.end = next_fold_range.end; } } if fold_range.start.0 > sum.input.len { let text_summary = inlay_snapshot .text_summary_for_range(InlayOffset(sum.input.len)..fold_range.start); push_isomorphic(&mut new_transforms, text_summary); } if fold_range.end > fold_range.start { const ELLIPSIS: &str = "⋯"; let fold_id = fold.id; new_transforms.push( Transform { summary: TransformSummary { output: TextSummary::from(ELLIPSIS), input: inlay_snapshot .text_summary_for_range(fold_range.start..fold_range.end), }, placeholder: Some(TransformPlaceholder { text: ELLIPSIS, renderer: ChunkRenderer { render: Arc::new(move |cx| { (fold.placeholder.render)( fold_id, fold.range.0.clone(), cx, ) }), constrain_width: fold.placeholder.constrain_width, }, }), }, &(), ); } } let sum = new_transforms.summary(); if sum.input.len < edit.new.end.0 { let text_summary = inlay_snapshot .text_summary_for_range(InlayOffset(sum.input.len)..edit.new.end); push_isomorphic(&mut new_transforms, text_summary); } } new_transforms.append(cursor.suffix(&()), &()); if new_transforms.is_empty() { let text_summary = inlay_snapshot.text_summary(); push_isomorphic(&mut new_transforms, text_summary); } drop(cursor); let mut fold_edits = Vec::with_capacity(inlay_edits.len()); { let mut old_transforms = self .snapshot .transforms .cursor::<(InlayOffset, FoldOffset)>(); let mut new_transforms = new_transforms.cursor::<(InlayOffset, FoldOffset)>(); 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).0; 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).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).0; new_transforms.seek_forward(&edit.new.end, Bias::Right, &()); if new_transforms.item().map_or(false, |t| t.is_fold()) {