multi_buffer: Typed MultiBufferOffset (#42707)
This PR introduces a new `MultiBufferOffset` new type wrapping size. The goal of this is to make it clear at the type level when we are interacting with offsets of a multi buffer versus offsets of a language / text buffer. This improves readability of things quite a bit by making it clear what kind of offsets one is working with while also reducing accidental bugs by using the wrong kin of offset for the wrong API. This PR also uncovered two minor bugs due to that. Does not yet introduce the MultiBufferPoint equivalent, that is for a follow up PR. Release Notes: - N/A *or* Added/Fixed/Improved ...
This commit is contained in:
@@ -11,8 +11,8 @@ use collections::{Bound, HashMap, HashSet};
|
||||
use gpui::{AnyElement, App, EntityId, Pixels, Window};
|
||||
use language::{Patch, Point};
|
||||
use multi_buffer::{
|
||||
Anchor, ExcerptId, ExcerptInfo, MultiBuffer, MultiBufferRow, MultiBufferSnapshot, RowInfo,
|
||||
ToOffset, ToPoint as _,
|
||||
Anchor, ExcerptId, ExcerptInfo, MultiBuffer, MultiBufferOffset, MultiBufferRow,
|
||||
MultiBufferSnapshot, RowInfo, ToOffset, ToPoint as _,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
@@ -1208,7 +1208,7 @@ impl BlockMapWriter<'_> {
|
||||
|
||||
pub fn remove_intersecting_replace_blocks(
|
||||
&mut self,
|
||||
ranges: impl IntoIterator<Item = Range<usize>>,
|
||||
ranges: impl IntoIterator<Item = Range<MultiBufferOffset>>,
|
||||
inclusive: bool,
|
||||
) {
|
||||
let wrap_snapshot = self.0.wrap_snapshot.borrow();
|
||||
@@ -1283,7 +1283,7 @@ impl BlockMapWriter<'_> {
|
||||
|
||||
fn blocks_intersecting_buffer_range(
|
||||
&self,
|
||||
range: Range<usize>,
|
||||
range: Range<MultiBufferOffset>,
|
||||
inclusive: bool,
|
||||
) -> &[Arc<CustomBlock>] {
|
||||
if range.is_empty() && !inclusive {
|
||||
@@ -3043,8 +3043,10 @@ mod tests {
|
||||
let block_properties = (0..block_count)
|
||||
.map(|_| {
|
||||
let buffer = cx.update(|cx| buffer.read(cx).read(cx).clone());
|
||||
let offset =
|
||||
buffer.clip_offset(rng.random_range(0..=buffer.len()), Bias::Left);
|
||||
let offset = buffer.clip_offset(
|
||||
rng.random_range(MultiBufferOffset(0)..=buffer.len()),
|
||||
Bias::Left,
|
||||
);
|
||||
let mut min_height = 0;
|
||||
let placement = match rng.random_range(0..3) {
|
||||
0 => {
|
||||
@@ -3244,7 +3246,7 @@ mod tests {
|
||||
// Note that this needs to be synced with the related section in BlockMap::sync
|
||||
expected_blocks.extend(block_map.header_and_footer_blocks(
|
||||
&buffer_snapshot,
|
||||
0..,
|
||||
MultiBufferOffset(0)..,
|
||||
&wraps_snapshot,
|
||||
));
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use collections::BTreeMap;
|
||||
use gpui::HighlightStyle;
|
||||
use language::Chunk;
|
||||
use multi_buffer::{MultiBufferChunks, MultiBufferSnapshot, ToOffset as _};
|
||||
use multi_buffer::{MultiBufferChunks, MultiBufferOffset, MultiBufferSnapshot, ToOffset as _};
|
||||
use std::{
|
||||
cmp,
|
||||
iter::{self, Peekable},
|
||||
@@ -14,7 +14,7 @@ use crate::display_map::{HighlightKey, TextHighlights};
|
||||
pub struct CustomHighlightsChunks<'a> {
|
||||
buffer_chunks: MultiBufferChunks<'a>,
|
||||
buffer_chunk: Option<Chunk<'a>>,
|
||||
offset: usize,
|
||||
offset: MultiBufferOffset,
|
||||
multibuffer_snapshot: &'a MultiBufferSnapshot,
|
||||
|
||||
highlight_endpoints: Peekable<vec::IntoIter<HighlightEndpoint>>,
|
||||
@@ -24,14 +24,14 @@ pub struct CustomHighlightsChunks<'a> {
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
struct HighlightEndpoint {
|
||||
offset: usize,
|
||||
offset: MultiBufferOffset,
|
||||
tag: HighlightKey,
|
||||
style: Option<HighlightStyle>,
|
||||
}
|
||||
|
||||
impl<'a> CustomHighlightsChunks<'a> {
|
||||
pub fn new(
|
||||
range: Range<usize>,
|
||||
range: Range<MultiBufferOffset>,
|
||||
language_aware: bool,
|
||||
text_highlights: Option<&'a TextHighlights>,
|
||||
multibuffer_snapshot: &'a MultiBufferSnapshot,
|
||||
@@ -52,7 +52,7 @@ impl<'a> CustomHighlightsChunks<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn seek(&mut self, new_range: Range<usize>) {
|
||||
pub fn seek(&mut self, new_range: Range<MultiBufferOffset>) {
|
||||
self.highlight_endpoints =
|
||||
create_highlight_endpoints(&new_range, self.text_highlights, self.multibuffer_snapshot);
|
||||
self.offset = new_range.start;
|
||||
@@ -63,7 +63,7 @@ impl<'a> CustomHighlightsChunks<'a> {
|
||||
}
|
||||
|
||||
fn create_highlight_endpoints(
|
||||
range: &Range<usize>,
|
||||
range: &Range<MultiBufferOffset>,
|
||||
text_highlights: Option<&TextHighlights>,
|
||||
buffer: &MultiBufferSnapshot,
|
||||
) -> iter::Peekable<vec::IntoIter<HighlightEndpoint>> {
|
||||
@@ -117,7 +117,7 @@ impl<'a> Iterator for CustomHighlightsChunks<'a> {
|
||||
type Item = Chunk<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut next_highlight_endpoint = usize::MAX;
|
||||
let mut next_highlight_endpoint = MultiBufferOffset(usize::MAX);
|
||||
while let Some(endpoint) = self.highlight_endpoints.peek().copied() {
|
||||
if endpoint.offset <= self.offset {
|
||||
if let Some(style) = endpoint.style {
|
||||
@@ -224,20 +224,22 @@ mod tests {
|
||||
let range_count = rng.random_range(1..10);
|
||||
let text = buffer_snapshot.text();
|
||||
for _ in 0..range_count {
|
||||
if buffer_snapshot.len() == 0 {
|
||||
if buffer_snapshot.len() == MultiBufferOffset(0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut start = rng.random_range(0..=buffer_snapshot.len().saturating_sub(10));
|
||||
let mut start = rng.random_range(
|
||||
MultiBufferOffset(0)..=buffer_snapshot.len().saturating_sub_usize(10),
|
||||
);
|
||||
|
||||
while !text.is_char_boundary(start) {
|
||||
start = start.saturating_sub(1);
|
||||
while !text.is_char_boundary(start.0) {
|
||||
start = start.saturating_sub_usize(1);
|
||||
}
|
||||
|
||||
let end_end = buffer_snapshot.len().min(start + 100);
|
||||
let end_end = buffer_snapshot.len().min(start + 100usize);
|
||||
let mut end = rng.random_range(start..=end_end);
|
||||
while !text.is_char_boundary(end) {
|
||||
end = end.saturating_sub(1);
|
||||
while !text.is_char_boundary(end.0) {
|
||||
end = end.saturating_sub_usize(1);
|
||||
}
|
||||
|
||||
if start < end {
|
||||
@@ -253,8 +255,12 @@ mod tests {
|
||||
}
|
||||
|
||||
// Get all chunks and verify their bitmaps
|
||||
let chunks =
|
||||
CustomHighlightsChunks::new(0..buffer_snapshot.len(), false, None, &buffer_snapshot);
|
||||
let chunks = CustomHighlightsChunks::new(
|
||||
MultiBufferOffset(0)..buffer_snapshot.len(),
|
||||
false,
|
||||
None,
|
||||
&buffer_snapshot,
|
||||
);
|
||||
|
||||
for chunk in chunks {
|
||||
let chunk_text = chunk.text;
|
||||
|
||||
@@ -5,16 +5,17 @@ use super::{
|
||||
inlay_map::{InlayBufferRows, InlayChunks, InlayEdit, InlayOffset, InlayPoint, InlaySnapshot},
|
||||
};
|
||||
use gpui::{AnyElement, App, ElementId, HighlightStyle, Pixels, Window};
|
||||
use language::{Edit, HighlightId, Point, TextSummary};
|
||||
use language::{Edit, HighlightId, Point};
|
||||
use multi_buffer::{
|
||||
Anchor, AnchorRangeExt, MultiBufferRow, MultiBufferSnapshot, RowInfo, ToOffset,
|
||||
Anchor, AnchorRangeExt, MBTextSummary, MultiBufferOffset, MultiBufferRow, MultiBufferSnapshot,
|
||||
RowInfo, ToOffset,
|
||||
};
|
||||
use project::InlayId;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
cmp::{self, Ordering},
|
||||
fmt, iter,
|
||||
ops::{Add, AddAssign, Deref, DerefMut, Range, Sub},
|
||||
ops::{Add, AddAssign, Deref, DerefMut, Range, Sub, SubAssign},
|
||||
sync::Arc,
|
||||
usize,
|
||||
};
|
||||
@@ -261,7 +262,7 @@ impl FoldMapWriter<'_> {
|
||||
fold_ixs_to_delete.dedup();
|
||||
|
||||
self.0.snapshot.folds = {
|
||||
let mut cursor = self.0.snapshot.folds.cursor::<usize>(buffer);
|
||||
let mut cursor = self.0.snapshot.folds.cursor::<MultiBufferOffset>(buffer);
|
||||
let mut folds = SumTree::new(buffer);
|
||||
for fold_ix in fold_ixs_to_delete {
|
||||
folds.append(cursor.slice(&fold_ix, Bias::Right), buffer);
|
||||
@@ -413,7 +414,7 @@ impl FoldMap {
|
||||
|
||||
let mut new_transforms = SumTree::<Transform>::default();
|
||||
let mut cursor = self.snapshot.transforms.cursor::<InlayOffset>(());
|
||||
cursor.seek(&InlayOffset(0), Bias::Right);
|
||||
cursor.seek(&InlayOffset(MultiBufferOffset(0)), Bias::Right);
|
||||
|
||||
while let Some(mut edit) = inlay_edits_iter.next() {
|
||||
if let Some(item) = cursor.item()
|
||||
@@ -436,7 +437,7 @@ impl FoldMap {
|
||||
cursor.seek(&edit.old.end, Bias::Right);
|
||||
cursor.next();
|
||||
|
||||
let mut delta = edit.new_len().0 as isize - edit.old_len().0 as isize;
|
||||
let mut delta = edit.new_len() as isize - edit.old_len() as isize;
|
||||
loop {
|
||||
edit.old.end = *cursor.start();
|
||||
|
||||
@@ -446,7 +447,7 @@ impl FoldMap {
|
||||
}
|
||||
|
||||
let next_edit = inlay_edits_iter.next().unwrap();
|
||||
delta += next_edit.new_len().0 as isize - next_edit.old_len().0 as isize;
|
||||
delta += next_edit.new_len() as isize - next_edit.old_len() as isize;
|
||||
|
||||
if next_edit.old.end >= edit.old.end {
|
||||
edit.old.end = next_edit.old.end;
|
||||
@@ -458,8 +459,9 @@ impl FoldMap {
|
||||
}
|
||||
}
|
||||
|
||||
edit.new.end =
|
||||
InlayOffset(((edit.new.start + edit.old_len()).0 as isize + delta) as usize);
|
||||
edit.new.end = InlayOffset(MultiBufferOffset(
|
||||
((edit.new.start + edit.old_len()).0.0 as isize + delta) as usize,
|
||||
));
|
||||
|
||||
let anchor = inlay_snapshot
|
||||
.buffer
|
||||
@@ -522,7 +524,7 @@ impl FoldMap {
|
||||
new_transforms.push(
|
||||
Transform {
|
||||
summary: TransformSummary {
|
||||
output: TextSummary::from(ELLIPSIS),
|
||||
output: MBTextSummary::from(ELLIPSIS),
|
||||
input: inlay_snapshot
|
||||
.text_summary_for_range(fold_range.start..fold_range.end),
|
||||
},
|
||||
@@ -579,7 +581,7 @@ impl FoldMap {
|
||||
edit.old.start = old_transforms.start().0;
|
||||
}
|
||||
let old_start =
|
||||
old_transforms.start().1.0 + (edit.old.start - old_transforms.start().0).0;
|
||||
old_transforms.start().1.0 + (edit.old.start - old_transforms.start().0);
|
||||
|
||||
old_transforms.seek_forward(&edit.old.end, Bias::Right);
|
||||
if old_transforms.item().is_some_and(|t| t.is_fold()) {
|
||||
@@ -587,14 +589,14 @@ impl FoldMap {
|
||||
edit.old.end = old_transforms.start().0;
|
||||
}
|
||||
let old_end =
|
||||
old_transforms.start().1.0 + (edit.old.end - old_transforms.start().0).0;
|
||||
old_transforms.start().1.0 + (edit.old.end - old_transforms.start().0);
|
||||
|
||||
new_transforms.seek(&edit.new.start, Bias::Left);
|
||||
if new_transforms.item().is_some_and(|t| t.is_fold()) {
|
||||
edit.new.start = new_transforms.start().0;
|
||||
}
|
||||
let new_start =
|
||||
new_transforms.start().1.0 + (edit.new.start - new_transforms.start().0).0;
|
||||
new_transforms.start().1.0 + (edit.new.start - new_transforms.start().0);
|
||||
|
||||
new_transforms.seek_forward(&edit.new.end, Bias::Right);
|
||||
if new_transforms.item().is_some_and(|t| t.is_fold()) {
|
||||
@@ -602,7 +604,7 @@ impl FoldMap {
|
||||
edit.new.end = new_transforms.start().0;
|
||||
}
|
||||
let new_end =
|
||||
new_transforms.start().1.0 + (edit.new.end - new_transforms.start().0).0;
|
||||
new_transforms.start().1.0 + (edit.new.end - new_transforms.start().0);
|
||||
|
||||
fold_edits.push(FoldEdit {
|
||||
old: FoldOffset(old_start)..FoldOffset(old_end),
|
||||
@@ -649,9 +651,13 @@ impl FoldSnapshot {
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn text(&self) -> String {
|
||||
self.chunks(FoldOffset(0)..self.len(), false, Highlights::default())
|
||||
.map(|c| c.text)
|
||||
.collect()
|
||||
self.chunks(
|
||||
FoldOffset(MultiBufferOffset(0))..self.len(),
|
||||
false,
|
||||
Highlights::default(),
|
||||
)
|
||||
.map(|c| c.text)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -659,8 +665,8 @@ impl FoldSnapshot {
|
||||
self.folds.items(&self.inlay_snapshot.buffer).len()
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range(&self, range: Range<FoldPoint>) -> TextSummary {
|
||||
let mut summary = TextSummary::default();
|
||||
pub fn text_summary_for_range(&self, range: Range<FoldPoint>) -> MBTextSummary {
|
||||
let mut summary = MBTextSummary::default();
|
||||
|
||||
let mut cursor = self
|
||||
.transforms
|
||||
@@ -670,7 +676,7 @@ impl FoldSnapshot {
|
||||
let start_in_transform = range.start.0 - cursor.start().0.0;
|
||||
let end_in_transform = cmp::min(range.end, cursor.end().0).0 - cursor.start().0.0;
|
||||
if let Some(placeholder) = transform.placeholder.as_ref() {
|
||||
summary = TextSummary::from(
|
||||
summary = MBTextSummary::from(
|
||||
&placeholder.text
|
||||
[start_in_transform.column as usize..end_in_transform.column as usize],
|
||||
);
|
||||
@@ -689,14 +695,14 @@ impl FoldSnapshot {
|
||||
|
||||
if range.end > cursor.end().0 {
|
||||
cursor.next();
|
||||
summary += &cursor
|
||||
summary += cursor
|
||||
.summary::<_, TransformSummary>(&range.end, Bias::Right)
|
||||
.output;
|
||||
if let Some(transform) = cursor.item() {
|
||||
let end_in_transform = range.end.0 - cursor.start().0.0;
|
||||
if let Some(placeholder) = transform.placeholder.as_ref() {
|
||||
summary +=
|
||||
TextSummary::from(&placeholder.text[..end_in_transform.column as usize]);
|
||||
MBTextSummary::from(&placeholder.text[..end_in_transform.column as usize]);
|
||||
} else {
|
||||
let inlay_start = self.inlay_snapshot.to_offset(cursor.start().1);
|
||||
let inlay_end = self
|
||||
@@ -839,8 +845,8 @@ impl FoldSnapshot {
|
||||
transform_cursor.seek(&range.start, Bias::Right);
|
||||
|
||||
let inlay_start = {
|
||||
let overshoot = range.start.0 - transform_cursor.start().0.0;
|
||||
transform_cursor.start().1 + InlayOffset(overshoot)
|
||||
let overshoot = range.start - transform_cursor.start().0;
|
||||
transform_cursor.start().1 + overshoot
|
||||
};
|
||||
|
||||
let transform_end = transform_cursor.end();
|
||||
@@ -851,8 +857,8 @@ impl FoldSnapshot {
|
||||
{
|
||||
inlay_start
|
||||
} else if range.end < transform_end.0 {
|
||||
let overshoot = range.end.0 - transform_cursor.start().0.0;
|
||||
transform_cursor.start().1 + InlayOffset(overshoot)
|
||||
let overshoot = range.end - transform_cursor.start().0;
|
||||
transform_cursor.start().1 + overshoot
|
||||
} else {
|
||||
transform_end.1
|
||||
};
|
||||
@@ -921,7 +927,7 @@ impl FoldSnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
fn push_isomorphic(transforms: &mut SumTree<Transform>, summary: TextSummary) {
|
||||
fn push_isomorphic(transforms: &mut SumTree<Transform>, summary: MBTextSummary) {
|
||||
let mut did_merge = false;
|
||||
transforms.update_last(
|
||||
|last| {
|
||||
@@ -950,13 +956,13 @@ fn push_isomorphic(transforms: &mut SumTree<Transform>, summary: TextSummary) {
|
||||
fn intersecting_folds<'a>(
|
||||
inlay_snapshot: &'a InlaySnapshot,
|
||||
folds: &'a SumTree<Fold>,
|
||||
range: Range<usize>,
|
||||
range: Range<MultiBufferOffset>,
|
||||
inclusive: bool,
|
||||
) -> FilterCursor<'a, 'a, impl 'a + FnMut(&FoldSummary) -> bool, Fold, usize> {
|
||||
) -> FilterCursor<'a, 'a, impl 'a + FnMut(&FoldSummary) -> bool, Fold, MultiBufferOffset> {
|
||||
let buffer = &inlay_snapshot.buffer;
|
||||
let start = buffer.anchor_before(range.start.to_offset(buffer));
|
||||
let end = buffer.anchor_after(range.end.to_offset(buffer));
|
||||
let mut cursor = folds.filter::<_, usize>(buffer, move |summary| {
|
||||
let mut cursor = folds.filter::<_, MultiBufferOffset>(buffer, move |summary| {
|
||||
let start_cmp = start.cmp(&summary.max_end, buffer);
|
||||
let end_cmp = end.cmp(&summary.min_start, buffer);
|
||||
|
||||
@@ -1061,8 +1067,8 @@ impl Transform {
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||
struct TransformSummary {
|
||||
output: TextSummary,
|
||||
input: TextSummary,
|
||||
output: MBTextSummary,
|
||||
input: MBTextSummary,
|
||||
}
|
||||
|
||||
impl sum_tree::Item for Transform {
|
||||
@@ -1079,8 +1085,8 @@ impl sum_tree::ContextLessSummary for TransformSummary {
|
||||
}
|
||||
|
||||
fn add_summary(&mut self, other: &Self) {
|
||||
self.input += &other.input;
|
||||
self.output += &other.output;
|
||||
self.input += other.input;
|
||||
self.output += other.output;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1211,7 +1217,7 @@ impl sum_tree::SeekTarget<'_, FoldSummary, FoldRange> for FoldRange {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> sum_tree::Dimension<'a, FoldSummary> for usize {
|
||||
impl<'a> sum_tree::Dimension<'a, FoldSummary> for MultiBufferOffset {
|
||||
fn zero(_cx: &MultiBufferSnapshot) -> Self {
|
||||
Default::default()
|
||||
}
|
||||
@@ -1357,8 +1363,8 @@ impl FoldChunks<'_> {
|
||||
self.transform_cursor.seek(&range.start, Bias::Right);
|
||||
|
||||
let inlay_start = {
|
||||
let overshoot = range.start.0 - self.transform_cursor.start().0.0;
|
||||
self.transform_cursor.start().1 + InlayOffset(overshoot)
|
||||
let overshoot = range.start - self.transform_cursor.start().0;
|
||||
self.transform_cursor.start().1 + overshoot
|
||||
};
|
||||
|
||||
let transform_end = self.transform_cursor.end();
|
||||
@@ -1370,8 +1376,8 @@ impl FoldChunks<'_> {
|
||||
{
|
||||
inlay_start
|
||||
} else if range.end < transform_end.0 {
|
||||
let overshoot = range.end.0 - self.transform_cursor.start().0.0;
|
||||
self.transform_cursor.start().1 + InlayOffset(overshoot)
|
||||
let overshoot = range.end - self.transform_cursor.start().0;
|
||||
self.transform_cursor.start().1 + overshoot
|
||||
} else {
|
||||
transform_end.1
|
||||
};
|
||||
@@ -1423,8 +1429,8 @@ impl<'a> Iterator for FoldChunks<'a> {
|
||||
let transform_start = self.transform_cursor.start();
|
||||
let transform_end = self.transform_cursor.end();
|
||||
let inlay_end = if self.max_output_offset < transform_end.0 {
|
||||
let overshoot = self.max_output_offset.0 - transform_start.0.0;
|
||||
transform_start.1 + InlayOffset(overshoot)
|
||||
let overshoot = self.max_output_offset - transform_start.0;
|
||||
transform_start.1 + overshoot
|
||||
} else {
|
||||
transform_end.1
|
||||
};
|
||||
@@ -1441,15 +1447,15 @@ impl<'a> Iterator for FoldChunks<'a> {
|
||||
// Otherwise, take a chunk from the buffer's text.
|
||||
if let Some((buffer_chunk_start, mut inlay_chunk)) = self.inlay_chunk.clone() {
|
||||
let chunk = &mut inlay_chunk.chunk;
|
||||
let buffer_chunk_end = buffer_chunk_start + InlayOffset(chunk.text.len());
|
||||
let buffer_chunk_end = buffer_chunk_start + chunk.text.len();
|
||||
let transform_end = self.transform_cursor.end().1;
|
||||
let chunk_end = buffer_chunk_end.min(transform_end);
|
||||
|
||||
let bit_start = (self.inlay_offset - buffer_chunk_start).0;
|
||||
let bit_end = (chunk_end - buffer_chunk_start).0;
|
||||
let bit_start = self.inlay_offset - buffer_chunk_start;
|
||||
let bit_end = chunk_end - buffer_chunk_start;
|
||||
chunk.text = &chunk.text[bit_start..bit_end];
|
||||
|
||||
let bit_end = (chunk_end - buffer_chunk_start).0;
|
||||
let bit_end = chunk_end - buffer_chunk_start;
|
||||
let mask = 1u128.unbounded_shl(bit_end as u32).wrapping_sub(1);
|
||||
|
||||
chunk.tabs = (chunk.tabs >> bit_start) & mask;
|
||||
@@ -1483,7 +1489,7 @@ impl<'a> Iterator for FoldChunks<'a> {
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
|
||||
pub struct FoldOffset(pub usize);
|
||||
pub struct FoldOffset(pub MultiBufferOffset);
|
||||
|
||||
impl FoldOffset {
|
||||
pub fn to_point(self, snapshot: &FoldSnapshot) -> FoldPoint {
|
||||
@@ -1493,7 +1499,7 @@ impl FoldOffset {
|
||||
let overshoot = if item.is_none_or(|t| t.is_fold()) {
|
||||
Point::new(0, (self.0 - start.0.0) as u32)
|
||||
} else {
|
||||
let inlay_offset = start.1.input.len + self.0 - start.0.0;
|
||||
let inlay_offset = start.1.input.len + (self - start.0);
|
||||
let inlay_point = snapshot.inlay_snapshot.to_point(InlayOffset(inlay_offset));
|
||||
inlay_point.0 - start.1.input.lines
|
||||
};
|
||||
@@ -1505,7 +1511,7 @@ impl FoldOffset {
|
||||
let (start, _, _) = snapshot
|
||||
.transforms
|
||||
.find::<Dimensions<FoldOffset, InlayOffset>, _>((), &self, Bias::Right);
|
||||
let overshoot = self.0 - start.0.0;
|
||||
let overshoot = self - start.0;
|
||||
InlayOffset(start.1.0 + overshoot)
|
||||
}
|
||||
}
|
||||
@@ -1518,17 +1524,46 @@ impl Add for FoldOffset {
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for FoldOffset {
|
||||
type Output = <MultiBufferOffset as Sub>::Output;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
self.0 - rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> SubAssign<T> for FoldOffset
|
||||
where
|
||||
MultiBufferOffset: SubAssign<T>,
|
||||
{
|
||||
fn sub_assign(&mut self, rhs: T) {
|
||||
self.0 -= rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Add<T> for FoldOffset
|
||||
where
|
||||
MultiBufferOffset: Add<T, Output = MultiBufferOffset>,
|
||||
{
|
||||
type Output = Self;
|
||||
|
||||
fn add(self, rhs: T) -> Self::Output {
|
||||
Self(self.0 + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for FoldOffset {
|
||||
fn add_assign(&mut self, rhs: Self) {
|
||||
self.0 += rhs.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl Sub for FoldOffset {
|
||||
type Output = Self;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 - rhs.0)
|
||||
impl<T> AddAssign<T> for FoldOffset
|
||||
where
|
||||
MultiBufferOffset: AddAssign<T>,
|
||||
{
|
||||
fn add_assign(&mut self, rhs: T) {
|
||||
self.0 += rhs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1538,7 +1573,7 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for FoldOffset {
|
||||
}
|
||||
|
||||
fn add_summary(&mut self, summary: &'a TransformSummary, _: ()) {
|
||||
self.0 += &summary.output.len;
|
||||
self.0 += summary.output.len;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1558,7 +1593,7 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayOffset {
|
||||
}
|
||||
|
||||
fn add_summary(&mut self, summary: &'a TransformSummary, _: ()) {
|
||||
self.0 += &summary.input.len;
|
||||
self.0 += summary.input.len;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1596,12 +1631,12 @@ mod tests {
|
||||
edits,
|
||||
&[
|
||||
FoldEdit {
|
||||
old: FoldOffset(2)..FoldOffset(16),
|
||||
new: FoldOffset(2)..FoldOffset(5),
|
||||
old: FoldOffset(MultiBufferOffset(2))..FoldOffset(MultiBufferOffset(16)),
|
||||
new: FoldOffset(MultiBufferOffset(2))..FoldOffset(MultiBufferOffset(5)),
|
||||
},
|
||||
FoldEdit {
|
||||
old: FoldOffset(18)..FoldOffset(29),
|
||||
new: FoldOffset(7)..FoldOffset(10)
|
||||
old: FoldOffset(MultiBufferOffset(18))..FoldOffset(MultiBufferOffset(29)),
|
||||
new: FoldOffset(MultiBufferOffset(7))..FoldOffset(MultiBufferOffset(10)),
|
||||
},
|
||||
]
|
||||
);
|
||||
@@ -1626,12 +1661,12 @@ mod tests {
|
||||
edits,
|
||||
&[
|
||||
FoldEdit {
|
||||
old: FoldOffset(0)..FoldOffset(1),
|
||||
new: FoldOffset(0)..FoldOffset(3),
|
||||
old: FoldOffset(MultiBufferOffset(0))..FoldOffset(MultiBufferOffset(1)),
|
||||
new: FoldOffset(MultiBufferOffset(0))..FoldOffset(MultiBufferOffset(3)),
|
||||
},
|
||||
FoldEdit {
|
||||
old: FoldOffset(6)..FoldOffset(6),
|
||||
new: FoldOffset(8)..FoldOffset(11),
|
||||
old: FoldOffset(MultiBufferOffset(6))..FoldOffset(MultiBufferOffset(6)),
|
||||
new: FoldOffset(MultiBufferOffset(8))..FoldOffset(MultiBufferOffset(11)),
|
||||
},
|
||||
]
|
||||
);
|
||||
@@ -1668,15 +1703,24 @@ mod tests {
|
||||
let mut map = FoldMap::new(inlay_snapshot.clone()).0;
|
||||
|
||||
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
|
||||
writer.fold(vec![(5..8, FoldPlaceholder::test())]);
|
||||
writer.fold(vec![(
|
||||
MultiBufferOffset(5)..MultiBufferOffset(8),
|
||||
FoldPlaceholder::test(),
|
||||
)]);
|
||||
let (snapshot, _) = map.read(inlay_snapshot.clone(), vec![]);
|
||||
assert_eq!(snapshot.text(), "abcde⋯ijkl");
|
||||
|
||||
// Create an fold adjacent to the start of the first fold.
|
||||
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
|
||||
writer.fold(vec![
|
||||
(0..1, FoldPlaceholder::test()),
|
||||
(2..5, FoldPlaceholder::test()),
|
||||
(
|
||||
MultiBufferOffset(0)..MultiBufferOffset(1),
|
||||
FoldPlaceholder::test(),
|
||||
),
|
||||
(
|
||||
MultiBufferOffset(2)..MultiBufferOffset(5),
|
||||
FoldPlaceholder::test(),
|
||||
),
|
||||
]);
|
||||
let (snapshot, _) = map.read(inlay_snapshot.clone(), vec![]);
|
||||
assert_eq!(snapshot.text(), "⋯b⋯ijkl");
|
||||
@@ -1684,8 +1728,14 @@ mod tests {
|
||||
// Create an fold adjacent to the end of the first fold.
|
||||
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
|
||||
writer.fold(vec![
|
||||
(11..11, FoldPlaceholder::test()),
|
||||
(8..10, FoldPlaceholder::test()),
|
||||
(
|
||||
MultiBufferOffset(11)..MultiBufferOffset(11),
|
||||
FoldPlaceholder::test(),
|
||||
),
|
||||
(
|
||||
MultiBufferOffset(8)..MultiBufferOffset(10),
|
||||
FoldPlaceholder::test(),
|
||||
),
|
||||
]);
|
||||
let (snapshot, _) = map.read(inlay_snapshot.clone(), vec![]);
|
||||
assert_eq!(snapshot.text(), "⋯b⋯kl");
|
||||
@@ -1697,15 +1747,25 @@ mod tests {
|
||||
// Create two adjacent folds.
|
||||
let (mut writer, _, _) = map.write(inlay_snapshot.clone(), vec![]);
|
||||
writer.fold(vec![
|
||||
(0..2, FoldPlaceholder::test()),
|
||||
(2..5, FoldPlaceholder::test()),
|
||||
(
|
||||
MultiBufferOffset(0)..MultiBufferOffset(2),
|
||||
FoldPlaceholder::test(),
|
||||
),
|
||||
(
|
||||
MultiBufferOffset(2)..MultiBufferOffset(5),
|
||||
FoldPlaceholder::test(),
|
||||
),
|
||||
]);
|
||||
let (snapshot, _) = map.read(inlay_snapshot, vec![]);
|
||||
assert_eq!(snapshot.text(), "⋯fghijkl");
|
||||
|
||||
// Edit within one of the folds.
|
||||
let buffer_snapshot = buffer.update(cx, |buffer, cx| {
|
||||
buffer.edit([(0..1, "12345")], None, cx);
|
||||
buffer.edit(
|
||||
[(MultiBufferOffset(0)..MultiBufferOffset(1), "12345")],
|
||||
None,
|
||||
cx,
|
||||
);
|
||||
buffer.snapshot(cx)
|
||||
});
|
||||
let (inlay_snapshot, inlay_edits) =
|
||||
@@ -1849,7 +1909,7 @@ mod tests {
|
||||
for fold_range in map.merged_folds().into_iter().rev() {
|
||||
let fold_inlay_start = inlay_snapshot.to_inlay_offset(fold_range.start);
|
||||
let fold_inlay_end = inlay_snapshot.to_inlay_offset(fold_range.end);
|
||||
expected_text.replace_range(fold_inlay_start.0..fold_inlay_end.0, "⋯");
|
||||
expected_text.replace_range(fold_inlay_start.0.0..fold_inlay_end.0.0, "⋯");
|
||||
}
|
||||
|
||||
assert_eq!(snapshot.text(), expected_text);
|
||||
@@ -1898,7 +1958,7 @@ mod tests {
|
||||
.chars()
|
||||
.count();
|
||||
let mut fold_point = FoldPoint::new(0, 0);
|
||||
let mut fold_offset = FoldOffset(0);
|
||||
let mut fold_offset = FoldOffset(MultiBufferOffset(0));
|
||||
let mut char_column = 0;
|
||||
for c in expected_text.chars() {
|
||||
let inlay_point = fold_point.to_inlay_point(&snapshot);
|
||||
@@ -1944,18 +2004,18 @@ mod tests {
|
||||
|
||||
for _ in 0..5 {
|
||||
let mut start = snapshot.clip_offset(
|
||||
FoldOffset(rng.random_range(0..=snapshot.len().0)),
|
||||
FoldOffset(rng.random_range(MultiBufferOffset(0)..=snapshot.len().0)),
|
||||
Bias::Left,
|
||||
);
|
||||
let mut end = snapshot.clip_offset(
|
||||
FoldOffset(rng.random_range(0..=snapshot.len().0)),
|
||||
FoldOffset(rng.random_range(MultiBufferOffset(0)..=snapshot.len().0)),
|
||||
Bias::Right,
|
||||
);
|
||||
if start > end {
|
||||
mem::swap(&mut start, &mut end);
|
||||
}
|
||||
|
||||
let text = &expected_text[start.0..end.0];
|
||||
let text = &expected_text[start.0.0..end.0.0];
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.chunks(start..end, false, Highlights::default())
|
||||
@@ -2004,9 +2064,12 @@ mod tests {
|
||||
}
|
||||
|
||||
for _ in 0..5 {
|
||||
let end =
|
||||
buffer_snapshot.clip_offset(rng.random_range(0..=buffer_snapshot.len()), Right);
|
||||
let start = buffer_snapshot.clip_offset(rng.random_range(0..=end), Left);
|
||||
let end = buffer_snapshot.clip_offset(
|
||||
rng.random_range(MultiBufferOffset(0)..=buffer_snapshot.len()),
|
||||
Right,
|
||||
);
|
||||
let start =
|
||||
buffer_snapshot.clip_offset(rng.random_range(MultiBufferOffset(0)..=end), Left);
|
||||
let expected_folds = map
|
||||
.snapshot
|
||||
.folds
|
||||
@@ -2046,7 +2109,7 @@ mod tests {
|
||||
let bytes = start.to_offset(&snapshot)..end.to_offset(&snapshot);
|
||||
assert_eq!(
|
||||
snapshot.text_summary_for_range(lines),
|
||||
TextSummary::from(&text[bytes.start.0..bytes.end.0])
|
||||
MBTextSummary::from(&text[bytes.start.0.0..bytes.end.0.0])
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2054,8 +2117,8 @@ mod tests {
|
||||
for (snapshot, edits) in snapshot_edits.drain(..) {
|
||||
let new_text = snapshot.text();
|
||||
for edit in edits {
|
||||
let old_bytes = edit.new.start.0..edit.new.start.0 + edit.old_len().0;
|
||||
let new_bytes = edit.new.start.0..edit.new.end.0;
|
||||
let old_bytes = edit.new.start.0.0..edit.new.start.0.0 + edit.old_len();
|
||||
let new_bytes = edit.new.start.0.0..edit.new.end.0.0;
|
||||
text.replace_range(old_bytes, &new_text[new_bytes]);
|
||||
}
|
||||
|
||||
@@ -2126,7 +2189,7 @@ mod tests {
|
||||
|
||||
// Get all chunks and verify their bitmaps
|
||||
let chunks = snapshot.chunks(
|
||||
FoldOffset(0)..FoldOffset(snapshot.len().0),
|
||||
FoldOffset(MultiBufferOffset(0))..FoldOffset(snapshot.len().0),
|
||||
false,
|
||||
Highlights::default(),
|
||||
);
|
||||
@@ -2195,7 +2258,7 @@ mod tests {
|
||||
}
|
||||
|
||||
impl FoldMap {
|
||||
fn merged_folds(&self) -> Vec<Range<usize>> {
|
||||
fn merged_folds(&self) -> Vec<Range<MultiBufferOffset>> {
|
||||
let inlay_snapshot = self.snapshot.inlay_snapshot.clone();
|
||||
let buffer = &inlay_snapshot.buffer;
|
||||
let mut folds = self.snapshot.folds.items(buffer);
|
||||
@@ -2236,8 +2299,12 @@ mod tests {
|
||||
let buffer = &inlay_snapshot.buffer;
|
||||
let mut to_unfold = Vec::new();
|
||||
for _ in 0..rng.random_range(1..=3) {
|
||||
let end = buffer.clip_offset(rng.random_range(0..=buffer.len()), Right);
|
||||
let start = buffer.clip_offset(rng.random_range(0..=end), Left);
|
||||
let end = buffer.clip_offset(
|
||||
rng.random_range(MultiBufferOffset(0)..=buffer.len()),
|
||||
Right,
|
||||
);
|
||||
let start =
|
||||
buffer.clip_offset(rng.random_range(MultiBufferOffset(0)..=end), Left);
|
||||
to_unfold.push(start..end);
|
||||
}
|
||||
let inclusive = rng.random();
|
||||
@@ -2252,8 +2319,12 @@ mod tests {
|
||||
let buffer = &inlay_snapshot.buffer;
|
||||
let mut to_fold = Vec::new();
|
||||
for _ in 0..rng.random_range(1..=2) {
|
||||
let end = buffer.clip_offset(rng.random_range(0..=buffer.len()), Right);
|
||||
let start = buffer.clip_offset(rng.random_range(0..=end), Left);
|
||||
let end = buffer.clip_offset(
|
||||
rng.random_range(MultiBufferOffset(0)..=buffer.len()),
|
||||
Right,
|
||||
);
|
||||
let start =
|
||||
buffer.clip_offset(rng.random_range(MultiBufferOffset(0)..=end), Left);
|
||||
to_fold.push((start..end, FoldPlaceholder::test()));
|
||||
}
|
||||
log::info!("folding {:?}", to_fold);
|
||||
|
||||
@@ -4,7 +4,10 @@ use crate::{
|
||||
};
|
||||
use collections::BTreeSet;
|
||||
use language::{Chunk, Edit, Point, TextSummary};
|
||||
use multi_buffer::{MultiBufferRow, MultiBufferRows, MultiBufferSnapshot, RowInfo, ToOffset};
|
||||
use multi_buffer::{
|
||||
MBTextSummary, MultiBufferOffset, MultiBufferRow, MultiBufferRows, MultiBufferSnapshot,
|
||||
RowInfo, ToOffset,
|
||||
};
|
||||
use project::InlayId;
|
||||
use std::{
|
||||
cmp,
|
||||
@@ -42,7 +45,7 @@ impl std::ops::Deref for InlaySnapshot {
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum Transform {
|
||||
Isomorphic(TextSummary),
|
||||
Isomorphic(MBTextSummary),
|
||||
Inlay(Inlay),
|
||||
}
|
||||
|
||||
@@ -56,8 +59,8 @@ impl sum_tree::Item for Transform {
|
||||
output: *summary,
|
||||
},
|
||||
Transform::Inlay(inlay) => TransformSummary {
|
||||
input: TextSummary::default(),
|
||||
output: inlay.text().summary(),
|
||||
input: MBTextSummary::default(),
|
||||
output: MBTextSummary::from(inlay.text().summary()),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -65,8 +68,8 @@ impl sum_tree::Item for Transform {
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct TransformSummary {
|
||||
input: TextSummary,
|
||||
output: TextSummary,
|
||||
input: MBTextSummary,
|
||||
output: MBTextSummary,
|
||||
}
|
||||
|
||||
impl sum_tree::ContextLessSummary for TransformSummary {
|
||||
@@ -75,15 +78,15 @@ impl sum_tree::ContextLessSummary for TransformSummary {
|
||||
}
|
||||
|
||||
fn add_summary(&mut self, other: &Self) {
|
||||
self.input += &other.input;
|
||||
self.output += &other.output;
|
||||
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);
|
||||
pub struct InlayOffset(pub MultiBufferOffset);
|
||||
|
||||
impl Add for InlayOffset {
|
||||
type Output = Self;
|
||||
@@ -94,10 +97,30 @@ impl Add for InlayOffset {
|
||||
}
|
||||
|
||||
impl Sub for InlayOffset {
|
||||
type Output = Self;
|
||||
type Output = <MultiBufferOffset as Sub>::Output;
|
||||
|
||||
fn sub(self, rhs: Self) -> Self::Output {
|
||||
Self(self.0 - rhs.0)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,9 +130,12 @@ impl AddAssign for InlayOffset {
|
||||
}
|
||||
}
|
||||
|
||||
impl SubAssign for InlayOffset {
|
||||
fn sub_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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +145,7 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayOffset {
|
||||
}
|
||||
|
||||
fn add_summary(&mut self, summary: &'a TransformSummary, _: ()) {
|
||||
self.0 += &summary.output.len;
|
||||
self.0 += summary.output.len;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,13 +178,13 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for InlayPoint {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> sum_tree::Dimension<'a, TransformSummary> for usize {
|
||||
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;
|
||||
*self += summary.input.len;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +207,7 @@ pub struct InlayBufferRows<'a> {
|
||||
}
|
||||
|
||||
pub struct InlayChunks<'a> {
|
||||
transforms: Cursor<'a, 'static, Transform, Dimensions<InlayOffset, usize>>,
|
||||
transforms: Cursor<'a, 'static, Transform, Dimensions<InlayOffset, MultiBufferOffset>>,
|
||||
buffer_chunks: CustomHighlightsChunks<'a>,
|
||||
buffer_chunk: Option<Chunk<'a>>,
|
||||
inlay_chunks: Option<text::ChunkWithBitmaps<'a>>,
|
||||
@@ -332,12 +358,12 @@ impl<'a> Iterator for InlayChunks<'a> {
|
||||
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 {
|
||||
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.0;
|
||||
next_inlay_highlight_endpoint = range.end - offset_in_inlay;
|
||||
highlight_style = highlight_style
|
||||
.map(|highlight| highlight.highlight(*style))
|
||||
.or_else(|| Some(*style));
|
||||
@@ -350,7 +376,7 @@ 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;
|
||||
let chunks = inlay.text().chunks_in_range(start.0..end.0);
|
||||
let chunks = inlay.text().chunks_in_range(start..end);
|
||||
text::ChunkWithBitmaps(chunks)
|
||||
});
|
||||
let ChunkBitmaps {
|
||||
@@ -488,7 +514,7 @@ impl InlayMap {
|
||||
pub fn sync(
|
||||
&mut self,
|
||||
buffer_snapshot: MultiBufferSnapshot,
|
||||
mut buffer_edits: Vec<text::Edit<usize>>,
|
||||
mut buffer_edits: Vec<text::Edit<MultiBufferOffset>>,
|
||||
) -> (InlaySnapshot, Vec<InlayEdit>) {
|
||||
let snapshot = &mut self.snapshot;
|
||||
|
||||
@@ -519,7 +545,7 @@ impl InlayMap {
|
||||
let mut new_transforms = SumTree::default();
|
||||
let mut cursor = snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<usize, InlayOffset>>(());
|
||||
.cursor::<Dimensions<MultiBufferOffset, 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), ());
|
||||
@@ -531,11 +557,9 @@ impl InlayMap {
|
||||
}
|
||||
|
||||
// Remove all the inlays and transforms contained by the edit.
|
||||
let old_start =
|
||||
cursor.start().1 + InlayOffset(buffer_edit.old.start - cursor.start().0);
|
||||
let old_start = cursor.start().1 + (buffer_edit.old.start - cursor.start().0);
|
||||
cursor.seek(&buffer_edit.old.end, Bias::Right);
|
||||
let old_end =
|
||||
cursor.start().1 + InlayOffset(buffer_edit.old.end - cursor.start().0);
|
||||
let old_end = cursor.start().1 + (buffer_edit.old.end - cursor.start().0);
|
||||
|
||||
// Push the unchanged prefix.
|
||||
let prefix_start = new_transforms.summary().input.len;
|
||||
@@ -687,7 +711,10 @@ impl InlayMap {
|
||||
let snapshot = &mut self.snapshot;
|
||||
for i in 0..rng.random_range(1..=5) {
|
||||
if self.inlays.is_empty() || rng.random() {
|
||||
let position = snapshot.buffer.random_byte_range(0, rng).start;
|
||||
let position = snapshot
|
||||
.buffer
|
||||
.random_byte_range(MultiBufferOffset(0), rng)
|
||||
.start;
|
||||
let bias = if rng.random() {
|
||||
Bias::Left
|
||||
} else {
|
||||
@@ -740,9 +767,11 @@ impl InlayMap {
|
||||
|
||||
impl InlaySnapshot {
|
||||
pub fn to_point(&self, offset: InlayOffset) -> InlayPoint {
|
||||
let (start, _, item) = self
|
||||
.transforms
|
||||
.find::<Dimensions<InlayOffset, InlayPoint, usize>, _>((), &offset, Bias::Right);
|
||||
let (start, _, item) = self.transforms.find::<Dimensions<
|
||||
InlayOffset,
|
||||
InlayPoint,
|
||||
MultiBufferOffset,
|
||||
>, _>((), &offset, Bias::Right);
|
||||
let overshoot = offset.0 - start.0.0;
|
||||
match item {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
@@ -801,22 +830,24 @@ impl InlaySnapshot {
|
||||
None => self.buffer.max_point(),
|
||||
}
|
||||
}
|
||||
pub fn to_buffer_offset(&self, offset: InlayOffset) -> usize {
|
||||
let (start, _, item) =
|
||||
self.transforms
|
||||
.find::<Dimensions<InlayOffset, usize>, _>((), &offset, Bias::Right);
|
||||
pub fn to_buffer_offset(&self, offset: InlayOffset) -> MultiBufferOffset {
|
||||
let (start, _, item) = self
|
||||
.transforms
|
||||
.find::<Dimensions<InlayOffset, MultiBufferOffset>, _>((), &offset, Bias::Right);
|
||||
match item {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let overshoot = offset - start.0;
|
||||
start.1 + overshoot.0
|
||||
start.1 + overshoot
|
||||
}
|
||||
Some(Transform::Inlay(_)) => start.1,
|
||||
None => self.buffer.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_inlay_offset(&self, offset: usize) -> InlayOffset {
|
||||
let mut cursor = self.transforms.cursor::<Dimensions<usize, InlayOffset>>(());
|
||||
pub fn to_inlay_offset(&self, offset: MultiBufferOffset) -> InlayOffset {
|
||||
let mut cursor = self
|
||||
.transforms
|
||||
.cursor::<Dimensions<MultiBufferOffset, InlayOffset>>(());
|
||||
cursor.seek(&offset, Bias::Left);
|
||||
loop {
|
||||
match cursor.item() {
|
||||
@@ -973,14 +1004,16 @@ impl InlaySnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text_summary(&self) -> TextSummary {
|
||||
pub fn text_summary(&self) -> MBTextSummary {
|
||||
self.transforms.summary().output
|
||||
}
|
||||
|
||||
pub fn text_summary_for_range(&self, range: Range<InlayOffset>) -> TextSummary {
|
||||
let mut summary = TextSummary::default();
|
||||
pub fn text_summary_for_range(&self, range: Range<InlayOffset>) -> MBTextSummary {
|
||||
let mut summary = MBTextSummary::default();
|
||||
|
||||
let mut cursor = self.transforms.cursor::<Dimensions<InlayOffset, usize>>(());
|
||||
let mut cursor = self
|
||||
.transforms
|
||||
.cursor::<Dimensions<InlayOffset, MultiBufferOffset>>(());
|
||||
cursor.seek(&range.start, Bias::Right);
|
||||
|
||||
let overshoot = range.start.0 - cursor.start().0.0;
|
||||
@@ -996,7 +1029,12 @@ impl InlaySnapshot {
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
let suffix_start = overshoot;
|
||||
let suffix_end = cmp::min(cursor.end().0, range.end).0 - cursor.start().0.0;
|
||||
summary = inlay.text().cursor(suffix_start).summary(suffix_end);
|
||||
summary = MBTextSummary::from(
|
||||
inlay
|
||||
.text()
|
||||
.cursor(suffix_start)
|
||||
.summary::<TextSummary>(suffix_end),
|
||||
);
|
||||
cursor.next();
|
||||
}
|
||||
None => {}
|
||||
@@ -1014,7 +1052,7 @@ impl InlaySnapshot {
|
||||
let prefix_end = prefix_start + overshoot;
|
||||
summary += self
|
||||
.buffer
|
||||
.text_summary_for_range::<TextSummary, _>(prefix_start..prefix_end);
|
||||
.text_summary_for_range::<MBTextSummary, _>(prefix_start..prefix_end);
|
||||
}
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
let prefix_end = overshoot;
|
||||
@@ -1070,7 +1108,9 @@ impl InlaySnapshot {
|
||||
language_aware: bool,
|
||||
highlights: Highlights<'a>,
|
||||
) -> InlayChunks<'a> {
|
||||
let mut cursor = self.transforms.cursor::<Dimensions<InlayOffset, usize>>(());
|
||||
let mut cursor = self
|
||||
.transforms
|
||||
.cursor::<Dimensions<InlayOffset, MultiBufferOffset>>(());
|
||||
cursor.seek(&range.start, Bias::Right);
|
||||
|
||||
let buffer_range = self.to_buffer_offset(range.start)..self.to_buffer_offset(range.end);
|
||||
@@ -1122,8 +1162,8 @@ impl InlaySnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
fn push_isomorphic(sum_tree: &mut SumTree<Transform>, summary: TextSummary) {
|
||||
if summary.len == 0 {
|
||||
fn push_isomorphic(sum_tree: &mut SumTree<Transform>, summary: MBTextSummary) {
|
||||
if summary.len == MultiBufferOffset(0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1279,7 +1319,10 @@ mod tests {
|
||||
&[],
|
||||
vec![Inlay::mock_hint(
|
||||
post_inc(&mut next_inlay_id),
|
||||
buffer.read(cx).snapshot(cx).anchor_after(3),
|
||||
buffer
|
||||
.read(cx)
|
||||
.snapshot(cx)
|
||||
.anchor_after(MultiBufferOffset(3)),
|
||||
"|123|",
|
||||
)],
|
||||
);
|
||||
@@ -1335,7 +1378,15 @@ mod tests {
|
||||
|
||||
// Edits before or after the inlay should not affect it.
|
||||
buffer.update(cx, |buffer, cx| {
|
||||
buffer.edit([(2..3, "x"), (3..3, "y"), (4..4, "z")], None, cx)
|
||||
buffer.edit(
|
||||
[
|
||||
(MultiBufferOffset(2)..MultiBufferOffset(3), "x"),
|
||||
(MultiBufferOffset(3)..MultiBufferOffset(3), "y"),
|
||||
(MultiBufferOffset(4)..MultiBufferOffset(4), "z"),
|
||||
],
|
||||
None,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (inlay_snapshot, _) = inlay_map.sync(
|
||||
buffer.read(cx).snapshot(cx),
|
||||
@@ -1344,7 +1395,13 @@ mod tests {
|
||||
assert_eq!(inlay_snapshot.text(), "abxy|123|dzefghi");
|
||||
|
||||
// An edit surrounding the inlay should invalidate it.
|
||||
buffer.update(cx, |buffer, cx| buffer.edit([(4..5, "D")], None, cx));
|
||||
buffer.update(cx, |buffer, cx| {
|
||||
buffer.edit(
|
||||
[(MultiBufferOffset(4)..MultiBufferOffset(5), "D")],
|
||||
None,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (inlay_snapshot, _) = inlay_map.sync(
|
||||
buffer.read(cx).snapshot(cx),
|
||||
buffer_edits.consume().into_inner(),
|
||||
@@ -1356,12 +1413,18 @@ mod tests {
|
||||
vec![
|
||||
Inlay::mock_hint(
|
||||
post_inc(&mut next_inlay_id),
|
||||
buffer.read(cx).snapshot(cx).anchor_before(3),
|
||||
buffer
|
||||
.read(cx)
|
||||
.snapshot(cx)
|
||||
.anchor_before(MultiBufferOffset(3)),
|
||||
"|123|",
|
||||
),
|
||||
Inlay::edit_prediction(
|
||||
post_inc(&mut next_inlay_id),
|
||||
buffer.read(cx).snapshot(cx).anchor_after(3),
|
||||
buffer
|
||||
.read(cx)
|
||||
.snapshot(cx)
|
||||
.anchor_after(MultiBufferOffset(3)),
|
||||
"|456|",
|
||||
),
|
||||
],
|
||||
@@ -1369,7 +1432,13 @@ mod tests {
|
||||
assert_eq!(inlay_snapshot.text(), "abx|123||456|yDzefghi");
|
||||
|
||||
// Edits ending where the inlay starts should not move it if it has a left bias.
|
||||
buffer.update(cx, |buffer, cx| buffer.edit([(3..3, "JKL")], None, cx));
|
||||
buffer.update(cx, |buffer, cx| {
|
||||
buffer.edit(
|
||||
[(MultiBufferOffset(3)..MultiBufferOffset(3), "JKL")],
|
||||
None,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
let (inlay_snapshot, _) = inlay_map.sync(
|
||||
buffer.read(cx).snapshot(cx),
|
||||
buffer_edits.consume().into_inner(),
|
||||
@@ -1571,17 +1640,26 @@ mod tests {
|
||||
vec![
|
||||
Inlay::mock_hint(
|
||||
post_inc(&mut next_inlay_id),
|
||||
buffer.read(cx).snapshot(cx).anchor_before(0),
|
||||
buffer
|
||||
.read(cx)
|
||||
.snapshot(cx)
|
||||
.anchor_before(MultiBufferOffset(0)),
|
||||
"|123|\n",
|
||||
),
|
||||
Inlay::mock_hint(
|
||||
post_inc(&mut next_inlay_id),
|
||||
buffer.read(cx).snapshot(cx).anchor_before(4),
|
||||
buffer
|
||||
.read(cx)
|
||||
.snapshot(cx)
|
||||
.anchor_before(MultiBufferOffset(4)),
|
||||
"|456|",
|
||||
),
|
||||
Inlay::edit_prediction(
|
||||
post_inc(&mut next_inlay_id),
|
||||
buffer.read(cx).snapshot(cx).anchor_before(7),
|
||||
buffer
|
||||
.read(cx)
|
||||
.snapshot(cx)
|
||||
.anchor_before(MultiBufferOffset(7)),
|
||||
"\n|567|\n",
|
||||
),
|
||||
],
|
||||
@@ -1658,7 +1736,7 @@ mod tests {
|
||||
.collect::<Vec<_>>();
|
||||
let mut expected_text = Rope::from(&buffer_snapshot.text());
|
||||
for (offset, inlay) in inlays.iter().rev() {
|
||||
expected_text.replace(*offset..*offset, &inlay.text().to_string());
|
||||
expected_text.replace(offset.0..offset.0, &inlay.text().to_string());
|
||||
}
|
||||
assert_eq!(inlay_snapshot.text(), expected_text.to_string());
|
||||
|
||||
@@ -1681,7 +1759,7 @@ mod tests {
|
||||
let mut text_highlights = TextHighlights::default();
|
||||
let text_highlight_count = rng.random_range(0_usize..10);
|
||||
let mut text_highlight_ranges = (0..text_highlight_count)
|
||||
.map(|_| buffer_snapshot.random_byte_range(0, &mut rng))
|
||||
.map(|_| buffer_snapshot.random_byte_range(MultiBufferOffset(0), &mut rng))
|
||||
.collect::<Vec<_>>();
|
||||
text_highlight_ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
|
||||
log::info!("highlighting text ranges {text_highlight_ranges:?}");
|
||||
@@ -1744,12 +1822,13 @@ mod tests {
|
||||
}
|
||||
|
||||
for _ in 0..5 {
|
||||
let mut end = rng.random_range(0..=inlay_snapshot.len().0);
|
||||
let mut end = rng.random_range(0..=inlay_snapshot.len().0.0);
|
||||
end = expected_text.clip_offset(end, Bias::Right);
|
||||
let mut start = rng.random_range(0..=end);
|
||||
start = expected_text.clip_offset(start, Bias::Right);
|
||||
|
||||
let range = InlayOffset(start)..InlayOffset(end);
|
||||
let range =
|
||||
InlayOffset(MultiBufferOffset(start))..InlayOffset(MultiBufferOffset(end));
|
||||
log::info!("calling inlay_snapshot.chunks({range:?})");
|
||||
let actual_text = inlay_snapshot
|
||||
.chunks(
|
||||
@@ -1771,25 +1850,27 @@ mod tests {
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
inlay_snapshot.text_summary_for_range(InlayOffset(start)..InlayOffset(end)),
|
||||
expected_text.slice(start..end).summary()
|
||||
inlay_snapshot.text_summary_for_range(
|
||||
InlayOffset(MultiBufferOffset(start))..InlayOffset(MultiBufferOffset(end))
|
||||
),
|
||||
MBTextSummary::from(expected_text.slice(start..end).summary())
|
||||
);
|
||||
}
|
||||
|
||||
for edit in inlay_edits {
|
||||
prev_inlay_text.replace_range(
|
||||
edit.new.start.0..edit.new.start.0 + edit.old_len().0,
|
||||
&inlay_snapshot.text()[edit.new.start.0..edit.new.end.0],
|
||||
edit.new.start.0.0..edit.new.start.0.0 + edit.old_len(),
|
||||
&inlay_snapshot.text()[edit.new.start.0.0..edit.new.end.0.0],
|
||||
);
|
||||
}
|
||||
assert_eq!(prev_inlay_text, inlay_snapshot.text());
|
||||
|
||||
assert_eq!(expected_text.max_point(), inlay_snapshot.max_point().0);
|
||||
assert_eq!(expected_text.len(), inlay_snapshot.len().0);
|
||||
assert_eq!(expected_text.len(), inlay_snapshot.len().0.0);
|
||||
|
||||
let mut buffer_point = Point::default();
|
||||
let mut inlay_point = inlay_snapshot.to_inlay_point(buffer_point);
|
||||
let mut buffer_chars = buffer_snapshot.chars_at(0);
|
||||
let mut buffer_chars = buffer_snapshot.chars_at(MultiBufferOffset(0));
|
||||
loop {
|
||||
// Ensure conversion from buffer coordinates to inlay coordinates
|
||||
// is consistent.
|
||||
@@ -1930,7 +2011,7 @@ mod tests {
|
||||
|
||||
// Get all chunks and verify their bitmaps
|
||||
let chunks = snapshot.chunks(
|
||||
InlayOffset(0)..InlayOffset(snapshot.len().0),
|
||||
InlayOffset(MultiBufferOffset(0))..snapshot.len(),
|
||||
false,
|
||||
Highlights::default(),
|
||||
);
|
||||
@@ -2064,7 +2145,7 @@ mod tests {
|
||||
// Collect chunks - this previously would panic
|
||||
let chunks: Vec<_> = inlay_snapshot
|
||||
.chunks(
|
||||
InlayOffset(0)..InlayOffset(inlay_snapshot.len().0),
|
||||
InlayOffset(MultiBufferOffset(0))..inlay_snapshot.len(),
|
||||
false,
|
||||
highlights,
|
||||
)
|
||||
@@ -2178,7 +2259,7 @@ mod tests {
|
||||
|
||||
let chunks: Vec<_> = inlay_snapshot
|
||||
.chunks(
|
||||
InlayOffset(0)..InlayOffset(inlay_snapshot.len().0),
|
||||
InlayOffset(MultiBufferOffset(0))..inlay_snapshot.len(),
|
||||
false,
|
||||
highlights,
|
||||
)
|
||||
|
||||
@@ -648,6 +648,7 @@ mod tests {
|
||||
inlay_map::InlayMap,
|
||||
},
|
||||
};
|
||||
use multi_buffer::MultiBufferOffset;
|
||||
use rand::{Rng, prelude::StdRng};
|
||||
use util;
|
||||
|
||||
@@ -1156,7 +1157,7 @@ mod tests {
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot);
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let chunks = fold_snapshot.chunks(
|
||||
FoldOffset(0)..fold_snapshot.len(),
|
||||
FoldOffset(MultiBufferOffset(0))..fold_snapshot.len(),
|
||||
false,
|
||||
Default::default(),
|
||||
);
|
||||
@@ -1318,7 +1319,7 @@ mod tests {
|
||||
let (_, inlay_snapshot) = InlayMap::new(buffer_snapshot);
|
||||
let (_, fold_snapshot) = FoldMap::new(inlay_snapshot);
|
||||
let chunks = fold_snapshot.chunks(
|
||||
FoldOffset(0)..fold_snapshot.len(),
|
||||
FoldOffset(MultiBufferOffset(0))..fold_snapshot.len(),
|
||||
false,
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user