multi_buffer: Make anchor_in_excerpt fallible for bad text anchors (#40496)
`MultiBuffer::anchor_in_excerpt` currently just wraps the given text anchor in a multibuffer anchor. This allows one to get a multibuffer anchor that points outside its excerpt which is basically never what one wants. This PR now does a bounds check and returns `None` if the given text anchor is not within the bounds of the excerpt. Release Notes: - N/A *or* Added/Fixed/Improved ... Co-authored-by: Kirill Bulatov <kirill@zed.dev>
This commit is contained in:
co-authored by
Kirill Bulatov
parent
7f9898a90b
commit
83bfe2ff7b
@@ -5989,15 +5989,8 @@ impl Editor {
|
||||
let snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
let newest_anchor = self.selections.newest_anchor();
|
||||
let replace_range_multibuffer = {
|
||||
let excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
|
||||
let multibuffer_anchor = snapshot
|
||||
.anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.start))
|
||||
.unwrap()
|
||||
..snapshot
|
||||
.anchor_in_excerpt(excerpt.id(), buffer.anchor_before(replace_range.end))
|
||||
.unwrap();
|
||||
multibuffer_anchor.start.to_offset(&snapshot)
|
||||
..multibuffer_anchor.end.to_offset(&snapshot)
|
||||
let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
|
||||
excerpt.map_range_from_buffer(replace_range.clone())
|
||||
};
|
||||
if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
|
||||
return None;
|
||||
@@ -7981,9 +7974,10 @@ impl Editor {
|
||||
let edits = edits
|
||||
.into_iter()
|
||||
.flat_map(|(range, new_text)| {
|
||||
let start = multibuffer.anchor_in_excerpt(excerpt_id, range.start)?;
|
||||
let end = multibuffer.anchor_in_excerpt(excerpt_id, range.end)?;
|
||||
Some((start..end, new_text))
|
||||
Some((
|
||||
multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
|
||||
new_text,
|
||||
))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if edits.is_empty() {
|
||||
|
||||
@@ -7464,8 +7464,8 @@ impl EditorElement {
|
||||
}
|
||||
let clipped_start = range.start.max(&buffer_range.start, buffer);
|
||||
let clipped_end = range.end.min(&buffer_range.end, buffer);
|
||||
let range = buffer_snapshot.anchor_in_excerpt(excerpt_id, clipped_start)?
|
||||
..buffer_snapshot.anchor_in_excerpt(excerpt_id, clipped_end)?;
|
||||
let range = buffer_snapshot
|
||||
.anchor_range_in_excerpt(excerpt_id, clipped_start..clipped_end)?;
|
||||
let start = range.start.to_display_point(display_snapshot);
|
||||
let end = range.end.to_display_point(display_snapshot);
|
||||
let selection_layout = SelectionLayout {
|
||||
|
||||
@@ -534,10 +534,9 @@ pub fn show_link_definition(
|
||||
if let Some((url_range, url)) = find_url(&buffer, text_anchor, cx.clone()) {
|
||||
this.read_with(cx, |_, _| {
|
||||
let range = maybe!({
|
||||
let start =
|
||||
snapshot.anchor_in_excerpt(excerpt_id, url_range.start)?;
|
||||
let end = snapshot.anchor_in_excerpt(excerpt_id, url_range.end)?;
|
||||
Some(RangeInEditor::Text(start..end))
|
||||
let range =
|
||||
snapshot.anchor_range_in_excerpt(excerpt_id, url_range)?;
|
||||
Some(RangeInEditor::Text(range))
|
||||
});
|
||||
(range, vec![HoverLink::Url(url)])
|
||||
})
|
||||
@@ -546,10 +545,9 @@ pub fn show_link_definition(
|
||||
find_file(&buffer, project.clone(), text_anchor, cx).await
|
||||
{
|
||||
let range = maybe!({
|
||||
let start =
|
||||
snapshot.anchor_in_excerpt(excerpt_id, filename_range.start)?;
|
||||
let end = snapshot.anchor_in_excerpt(excerpt_id, filename_range.end)?;
|
||||
Some(RangeInEditor::Text(start..end))
|
||||
let range =
|
||||
snapshot.anchor_range_in_excerpt(excerpt_id, filename_range)?;
|
||||
Some(RangeInEditor::Text(range))
|
||||
});
|
||||
|
||||
Some((range, vec![HoverLink::File(filename)]))
|
||||
@@ -562,13 +560,11 @@ pub fn show_link_definition(
|
||||
(
|
||||
definition_result.iter().find_map(|link| {
|
||||
link.origin.as_ref().and_then(|origin| {
|
||||
let start = snapshot.anchor_in_excerpt(
|
||||
let range = snapshot.anchor_range_in_excerpt(
|
||||
excerpt_id,
|
||||
origin.range.start,
|
||||
origin.range.clone(),
|
||||
)?;
|
||||
let end = snapshot
|
||||
.anchor_in_excerpt(excerpt_id, origin.range.end)?;
|
||||
Some(RangeInEditor::Text(start..end))
|
||||
Some(RangeInEditor::Text(range))
|
||||
})
|
||||
}),
|
||||
definition_result.into_iter().map(HoverLink::Text).collect(),
|
||||
|
||||
@@ -467,13 +467,10 @@ fn show_hover(
|
||||
let range = hover_result
|
||||
.range
|
||||
.and_then(|range| {
|
||||
let start = snapshot
|
||||
let range = snapshot
|
||||
.buffer_snapshot()
|
||||
.anchor_in_excerpt(excerpt_id, range.start)?;
|
||||
let end = snapshot
|
||||
.buffer_snapshot()
|
||||
.anchor_in_excerpt(excerpt_id, range.end)?;
|
||||
Some(start..end)
|
||||
.anchor_range_in_excerpt(excerpt_id, range)?;
|
||||
Some(range)
|
||||
})
|
||||
.or_else(|| {
|
||||
let snapshot = &snapshot.buffer_snapshot();
|
||||
|
||||
@@ -364,10 +364,9 @@ impl FollowableItem for Editor {
|
||||
) {
|
||||
let buffer = self.buffer.read(cx);
|
||||
let buffer = buffer.read(cx);
|
||||
let Some((excerpt_id, _, _)) = buffer.as_singleton() else {
|
||||
let Some(position) = buffer.as_singleton_anchor(location) else {
|
||||
return;
|
||||
};
|
||||
let position = buffer.anchor_in_excerpt(*excerpt_id, location).unwrap();
|
||||
let selection = Selection {
|
||||
id: 0,
|
||||
reversed: false,
|
||||
|
||||
@@ -251,25 +251,14 @@ impl Editor {
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let Some(color_start_anchor) = multi_buffer_snapshot
|
||||
.anchor_in_excerpt(
|
||||
*excerpt_id,
|
||||
buffer_snapshot.anchor_before(
|
||||
buffer_snapshot
|
||||
.clip_point_utf16(color_start, Bias::Left),
|
||||
),
|
||||
)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let Some(color_end_anchor) = multi_buffer_snapshot
|
||||
.anchor_in_excerpt(
|
||||
*excerpt_id,
|
||||
buffer_snapshot.anchor_after(
|
||||
buffer_snapshot
|
||||
.clip_point_utf16(color_end, Bias::Right),
|
||||
),
|
||||
)
|
||||
let start = buffer_snapshot.anchor_before(
|
||||
buffer_snapshot.clip_point_utf16(color_start, Bias::Left),
|
||||
);
|
||||
let end = buffer_snapshot.anchor_after(
|
||||
buffer_snapshot.clip_point_utf16(color_end, Bias::Right),
|
||||
);
|
||||
let Some(range) = multi_buffer_snapshot
|
||||
.anchor_range_in_excerpt(*excerpt_id, start..end)
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
@@ -285,16 +274,14 @@ impl Editor {
|
||||
new_buffer_colors.binary_search_by(|(probe, _)| {
|
||||
probe
|
||||
.start
|
||||
.cmp(&color_start_anchor, &multi_buffer_snapshot)
|
||||
.cmp(&range.start, &multi_buffer_snapshot)
|
||||
.then_with(|| {
|
||||
probe.end.cmp(
|
||||
&color_end_anchor,
|
||||
&multi_buffer_snapshot,
|
||||
)
|
||||
probe
|
||||
.end
|
||||
.cmp(&range.end, &multi_buffer_snapshot)
|
||||
})
|
||||
});
|
||||
new_buffer_colors
|
||||
.insert(i, (color_start_anchor..color_end_anchor, color));
|
||||
new_buffer_colors.insert(i, (range, color));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user