Fix panic when editor::OpenSelectionsInMultibuffer only has pending selection (#32842)

On the panics dashboard, saw this panic of `There must be at least one
selection` in `open_locations_in_multibuffer`. Only seems to have
happened once in the past month.

Fix is to include the pending selection. Since `selections.all()` cannot
provide anchor selections, added `selections.all_anchors()` which only
really does any work if there is a pending selection.

Also fixes a corner case in jump-to-definitions where if the definition
is `HoverLink::InlayHint` and the `compute_target_location` fails for
all definitions it could potentially also trigger this case (and return
`Navigated::Yes` instead of `Navigated::No`

Release Notes:

- N/A
This commit is contained in:
Michael Sloan 2025-06-17 02:35:14 -06:00 committed by GitHub
parent 0e794fa0ac
commit 2f3acb6185
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 60 additions and 25 deletions

View file

@ -81,9 +81,9 @@ impl SelectionsCollection {
count
}
/// The non-pending, non-overlapping selections. There could still be a pending
/// selection that overlaps these if the mouse is being dragged, etc. Returned as
/// selections over Anchors.
/// The non-pending, non-overlapping selections. There could be a pending selection that
/// overlaps these if the mouse is being dragged, etc. This could also be empty if there is a
/// pending selection. Returned as selections over Anchors.
pub fn disjoint_anchors(&self) -> Arc<[Selection<Anchor>]> {
self.disjoint.clone()
}
@ -94,6 +94,20 @@ impl SelectionsCollection {
(0..disjoint.len()).map(move |ix| disjoint[ix].range())
}
/// Non-overlapping selections using anchors, including the pending selection.
pub fn all_anchors(&self, cx: &mut App) -> Arc<[Selection<Anchor>]> {
if self.pending.is_none() {
self.disjoint_anchors()
} else {
let all_offset_selections = self.all::<usize>(cx);
let buffer = self.buffer(cx);
all_offset_selections
.into_iter()
.map(|selection| selection_to_anchor_selection(selection, &buffer))
.collect()
}
}
pub fn pending_anchor(&self) -> Option<Selection<Anchor>> {
self.pending
.as_ref()
@ -534,21 +548,11 @@ impl<'a> MutableSelectionsCollection<'a> {
}
}
self.collection.disjoint = Arc::from_iter(selections.into_iter().map(|selection| {
let end_bias = if selection.end > selection.start {
Bias::Left
} else {
Bias::Right
};
Selection {
id: selection.id,
start: buffer.anchor_after(selection.start),
end: buffer.anchor_at(selection.end, end_bias),
reversed: selection.reversed,
goal: selection.goal,
}
}));
self.collection.disjoint = Arc::from_iter(
selections
.into_iter()
.map(|selection| selection_to_anchor_selection(selection, &buffer)),
);
self.collection.pending = None;
self.selections_changed = true;
}
@ -880,6 +884,27 @@ impl DerefMut for MutableSelectionsCollection<'_> {
}
}
fn selection_to_anchor_selection<T>(
selection: Selection<T>,
buffer: &MultiBufferSnapshot,
) -> Selection<Anchor>
where
T: ToOffset + Ord,
{
let end_bias = if selection.end > selection.start {
Bias::Left
} else {
Bias::Right
};
Selection {
id: selection.id,
start: buffer.anchor_after(selection.start),
end: buffer.anchor_at(selection.end, end_bias),
reversed: selection.reversed,
goal: selection.goal,
}
}
// Panics if passed selections are not in order
fn resolve_selections_display<'a>(
selections: impl 'a + IntoIterator<Item = &'a Selection<Anchor>>,