editor: Use unbounded shifts for chunk bitmaps (#40879)
This simplifies some code and is also more correct in some others (I believe some of these might've overflowed causing panics in sentry) Release Notes: - N/A *or* Added/Fixed/Improved ...
This commit is contained in:
@@ -26,8 +26,8 @@ use sum_tree::{Bias, ContextLessSummary, Dimensions, SumTree, TreeMap};
|
||||
use text::{BufferId, Edit};
|
||||
use ui::ElementId;
|
||||
|
||||
const NEWLINES: &[u8; u128::BITS as usize] = &[b'\n'; _];
|
||||
const BULLETS: &[u8; u128::BITS as usize] = &[b'*'; _];
|
||||
const NEWLINES: &[u8; rope::Chunk::MASK_BITS] = &[b'\n'; _];
|
||||
const BULLETS: &[u8; rope::Chunk::MASK_BITS] = &[b'*'; _];
|
||||
|
||||
/// Tracks custom blocks such as diagnostics that should be displayed within buffer.
|
||||
///
|
||||
@@ -1783,11 +1783,11 @@ impl<'a> Iterator for BlockChunks<'a> {
|
||||
|
||||
if self.masked {
|
||||
// Not great for multibyte text because to keep cursor math correct we
|
||||
// need to have the same number of bytes in the input as output.
|
||||
// need to have the same number of chars in the input as output.
|
||||
let chars_count = prefix.chars().count();
|
||||
let bullet_len = chars_count;
|
||||
prefix = unsafe { std::str::from_utf8_unchecked(&BULLETS[..bullet_len]) };
|
||||
chars = 1u128.unbounded_shl(bullet_len as u32) - 1;
|
||||
chars = 1u128.unbounded_shl(bullet_len as u32).wrapping_sub(1);
|
||||
tabs = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -132,37 +132,31 @@ impl<'a> Iterator for CustomHighlightsChunks<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
let chunk = self
|
||||
.buffer_chunk
|
||||
.get_or_insert_with(|| self.buffer_chunks.next().unwrap_or_default());
|
||||
if chunk.text.is_empty() {
|
||||
let chunk = match &mut self.buffer_chunk {
|
||||
Some(it) => it,
|
||||
slot => slot.insert(self.buffer_chunks.next()?),
|
||||
};
|
||||
while chunk.text.is_empty() {
|
||||
*chunk = self.buffer_chunks.next()?;
|
||||
}
|
||||
|
||||
let split_idx = chunk.text.len().min(next_highlight_endpoint - self.offset);
|
||||
let (prefix, suffix) = chunk.text.split_at(split_idx);
|
||||
|
||||
let (chars, tabs) = if split_idx == 128 {
|
||||
let output = (chunk.chars, chunk.tabs);
|
||||
chunk.chars = 0;
|
||||
chunk.tabs = 0;
|
||||
output
|
||||
} else {
|
||||
let mask = (1 << split_idx) - 1;
|
||||
let output = (chunk.chars & mask, chunk.tabs & mask);
|
||||
chunk.chars = chunk.chars >> split_idx;
|
||||
chunk.tabs = chunk.tabs >> split_idx;
|
||||
output
|
||||
};
|
||||
|
||||
chunk.text = suffix;
|
||||
self.offset += prefix.len();
|
||||
|
||||
let mask = 1u128.unbounded_shl(split_idx as u32).wrapping_sub(1);
|
||||
let chars = chunk.chars & mask;
|
||||
let tabs = chunk.tabs & mask;
|
||||
let mut prefix = Chunk {
|
||||
text: prefix,
|
||||
chars,
|
||||
tabs,
|
||||
..chunk.clone()
|
||||
};
|
||||
|
||||
chunk.chars = chunk.chars.unbounded_shr(split_idx as u32);
|
||||
chunk.tabs = chunk.tabs.unbounded_shr(split_idx as u32);
|
||||
chunk.text = suffix;
|
||||
if !self.active_highlights.is_empty() {
|
||||
prefix.highlight_style = self
|
||||
.active_highlights
|
||||
|
||||
@@ -1436,14 +1436,15 @@ impl<'a> Iterator for FoldChunks<'a> {
|
||||
let transform_end = self.transform_cursor.end().1;
|
||||
let chunk_end = buffer_chunk_end.min(transform_end);
|
||||
|
||||
chunk.text = &chunk.text
|
||||
[(self.inlay_offset - buffer_chunk_start).0..(chunk_end - buffer_chunk_start).0];
|
||||
let bit_start = (self.inlay_offset - buffer_chunk_start).0;
|
||||
let bit_end = (chunk_end - buffer_chunk_start).0;
|
||||
chunk.text = &chunk.text[bit_start..bit_end];
|
||||
|
||||
let bit_end = (chunk_end - buffer_chunk_start).0;
|
||||
let mask = 1u128.unbounded_shl(bit_end as u32).wrapping_sub(1);
|
||||
|
||||
chunk.tabs = (chunk.tabs >> (self.inlay_offset - buffer_chunk_start).0) & mask;
|
||||
chunk.chars = (chunk.chars >> (self.inlay_offset - buffer_chunk_start).0) & mask;
|
||||
chunk.tabs = (chunk.tabs >> bit_start) & mask;
|
||||
chunk.chars = (chunk.chars >> bit_start) & mask;
|
||||
|
||||
if chunk_end == transform_end {
|
||||
self.transform_cursor.next();
|
||||
|
||||
@@ -325,21 +325,16 @@ impl<'a> Iterator for InlayChunks<'a> {
|
||||
};
|
||||
|
||||
let (prefix, suffix) = chunk.text.split_at(split_index);
|
||||
|
||||
let (chars, tabs) = if split_index == 128 {
|
||||
let output = (chunk.chars, chunk.tabs);
|
||||
chunk.chars = 0;
|
||||
chunk.tabs = 0;
|
||||
output
|
||||
} else {
|
||||
let mask = (1 << split_index) - 1;
|
||||
let output = (chunk.chars & mask, chunk.tabs & mask);
|
||||
chunk.chars = chunk.chars >> split_index;
|
||||
chunk.tabs = chunk.tabs >> split_index;
|
||||
output
|
||||
};
|
||||
chunk.text = suffix;
|
||||
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;
|
||||
|
||||
chunk.chars = chunk.chars.unbounded_shr(split_index as u32);
|
||||
chunk.tabs = chunk.tabs.unbounded_shr(split_index as u32);
|
||||
chunk.text = suffix;
|
||||
|
||||
InlayChunk {
|
||||
chunk: Chunk {
|
||||
text: prefix,
|
||||
@@ -457,18 +452,12 @@ impl<'a> Iterator for InlayChunks<'a> {
|
||||
let (chunk, remainder) = inlay_chunk.split_at(split_index);
|
||||
*inlay_chunk = remainder;
|
||||
|
||||
let (chars, tabs) = if split_index == 128 {
|
||||
let output = (*chars, *tabs);
|
||||
*chars = 0;
|
||||
*tabs = 0;
|
||||
output
|
||||
} else {
|
||||
let mask = (1 << split_index as u32) - 1;
|
||||
let output = (*chars & mask, *tabs & mask);
|
||||
*chars = *chars >> split_index;
|
||||
*tabs = *tabs >> split_index;
|
||||
output
|
||||
};
|
||||
let mask = 1u128.unbounded_shl(split_index as u32).wrapping_sub(1);
|
||||
let new_chars = *chars & mask;
|
||||
let new_tabs = *tabs & mask;
|
||||
|
||||
*chars = chars.unbounded_shr(split_index as u32);
|
||||
*tabs = tabs.unbounded_shr(split_index as u32);
|
||||
|
||||
if inlay_chunk.is_empty() {
|
||||
self.inlay_chunk = None;
|
||||
@@ -479,8 +468,8 @@ impl<'a> Iterator for InlayChunks<'a> {
|
||||
InlayChunk {
|
||||
chunk: Chunk {
|
||||
text: chunk,
|
||||
chars,
|
||||
tabs,
|
||||
chars: new_chars,
|
||||
tabs: new_tabs,
|
||||
highlight_style,
|
||||
is_inlay: true,
|
||||
..Chunk::default()
|
||||
|
||||
@@ -11,7 +11,7 @@ use sum_tree::Bias;
|
||||
const MAX_EXPANSION_COLUMN: u32 = 256;
|
||||
|
||||
// Handles a tab width <= 128
|
||||
const SPACES: &[u8; u128::BITS as usize] = &[b' '; _];
|
||||
const SPACES: &[u8; rope::Chunk::MASK_BITS] = &[b' '; _];
|
||||
const MAX_TABS: NonZeroU32 = NonZeroU32::new(SPACES.len() as u32).unwrap();
|
||||
|
||||
/// Keeps track of hard tabs in a text buffer.
|
||||
@@ -569,56 +569,47 @@ impl<'a> Iterator for TabChunks<'a> {
|
||||
//todo(improve performance by using tab cursor)
|
||||
for (ix, c) in self.chunk.text.char_indices() {
|
||||
match c {
|
||||
'\t' if ix > 0 => {
|
||||
let (prefix, suffix) = self.chunk.text.split_at(ix);
|
||||
|
||||
let mask = 1u128.unbounded_shl(ix as u32).wrapping_sub(1);
|
||||
let chars = self.chunk.chars & mask;
|
||||
let tabs = self.chunk.tabs & mask;
|
||||
self.chunk.tabs = self.chunk.tabs.unbounded_shr(ix as u32);
|
||||
self.chunk.chars = self.chunk.chars.unbounded_shr(ix as u32);
|
||||
self.chunk.text = suffix;
|
||||
return Some(Chunk {
|
||||
text: prefix,
|
||||
chars,
|
||||
tabs,
|
||||
..self.chunk.clone()
|
||||
});
|
||||
}
|
||||
'\t' => {
|
||||
if ix > 0 {
|
||||
let (prefix, suffix) = self.chunk.text.split_at(ix);
|
||||
|
||||
let (chars, tabs) = if ix == 128 {
|
||||
let output = (self.chunk.chars, self.chunk.tabs);
|
||||
self.chunk.chars = 0;
|
||||
self.chunk.tabs = 0;
|
||||
output
|
||||
} else {
|
||||
let mask = (1 << ix) - 1;
|
||||
let output = (self.chunk.chars & mask, self.chunk.tabs & mask);
|
||||
self.chunk.chars = self.chunk.chars >> ix;
|
||||
self.chunk.tabs = self.chunk.tabs >> ix;
|
||||
output
|
||||
};
|
||||
|
||||
self.chunk.text = suffix;
|
||||
return Some(Chunk {
|
||||
text: prefix,
|
||||
chars,
|
||||
tabs,
|
||||
..self.chunk.clone()
|
||||
});
|
||||
self.chunk.text = &self.chunk.text[1..];
|
||||
self.chunk.tabs >>= 1;
|
||||
self.chunk.chars >>= 1;
|
||||
let tab_size = if self.input_column < self.max_expansion_column {
|
||||
self.tab_size.get()
|
||||
} else {
|
||||
self.chunk.text = &self.chunk.text[1..];
|
||||
self.chunk.tabs >>= 1;
|
||||
self.chunk.chars >>= 1;
|
||||
let tab_size = if self.input_column < self.max_expansion_column {
|
||||
self.tab_size.get()
|
||||
} else {
|
||||
1
|
||||
};
|
||||
let mut len = tab_size - self.column % tab_size;
|
||||
let next_output_position = cmp::min(
|
||||
self.output_position + Point::new(0, len),
|
||||
self.max_output_position,
|
||||
);
|
||||
len = next_output_position.column - self.output_position.column;
|
||||
self.column += len;
|
||||
self.input_column += 1;
|
||||
self.output_position = next_output_position;
|
||||
return Some(Chunk {
|
||||
text: unsafe { std::str::from_utf8_unchecked(&SPACES[..len as usize]) },
|
||||
is_tab: true,
|
||||
chars: 1u128.unbounded_shl(len) - 1,
|
||||
tabs: 0,
|
||||
..self.chunk.clone()
|
||||
});
|
||||
}
|
||||
1
|
||||
};
|
||||
let mut len = tab_size - self.column % tab_size;
|
||||
let next_output_position = cmp::min(
|
||||
self.output_position + Point::new(0, len),
|
||||
self.max_output_position,
|
||||
);
|
||||
len = next_output_position.column - self.output_position.column;
|
||||
self.column += len;
|
||||
self.input_column += 1;
|
||||
self.output_position = next_output_position;
|
||||
return Some(Chunk {
|
||||
text: unsafe { std::str::from_utf8_unchecked(&SPACES[..len as usize]) },
|
||||
is_tab: true,
|
||||
chars: 1u128.unbounded_shl(len) - 1,
|
||||
tabs: 0,
|
||||
..self.chunk.clone()
|
||||
});
|
||||
}
|
||||
'\n' => {
|
||||
self.column = 0;
|
||||
|
||||
@@ -972,18 +972,11 @@ impl<'a> Iterator for WrapChunks<'a> {
|
||||
|
||||
let (prefix, suffix) = self.input_chunk.text.split_at(input_len);
|
||||
|
||||
let (chars, tabs) = if input_len == 128 {
|
||||
let output = (self.input_chunk.chars, self.input_chunk.tabs);
|
||||
self.input_chunk.chars = 0;
|
||||
self.input_chunk.tabs = 0;
|
||||
output
|
||||
} else {
|
||||
let mask = (1 << input_len) - 1;
|
||||
let output = (self.input_chunk.chars & mask, self.input_chunk.tabs & mask);
|
||||
self.input_chunk.chars = self.input_chunk.chars >> input_len;
|
||||
self.input_chunk.tabs = self.input_chunk.tabs >> input_len;
|
||||
output
|
||||
};
|
||||
let mask = 1u128.unbounded_shl(input_len as u32).wrapping_sub(1);
|
||||
let chars = self.input_chunk.chars & mask;
|
||||
let tabs = self.input_chunk.tabs & mask;
|
||||
self.input_chunk.tabs = self.input_chunk.tabs.unbounded_shr(input_len as u32);
|
||||
self.input_chunk.chars = self.input_chunk.chars.unbounded_shr(input_len as u32);
|
||||
|
||||
self.input_chunk.text = suffix;
|
||||
Some(Chunk {
|
||||
|
||||
Reference in New Issue
Block a user