sum_tree: Implement recursive Sumtree::find, use it over Cursor::seek if possible (#40700)
Reduces peak stack usage in these functions and should generally be a
bit performant.
Display map benchmark results
```
To tab point/to_tab_point/1024
time: [531.40 ns 532.10 ns 532.97 ns]
change: [-2.1824% -2.0054% -1.8125%] (p = 0.00 < 0.05)
Performance has improved.
Found 1 outliers among 100 measurements (1.00%)
1 (1.00%) high severe
To fold point/to_fold_point/1024
time: [530.81 ns 531.30 ns 531.80 ns]
change: [-2.0295% -1.9054% -1.7716%] (p = 0.00 < 0.05)
Performance has improved.
Found 3 outliers among 100 measurements (3.00%)
2 (2.00%) high mild
1 (1.00%) high severe
```
Release Notes:
- N/A *or* Added/Fixed/Improved ...
This commit is contained in:
@@ -1521,10 +1521,11 @@ impl BlockSnapshot {
|
||||
}
|
||||
|
||||
pub(super) fn line_len(&self, row: BlockRow) -> u32 {
|
||||
let mut cursor = self.transforms.cursor::<Dimensions<BlockRow, WrapRow>>(());
|
||||
cursor.seek(&BlockRow(row.0), Bias::Right);
|
||||
if let Some(transform) = cursor.item() {
|
||||
let Dimensions(output_start, input_start, _) = cursor.start();
|
||||
let (start, _, item) =
|
||||
self.transforms
|
||||
.find::<Dimensions<BlockRow, WrapRow>, _>((), &row, Bias::Right);
|
||||
if let Some(transform) = item {
|
||||
let Dimensions(output_start, input_start, _) = start;
|
||||
let overshoot = row.0 - output_start.0;
|
||||
if transform.block.is_some() {
|
||||
0
|
||||
@@ -1539,15 +1540,13 @@ impl BlockSnapshot {
|
||||
}
|
||||
|
||||
pub(super) fn is_block_line(&self, row: BlockRow) -> bool {
|
||||
let mut cursor = self.transforms.cursor::<Dimensions<BlockRow, WrapRow>>(());
|
||||
cursor.seek(&row, Bias::Right);
|
||||
cursor.item().is_some_and(|t| t.block.is_some())
|
||||
let (_, _, item) = self.transforms.find::<BlockRow, _>((), &row, Bias::Right);
|
||||
item.is_some_and(|t| t.block.is_some())
|
||||
}
|
||||
|
||||
pub(super) fn is_folded_buffer_header(&self, row: BlockRow) -> bool {
|
||||
let mut cursor = self.transforms.cursor::<Dimensions<BlockRow, WrapRow>>(());
|
||||
cursor.seek(&row, Bias::Right);
|
||||
let Some(transform) = cursor.item() else {
|
||||
let (_, _, item) = self.transforms.find::<BlockRow, _>((), &row, Bias::Right);
|
||||
let Some(transform) = item else {
|
||||
return false;
|
||||
};
|
||||
matches!(transform.block, Some(Block::FoldedBuffer { .. }))
|
||||
@@ -1557,9 +1556,10 @@ impl BlockSnapshot {
|
||||
let wrap_point = self
|
||||
.wrap_snapshot
|
||||
.make_wrap_point(Point::new(row.0, 0), Bias::Left);
|
||||
let mut cursor = self.transforms.cursor::<Dimensions<WrapRow, BlockRow>>(());
|
||||
cursor.seek(&WrapRow(wrap_point.row()), Bias::Right);
|
||||
cursor.item().is_some_and(|transform| {
|
||||
let (_, _, item) =
|
||||
self.transforms
|
||||
.find::<WrapRow, _>((), &WrapRow(wrap_point.row()), Bias::Right);
|
||||
item.is_some_and(|transform| {
|
||||
transform
|
||||
.block
|
||||
.as_ref()
|
||||
@@ -1627,13 +1627,16 @@ impl BlockSnapshot {
|
||||
}
|
||||
|
||||
pub fn to_block_point(&self, wrap_point: WrapPoint) -> BlockPoint {
|
||||
let mut cursor = self.transforms.cursor::<Dimensions<WrapRow, BlockRow>>(());
|
||||
cursor.seek(&WrapRow(wrap_point.row()), Bias::Right);
|
||||
if let Some(transform) = cursor.item() {
|
||||
let (start, _, item) = self.transforms.find::<Dimensions<WrapRow, BlockRow>, _>(
|
||||
(),
|
||||
&WrapRow(wrap_point.row()),
|
||||
Bias::Right,
|
||||
);
|
||||
if let Some(transform) = item {
|
||||
if transform.block.is_some() {
|
||||
BlockPoint::new(cursor.start().1.0, 0)
|
||||
BlockPoint::new(start.1.0, 0)
|
||||
} else {
|
||||
let Dimensions(input_start_row, output_start_row, _) = cursor.start();
|
||||
let Dimensions(input_start_row, output_start_row, _) = start;
|
||||
let input_start = Point::new(input_start_row.0, 0);
|
||||
let output_start = Point::new(output_start_row.0, 0);
|
||||
let input_overshoot = wrap_point.0 - input_start;
|
||||
@@ -1645,26 +1648,29 @@ impl BlockSnapshot {
|
||||
}
|
||||
|
||||
pub fn to_wrap_point(&self, block_point: BlockPoint, bias: Bias) -> WrapPoint {
|
||||
let mut cursor = self.transforms.cursor::<Dimensions<BlockRow, WrapRow>>(());
|
||||
cursor.seek(&BlockRow(block_point.row), Bias::Right);
|
||||
if let Some(transform) = cursor.item() {
|
||||
let (start, end, item) = self.transforms.find::<Dimensions<BlockRow, WrapRow>, _>(
|
||||
(),
|
||||
&BlockRow(block_point.row),
|
||||
Bias::Right,
|
||||
);
|
||||
if let Some(transform) = item {
|
||||
match transform.block.as_ref() {
|
||||
Some(block) => {
|
||||
if block.place_below() {
|
||||
let wrap_row = cursor.start().1.0 - 1;
|
||||
let wrap_row = start.1.0 - 1;
|
||||
WrapPoint::new(wrap_row, self.wrap_snapshot.line_len(wrap_row))
|
||||
} else if block.place_above() {
|
||||
WrapPoint::new(cursor.start().1.0, 0)
|
||||
WrapPoint::new(start.1.0, 0)
|
||||
} else if bias == Bias::Left {
|
||||
WrapPoint::new(cursor.start().1.0, 0)
|
||||
WrapPoint::new(start.1.0, 0)
|
||||
} else {
|
||||
let wrap_row = cursor.end().1.0 - 1;
|
||||
let wrap_row = end.1.0 - 1;
|
||||
WrapPoint::new(wrap_row, self.wrap_snapshot.line_len(wrap_row))
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let overshoot = block_point.row - cursor.start().0.0;
|
||||
let wrap_row = cursor.start().1.0 + overshoot;
|
||||
let overshoot = block_point.row - start.0.0;
|
||||
let wrap_row = start.1.0 + overshoot;
|
||||
WrapPoint::new(wrap_row, block_point.column)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,28 +98,26 @@ impl FoldPoint {
|
||||
}
|
||||
|
||||
pub fn to_inlay_point(self, snapshot: &FoldSnapshot) -> InlayPoint {
|
||||
let mut cursor = snapshot
|
||||
let (start, _, _) = snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<FoldPoint, InlayPoint>>(());
|
||||
cursor.seek(&self, Bias::Right);
|
||||
let overshoot = self.0 - cursor.start().0.0;
|
||||
InlayPoint(cursor.start().1.0 + overshoot)
|
||||
.find::<Dimensions<FoldPoint, InlayPoint>, _>((), &self, Bias::Right);
|
||||
let overshoot = self.0 - start.0.0;
|
||||
InlayPoint(start.1.0 + overshoot)
|
||||
}
|
||||
|
||||
pub fn to_offset(self, snapshot: &FoldSnapshot) -> FoldOffset {
|
||||
let mut cursor = snapshot
|
||||
let (start, _, item) = snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<FoldPoint, TransformSummary>>(());
|
||||
cursor.seek(&self, Bias::Right);
|
||||
let overshoot = self.0 - cursor.start().1.output.lines;
|
||||
let mut offset = cursor.start().1.output.len;
|
||||
.find::<Dimensions<FoldPoint, TransformSummary>, _>((), &self, Bias::Right);
|
||||
let overshoot = self.0 - start.1.output.lines;
|
||||
let mut offset = start.1.output.len;
|
||||
if !overshoot.is_zero() {
|
||||
let transform = cursor.item().expect("display point out of range");
|
||||
let transform = item.expect("display point out of range");
|
||||
assert!(transform.placeholder.is_none());
|
||||
let end_inlay_offset = snapshot
|
||||
.inlay_snapshot
|
||||
.to_offset(InlayPoint(cursor.start().1.input.lines + overshoot));
|
||||
offset += end_inlay_offset.0 - cursor.start().1.input.len;
|
||||
.to_offset(InlayPoint(start.1.input.lines + overshoot));
|
||||
offset += end_inlay_offset.0 - start.1.input.len;
|
||||
}
|
||||
FoldOffset(offset)
|
||||
}
|
||||
@@ -706,19 +704,18 @@ impl FoldSnapshot {
|
||||
}
|
||||
|
||||
pub fn to_fold_point(&self, point: InlayPoint, bias: Bias) -> FoldPoint {
|
||||
let mut cursor = self
|
||||
let (start, end, item) = self
|
||||
.transforms
|
||||
.cursor::<Dimensions<InlayPoint, FoldPoint>>(());
|
||||
cursor.seek(&point, Bias::Right);
|
||||
if cursor.item().is_some_and(|t| t.is_fold()) {
|
||||
if bias == Bias::Left || point == cursor.start().0 {
|
||||
cursor.start().1
|
||||
.find::<Dimensions<InlayPoint, FoldPoint>, _>((), &point, Bias::Right);
|
||||
if item.is_some_and(|t| t.is_fold()) {
|
||||
if bias == Bias::Left || point == start.0 {
|
||||
start.1
|
||||
} else {
|
||||
cursor.end().1
|
||||
end.1
|
||||
}
|
||||
} else {
|
||||
let overshoot = point.0 - cursor.start().0.0;
|
||||
FoldPoint(cmp::min(cursor.start().1.0 + overshoot, cursor.end().1.0))
|
||||
let overshoot = point.0 - start.0.0;
|
||||
FoldPoint(cmp::min(start.1.0 + overshoot, end.1.0))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -787,9 +784,10 @@ impl FoldSnapshot {
|
||||
{
|
||||
let buffer_offset = offset.to_offset(&self.inlay_snapshot.buffer);
|
||||
let inlay_offset = self.inlay_snapshot.to_inlay_offset(buffer_offset);
|
||||
let mut cursor = self.transforms.cursor::<InlayOffset>(());
|
||||
cursor.seek(&inlay_offset, Bias::Right);
|
||||
cursor.item().is_some_and(|t| t.placeholder.is_some())
|
||||
let (_, _, item) = self
|
||||
.transforms
|
||||
.find::<InlayOffset, _>((), &inlay_offset, Bias::Right);
|
||||
item.is_some_and(|t| t.placeholder.is_some())
|
||||
}
|
||||
|
||||
pub fn is_line_folded(&self, buffer_row: MultiBufferRow) -> bool {
|
||||
@@ -891,23 +889,22 @@ impl FoldSnapshot {
|
||||
}
|
||||
|
||||
pub fn clip_point(&self, point: FoldPoint, bias: Bias) -> FoldPoint {
|
||||
let mut cursor = self
|
||||
let (start, end, item) = self
|
||||
.transforms
|
||||
.cursor::<Dimensions<FoldPoint, InlayPoint>>(());
|
||||
cursor.seek(&point, Bias::Right);
|
||||
if let Some(transform) = cursor.item() {
|
||||
let transform_start = cursor.start().0.0;
|
||||
.find::<Dimensions<FoldPoint, InlayPoint>, _>((), &point, Bias::Right);
|
||||
if let Some(transform) = item {
|
||||
let transform_start = start.0.0;
|
||||
if transform.placeholder.is_some() {
|
||||
if point.0 == transform_start || matches!(bias, Bias::Left) {
|
||||
FoldPoint(transform_start)
|
||||
} else {
|
||||
FoldPoint(cursor.end().0.0)
|
||||
FoldPoint(end.0.0)
|
||||
}
|
||||
} else {
|
||||
let overshoot = InlayPoint(point.0 - transform_start);
|
||||
let inlay_point = cursor.start().1 + overshoot;
|
||||
let inlay_point = start.1 + overshoot;
|
||||
let clipped_inlay_point = self.inlay_snapshot.clip_point(inlay_point, bias);
|
||||
FoldPoint(cursor.start().0.0 + (clipped_inlay_point - cursor.start().1).0)
|
||||
FoldPoint(start.0.0 + (clipped_inlay_point - start.1).0)
|
||||
}
|
||||
} else {
|
||||
FoldPoint(self.transforms.summary().output.lines)
|
||||
@@ -1480,28 +1477,26 @@ pub struct FoldOffset(pub usize);
|
||||
|
||||
impl FoldOffset {
|
||||
pub fn to_point(self, snapshot: &FoldSnapshot) -> FoldPoint {
|
||||
let mut cursor = snapshot
|
||||
let (start, _, item) = snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<FoldOffset, TransformSummary>>(());
|
||||
cursor.seek(&self, Bias::Right);
|
||||
let overshoot = if cursor.item().is_none_or(|t| t.is_fold()) {
|
||||
Point::new(0, (self.0 - cursor.start().0.0) as u32)
|
||||
.find::<Dimensions<FoldOffset, TransformSummary>, _>((), &self, Bias::Right);
|
||||
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 = cursor.start().1.input.len + self.0 - cursor.start().0.0;
|
||||
let inlay_offset = start.1.input.len + self.0 - start.0.0;
|
||||
let inlay_point = snapshot.inlay_snapshot.to_point(InlayOffset(inlay_offset));
|
||||
inlay_point.0 - cursor.start().1.input.lines
|
||||
inlay_point.0 - start.1.input.lines
|
||||
};
|
||||
FoldPoint(cursor.start().1.output.lines + overshoot)
|
||||
FoldPoint(start.1.output.lines + overshoot)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn to_inlay_offset(self, snapshot: &FoldSnapshot) -> InlayOffset {
|
||||
let mut cursor = snapshot
|
||||
let (start, _, _) = snapshot
|
||||
.transforms
|
||||
.cursor::<Dimensions<FoldOffset, InlayOffset>>(());
|
||||
cursor.seek(&self, Bias::Right);
|
||||
let overshoot = self.0 - cursor.start().0.0;
|
||||
InlayOffset(cursor.start().1.0 + overshoot)
|
||||
.find::<Dimensions<FoldOffset, InlayOffset>, _>((), &self, Bias::Right);
|
||||
let overshoot = self.0 - start.0.0;
|
||||
InlayOffset(start.1.0 + overshoot)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -825,22 +825,21 @@ impl InlayMap {
|
||||
|
||||
impl InlaySnapshot {
|
||||
pub fn to_point(&self, offset: InlayOffset) -> InlayPoint {
|
||||
let mut cursor = self
|
||||
let (start, _, item) = self
|
||||
.transforms
|
||||
.cursor::<Dimensions<InlayOffset, InlayPoint, usize>>(());
|
||||
cursor.seek(&offset, Bias::Right);
|
||||
let overshoot = offset.0 - cursor.start().0.0;
|
||||
match cursor.item() {
|
||||
.find::<Dimensions<InlayOffset, InlayPoint, usize>, _>((), &offset, Bias::Right);
|
||||
let overshoot = offset.0 - start.0.0;
|
||||
match item {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let buffer_offset_start = cursor.start().2;
|
||||
let buffer_offset_start = start.2;
|
||||
let buffer_offset_end = buffer_offset_start + overshoot;
|
||||
let buffer_start = self.buffer.offset_to_point(buffer_offset_start);
|
||||
let buffer_end = self.buffer.offset_to_point(buffer_offset_end);
|
||||
InlayPoint(cursor.start().1.0 + (buffer_end - buffer_start))
|
||||
InlayPoint(start.1.0 + (buffer_end - buffer_start))
|
||||
}
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
let overshoot = inlay.text().offset_to_point(overshoot);
|
||||
InlayPoint(cursor.start().1.0 + overshoot)
|
||||
InlayPoint(start.1.0 + overshoot)
|
||||
}
|
||||
None => self.max_point(),
|
||||
}
|
||||
@@ -855,47 +854,48 @@ impl InlaySnapshot {
|
||||
}
|
||||
|
||||
pub fn to_offset(&self, point: InlayPoint) -> InlayOffset {
|
||||
let mut cursor = self
|
||||
let (start, _, item) = self
|
||||
.transforms
|
||||
.cursor::<Dimensions<InlayPoint, InlayOffset, Point>>(());
|
||||
cursor.seek(&point, Bias::Right);
|
||||
let overshoot = point.0 - cursor.start().0.0;
|
||||
match cursor.item() {
|
||||
.find::<Dimensions<InlayPoint, InlayOffset, Point>, _>((), &point, Bias::Right);
|
||||
let overshoot = point.0 - start.0.0;
|
||||
match item {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let buffer_point_start = cursor.start().2;
|
||||
let buffer_point_start = start.2;
|
||||
let buffer_point_end = buffer_point_start + overshoot;
|
||||
let buffer_offset_start = self.buffer.point_to_offset(buffer_point_start);
|
||||
let buffer_offset_end = self.buffer.point_to_offset(buffer_point_end);
|
||||
InlayOffset(cursor.start().1.0 + (buffer_offset_end - buffer_offset_start))
|
||||
InlayOffset(start.1.0 + (buffer_offset_end - buffer_offset_start))
|
||||
}
|
||||
Some(Transform::Inlay(inlay)) => {
|
||||
let overshoot = inlay.text().point_to_offset(overshoot);
|
||||
InlayOffset(cursor.start().1.0 + overshoot)
|
||||
InlayOffset(start.1.0 + overshoot)
|
||||
}
|
||||
None => self.len(),
|
||||
}
|
||||
}
|
||||
pub fn to_buffer_point(&self, point: InlayPoint) -> Point {
|
||||
let mut cursor = self.transforms.cursor::<Dimensions<InlayPoint, Point>>(());
|
||||
cursor.seek(&point, Bias::Right);
|
||||
match cursor.item() {
|
||||
let (start, _, item) =
|
||||
self.transforms
|
||||
.find::<Dimensions<InlayPoint, Point>, _>((), &point, Bias::Right);
|
||||
match item {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let overshoot = point.0 - cursor.start().0.0;
|
||||
cursor.start().1 + overshoot
|
||||
let overshoot = point.0 - start.0.0;
|
||||
start.1 + overshoot
|
||||
}
|
||||
Some(Transform::Inlay(_)) => cursor.start().1,
|
||||
Some(Transform::Inlay(_)) => start.1,
|
||||
None => self.buffer.max_point(),
|
||||
}
|
||||
}
|
||||
pub fn to_buffer_offset(&self, offset: InlayOffset) -> usize {
|
||||
let mut cursor = self.transforms.cursor::<Dimensions<InlayOffset, usize>>(());
|
||||
cursor.seek(&offset, Bias::Right);
|
||||
match cursor.item() {
|
||||
let (start, _, item) =
|
||||
self.transforms
|
||||
.find::<Dimensions<InlayOffset, usize>, _>((), &offset, Bias::Right);
|
||||
match item {
|
||||
Some(Transform::Isomorphic(_)) => {
|
||||
let overshoot = offset - cursor.start().0;
|
||||
cursor.start().1 + overshoot.0
|
||||
let overshoot = offset - start.0;
|
||||
start.1 + overshoot.0
|
||||
}
|
||||
Some(Transform::Inlay(_)) => cursor.start().1,
|
||||
Some(Transform::Inlay(_)) => start.1,
|
||||
None => self.buffer.len(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,14 +568,17 @@ impl WrapSnapshot {
|
||||
let mut old_start = old_cursor.start().output.lines;
|
||||
old_start += tab_edit.old.start.0 - old_cursor.start().input.lines;
|
||||
|
||||
// todo(lw): Should these be seek_forward?
|
||||
old_cursor.seek(&tab_edit.old.end, Bias::Right);
|
||||
let mut old_end = old_cursor.start().output.lines;
|
||||
old_end += tab_edit.old.end.0 - old_cursor.start().input.lines;
|
||||
|
||||
// todo(lw): Should these be seek_forward?
|
||||
new_cursor.seek(&tab_edit.new.start, Bias::Right);
|
||||
let mut new_start = new_cursor.start().output.lines;
|
||||
new_start += tab_edit.new.start.0 - new_cursor.start().input.lines;
|
||||
|
||||
// todo(lw): Should these be seek_forward?
|
||||
new_cursor.seek(&tab_edit.new.end, Bias::Right);
|
||||
let mut new_end = new_cursor.start().output.lines;
|
||||
new_end += tab_edit.new.end.0 - new_cursor.start().input.lines;
|
||||
@@ -628,24 +631,22 @@ impl WrapSnapshot {
|
||||
}
|
||||
|
||||
pub fn line_len(&self, row: u32) -> u32 {
|
||||
let mut cursor = self
|
||||
.transforms
|
||||
.cursor::<Dimensions<WrapPoint, TabPoint>>(());
|
||||
cursor.seek(&WrapPoint::new(row + 1, 0), Bias::Left);
|
||||
if cursor
|
||||
.item()
|
||||
.is_some_and(|transform| transform.is_isomorphic())
|
||||
{
|
||||
let overshoot = row - cursor.start().0.row();
|
||||
let tab_row = cursor.start().1.row() + overshoot;
|
||||
let (start, _, item) = self.transforms.find::<Dimensions<WrapPoint, TabPoint>, _>(
|
||||
(),
|
||||
&WrapPoint::new(row + 1, 0),
|
||||
Bias::Left,
|
||||
);
|
||||
if item.is_some_and(|transform| transform.is_isomorphic()) {
|
||||
let overshoot = row - start.0.row();
|
||||
let tab_row = start.1.row() + overshoot;
|
||||
let tab_line_len = self.tab_snapshot.line_len(tab_row);
|
||||
if overshoot == 0 {
|
||||
cursor.start().0.column() + (tab_line_len - cursor.start().1.column())
|
||||
start.0.column() + (tab_line_len - start.1.column())
|
||||
} else {
|
||||
tab_line_len
|
||||
}
|
||||
} else {
|
||||
cursor.start().0.column()
|
||||
start.0.column()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -711,9 +712,10 @@ impl WrapSnapshot {
|
||||
}
|
||||
|
||||
pub fn soft_wrap_indent(&self, row: u32) -> Option<u32> {
|
||||
let mut cursor = self.transforms.cursor::<WrapPoint>(());
|
||||
cursor.seek(&WrapPoint::new(row + 1, 0), Bias::Right);
|
||||
cursor.item().and_then(|transform| {
|
||||
let (.., item) =
|
||||
self.transforms
|
||||
.find::<WrapPoint, _>((), &WrapPoint::new(row + 1, 0), Bias::Right);
|
||||
item.and_then(|transform| {
|
||||
if transform.is_isomorphic() {
|
||||
None
|
||||
} else {
|
||||
@@ -749,13 +751,12 @@ impl WrapSnapshot {
|
||||
}
|
||||
|
||||
pub fn to_tab_point(&self, point: WrapPoint) -> TabPoint {
|
||||
let mut cursor = self
|
||||
.transforms
|
||||
.cursor::<Dimensions<WrapPoint, TabPoint>>(());
|
||||
cursor.seek(&point, Bias::Right);
|
||||
let mut tab_point = cursor.start().1.0;
|
||||
if cursor.item().is_some_and(|t| t.is_isomorphic()) {
|
||||
tab_point += point.0 - cursor.start().0.0;
|
||||
let (start, _, item) =
|
||||
self.transforms
|
||||
.find::<Dimensions<WrapPoint, TabPoint>, _>((), &point, Bias::Right);
|
||||
let mut tab_point = start.1.0;
|
||||
if item.is_some_and(|t| t.is_isomorphic()) {
|
||||
tab_point += point.0 - start.0.0;
|
||||
}
|
||||
TabPoint(tab_point)
|
||||
}
|
||||
@@ -769,19 +770,19 @@ impl WrapSnapshot {
|
||||
}
|
||||
|
||||
pub fn tab_point_to_wrap_point(&self, point: TabPoint) -> WrapPoint {
|
||||
let mut cursor = self
|
||||
.transforms
|
||||
.cursor::<Dimensions<TabPoint, WrapPoint>>(());
|
||||
cursor.seek(&point, Bias::Right);
|
||||
WrapPoint(cursor.start().1.0 + (point.0 - cursor.start().0.0))
|
||||
let (start, ..) =
|
||||
self.transforms
|
||||
.find::<Dimensions<TabPoint, WrapPoint>, _>((), &point, Bias::Right);
|
||||
WrapPoint(start.1.0 + (point.0 - start.0.0))
|
||||
}
|
||||
|
||||
pub fn clip_point(&self, mut point: WrapPoint, bias: Bias) -> WrapPoint {
|
||||
if bias == Bias::Left {
|
||||
let mut cursor = self.transforms.cursor::<WrapPoint>(());
|
||||
cursor.seek(&point, Bias::Right);
|
||||
if cursor.item().is_some_and(|t| !t.is_isomorphic()) {
|
||||
point = *cursor.start();
|
||||
let (start, _, item) = self
|
||||
.transforms
|
||||
.find::<WrapPoint, _>((), &point, Bias::Right);
|
||||
if item.is_some_and(|t| !t.is_isomorphic()) {
|
||||
point = start;
|
||||
*point.column_mut() -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,10 +509,11 @@ impl StateInner {
|
||||
if self.alignment == ListAlignment::Bottom && new_scroll_top == scroll_max {
|
||||
self.logical_scroll_top = None;
|
||||
} else {
|
||||
let mut cursor = self.items.cursor::<ListItemSummary>(());
|
||||
cursor.seek(&Height(new_scroll_top), Bias::Right);
|
||||
let item_ix = cursor.start().count;
|
||||
let offset_in_item = new_scroll_top - cursor.start().height;
|
||||
let (start, ..) =
|
||||
self.items
|
||||
.find::<ListItemSummary, _>((), &Height(new_scroll_top), Bias::Right);
|
||||
let item_ix = start.count;
|
||||
let offset_in_item = new_scroll_top - start.height;
|
||||
self.logical_scroll_top = Some(ListOffset {
|
||||
item_ix,
|
||||
offset_in_item,
|
||||
@@ -550,9 +551,12 @@ impl StateInner {
|
||||
}
|
||||
|
||||
fn scroll_top(&self, logical_scroll_top: &ListOffset) -> Pixels {
|
||||
let mut cursor = self.items.cursor::<ListItemSummary>(());
|
||||
cursor.seek(&Count(logical_scroll_top.item_ix), Bias::Right);
|
||||
cursor.start().height + logical_scroll_top.offset_in_item
|
||||
let (start, ..) = self.items.find::<ListItemSummary, _>(
|
||||
(),
|
||||
&Count(logical_scroll_top.item_ix),
|
||||
Bias::Right,
|
||||
);
|
||||
start.height + logical_scroll_top.offset_in_item
|
||||
}
|
||||
|
||||
fn layout_all_items(
|
||||
@@ -882,11 +886,12 @@ impl StateInner {
|
||||
if self.alignment == ListAlignment::Bottom && new_scroll_top == scroll_max {
|
||||
self.logical_scroll_top = None;
|
||||
} else {
|
||||
let mut cursor = self.items.cursor::<ListItemSummary>(());
|
||||
cursor.seek(&Height(new_scroll_top), Bias::Right);
|
||||
let (start, _, _) =
|
||||
self.items
|
||||
.find::<ListItemSummary, _>((), &Height(new_scroll_top), Bias::Right);
|
||||
|
||||
let item_ix = cursor.start().count;
|
||||
let offset_in_item = new_scroll_top - cursor.start().height;
|
||||
let item_ix = start.count;
|
||||
let offset_in_item = new_scroll_top - start.height;
|
||||
self.logical_scroll_top = Some(ListOffset {
|
||||
item_ix,
|
||||
offset_in_item,
|
||||
|
||||
@@ -6140,9 +6140,8 @@ impl MultiBufferSnapshot {
|
||||
} else if id == ExcerptId::max() {
|
||||
Locator::max_ref()
|
||||
} else {
|
||||
let mut cursor = self.excerpt_ids.cursor::<ExcerptId>(());
|
||||
cursor.seek(&id, Bias::Left);
|
||||
if let Some(entry) = cursor.item()
|
||||
let (_, _, item) = self.excerpt_ids.find::<ExcerptId, _>((), &id, Bias::Left);
|
||||
if let Some(entry) = item
|
||||
&& entry.id == id
|
||||
{
|
||||
return &entry.locator;
|
||||
|
||||
@@ -123,14 +123,16 @@ impl NotificationStore {
|
||||
return None;
|
||||
}
|
||||
let ix = count - 1 - ix;
|
||||
let mut cursor = self.notifications.cursor::<Count>(());
|
||||
cursor.seek(&Count(ix), Bias::Right);
|
||||
cursor.item()
|
||||
let (.., item) = self
|
||||
.notifications
|
||||
.find::<Count, _>((), &Count(ix), Bias::Right);
|
||||
item
|
||||
}
|
||||
pub fn notification_for_id(&self, id: u64) -> Option<&NotificationEntry> {
|
||||
let mut cursor = self.notifications.cursor::<NotificationId>(());
|
||||
cursor.seek(&NotificationId(id), Bias::Left);
|
||||
if let Some(item) = cursor.item()
|
||||
let (.., item) =
|
||||
self.notifications
|
||||
.find::<NotificationId, _>((), &NotificationId(id), Bias::Left);
|
||||
if let Some(item) = item
|
||||
&& item.id == id
|
||||
{
|
||||
return Some(item);
|
||||
|
||||
+17
-21
@@ -41,12 +41,9 @@ impl Rope {
|
||||
if self.chunks.is_empty() {
|
||||
return offset == 0;
|
||||
}
|
||||
let mut cursor = self.chunks.cursor::<usize>(());
|
||||
cursor.seek(&offset, Bias::Left);
|
||||
let chunk_offset = offset - cursor.start();
|
||||
cursor
|
||||
.item()
|
||||
.map(|chunk| chunk.text.is_char_boundary(chunk_offset))
|
||||
let (start, _, item) = self.chunks.find::<usize, _>((), &offset, Bias::Left);
|
||||
let chunk_offset = offset - start;
|
||||
item.map(|chunk| chunk.text.is_char_boundary(chunk_offset))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
@@ -60,10 +57,9 @@ impl Rope {
|
||||
(u8 as i8) >= -0x40
|
||||
}
|
||||
|
||||
let mut cursor = self.chunks.cursor::<usize>(());
|
||||
cursor.seek(&index, Bias::Left);
|
||||
let chunk_offset = index - cursor.start();
|
||||
let lower_idx = cursor.item().map(|chunk| {
|
||||
let (start, _, item) = self.chunks.find::<usize, _>((), &index, Bias::Left);
|
||||
let chunk_offset = index - start;
|
||||
let lower_idx = item.map(|chunk| {
|
||||
let lower_bound = chunk_offset.saturating_sub(3);
|
||||
chunk
|
||||
.text
|
||||
@@ -78,7 +74,7 @@ impl Rope {
|
||||
})
|
||||
.unwrap_or(chunk.text.len())
|
||||
});
|
||||
lower_idx.map_or_else(|| self.len(), |idx| cursor.start() + idx)
|
||||
lower_idx.map_or_else(|| self.len(), |idx| start + idx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,10 +88,9 @@ impl Rope {
|
||||
(u8 as i8) >= -0x40
|
||||
}
|
||||
|
||||
let mut cursor = self.chunks.cursor::<usize>(());
|
||||
cursor.seek(&index, Bias::Left);
|
||||
let chunk_offset = index - cursor.start();
|
||||
let upper_idx = cursor.item().map(|chunk| {
|
||||
let (start, _, item) = self.chunks.find::<usize, _>((), &index, Bias::Left);
|
||||
let chunk_offset = index - start;
|
||||
let upper_idx = item.map(|chunk| {
|
||||
let upper_bound = Ord::min(chunk_offset + 4, chunk.text.len());
|
||||
chunk.text.as_bytes()[chunk_offset..upper_bound]
|
||||
.iter()
|
||||
@@ -103,7 +98,7 @@ impl Rope {
|
||||
.map_or(upper_bound, |pos| pos + chunk_offset)
|
||||
});
|
||||
|
||||
upper_idx.map_or_else(|| self.len(), |idx| cursor.start() + idx)
|
||||
upper_idx.map_or_else(|| self.len(), |idx| start + idx)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,11 +351,12 @@ impl Rope {
|
||||
if offset >= self.summary().len {
|
||||
return self.summary().len_utf16;
|
||||
}
|
||||
let mut cursor = self.chunks.cursor::<Dimensions<usize, OffsetUtf16>>(());
|
||||
cursor.seek(&offset, Bias::Left);
|
||||
let overshoot = offset - cursor.start().0;
|
||||
cursor.start().1
|
||||
+ cursor.item().map_or(Default::default(), |chunk| {
|
||||
let (start, _, item) =
|
||||
self.chunks
|
||||
.find::<Dimensions<usize, OffsetUtf16>, _>((), &offset, Bias::Left);
|
||||
let overshoot = offset - start.0;
|
||||
start.1
|
||||
+ item.map_or(Default::default(), |chunk| {
|
||||
chunk.as_slice().offset_to_offset_utf16(overshoot)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -388,6 +388,7 @@ where
|
||||
T: Item,
|
||||
D: Dimension<'a, T::Summary>,
|
||||
{
|
||||
/// Returns whether we found the item you were seeking for.
|
||||
#[track_caller]
|
||||
pub fn seek<Target>(&mut self, pos: &Target, bias: Bias) -> bool
|
||||
where
|
||||
@@ -397,6 +398,7 @@ where
|
||||
self.seek_internal(pos, bias, &mut ())
|
||||
}
|
||||
|
||||
/// Returns whether we found the item you were seeking for.
|
||||
#[track_caller]
|
||||
pub fn seek_forward<Target>(&mut self, pos: &Target, bias: Bias) -> bool
|
||||
where
|
||||
@@ -437,7 +439,7 @@ where
|
||||
summary.0
|
||||
}
|
||||
|
||||
/// Returns whether we found the item you were seeking for
|
||||
/// Returns whether we found the item you were seeking for.
|
||||
#[track_caller]
|
||||
fn seek_internal(
|
||||
&mut self,
|
||||
|
||||
@@ -82,6 +82,11 @@ pub trait Dimension<'a, S: Summary>: Clone {
|
||||
fn zero(cx: S::Context<'_>) -> Self;
|
||||
|
||||
fn add_summary(&mut self, summary: &'a S, cx: S::Context<'_>);
|
||||
#[must_use]
|
||||
fn with_added_summary(mut self, summary: &'a S, cx: S::Context<'_>) -> Self {
|
||||
self.add_summary(summary, cx);
|
||||
self
|
||||
}
|
||||
|
||||
fn from_summary(summary: &'a S, cx: S::Context<'_>) -> Self {
|
||||
let mut dimension = Self::zero(cx);
|
||||
@@ -371,12 +376,122 @@ impl<T: Item> SumTree<T> {
|
||||
Iter::new(self)
|
||||
}
|
||||
|
||||
pub fn cursor<'a, 'b, S>(
|
||||
/// A more efficient version of `Cursor::new()` + `Cursor::seek()` + `Cursor::item()`.
|
||||
///
|
||||
/// Only returns the item that exactly has the target match.
|
||||
pub fn find_exact<'a, 'slf, D, Target>(
|
||||
&'slf self,
|
||||
cx: <T::Summary as Summary>::Context<'a>,
|
||||
target: &Target,
|
||||
bias: Bias,
|
||||
) -> (D, D, Option<&'slf T>)
|
||||
where
|
||||
D: Dimension<'slf, T::Summary>,
|
||||
Target: SeekTarget<'slf, T::Summary, D>,
|
||||
{
|
||||
let tree_end = D::zero(cx).with_added_summary(self.summary(), cx);
|
||||
let comparison = target.cmp(&tree_end, cx);
|
||||
if comparison == Ordering::Greater || (comparison == Ordering::Equal && bias == Bias::Right)
|
||||
{
|
||||
return (tree_end.clone(), tree_end, None);
|
||||
}
|
||||
|
||||
let mut pos = D::zero(cx);
|
||||
return match Self::find_recurse::<_, _, true>(cx, target, bias, &mut pos, self) {
|
||||
Some((item, end)) => (pos, end, Some(item)),
|
||||
None => (pos.clone(), pos, None),
|
||||
};
|
||||
}
|
||||
|
||||
/// A more efficient version of `Cursor::new()` + `Cursor::seek()` + `Cursor::item()`
|
||||
pub fn find<'a, 'slf, D, Target>(
|
||||
&'slf self,
|
||||
cx: <T::Summary as Summary>::Context<'a>,
|
||||
target: &Target,
|
||||
bias: Bias,
|
||||
) -> (D, D, Option<&'slf T>)
|
||||
where
|
||||
D: Dimension<'slf, T::Summary>,
|
||||
Target: SeekTarget<'slf, T::Summary, D>,
|
||||
{
|
||||
let tree_end = D::zero(cx).with_added_summary(self.summary(), cx);
|
||||
let comparison = target.cmp(&tree_end, cx);
|
||||
if comparison == Ordering::Greater || (comparison == Ordering::Equal && bias == Bias::Right)
|
||||
{
|
||||
return (tree_end.clone(), tree_end, None);
|
||||
}
|
||||
|
||||
let mut pos = D::zero(cx);
|
||||
return match Self::find_recurse::<_, _, false>(cx, target, bias, &mut pos, self) {
|
||||
Some((item, end)) => (pos, end, Some(item)),
|
||||
None => (pos.clone(), pos, None),
|
||||
};
|
||||
}
|
||||
|
||||
fn find_recurse<'tree, 'a, D, Target, const EXACT: bool>(
|
||||
cx: <T::Summary as Summary>::Context<'a>,
|
||||
target: &Target,
|
||||
bias: Bias,
|
||||
position: &mut D,
|
||||
this: &'tree SumTree<T>,
|
||||
) -> Option<(&'tree T, D)>
|
||||
where
|
||||
D: Dimension<'tree, T::Summary>,
|
||||
Target: SeekTarget<'tree, T::Summary, D>,
|
||||
{
|
||||
match &*this.0 {
|
||||
Node::Internal {
|
||||
child_summaries,
|
||||
child_trees,
|
||||
..
|
||||
} => {
|
||||
for (child_tree, child_summary) in child_trees.iter().zip(child_summaries) {
|
||||
let child_end = position.clone().with_added_summary(child_summary, cx);
|
||||
|
||||
let comparison = target.cmp(&child_end, cx);
|
||||
let target_in_child = comparison == Ordering::Less
|
||||
|| (comparison == Ordering::Equal && bias == Bias::Left);
|
||||
if target_in_child {
|
||||
return Self::find_recurse::<D, Target, EXACT>(
|
||||
cx, target, bias, position, child_tree,
|
||||
);
|
||||
}
|
||||
*position = child_end;
|
||||
}
|
||||
}
|
||||
Node::Leaf {
|
||||
items,
|
||||
item_summaries,
|
||||
..
|
||||
} => {
|
||||
for (item, item_summary) in items.iter().zip(item_summaries) {
|
||||
let mut child_end = position.clone();
|
||||
child_end.add_summary(item_summary, cx);
|
||||
|
||||
let comparison = target.cmp(&child_end, cx);
|
||||
let entry_found = if EXACT {
|
||||
comparison == Ordering::Equal
|
||||
} else {
|
||||
comparison == Ordering::Less
|
||||
|| (comparison == Ordering::Equal && bias == Bias::Left)
|
||||
};
|
||||
if entry_found {
|
||||
return Some((item, child_end));
|
||||
}
|
||||
|
||||
*position = child_end;
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn cursor<'a, 'b, D>(
|
||||
&'a self,
|
||||
cx: <T::Summary as Summary>::Context<'b>,
|
||||
) -> Cursor<'a, 'b, T, S>
|
||||
) -> Cursor<'a, 'b, T, D>
|
||||
where
|
||||
S: Dimension<'a, T::Summary>,
|
||||
D: Dimension<'a, T::Summary>,
|
||||
{
|
||||
Cursor::new(self, cx)
|
||||
}
|
||||
@@ -787,9 +902,8 @@ impl<T: KeyedItem> SumTree<T> {
|
||||
key: &T::Key,
|
||||
cx: <T::Summary as Summary>::Context<'a>,
|
||||
) -> Option<&'a T> {
|
||||
let mut cursor = self.cursor::<T::Key>(cx);
|
||||
if cursor.seek(key, Bias::Left) {
|
||||
cursor.item()
|
||||
if let (_, _, Some(item)) = self.find_exact::<T::Key, _>(cx, key, Bias::Left) {
|
||||
Some(item)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -54,9 +54,10 @@ impl<K: Clone + Ord, V: Clone> TreeMap<K, V> {
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &K) -> Option<&V> {
|
||||
let mut cursor = self.0.cursor::<MapKeyRef<'_, K>>(());
|
||||
cursor.seek(&MapKeyRef(Some(key)), Bias::Left);
|
||||
if let Some(item) = cursor.item() {
|
||||
let (.., item) = self
|
||||
.0
|
||||
.find::<MapKeyRef<'_, K>, _>((), &MapKeyRef(Some(key)), Bias::Left);
|
||||
if let Some(item) = item {
|
||||
if Some(key) == item.key().0.as_ref() {
|
||||
Some(&item.value)
|
||||
} else {
|
||||
|
||||
@@ -99,13 +99,14 @@ impl Anchor {
|
||||
let Some(fragment_id) = buffer.try_fragment_id_for_anchor(self) else {
|
||||
return false;
|
||||
};
|
||||
let mut fragment_cursor = buffer
|
||||
let (.., item) = buffer
|
||||
.fragments
|
||||
.cursor::<Dimensions<Option<&Locator>, usize>>(&None);
|
||||
fragment_cursor.seek(&Some(fragment_id), Bias::Left);
|
||||
fragment_cursor
|
||||
.item()
|
||||
.is_some_and(|fragment| fragment.visible)
|
||||
.find::<Dimensions<Option<&Locator>, usize>, _>(
|
||||
&None,
|
||||
&Some(fragment_id),
|
||||
Bias::Left,
|
||||
);
|
||||
item.is_some_and(|fragment| fragment.visible)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-17
@@ -2323,12 +2323,15 @@ impl BufferSnapshot {
|
||||
);
|
||||
};
|
||||
|
||||
let mut fragment_cursor = self
|
||||
let (start, _, item) = self
|
||||
.fragments
|
||||
.cursor::<Dimensions<Option<&Locator>, usize>>(&None);
|
||||
fragment_cursor.seek(&Some(&insertion.fragment_id), Bias::Left);
|
||||
let fragment = fragment_cursor.item().unwrap();
|
||||
let mut fragment_offset = fragment_cursor.start().1;
|
||||
.find::<Dimensions<Option<&Locator>, usize>, _>(
|
||||
&None,
|
||||
&Some(&insertion.fragment_id),
|
||||
Bias::Left,
|
||||
);
|
||||
let fragment = item.unwrap();
|
||||
let mut fragment_offset = start.1;
|
||||
if fragment.visible {
|
||||
fragment_offset += anchor.offset - insertion.split_offset;
|
||||
}
|
||||
@@ -2410,10 +2413,9 @@ impl BufferSnapshot {
|
||||
offset, ch, char_range,
|
||||
);
|
||||
}
|
||||
let mut fragment_cursor = self.fragments.cursor::<usize>(&None);
|
||||
fragment_cursor.seek(&offset, bias);
|
||||
let fragment = fragment_cursor.item().unwrap();
|
||||
let overshoot = offset - *fragment_cursor.start();
|
||||
let (start, _, item) = self.fragments.find::<usize, _>(&None, &offset, bias);
|
||||
let fragment = item.unwrap();
|
||||
let overshoot = offset - start;
|
||||
Anchor {
|
||||
timestamp: fragment.timestamp,
|
||||
offset: fragment.insertion_offset + overshoot,
|
||||
@@ -2494,15 +2496,17 @@ impl BufferSnapshot {
|
||||
cursor.next();
|
||||
Some(cursor)
|
||||
};
|
||||
let mut cursor = self
|
||||
.fragments
|
||||
.cursor::<Dimensions<Option<&Locator>, FragmentTextSummary>>(&None);
|
||||
|
||||
let start_fragment_id = self.fragment_id_for_anchor(&range.start);
|
||||
cursor.seek(&Some(start_fragment_id), Bias::Left);
|
||||
let mut visible_start = cursor.start().1.visible;
|
||||
let mut deleted_start = cursor.start().1.deleted;
|
||||
if let Some(fragment) = cursor.item() {
|
||||
let (start, _, item) = self
|
||||
.fragments
|
||||
.find::<Dimensions<Option<&Locator>, FragmentTextSummary>, _>(
|
||||
&None,
|
||||
&Some(start_fragment_id),
|
||||
Bias::Left,
|
||||
);
|
||||
let mut visible_start = start.1.visible;
|
||||
let mut deleted_start = start.1.deleted;
|
||||
if let Some(fragment) = item {
|
||||
let overshoot = range.start.offset - fragment.insertion_offset;
|
||||
if fragment.visible {
|
||||
visible_start += overshoot;
|
||||
|
||||
Reference in New Issue
Block a user