use crate::{HighlightStyles, InlayId};use collections::BTreeSet;use gpui::{Hsla, Rgba};use language::{Chunk, Edit, Point, TextSummary};use multi_buffer::{ Anchor, MultiBufferRow, MultiBufferRows, MultiBufferSnapshot, RowInfo, ToOffset,};use std::{ cmp, ops::{Add, AddAssign, Range, Sub, SubAssign},};use sum_tree::{Bias, Cursor, SumTree};use text::{Patch, Rope}; use super::{Highlights, custom_highlights::CustomHighlightsChunks}; /// 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 id: InlayId, pub position: Anchor, pub text: text::Rope, color: Option<Hsla>,} 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(), color: None, } } #[cfg(any(test, feature = "test-support"))] pub fn mock_hint(id: usize, position: Anchor, text: impl Into<Rope>) -> Self { Self { id: InlayId::Hint(id), position, text: text.into(), color: None, } } pub fn color(id: usize, position: Anchor, color: Rgba) -> Self { Self { id: InlayId::Color(id), position, text: Rope::from("◼"), color: Some(Hsla::from(color)), } } pub fn inline_completion<T: Into<Rope>>(id: usize, position: Anchor, text: T) -> Self { Self { id: InlayId::InlineCompletion(id), position, text: text.into(), color: None, } } pub fn debugger<T: Into<Rope>>(id: usize, position: Anchor, text: T) -> Self { Self { id: InlayId::DebuggerValue(id), position, text: text.into(), color: None, } } #[cfg(any(test, feature = "test-support"))] pub fn get_color(&self) -> Option<Hsla> { self.color }} impl sum_tree::Item for Transform { type Summary = TransformSummary; fn summary(&self, _: &()) -> Self::Summary { match self { Transform::Isomorphic(summary) => TransformSummary { input: *summary, output: *summary, }, 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 InlayChunks<'_> { 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, InlayId::DebuggerValue(_) => self.highlight_styles.inlay_hint, InlayId::Color(_) => match inlay.color { Some(color) => { let style = self.highlight_styles.inlay_hint.get_or_insert_default(); style.color = Some(color); Some(*style) } None => 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, is_inlay: true, ..Default::default() } } }; if self.output_offset == self.transforms.end(&()).0 { self.inlay_chunks = None; self.transforms.next(&()); } Some(chunk) }} impl InlayBufferRows<'_> { 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 Iterator for InlayBufferRows<'_> { type Item = RowInfo; 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(_) => Default::default(), 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);Lines 1–500 of 1852. Load more
use crate::{HighlightStyles, InlayId}; use collections::BTreeSet; use gpui::{Hsla, Rgba}; use language::{Chunk, Edit, Point, TextSummary}; use multi_buffer::{ Anchor, MultiBufferRow, MultiBufferRows, MultiBufferSnapshot, RowInfo, ToOffset, }; use std::{ cmp, ops::{Add, AddAssign, Range, Sub, SubAssign}, }; use sum_tree::{Bias, Cursor, SumTree}; use text::{Patch, Rope}; use super::{Highlights, custom_highlights::CustomHighlightsChunks}; /// 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 id: InlayId, pub position: Anchor, pub text: text::Rope, color: Option<Hsla>, } 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(), color: None, } } #[cfg(any(test, feature = "test-support"))] pub fn mock_hint(id: usize, position: Anchor, text: impl Into<Rope>) -> Self { Self { id: InlayId::Hint(id), position, text: text.into(), color: None, } } pub fn color(id: usize, position: Anchor, color: Rgba) -> Self { Self { id: InlayId::Color(id), position, text: Rope::from("◼"), color: Some(Hsla::from(color)), } } pub fn inline_completion<T: Into<Rope>>(id: usize, position: Anchor, text: T) -> Self { Self { id: InlayId::InlineCompletion(id), position, text: text.into(), color: None, } } pub fn debugger<T: Into<Rope>>(id: usize, position: Anchor, text: T) -> Self { Self { id: InlayId::DebuggerValue(id), position, text: text.into(), color: None, } } #[cfg(any(test, feature = "test-support"))] pub fn get_color(&self) -> Option<Hsla> { self.color } } impl sum_tree::Item for Transform { type Summary = TransformSummary; fn summary(&self, _: &()) -> Self::Summary { match self { Transform::Isomorphic(summary) => TransformSummary { input: *summary, output: *summary, }, 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 InlayChunks<'_> { 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, InlayId::DebuggerValue(_) => self.highlight_styles.inlay_hint, InlayId::Color(_) => match inlay.color { Some(color) => { let style = self.highlight_styles.inlay_hint.get_or_insert_default(); style.color = Some(color); Some(*style) } None => 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, is_inlay: true, ..Default::default() } } }; if self.output_offset == self.transforms.end(&()).0 { self.inlay_chunks = None; self.transforms.next(&()); } Some(chunk) } } impl InlayBufferRows<'_> { 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 Iterator for InlayBufferRows<'_> { type Item = RowInfo; 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(_) => Default::default(), 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);