multi_buffer: Fix handling of ExcerptId::max() (#38887)
This removes a hack from `MultiBuffer::anchor_at` that works around missing logic for handling `ExcerptId::max()` by implementing that said missing logic. Generally, `ExcerptId::min()` is already being handled correctly due to how `Cursor` seeking works, we tend to seek to or beyond a seek target, meaning `min` will always match the first excerpt as expected. `max` on the other hand will always seek beyond the last excerpt resulting in no excerpt being found, so any code path dealing with the excerpt sumtree will have to specially check for this special excerpt ID to work correctly. Release Notes: - N/A *or* Added/Fixed/Improved ...
This commit is contained in:
+23
-28
@@ -3211,22 +3211,27 @@ impl Editor {
|
||||
let background_executor = cx.background_executor().clone();
|
||||
let editor_id = cx.entity().entity_id().as_u64() as ItemId;
|
||||
self.serialize_selections = cx.background_spawn(async move {
|
||||
background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
|
||||
let db_selections = selections
|
||||
.iter()
|
||||
.map(|selection| {
|
||||
(
|
||||
selection.start.to_offset(&snapshot),
|
||||
selection.end.to_offset(&snapshot),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
|
||||
let db_selections = selections
|
||||
.iter()
|
||||
.map(|selection| {
|
||||
(
|
||||
selection.start.to_offset(&snapshot),
|
||||
selection.end.to_offset(&snapshot),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
DB.save_editor_selections(editor_id, workspace_id, db_selections)
|
||||
.await
|
||||
.with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
|
||||
.log_err();
|
||||
});
|
||||
DB.save_editor_selections(editor_id, workspace_id, db_selections)
|
||||
.await
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"persisting editor selections for editor {editor_id}, \
|
||||
workspace {workspace_id:?}"
|
||||
)
|
||||
})
|
||||
.log_err();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6871,17 +6876,7 @@ impl Editor {
|
||||
continue;
|
||||
}
|
||||
|
||||
let range = Anchor {
|
||||
buffer_id: Some(buffer_id),
|
||||
excerpt_id,
|
||||
text_anchor: start,
|
||||
diff_base_anchor: None,
|
||||
}..Anchor {
|
||||
buffer_id: Some(buffer_id),
|
||||
excerpt_id,
|
||||
text_anchor: end,
|
||||
diff_base_anchor: None,
|
||||
};
|
||||
let range = Anchor::range_in_buffer(excerpt_id, buffer_id, start..end);
|
||||
if highlight.kind == lsp::DocumentHighlightKind::WRITE {
|
||||
write_ranges.push(range);
|
||||
} else {
|
||||
@@ -12886,7 +12881,7 @@ impl Editor {
|
||||
self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
|
||||
self.change_selections(Default::default(), window, cx, |s| {
|
||||
s.move_heads_with(|map, head, _| (movement::right(map, head), SelectionGoal::None));
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
|
||||
@@ -15873,7 +15868,7 @@ impl Editor {
|
||||
let snapshot = multi_buffer.snapshot(cx);
|
||||
if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
|
||||
&& let Some(buffer) = multi_buffer.buffer(buffer_id)
|
||||
&& let Some(excerpt_range) = snapshot.buffer_range_for_excerpt(excerpt)
|
||||
&& let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
|
||||
{
|
||||
let buffer_snapshot = buffer.read(cx).snapshot();
|
||||
let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
|
||||
|
||||
@@ -1311,10 +1311,10 @@ impl EditorElement {
|
||||
|
||||
let range = snapshot
|
||||
.buffer_snapshot
|
||||
.anchor_at(start.to_point(&snapshot.display_snapshot), Bias::Left)
|
||||
.anchor_before(start.to_point(&snapshot.display_snapshot))
|
||||
..snapshot
|
||||
.buffer_snapshot
|
||||
.anchor_at(end.to_point(&snapshot.display_snapshot), Bias::Right);
|
||||
.anchor_after(end.to_point(&snapshot.display_snapshot));
|
||||
|
||||
let Some(selection) = snapshot.remote_selections_in_range(&range, hub, cx).next() else {
|
||||
return;
|
||||
|
||||
@@ -301,14 +301,10 @@ pub fn update_inlay_link_and_hover_points(
|
||||
let mut hover_updated = false;
|
||||
if let Some(hovered_offset) = hovered_offset {
|
||||
let buffer_snapshot = editor.buffer().read(cx).snapshot(cx);
|
||||
let previous_valid_anchor = buffer_snapshot.anchor_at(
|
||||
point_for_position.previous_valid.to_point(snapshot),
|
||||
Bias::Left,
|
||||
);
|
||||
let next_valid_anchor = buffer_snapshot.anchor_at(
|
||||
point_for_position.next_valid.to_point(snapshot),
|
||||
Bias::Right,
|
||||
);
|
||||
let previous_valid_anchor =
|
||||
buffer_snapshot.anchor_before(point_for_position.previous_valid.to_point(snapshot));
|
||||
let next_valid_anchor =
|
||||
buffer_snapshot.anchor_after(point_for_position.next_valid.to_point(snapshot));
|
||||
if let Some(hovered_hint) = editor
|
||||
.visible_inlay_hints(cx)
|
||||
.into_iter()
|
||||
@@ -1400,7 +1396,7 @@ mod tests {
|
||||
let buffer_snapshot = editor.buffer().update(cx, |buffer, cx| buffer.snapshot(cx));
|
||||
let expected_highlight = InlayHighlight {
|
||||
inlay: InlayId::Hint(0),
|
||||
inlay_position: buffer_snapshot.anchor_at(inlay_range.start, Bias::Right),
|
||||
inlay_position: buffer_snapshot.anchor_after(inlay_range.start),
|
||||
range: 0..hint_label.len(),
|
||||
};
|
||||
assert_set_eq!(actual_highlights, vec![&expected_highlight]);
|
||||
|
||||
@@ -1785,7 +1785,7 @@ mod tests {
|
||||
popover.symbol_range,
|
||||
RangeInEditor::Inlay(InlayHighlight {
|
||||
inlay: InlayId::Hint(0),
|
||||
inlay_position: buffer_snapshot.anchor_at(inlay_range.start, Bias::Right),
|
||||
inlay_position: buffer_snapshot.anchor_after(inlay_range.start),
|
||||
range: ": ".len()..": ".len() + new_type_label.len(),
|
||||
}),
|
||||
"Popover range should match the new type label part"
|
||||
@@ -1840,7 +1840,7 @@ mod tests {
|
||||
popover.symbol_range,
|
||||
RangeInEditor::Inlay(InlayHighlight {
|
||||
inlay: InlayId::Hint(0),
|
||||
inlay_position: buffer_snapshot.anchor_at(inlay_range.start, Bias::Right),
|
||||
inlay_position: buffer_snapshot.anchor_after(inlay_range.start),
|
||||
range: ": ".len() + new_type_label.len() + "<".len()
|
||||
..": ".len() + new_type_label.len() + "<".len() + struct_label.len(),
|
||||
}),
|
||||
|
||||
@@ -2251,7 +2251,7 @@ pub mod tests {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[gpui::test(iterations = 10)]
|
||||
#[gpui::test(iterations = 4)]
|
||||
async fn test_large_buffer_inlay_requests_split(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |settings| {
|
||||
settings.defaults.inlay_hints = Some(InlayHintSettingsContent {
|
||||
|
||||
@@ -578,12 +578,11 @@ fn deserialize_selection(
|
||||
|
||||
fn deserialize_anchor(buffer: &MultiBufferSnapshot, anchor: proto::EditorAnchor) -> Option<Anchor> {
|
||||
let excerpt_id = ExcerptId::from_proto(anchor.excerpt_id);
|
||||
Some(Anchor {
|
||||
Some(Anchor::in_buffer(
|
||||
excerpt_id,
|
||||
text_anchor: language::proto::deserialize_anchor(anchor.anchor?)?,
|
||||
buffer_id: buffer.buffer_id_for_excerpt(excerpt_id),
|
||||
diff_base_anchor: None,
|
||||
})
|
||||
buffer.buffer_id_for_excerpt(excerpt_id)?,
|
||||
language::proto::deserialize_anchor(anchor.anchor?)?,
|
||||
))
|
||||
}
|
||||
|
||||
impl Item for Editor {
|
||||
@@ -1752,13 +1751,8 @@ impl SearchableItem for Editor {
|
||||
.anchor_after(search_range.start + match_range.start);
|
||||
let end = search_buffer
|
||||
.anchor_before(search_range.start + match_range.end);
|
||||
Anchor {
|
||||
diff_base_anchor: Some(start),
|
||||
..deleted_hunk_anchor
|
||||
}..Anchor {
|
||||
diff_base_anchor: Some(end),
|
||||
..deleted_hunk_anchor
|
||||
}
|
||||
deleted_hunk_anchor.with_diff_base_anchor(start)
|
||||
..deleted_hunk_anchor.with_diff_base_anchor(end)
|
||||
} else {
|
||||
let start = search_buffer
|
||||
.anchor_after(search_range.start + match_range.start);
|
||||
|
||||
@@ -1018,22 +1018,22 @@ mod tests {
|
||||
[
|
||||
Inlay::edit_prediction(
|
||||
post_inc(&mut id),
|
||||
buffer_snapshot.anchor_at(offset, Bias::Left),
|
||||
buffer_snapshot.anchor_before(offset),
|
||||
"test",
|
||||
),
|
||||
Inlay::edit_prediction(
|
||||
post_inc(&mut id),
|
||||
buffer_snapshot.anchor_at(offset, Bias::Right),
|
||||
buffer_snapshot.anchor_after(offset),
|
||||
"test",
|
||||
),
|
||||
Inlay::mock_hint(
|
||||
post_inc(&mut id),
|
||||
buffer_snapshot.anchor_at(offset, Bias::Left),
|
||||
buffer_snapshot.anchor_before(offset),
|
||||
"test",
|
||||
),
|
||||
Inlay::mock_hint(
|
||||
post_inc(&mut id),
|
||||
buffer_snapshot.anchor_at(offset, Bias::Right),
|
||||
buffer_snapshot.anchor_after(offset),
|
||||
"test",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -244,9 +244,7 @@ impl ScrollManager {
|
||||
Bias::Left,
|
||||
)
|
||||
.to_point(map);
|
||||
let top_anchor = map
|
||||
.buffer_snapshot
|
||||
.anchor_at(scroll_top_buffer_point, Bias::Right);
|
||||
let top_anchor = map.buffer_snapshot.anchor_after(scroll_top_buffer_point);
|
||||
|
||||
self.set_anchor(
|
||||
ScrollAnchor {
|
||||
@@ -767,7 +765,7 @@ impl Editor {
|
||||
.buffer()
|
||||
.read(cx)
|
||||
.snapshot(cx)
|
||||
.anchor_at(Point::new(top_row, 0), Bias::Left);
|
||||
.anchor_before(Point::new(top_row, 0));
|
||||
let scroll_anchor = ScrollAnchor {
|
||||
offset: gpui::Point::new(x, y),
|
||||
anchor: top_anchor,
|
||||
|
||||
@@ -440,6 +440,15 @@ pub struct MutableSelectionsCollection<'a> {
|
||||
cx: &'a mut App,
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for MutableSelectionsCollection<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("MutableSelectionsCollection")
|
||||
.field("collection", &self.collection)
|
||||
.field("selections_changed", &self.selections_changed)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MutableSelectionsCollection<'a> {
|
||||
pub fn display_map(&mut self) -> DisplaySnapshot {
|
||||
self.collection.display_map(self.cx)
|
||||
|
||||
Reference in New Issue
Block a user