diff --git a/crates/editor/src/display_map/inlay_map.rs b/crates/editor/src/display_map/inlay_map.rs index ad764101c9..305af2f35e 100644 --- a/crates/editor/src/display_map/inlay_map.rs +++ b/crates/editor/src/display_map/inlay_map.rs @@ -245,8 +245,9 @@ pub struct InlayChunks<'a> { transforms: Cursor<'a, Transform, (InlayOffset, usize)>, buffer_chunks: CustomHighlightsChunks<'a>, buffer_chunk: Option>, - inlay_chunks: Option>, - inlay_chunk: Option<&'a str>, + inlay_chunks: Option>, + /// text, char bitmap, tabs bitmap + inlay_chunk: Option<(&'a str, u128, u128)>, output_offset: InlayOffset, max_output_offset: InlayOffset, highlight_styles: HighlightStyles, @@ -403,24 +404,43 @@ impl<'a> Iterator for InlayChunks<'a> { 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 chunks = inlay.text.chunks_in_range(start.0..end.0); + text::ChunkWithBitmaps(chunks) }); - let inlay_chunk = self + let (inlay_chunk, chars, tabs) = 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)); + + let split_idx = inlay_chunk.len().min(next_inlay_highlight_endpoint); + + let (chunk, remainder) = inlay_chunk.split_at(split_idx); + *inlay_chunk = remainder; + + let (chars, tabs) = if split_idx == 128 { + let output = (*chars, *tabs); + *chars = 0; + *tabs = 0; + output + } else { + let mask = (1 << split_idx as u32) - 1; + let output = (*chars & mask, *tabs & mask); + *chars = *chars >> split_idx; + *tabs = *tabs >> split_idx; + output + }; + if inlay_chunk.is_empty() { self.inlay_chunk = None; } self.output_offset.0 += chunk.len(); - // todo! figure out how to get tabs here InlayChunk { chunk: Chunk { text: chunk, + chars, + tabs, highlight_style, is_inlay: true, ..Chunk::default() @@ -1930,7 +1950,7 @@ mod tests { Highlights::default(), ); - for chunk in chunks { + for chunk in chunks.into_iter().map(|inlay_chunk| inlay_chunk.chunk) { let chunk_text = chunk.text; let chars_bitmap = chunk.chars; let tabs_bitmap = chunk.tabs; diff --git a/crates/rope/src/rope.rs b/crates/rope/src/rope.rs index 9a0adf1b69..a15ef030ac 100644 --- a/crates/rope/src/rope.rs +++ b/crates/rope/src/rope.rs @@ -752,6 +752,32 @@ impl<'a> Chunks<'a> { self.offset < initial_offset && self.offset == 0 } + /// Returns bitmaps that represent character positions and tab positions + pub fn peak_with_bitmaps(&self) -> Option<(&'a str, u128, u128)> { + if !self.offset_is_valid() { + return None; + } + + let chunk = self.chunks.item()?; + let chunk_start = *self.chunks.start(); + let slice_range = if self.reversed { + let slice_start = cmp::max(chunk_start, self.range.start) - chunk_start; + let slice_end = self.offset - chunk_start; + slice_start..slice_end + } else { + let slice_start = self.offset - chunk_start; + let slice_end = cmp::min(self.chunks.end(&()), self.range.end) - chunk_start; + slice_start..slice_end + }; + + let bitmask = ((1 << (slice_range.end - slice_range.start + 1)) - 1) << slice_range.start; + Some(( + &chunk.text[slice_range], + chunk.chars() & bitmask, + chunk.tabs & bitmask, + )) + } + pub fn peek(&self) -> Option<&'a str> { if !self.offset_is_valid() { return None; @@ -843,6 +869,30 @@ impl<'a> Chunks<'a> { } } +pub struct ChunkWithBitmaps<'a>(pub Chunks<'a>); + +impl<'a> Iterator for ChunkWithBitmaps<'a> { + /// text, chars bitmap, tabs bitmap + type Item = (&'a str, u128, u128); + + fn next(&mut self) -> Option { + let chunk = self.0.peak_with_bitmaps()?; + if self.0.reversed { + self.0.offset -= chunk.0.len(); + if self.0.offset <= *self.0.chunks.start() { + self.0.chunks.prev(&()); + } + } else { + self.0.offset += chunk.0.len(); + if self.0.offset >= self.0.chunks.end(&()) { + self.0.chunks.next(&()); + } + } + + Some(chunk) + } +} + impl<'a> Iterator for Chunks<'a> { type Item = &'a str;