Detailed changes
@@ -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);
@@ -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)
}
}
}
@@ -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;