1862 lines · 68.3 KB · Rust
RawDownload
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: &'static 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 1862.