//! The inlay map. See the [`display_map`][super] docs for an overview of how the inlay map fits//! into the rest of the [`DisplayMap`][super::DisplayMap]. Much of the documentation for this//! module generalizes to other layers.//!//! The core of this module is the [`InlayMap`] struct, which maintains a vec of [`Inlay`]s, and//! [`InlaySnapshot`], which holds a sum tree of [`Transform`]s. use crate::{ ChunkRenderer, HighlightStyles, inlays::{Inlay, InlayContent},};use collections::BTreeSet;use language::{Chunk, Edit, LanguageAwareStyling, Point, TextSummary};use multi_buffer::{ MBTextSummary, MultiBufferOffset, MultiBufferRow, MultiBufferRows, MultiBufferSnapshot, RowInfo, ToOffset,};use project::InlayId;use smallvec::SmallVec;use std::{ cmp, iter, ops::{Add, AddAssign, Range, Sub, SubAssign}, sync::Arc,};use sum_tree::{Bias, Cursor, Dimensions, SumTree};use text::{ChunkBitmaps, Patch};use ui::{ActiveTheme, IntoElement as _, ParentElement as _, Styled as _, div}; use super::{Highlights, custom_highlights::CustomHighlightsChunks, fold_map::ChunkRendererId}; /// 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,} impl std::ops::Deref for InlaySnapshot { type Target = MultiBufferSnapshot; fn deref(&self) -> &Self::Target { &self.buffer }} #[derive(Clone, Debug)]enum Transform { Isomorphic(MBTextSummary), Inlay(Inlay),} impl sum_tree::Item for Transform { type Summary = TransformSummary; #[ztracing::instrument(skip_all)] fn summary(&self, _: ()) -> Self::Summary { match self { Transform::Isomorphic(summary) => TransformSummary { input: *summary, output: *summary, }, Transform::Inlay(inlay) => TransformSummary { input: MBTextSummary::default(), output: MBTextSummary::from(inlay.text().summary()), }, } }} #[derive(Clone, Debug, Default)]struct TransformSummary { /// Summary of the text before inlays have been applied. input: MBTextSummary, /// Summary of the text after inlays have been applied. output: MBTextSummary,} impl TransformSummary { fn has_inlays(&self) -> bool { self.input.len != self.output.len }} impl sum_tree::ContextLessSummary for TransformSummary { fn zero() -> 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 MultiBufferOffset); 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 = <MultiBufferOffset as Sub>::Output; fn sub(self, rhs: Self) -> Self::Output { self.0 - rhs.0 }} impl<T> SubAssign<T> for InlayOffsetwhere MultiBufferOffset: SubAssign<T>,{ fn sub_assign(&mut self, rhs: T) { self.0 -= rhs; }} impl<T> Add<T> for InlayOffsetwhere MultiBufferOffset: Add<T, Output = MultiBufferOffset>,{ type Output = Self; fn add(self, rhs: T) -> Self::Output { Self(self.0 + rhs) }} impl AddAssign for InlayOffset { fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0; }} impl<T> AddAssign<T> for InlayOffsetwhere MultiBufferOffset: AddAssign<T>,{ fn add_assign(&mut self, rhs: T) { self.0 += rhs; }} 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 MultiBufferOffset { 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, 'static, Transform, Dimensions<InlayPoint, Point>>, buffer_rows: MultiBufferRows<'a>, inlay_row: u32, max_buffer_row: MultiBufferRow,} pub struct InlayChunks<'a> { transforms: Cursor<'a, 'static, Transform, Dimensions<InlayOffset, MultiBufferOffset>>, buffer_chunks: CustomHighlightsChunks<'a>, buffer_chunk: Option<Chunk<'a>>, inlay_chunks: Option<text::ChunkWithBitmaps<'a>>, /// text, char bitmap, tabs bitmap inlay_chunk: Option<ChunkBitmaps<'a>>, output_offset: InlayOffset, max_output_offset: InlayOffset, highlight_styles: HighlightStyles, highlights: Highlights<'a>, snapshot: &'a InlaySnapshot,} #[derive(Clone)]pub struct InlayChunk<'a> { pub chunk: Chunk<'a>, /// Whether the inlay should be customly rendered. pub renderer: Option<ChunkRenderer>,} impl InlayChunks<'_> { #[ztracing::instrument(skip_all)] 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 = InlayChunk<'a>; #[ztracing::instrument(skip_all)] 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 desired_bytes = self.transforms.end().0.0 - self.output_offset.0; // If we're already at the transform boundary, skip to the next transform if desired_bytes == 0 { self.inlay_chunks = None; self.transforms.next(); return self.next(); } // Determine split index handling edge cases let split_index = if desired_bytes >= chunk.text.len() { chunk.text.len() } else { chunk.text.ceil_char_boundary(desired_bytes) }; let (prefix, suffix) = chunk.text.split_at(split_index); self.output_offset.0 += prefix.len(); let mask = 1u128.unbounded_shl(split_index as u32).wrapping_sub(1); let chars = chunk.chars & mask; let tabs = chunk.tabs & mask; let newlines = chunk.newlines & mask; chunk.chars = chunk.chars.unbounded_shr(split_index as u32); chunk.tabs = chunk.tabs.unbounded_shr(split_index as u32); chunk.newlines = chunk.newlines.unbounded_shr(split_index as u32); chunk.text = suffix; InlayChunk { chunk: Chunk { text: prefix, chars, tabs, newlines, ..chunk.clone() }, renderer: None, } } 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 renderer = None; let mut highlight_style = match inlay.id { InlayId::EditPrediction(_) => self.highlight_styles.edit_prediction.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::ReplResult(_) => { let text = inlay.text().to_string(); renderer = Some(ChunkRenderer { id: ChunkRendererId::Inlay(inlay.id), render: Arc::new(move |cx| { let colors = cx.theme().colors(); div() .flex() .flex_row() .items_center() .child(div().w_4()) .child( div() .px_1() .rounded_sm() .bg(colors.surface_background) .text_color(colors.text_muted) .text_xs() .child(text.trim().to_string()), ) .into_any_element() }), constrain_width: false, measured_width: None, }); self.highlight_styles.inlay_hint } InlayId::Color(_) => { if let InlayContent::Color(color) = inlay.content { renderer = Some(ChunkRenderer { id: ChunkRendererId::Inlay(inlay.id), render: Arc::new(move |cx| { div() .relative() .size_3p5() .child( div() .absolute() .right_1() .size_3() .border_1() .border_color( if cx.theme().appearance().is_light() { gpui::black().opacity(0.5) } else { gpui::white().opacity(0.5) }, ) .bg(color), ) .into_any_element() }), constrain_width: false, measured_width: 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 < range.start { next_inlay_highlight_endpoint = range.start - offset_in_inlay; } else if offset_in_inlay >= range.end { next_inlay_highlight_endpoint = usize::MAX; } else { next_inlay_highlight_endpoint = range.end - offset_in_inlay; highlight_style = highlight_style .map(|highlight| highlight.highlight(*style)) .or_else(|| Some(*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; let chunks = inlay.text().chunks_in_range(start..end); text::ChunkWithBitmaps(chunks) }); let ChunkBitmaps { text: inlay_chunk, chars, tabs, newlines, } = self .inlay_chunk .get_or_insert_with(|| inlay_chunks.next().unwrap()); // Determine split index handling edge cases let split_index = if next_inlay_highlight_endpoint >= inlay_chunk.len() { inlay_chunk.len() } else if next_inlay_highlight_endpoint == 0 { // Need to take at least one character to make progress inlay_chunk .chars() .next() .map(|c| c.len_utf8()) .unwrap_or(1) } else { inlay_chunk.ceil_char_boundary(next_inlay_highlight_endpoint) }; let (chunk, remainder) = inlay_chunk.split_at(split_index); *inlay_chunk = remainder; let mask = 1u128.unbounded_shl(split_index as u32).wrapping_sub(1); let new_chars = *chars & mask; let new_tabs = *tabs & mask; let new_newlines = *newlines & mask; *chars = chars.unbounded_shr(split_index as u32); *tabs = tabs.unbounded_shr(split_index as u32); *newlines = newlines.unbounded_shr(split_index as u32); if inlay_chunk.is_empty() { self.inlay_chunk = None; } self.output_offset.0 += chunk.len(); InlayChunk { chunk: Chunk { text: chunk, chars: new_chars, tabs: new_tabs, newlines: new_newlines, highlight_style, is_inlay: true, ..Chunk::default() }, renderer, } } }; if self.output_offset >= self.transforms.end().0 { self.inlay_chunks = None; self.transforms.next(); } Some(chunk) }} impl InlayBufferRows<'_> { #[ztracing::instrument(skip_all)] pub fn seek(&mut self, row: u32) { let inlay_point = InlayPoint::new(row, 0); self.transforms.seek(&inlay_point, Bias::Left);Lines 1–500 of 2574. Load more
//! The inlay map. See the [`display_map`][super] docs for an overview of how the inlay map fits //! into the rest of the [`DisplayMap`][super::DisplayMap]. Much of the documentation for this //! module generalizes to other layers. //! //! The core of this module is the [`InlayMap`] struct, which maintains a vec of [`Inlay`]s, and //! [`InlaySnapshot`], which holds a sum tree of [`Transform`]s. use crate::{ ChunkRenderer, HighlightStyles, inlays::{Inlay, InlayContent}, }; use collections::BTreeSet; use language::{Chunk, Edit, LanguageAwareStyling, Point, TextSummary}; use multi_buffer::{ MBTextSummary, MultiBufferOffset, MultiBufferRow, MultiBufferRows, MultiBufferSnapshot, RowInfo, ToOffset, }; use project::InlayId; use smallvec::SmallVec; use std::{ cmp, iter, ops::{Add, AddAssign, Range, Sub, SubAssign}, sync::Arc, }; use sum_tree::{Bias, Cursor, Dimensions, SumTree}; use text::{ChunkBitmaps, Patch}; use ui::{ActiveTheme, IntoElement as _, ParentElement as _, Styled as _, div}; use super::{Highlights, custom_highlights::CustomHighlightsChunks, fold_map::ChunkRendererId}; /// 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, } impl std::ops::Deref for InlaySnapshot { type Target = MultiBufferSnapshot; fn deref(&self) -> &Self::Target { &self.buffer } } #[derive(Clone, Debug)] enum Transform { Isomorphic(MBTextSummary), Inlay(Inlay), } impl sum_tree::Item for Transform { type Summary = TransformSummary; #[ztracing::instrument(skip_all)] fn summary(&self, _: ()) -> Self::Summary { match self { Transform::Isomorphic(summary) => TransformSummary { input: *summary, output: *summary, }, Transform::Inlay(inlay) => TransformSummary { input: MBTextSummary::default(), output: MBTextSummary::from(inlay.text().summary()), }, } } } #[derive(Clone, Debug, Default)] struct TransformSummary { /// Summary of the text before inlays have been applied. input: MBTextSummary, /// Summary of the text after inlays have been applied. output: MBTextSummary, } impl TransformSummary { fn has_inlays(&self) -> bool { self.input.len != self.output.len } } impl sum_tree::ContextLessSummary for TransformSummary { fn zero() -> 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 MultiBufferOffset); 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 = <MultiBufferOffset as Sub>::Output; fn sub(self, rhs: Self) -> Self::Output { self.0 - rhs.0 } } impl<T> SubAssign<T> for InlayOffset where MultiBufferOffset: SubAssign<T>, { fn sub_assign(&mut self, rhs: T) { self.0 -= rhs; } } impl<T> Add<T> for InlayOffset where MultiBufferOffset: Add<T, Output = MultiBufferOffset>, { type Output = Self; fn add(self, rhs: T) -> Self::Output { Self(self.0 + rhs) } } impl AddAssign for InlayOffset { fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0; } } impl<T> AddAssign<T> for InlayOffset where MultiBufferOffset: AddAssign<T>, { fn add_assign(&mut self, rhs: T) { self.0 += rhs; } } 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 MultiBufferOffset { 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, 'static, Transform, Dimensions<InlayPoint, Point>>, buffer_rows: MultiBufferRows<'a>, inlay_row: u32, max_buffer_row: MultiBufferRow, } pub struct InlayChunks<'a> { transforms: Cursor<'a, 'static, Transform, Dimensions<InlayOffset, MultiBufferOffset>>, buffer_chunks: CustomHighlightsChunks<'a>, buffer_chunk: Option<Chunk<'a>>, inlay_chunks: Option<text::ChunkWithBitmaps<'a>>, /// text, char bitmap, tabs bitmap inlay_chunk: Option<ChunkBitmaps<'a>>, output_offset: InlayOffset, max_output_offset: InlayOffset, highlight_styles: HighlightStyles, highlights: Highlights<'a>, snapshot: &'a InlaySnapshot, } #[derive(Clone)] pub struct InlayChunk<'a> { pub chunk: Chunk<'a>, /// Whether the inlay should be customly rendered. pub renderer: Option<ChunkRenderer>, } impl InlayChunks<'_> { #[ztracing::instrument(skip_all)] 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 = InlayChunk<'a>; #[ztracing::instrument(skip_all)] 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 desired_bytes = self.transforms.end().0.0 - self.output_offset.0; // If we're already at the transform boundary, skip to the next transform if desired_bytes == 0 { self.inlay_chunks = None; self.transforms.next(); return self.next(); } // Determine split index handling edge cases let split_index = if desired_bytes >= chunk.text.len() { chunk.text.len() } else { chunk.text.ceil_char_boundary(desired_bytes) }; let (prefix, suffix) = chunk.text.split_at(split_index); self.output_offset.0 += prefix.len(); let mask = 1u128.unbounded_shl(split_index as u32).wrapping_sub(1); let chars = chunk.chars & mask; let tabs = chunk.tabs & mask; let newlines = chunk.newlines & mask; chunk.chars = chunk.chars.unbounded_shr(split_index as u32); chunk.tabs = chunk.tabs.unbounded_shr(split_index as u32); chunk.newlines = chunk.newlines.unbounded_shr(split_index as u32); chunk.text = suffix; InlayChunk { chunk: Chunk { text: prefix, chars, tabs, newlines, ..chunk.clone() }, renderer: None, } } 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 renderer = None; let mut highlight_style = match inlay.id { InlayId::EditPrediction(_) => self.highlight_styles.edit_prediction.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::ReplResult(_) => { let text = inlay.text().to_string(); renderer = Some(ChunkRenderer { id: ChunkRendererId::Inlay(inlay.id), render: Arc::new(move |cx| { let colors = cx.theme().colors(); div() .flex() .flex_row() .items_center() .child(div().w_4()) .child( div() .px_1() .rounded_sm() .bg(colors.surface_background) .text_color(colors.text_muted) .text_xs() .child(text.trim().to_string()), ) .into_any_element() }), constrain_width: false, measured_width: None, }); self.highlight_styles.inlay_hint } InlayId::Color(_) => { if let InlayContent::Color(color) = inlay.content { renderer = Some(ChunkRenderer { id: ChunkRendererId::Inlay(inlay.id), render: Arc::new(move |cx| { div() .relative() .size_3p5() .child( div() .absolute() .right_1() .size_3() .border_1() .border_color( if cx.theme().appearance().is_light() { gpui::black().opacity(0.5) } else { gpui::white().opacity(0.5) }, ) .bg(color), ) .into_any_element() }), constrain_width: false, measured_width: 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 < range.start { next_inlay_highlight_endpoint = range.start - offset_in_inlay; } else if offset_in_inlay >= range.end { next_inlay_highlight_endpoint = usize::MAX; } else { next_inlay_highlight_endpoint = range.end - offset_in_inlay; highlight_style = highlight_style .map(|highlight| highlight.highlight(*style)) .or_else(|| Some(*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; let chunks = inlay.text().chunks_in_range(start..end); text::ChunkWithBitmaps(chunks) }); let ChunkBitmaps { text: inlay_chunk, chars, tabs, newlines, } = self .inlay_chunk .get_or_insert_with(|| inlay_chunks.next().unwrap()); // Determine split index handling edge cases let split_index = if next_inlay_highlight_endpoint >= inlay_chunk.len() { inlay_chunk.len() } else if next_inlay_highlight_endpoint == 0 { // Need to take at least one character to make progress inlay_chunk .chars() .next() .map(|c| c.len_utf8()) .unwrap_or(1) } else { inlay_chunk.ceil_char_boundary(next_inlay_highlight_endpoint) }; let (chunk, remainder) = inlay_chunk.split_at(split_index); *inlay_chunk = remainder; let mask = 1u128.unbounded_shl(split_index as u32).wrapping_sub(1); let new_chars = *chars & mask; let new_tabs = *tabs & mask; let new_newlines = *newlines & mask; *chars = chars.unbounded_shr(split_index as u32); *tabs = tabs.unbounded_shr(split_index as u32); *newlines = newlines.unbounded_shr(split_index as u32); if inlay_chunk.is_empty() { self.inlay_chunk = None; } self.output_offset.0 += chunk.len(); InlayChunk { chunk: Chunk { text: chunk, chars: new_chars, tabs: new_tabs, newlines: new_newlines, highlight_style, is_inlay: true, ..Chunk::default() }, renderer, } } }; if self.output_offset >= self.transforms.end().0 { self.inlay_chunks = None; self.transforms.next(); } Some(chunk) } } impl InlayBufferRows<'_> { #[ztracing::instrument(skip_all)] pub fn seek(&mut self, row: u32) { let inlay_point = InlayPoint::new(row, 0); self.transforms.seek(&inlay_point, Bias::Left);