Account for pending selections when calling Editor::refresh_selections
This commit is contained in:
parent
7acde40266
commit
d24bd6f19a
1 changed files with 92 additions and 20 deletions
|
@ -4876,26 +4876,40 @@ impl Editor {
|
||||||
/// the id of the new excerpt where the head of the selection has been moved.
|
/// the id of the new excerpt where the head of the selection has been moved.
|
||||||
pub fn refresh_selections(&mut self, cx: &mut ViewContext<Self>) -> HashMap<usize, ExcerptId> {
|
pub fn refresh_selections(&mut self, cx: &mut ViewContext<Self>) -> HashMap<usize, ExcerptId> {
|
||||||
let snapshot = self.buffer.read(cx).read(cx);
|
let snapshot = self.buffer.read(cx).read(cx);
|
||||||
|
let mut selections_with_lost_position = HashMap::default();
|
||||||
|
|
||||||
|
if let Some(pending) = self.pending_selection.as_mut() {
|
||||||
|
let anchors =
|
||||||
|
snapshot.refresh_anchors([&pending.selection.start, &pending.selection.end]);
|
||||||
|
let (_, start, kept_start) = anchors[0].clone();
|
||||||
|
let (_, end, kept_end) = anchors[1].clone();
|
||||||
|
let kept_head = if pending.selection.reversed {
|
||||||
|
kept_start
|
||||||
|
} else {
|
||||||
|
kept_end
|
||||||
|
};
|
||||||
|
if !kept_head {
|
||||||
|
selections_with_lost_position.insert(
|
||||||
|
pending.selection.id,
|
||||||
|
pending.selection.head().excerpt_id.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pending.selection.start = start;
|
||||||
|
pending.selection.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
let anchors_with_status = snapshot.refresh_anchors(
|
let anchors_with_status = snapshot.refresh_anchors(
|
||||||
self.selections
|
self.selections
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|selection| [&selection.start, &selection.end]),
|
.flat_map(|selection| [&selection.start, &selection.end]),
|
||||||
);
|
);
|
||||||
let offsets =
|
self.selections = anchors_with_status
|
||||||
snapshot.summaries_for_anchors::<usize, _>(anchors_with_status.iter().map(|a| &a.1));
|
|
||||||
assert_eq!(anchors_with_status.len(), 2 * self.selections.len());
|
|
||||||
assert_eq!(offsets.len(), anchors_with_status.len());
|
|
||||||
|
|
||||||
let offsets = offsets.chunks(2);
|
|
||||||
let statuses = anchors_with_status
|
|
||||||
.chunks(2)
|
.chunks(2)
|
||||||
.map(|a| (a[0].0 / 2, a[0].2, a[1].2));
|
.map(|selection_anchors| {
|
||||||
|
let (anchor_ix, start, kept_start) = selection_anchors[0].clone();
|
||||||
let mut selections_with_lost_position = HashMap::default();
|
let (_, end, kept_end) = selection_anchors[1].clone();
|
||||||
let new_selections = offsets
|
let selection = &self.selections[anchor_ix / 2];
|
||||||
.zip(statuses)
|
|
||||||
.map(|(offsets, (selection_ix, kept_start, kept_end))| {
|
|
||||||
let selection = &self.selections[selection_ix];
|
|
||||||
let kept_head = if selection.reversed {
|
let kept_head = if selection.reversed {
|
||||||
kept_start
|
kept_start
|
||||||
} else {
|
} else {
|
||||||
|
@ -4908,14 +4922,16 @@ impl Editor {
|
||||||
|
|
||||||
Selection {
|
Selection {
|
||||||
id: selection.id,
|
id: selection.id,
|
||||||
start: offsets[0],
|
start,
|
||||||
end: offsets[1],
|
end,
|
||||||
reversed: selection.reversed,
|
reversed: selection.reversed,
|
||||||
goal: selection.goal,
|
goal: selection.goal,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
drop(snapshot);
|
drop(snapshot);
|
||||||
|
|
||||||
|
let new_selections = self.local_selections::<usize>(cx);
|
||||||
self.update_selections(new_selections, Some(Autoscroll::Fit), cx);
|
self.update_selections(new_selections, Some(Autoscroll::Fit), cx);
|
||||||
selections_with_lost_position
|
selections_with_lost_position
|
||||||
}
|
}
|
||||||
|
@ -8708,13 +8724,15 @@ mod tests {
|
||||||
);
|
);
|
||||||
let (_, editor) = cx.add_window(Default::default(), |cx| {
|
let (_, editor) = cx.add_window(Default::default(), |cx| {
|
||||||
let mut editor = build_editor(multibuffer.clone(), cx);
|
let mut editor = build_editor(multibuffer.clone(), cx);
|
||||||
editor.select_ranges(
|
let snapshot = editor.snapshot(cx);
|
||||||
|
editor.select_ranges([Point::new(1, 3)..Point::new(1, 3)], None, cx);
|
||||||
|
editor.begin_selection(Point::new(2, 1).to_display_point(&snapshot), true, 1, cx);
|
||||||
|
assert_eq!(
|
||||||
|
editor.selected_ranges(cx),
|
||||||
[
|
[
|
||||||
Point::new(1, 3)..Point::new(1, 3),
|
Point::new(1, 3)..Point::new(1, 3),
|
||||||
Point::new(2, 1)..Point::new(2, 1),
|
Point::new(2, 1)..Point::new(2, 1),
|
||||||
],
|
]
|
||||||
None,
|
|
||||||
cx,
|
|
||||||
);
|
);
|
||||||
editor
|
editor
|
||||||
});
|
});
|
||||||
|
@ -8757,6 +8775,60 @@ mod tests {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn test_refresh_selections_while_selecting_with_mouse(cx: &mut gpui::MutableAppContext) {
|
||||||
|
populate_settings(cx);
|
||||||
|
let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(3, 4, 'a'), cx));
|
||||||
|
let mut excerpt1_id = None;
|
||||||
|
let multibuffer = cx.add_model(|cx| {
|
||||||
|
let mut multibuffer = MultiBuffer::new(0);
|
||||||
|
excerpt1_id = multibuffer
|
||||||
|
.push_excerpts(
|
||||||
|
buffer.clone(),
|
||||||
|
[
|
||||||
|
Point::new(0, 0)..Point::new(1, 4),
|
||||||
|
Point::new(1, 0)..Point::new(2, 4),
|
||||||
|
],
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.next();
|
||||||
|
multibuffer
|
||||||
|
});
|
||||||
|
assert_eq!(
|
||||||
|
multibuffer.read(cx).read(cx).text(),
|
||||||
|
"aaaa\nbbbb\nbbbb\ncccc"
|
||||||
|
);
|
||||||
|
let (_, editor) = cx.add_window(Default::default(), |cx| {
|
||||||
|
let mut editor = build_editor(multibuffer.clone(), cx);
|
||||||
|
let snapshot = editor.snapshot(cx);
|
||||||
|
editor.begin_selection(Point::new(1, 3).to_display_point(&snapshot), false, 1, cx);
|
||||||
|
assert_eq!(
|
||||||
|
editor.selected_ranges(cx),
|
||||||
|
[Point::new(1, 3)..Point::new(1, 3)]
|
||||||
|
);
|
||||||
|
editor
|
||||||
|
});
|
||||||
|
|
||||||
|
multibuffer.update(cx, |multibuffer, cx| {
|
||||||
|
multibuffer.remove_excerpts([&excerpt1_id.unwrap()], cx);
|
||||||
|
});
|
||||||
|
editor.update(cx, |editor, cx| {
|
||||||
|
assert_eq!(
|
||||||
|
editor.selected_ranges(cx),
|
||||||
|
[Point::new(0, 0)..Point::new(0, 0)]
|
||||||
|
);
|
||||||
|
|
||||||
|
// Ensure we don't panic when selections are refreshed and that the pending selection is finalized.
|
||||||
|
editor.refresh_selections(cx);
|
||||||
|
assert_eq!(
|
||||||
|
editor.selected_ranges(cx),
|
||||||
|
[Point::new(0, 3)..Point::new(0, 3)]
|
||||||
|
);
|
||||||
|
assert!(editor.pending_selection.is_none());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) {
|
async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) {
|
||||||
cx.update(populate_settings);
|
cx.update(populate_settings);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue