use super::{ inlay_map::{InlayBufferRows, InlayChunks, InlayEdit, InlayOffset, InlayPoint, InlaySnapshot}, Highlights,};use gpui::{ElementId, HighlightStyle, Hsla};use language::{Chunk, Edit, Point, TextSummary};use multi_buffer::{Anchor, AnchorRangeExt, MultiBufferRow, MultiBufferSnapshot, ToOffset};use std::{ cmp::{self, Ordering}, iter, ops::{Add, AddAssign, Deref, DerefMut, Range, Sub},};use sum_tree::{Bias, Cursor, FilterCursor, SumTree};use util::post_inc; #[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.output_text.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>>, ) -> (FoldSnapshot, Vec<FoldEdit>) { let mut edits = Vec::new(); let mut folds = Vec::new(); let snapshot = self.0.snapshot.inlay_snapshot.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. 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, }); 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 }; consolidate_inlay_edits(&mut 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 }; consolidate_inlay_edits(&mut 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, ellipses_color: Option<Hsla>, 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(), }, output_text: None, }, &(), ), inlay_snapshot: inlay_snapshot.clone(), version: 0, ellipses_color: None, }, ellipses_color: None, 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) } pub fn set_ellipses_color(&mut self, color: Hsla) -> bool { if self.ellipses_color == Some(color) { false } else { self.ellipses_color = Some(color); true } } 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 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::new(); let mut cursor = self.snapshot.transforms.cursor::<InlayOffset>(); cursor.seek(&InlayOffset(0), Bias::Right, &()); 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(); 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(|f| { let buffer_start = f.range.start.to_offset(&inlay_snapshot.buffer); let buffer_end = f.range.end.to_offset(&inlay_snapshot.buffer); 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| fold.start < edit.new.end) { let mut fold = folds.next().unwrap(); let sum = new_transforms.summary(); assert!(fold.start.0 >= 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.0 > sum.input.len { let text_summary = inlay_snapshot .text_summary_for_range(InlayOffset(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: inlay_snapshot .text_summary_for_range(fold.start..fold.end), }, output_text: Some(output_text), }, &(), ); } } 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); new_transforms.push( Transform { summary: TransformSummary { output: text_summary.clone(), input: text_summary, }, output_text: None, }, &(), ); } } 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, }, &(), ); } 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()) { 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).0; fold_edits.push(FoldEdit { old: FoldOffset(old_start)..FoldOffset(old_end), new: FoldOffset(new_start)..FoldOffset(new_end), }); } consolidate_fold_edits(&mut fold_edits); } self.snapshot.transforms = new_transforms; self.snapshot.inlay_snapshot = inlay_snapshot; self.snapshot.version += 1; fold_edits } }} #[derive(Clone)]pub struct FoldSnapshot { transforms: SumTree<Transform>, folds: SumTree<Fold>, pub inlay_snapshot: InlaySnapshot, pub version: usize, pub ellipses_color: Option<Hsla>,} impl FoldSnapshot { #[cfg(test)] pub fn text(&self) -> String { self.chunks(FoldOffset(0)..self.len(), false, Highlights::default()) .map(|c| c.text) .collect() } #[cfg(test)] pub fn fold_count(&self) -> usize { self.folds.items(&self.inlay_snapshot.buffer).len() } pub fn text_summary_for_range(&self, range: Range<FoldPoint>) -> TextSummary { let mut summary = TextSummary::default(); Lines 1–500 of 1726. Load more
use super::{ inlay_map::{InlayBufferRows, InlayChunks, InlayEdit, InlayOffset, InlayPoint, InlaySnapshot}, Highlights, }; use gpui::{ElementId, HighlightStyle, Hsla}; use language::{Chunk, Edit, Point, TextSummary}; use multi_buffer::{Anchor, AnchorRangeExt, MultiBufferRow, MultiBufferSnapshot, ToOffset}; use std::{ cmp::{self, Ordering}, iter, ops::{Add, AddAssign, Deref, DerefMut, Range, Sub}, }; use sum_tree::{Bias, Cursor, FilterCursor, SumTree}; use util::post_inc; #[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.output_text.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>>, ) -> (FoldSnapshot, Vec<FoldEdit>) { let mut edits = Vec::new(); let mut folds = Vec::new(); let snapshot = self.0.snapshot.inlay_snapshot.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. 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, }); 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 }; consolidate_inlay_edits(&mut 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 }; consolidate_inlay_edits(&mut 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, ellipses_color: Option<Hsla>, 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(), }, output_text: None, }, &(), ), inlay_snapshot: inlay_snapshot.clone(), version: 0, ellipses_color: None, }, ellipses_color: None, 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) } pub fn set_ellipses_color(&mut self, color: Hsla) -> bool { if self.ellipses_color == Some(color) { false } else { self.ellipses_color = Some(color); true } } 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 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::new(); let mut cursor = self.snapshot.transforms.cursor::<InlayOffset>(); cursor.seek(&InlayOffset(0), Bias::Right, &()); 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(); 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(|f| { let buffer_start = f.range.start.to_offset(&inlay_snapshot.buffer); let buffer_end = f.range.end.to_offset(&inlay_snapshot.buffer); 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| fold.start < edit.new.end) { let mut fold = folds.next().unwrap(); let sum = new_transforms.summary(); assert!(fold.start.0 >= 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.0 > sum.input.len { let text_summary = inlay_snapshot .text_summary_for_range(InlayOffset(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: inlay_snapshot .text_summary_for_range(fold.start..fold.end), }, output_text: Some(output_text), }, &(), ); } } 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); new_transforms.push( Transform { summary: TransformSummary { output: text_summary.clone(), input: text_summary, }, output_text: None, }, &(), ); } } 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, }, &(), ); } 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()) { 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).0; fold_edits.push(FoldEdit { old: FoldOffset(old_start)..FoldOffset(old_end), new: FoldOffset(new_start)..FoldOffset(new_end), }); } consolidate_fold_edits(&mut fold_edits); } self.snapshot.transforms = new_transforms; self.snapshot.inlay_snapshot = inlay_snapshot; self.snapshot.version += 1; fold_edits } } } #[derive(Clone)] pub struct FoldSnapshot { transforms: SumTree<Transform>, folds: SumTree<Fold>, pub inlay_snapshot: InlaySnapshot, pub version: usize, pub ellipses_color: Option<Hsla>, } impl FoldSnapshot { #[cfg(test)] pub fn text(&self) -> String { self.chunks(FoldOffset(0)..self.len(), false, Highlights::default()) .map(|c| c.text) .collect() } #[cfg(test)] pub fn fold_count(&self) -> usize { self.folds.items(&self.inlay_snapshot.buffer).len() } pub fn text_summary_for_range(&self, range: Range<FoldPoint>) -> TextSummary { let mut summary = TextSummary::default();