1726 lines · 62.3 KB · Rust
RawDownload
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.