1795 lines · 64.5 KB · Rust
RawDownload
use crate::{HighlightStyles, InlayId};use collections::BTreeSet;use language::{Chunk, Edit, Point, TextSummary};use multi_buffer::{Anchor, MultiBufferRow, MultiBufferRows, MultiBufferSnapshot, ToOffset};use std::{    cmp,    ops::{Add, AddAssign, Range, Sub, SubAssign},};use sum_tree::{Bias, Cursor, SumTree};use text::{Patch, Rope}; use super::{custom_highlights::CustomHighlightsChunks, Highlights}; /// Decides where the [`Inlay`]s should be displayed.////// See the [`display_map` module documentation](crate::display_map) for more information.pub struct InlayMap {    snapshot: InlaySnapshot,    inlays: Vec<Inlay>,} #[derive(Clone)]pub struct InlaySnapshot {    pub buffer: MultiBufferSnapshot,    transforms: SumTree<Transform>,    pub version: usize,} #[derive(Clone, Debug)]enum Transform {    Isomorphic(TextSummary),    Inlay(Inlay),} #[derive(Debug, Clone)]pub struct Inlay {    pub(crate) id: InlayId,    pub position: Anchor,    pub text: text::Rope,} impl Inlay {    pub fn hint(id: usize, position: Anchor, hint: &project::InlayHint) -> Self {        let mut text = hint.text();        if hint.padding_right && !text.ends_with(' ') {            text.push(' ');        }        if hint.padding_left && !text.starts_with(' ') {            text.insert(0, ' ');        }        Self {            id: InlayId::Hint(id),            position,            text: text.into(),        }    }     pub fn inline_completion<T: Into<Rope>>(id: usize, position: Anchor, text: T) -> Self {        Self {            id: InlayId::InlineCompletion(id),            position,            text: text.into(),        }    }} impl sum_tree::Item for Transform {    type Summary = TransformSummary;     fn summary(&self, _cx: &()) -> Self::Summary {        match self {            Transform::Isomorphic(summary) => TransformSummary {                input: summary.clone(),                output: summary.clone(),            },            Transform::Inlay(inlay) => TransformSummary {                input: TextSummary::default(),                output: inlay.text.summary(),            },        }    }} #[derive(Clone, Debug, Default)]struct TransformSummary {    input: TextSummary,    output: TextSummary,} impl sum_tree::Summary for TransformSummary {    type Context = ();     fn zero(_cx: &()) -> Self {        Default::default()    }     fn add_summary(&mut self, other: &Self, _: &()) {        self.input += &other.input;        self.output += &other.output;    }} pub type InlayEdit = Edit<InlayOffset>; #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]pub struct InlayOffset(pub usize); impl Add for InlayOffset {    type Output = Self;     fn add(self, rhs: Self) -> Self::Output {        Self(self.0 + rhs.0)    }} impl Sub for InlayOffset {    type Output = Self;     fn sub(self, rhs: Self) -> Self::Output {        Self(self.0 - rhs.0)    }} impl AddAssign for InlayOffset {    fn add_assign(&mut self, rhs: Self) {        self.0 += rhs.0;    }} impl SubAssign for InlayOffset {    fn sub_assign(&mut self, rhs: Self) {        self.0 -= rhs.0;    }} impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayOffset {    fn zero(_cx: &()) -> Self {        Default::default()    }     fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {        self.0 += &summary.output.len;    }} #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]pub struct InlayPoint(pub Point); impl Add for InlayPoint {    type Output = Self;     fn add(self, rhs: Self) -> Self::Output {        Self(self.0 + rhs.0)    }} impl Sub for InlayPoint {    type Output = Self;     fn sub(self, rhs: Self) -> Self::Output {        Self(self.0 - rhs.0)    }} impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayPoint {    fn zero(_cx: &()) -> Self {        Default::default()    }     fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {        self.0 += &summary.output.lines;    }} impl<'a> sum_tree::Dimension<'a, TransformSummary> for usize {    fn zero(_cx: &()) -> Self {        Default::default()    }     fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {        *self += &summary.input.len;    }} impl<'a> sum_tree::Dimension<'a, TransformSummary> for Point {    fn zero(_cx: &()) -> Self {        Default::default()    }     fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {        *self += &summary.input.lines;    }} #[derive(Clone)]pub struct InlayBufferRows<'a> {    transforms: Cursor<'a, Transform, (InlayPoint, Point)>,    buffer_rows: MultiBufferRows<'a>,    inlay_row: u32,    max_buffer_row: MultiBufferRow,} pub struct InlayChunks<'a> {    transforms: Cursor<'a, Transform, (InlayOffset, usize)>,    buffer_chunks: CustomHighlightsChunks<'a>,    buffer_chunk: Option<Chunk<'a>>,    inlay_chunks: Option<text::Chunks<'a>>,    inlay_chunk: Option<&'a str>,    output_offset: InlayOffset,    max_output_offset: InlayOffset,    highlight_styles: HighlightStyles,    highlights: Highlights<'a>,    snapshot: &'a InlaySnapshot,} impl<'a> InlayChunks<'a> {    pub fn seek(&mut self, new_range: Range<InlayOffset>) {        self.transforms.seek(&new_range.start, Bias::Right, &());         let buffer_range = self.snapshot.to_buffer_offset(new_range.start)            ..self.snapshot.to_buffer_offset(new_range.end);        self.buffer_chunks.seek(buffer_range);        self.inlay_chunks = None;        self.buffer_chunk = None;        self.output_offset = new_range.start;        self.max_output_offset = new_range.end;    }     pub fn offset(&self) -> InlayOffset {        self.output_offset    }} impl<'a> Iterator for InlayChunks<'a> {    type Item = Chunk<'a>;     fn next(&mut self) -> Option<Self::Item> {        if self.output_offset == self.max_output_offset {            return None;        }         let chunk = match self.transforms.item()? {            Transform::Isomorphic(_) => {                let chunk = self                    .buffer_chunk                    .get_or_insert_with(|| self.buffer_chunks.next().unwrap());                if chunk.text.is_empty() {                    *chunk = self.buffer_chunks.next().unwrap();                }                 let (prefix, suffix) = chunk.text.split_at(                    chunk                        .text                        .len()                        .min(self.transforms.end(&()).0 .0 - self.output_offset.0),                );                 chunk.text = suffix;                self.output_offset.0 += prefix.len();                Chunk {                    text: prefix,                    ..chunk.clone()                }            }            Transform::Inlay(inlay) => {                let mut inlay_style_and_highlight = None;                if let Some(inlay_highlights) = self.highlights.inlay_highlights {                    for (_, inlay_id_to_data) in inlay_highlights.iter() {                        let style_and_highlight = inlay_id_to_data.get(&inlay.id);                        if style_and_highlight.is_some() {                            inlay_style_and_highlight = style_and_highlight;                            break;                        }                    }                }                 let mut highlight_style = match inlay.id {                    InlayId::InlineCompletion(_) => {                        self.highlight_styles.inline_completion.map(|s| {                            if inlay.text.chars().all(|c| c.is_whitespace()) {                                s.whitespace                            } else {                                s.insertion                            }                        })                    }                    InlayId::Hint(_) => self.highlight_styles.inlay_hint,                };                let next_inlay_highlight_endpoint;                let offset_in_inlay = self.output_offset - self.transforms.start().0;                if let Some((style, highlight)) = inlay_style_and_highlight {                    let range = &highlight.range;                    if offset_in_inlay.0 < range.start {                        next_inlay_highlight_endpoint = range.start - offset_in_inlay.0;                    } else if offset_in_inlay.0 >= range.end {                        next_inlay_highlight_endpoint = usize::MAX;                    } else {                        next_inlay_highlight_endpoint = range.end - offset_in_inlay.0;                        highlight_style                            .get_or_insert_with(Default::default)                            .highlight(*style);                    }                } else {                    next_inlay_highlight_endpoint = usize::MAX;                }                 let inlay_chunks = self.inlay_chunks.get_or_insert_with(|| {                    let start = offset_in_inlay;                    let end = cmp::min(self.max_output_offset, self.transforms.end(&()).0)                        - self.transforms.start().0;                    inlay.text.chunks_in_range(start.0..end.0)                });                let inlay_chunk = self                    .inlay_chunk                    .get_or_insert_with(|| inlay_chunks.next().unwrap());                let (chunk, remainder) =                    inlay_chunk.split_at(inlay_chunk.len().min(next_inlay_highlight_endpoint));                *inlay_chunk = remainder;                if inlay_chunk.is_empty() {                    self.inlay_chunk = None;                }                 self.output_offset.0 += chunk.len();                 Chunk {                    text: chunk,                    highlight_style,                    ..Default::default()                }            }        };         if self.output_offset == self.transforms.end(&()).0 {            self.inlay_chunks = None;            self.transforms.next(&());        }         Some(chunk)    }} impl<'a> InlayBufferRows<'a> {    pub fn seek(&mut self, row: u32) {        let inlay_point = InlayPoint::new(row, 0);        self.transforms.seek(&inlay_point, Bias::Left, &());         let mut buffer_point = self.transforms.start().1;        let buffer_row = MultiBufferRow(if row == 0 {            0        } else {            match self.transforms.item() {                Some(Transform::Isomorphic(_)) => {                    buffer_point += inlay_point.0 - self.transforms.start().0 .0;                    buffer_point.row                }                _ => cmp::min(buffer_point.row + 1, self.max_buffer_row.0),            }        });        self.inlay_row = inlay_point.row();        self.buffer_rows.seek(buffer_row);    }} impl<'a> Iterator for InlayBufferRows<'a> {    type Item = Option<u32>;     fn next(&mut self) -> Option<Self::Item> {        let buffer_row = if self.inlay_row == 0 {            self.buffer_rows.next().unwrap()        } else {            match self.transforms.item()? {                Transform::Inlay(_) => None,                Transform::Isomorphic(_) => self.buffer_rows.next().unwrap(),            }        };         self.inlay_row += 1;        self.transforms            .seek_forward(&InlayPoint::new(self.inlay_row, 0), Bias::Left, &());         Some(buffer_row)    }} impl InlayPoint {    pub fn new(row: u32, column: u32) -> Self {        Self(Point::new(row, column))    }     pub fn row(self) -> u32 {        self.0.row    }} impl InlayMap {    pub fn new(buffer: MultiBufferSnapshot) -> (Self, InlaySnapshot) {        let version = 0;        let snapshot = InlaySnapshot {            buffer: buffer.clone(),            transforms: SumTree::from_iter(Some(Transform::Isomorphic(buffer.text_summary())), &()),            version,        };         (            Self {                snapshot: snapshot.clone(),                inlays: Vec::new(),            },            snapshot,        )    }     pub fn sync(        &mut self,        buffer_snapshot: MultiBufferSnapshot,        mut buffer_edits: Vec<text::Edit<usize>>,    ) -> (InlaySnapshot, Vec<InlayEdit>) {        let snapshot = &mut self.snapshot;         if buffer_edits.is_empty()            && snapshot.buffer.trailing_excerpt_update_count()                != buffer_snapshot.trailing_excerpt_update_count()        {            buffer_edits.push(Edit {                old: snapshot.buffer.len()..snapshot.buffer.len(),                new: buffer_snapshot.len()..buffer_snapshot.len(),            });        }         if buffer_edits.is_empty() {            if snapshot.buffer.edit_count() != buffer_snapshot.edit_count()                || snapshot.buffer.non_text_state_update_count()                    != buffer_snapshot.non_text_state_update_count()                || snapshot.buffer.trailing_excerpt_update_count()                    != buffer_snapshot.trailing_excerpt_update_count()            {                snapshot.version += 1;            }             snapshot.buffer = buffer_snapshot;            (snapshot.clone(), Vec::new())        } else {            let mut inlay_edits = Patch::default();            let mut new_transforms = SumTree::default();            let mut cursor = snapshot.transforms.cursor::<(usize, InlayOffset)>(&());            let mut buffer_edits_iter = buffer_edits.iter().peekable();            while let Some(buffer_edit) = buffer_edits_iter.next() {                new_transforms.append(cursor.slice(&buffer_edit.old.start, Bias::Left, &()), &());                if let Some(Transform::Isomorphic(transform)) = cursor.item() {                    if cursor.end(&()).0 == buffer_edit.old.start {                        push_isomorphic(&mut new_transforms, transform.clone());                        cursor.next(&());                    }                }                 // 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_ix = match self.inlays.binary_search_by(|probe| {                    probe                        .position                        .to_offset(&buffer_snapshot)                        .cmp(&buffer_edit.new.start)                        .then(std::cmp::Ordering::Greater)                }) {                    Ok(ix) | Err(ix) => ix,                };                 for inlay in &self.inlays[start_ix..] {                    let buffer_offset = inlay.position.to_offset(&buffer_snapshot);                    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.

Lines 1–500 of 1795.