Start work on optomizing tab map

We currently iterate over each character when looking for tab bytes even
though chunks keeps a bitmask that represents each tab position. This
commit is the first step in using the bitmask

Co-authored-by: Remco Smits <djsmits12@gmail.com>
Co-authored-by: Cole Miller <m@cole-miller.net>
This commit is contained in:
Anthony 2025-06-05 17:34:17 -04:00
parent 52770cd3ad
commit 765ed65e88
7 changed files with 284 additions and 42 deletions

View file

@ -28,6 +28,7 @@ use gpui::{
App, AppContext as _, Context, Entity, EventEmitter, HighlightStyle, SharedString, StyledText,
Task, TaskLabel, TextStyle,
};
use lsp::{LanguageServerId, NumberOrString};
use parking_lot::Mutex;
use schemars::JsonSchema;
@ -485,6 +486,8 @@ pub struct Chunk<'a> {
pub is_unnecessary: bool,
/// Whether this chunk of text was originally a tab character.
pub is_tab: bool,
/// A bitset of which characters are tabs in this string.
pub tabs: u128,
/// Whether this chunk of text was originally a tab character.
pub is_inlay: bool,
/// Whether to underline the corresponding text range in the editor.
@ -4579,7 +4582,7 @@ impl<'a> Iterator for BufferChunks<'a> {
}
self.diagnostic_endpoints = diagnostic_endpoints;
if let Some(chunk) = self.chunks.peek() {
if let Some((chunk, tabs)) = self.chunks.peek_tabs() {
let chunk_start = self.range.start;
let mut chunk_end = (self.chunks.offset() + chunk.len())
.min(next_capture_start)
@ -4594,6 +4597,8 @@ impl<'a> Iterator for BufferChunks<'a> {
let slice =
&chunk[chunk_start - self.chunks.offset()..chunk_end - self.chunks.offset()];
let tabs = tabs >> (chunk_start - self.chunks.offset());
self.range.start = chunk_end;
if self.range.start == self.chunks.offset() + chunk.len() {
self.chunks.next().unwrap();
@ -4605,6 +4610,7 @@ impl<'a> Iterator for BufferChunks<'a> {
underline: self.underline,
diagnostic_severity: self.current_diagnostic_severity(),
is_unnecessary: self.current_code_is_unnecessary(),
tabs,
..Chunk::default()
})
} else {

View file

@ -3279,6 +3279,28 @@ fn test_contiguous_ranges() {
);
}
#[test]
fn test_buffer_chunks_tabs() {
let buffer = text::Buffer::new(0, BufferId::new(1).unwrap(), "\ta\tbc");
let mut iter = buffer.as_rope().chunks();
while let Some((str, tabs)) = iter.peek_tabs() {
dbg!(str, format!("{:b}", tabs));
iter.next();
}
dbg!("---");
let buffer = text::Buffer::new(0, BufferId::new(1).unwrap(), "\ta\tbc");
let mut iter = buffer.as_rope().chunks();
iter.seek(3);
while let Some((str, tabs)) = iter.peek_tabs() {
dbg!(str, format!("{:b}", tabs));
iter.next();
}
assert!(false)
}
#[gpui::test(iterations = 500)]
fn test_trailing_whitespace_ranges(mut rng: StdRng) {
// Generate a random multi-line string containing