Ensure selections stay sorted after refreshing them

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2022-01-11 17:16:45 +01:00
parent e70b728758
commit aa543a4b0a
2 changed files with 42 additions and 25 deletions

View file

@ -1104,7 +1104,7 @@ impl Editor {
T: ToOffset, T: ToOffset,
{ {
let buffer = self.buffer.read(cx).snapshot(cx); let buffer = self.buffer.read(cx).snapshot(cx);
let mut selections = ranges let selections = ranges
.into_iter() .into_iter()
.map(|range| { .map(|range| {
let mut start = range.start.to_offset(&buffer); let mut start = range.start.to_offset(&buffer);
@ -1124,7 +1124,6 @@ impl Editor {
} }
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
selections.sort_unstable_by_key(|s| s.start);
self.update_selections(selections, autoscroll, cx); self.update_selections(selections, autoscroll, cx);
} }
@ -1649,7 +1648,6 @@ impl Editor {
edit_ranges.push(edit_start..edit_end); edit_ranges.push(edit_start..edit_end);
} }
new_cursors.sort_unstable_by(|a, b| a.1.cmp(&b.1, &buffer).unwrap());
let buffer = self.buffer.update(cx, |buffer, cx| { let buffer = self.buffer.update(cx, |buffer, cx| {
buffer.edit(edit_ranges, "", cx); buffer.edit(edit_ranges, "", cx);
buffer.snapshot(cx) buffer.snapshot(cx)
@ -2648,7 +2646,6 @@ impl Editor {
reversed: false, reversed: false,
goal: SelectionGoal::None, goal: SelectionGoal::None,
}); });
selections.sort_unstable_by_key(|s| s.start);
self.update_selections(selections, Some(Autoscroll::Newest), cx); self.update_selections(selections, Some(Autoscroll::Newest), cx);
} else { } else {
select_next_state.done = true; select_next_state.done = true;
@ -2801,7 +2798,7 @@ impl Editor {
let mut stack = mem::take(&mut self.select_larger_syntax_node_stack); let mut stack = mem::take(&mut self.select_larger_syntax_node_stack);
let mut selected_larger_node = false; let mut selected_larger_node = false;
let mut new_selections = old_selections let new_selections = old_selections
.iter() .iter()
.map(|selection| { .map(|selection| {
let old_range = selection.start..selection.end; let old_range = selection.start..selection.end;
@ -2830,7 +2827,6 @@ impl Editor {
if selected_larger_node { if selected_larger_node {
stack.push(old_selections); stack.push(old_selections);
new_selections.sort_unstable_by_key(|selection| selection.start);
self.update_selections(new_selections, Some(Autoscroll::Fit), cx); self.update_selections(new_selections, Some(Autoscroll::Fit), cx);
} }
self.select_larger_syntax_node_stack = stack; self.select_larger_syntax_node_stack = stack;
@ -3225,6 +3221,8 @@ impl Editor {
) where ) where
T: ToOffset + ToPoint + Ord + std::marker::Copy + std::fmt::Debug, T: ToOffset + ToPoint + Ord + std::marker::Copy + std::fmt::Debug,
{ {
selections.sort_unstable_by_key(|s| s.start);
// Merge overlapping selections. // Merge overlapping selections.
let buffer = self.buffer.read(cx).snapshot(cx); let buffer = self.buffer.read(cx).snapshot(cx);
let mut i = 1; let mut i = 1;
@ -3298,35 +3296,45 @@ impl Editor {
/// was no longer present. The keys of the map are selection ids. The values are /// was no longer present. The keys of the map are selection ids. The values are
/// 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 anchors_with_status = self.buffer.update(cx, |buffer, cx| { let snapshot = self.buffer.read(cx).read(cx);
let snapshot = buffer.read(cx); let anchors_with_status = snapshot.refresh_anchors(
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 =
snapshot.summaries_for_anchors::<usize, _>(anchors_with_status.iter().map(|a| &a.0));
let offsets = offsets.chunks(2);
let statuses = anchors_with_status.chunks(2).map(|a| (a[0].1, a[1].1));
let mut selections_with_lost_position = HashMap::default(); let mut selections_with_lost_position = HashMap::default();
self.selections = self let new_selections = self
.selections .selections
.iter() .iter()
.cloned() .zip(offsets)
.zip(anchors_with_status.chunks(2)) .zip(statuses)
.map(|(mut selection, anchors)| { .map(|((selection, offsets), (kept_start, kept_end))| {
selection.start = anchors[0].0.clone(); let kept_head = if selection.reversed {
selection.end = anchors[1].0.clone(); kept_start
let kept_head_position = if selection.reversed {
anchors[0].1
} else { } else {
anchors[1].1 kept_end
}; };
if !kept_head_position { if !kept_head {
selections_with_lost_position selections_with_lost_position
.insert(selection.id, selection.head().excerpt_id.clone()); .insert(selection.id, selection.head().excerpt_id.clone());
} }
selection
Selection {
id: selection.id,
start: offsets[0],
end: offsets[1],
reversed: selection.reversed,
goal: selection.goal,
}
}) })
.collect(); .collect();
drop(snapshot);
self.update_selections(new_selections, Some(Autoscroll::Fit), cx);
selections_with_lost_position selections_with_lost_position
} }

View file

@ -2688,6 +2688,15 @@ mod tests {
anchors.push(multibuffer.anchor_at(offset, bias)); anchors.push(multibuffer.anchor_at(offset, bias));
anchors.sort_by(|a, b| a.cmp(&b, &multibuffer).unwrap()); anchors.sort_by(|a, b| a.cmp(&b, &multibuffer).unwrap());
} }
40..=44 if !anchors.is_empty() => {
let multibuffer = multibuffer.read(cx).read(cx);
anchors = multibuffer
.refresh_anchors(&anchors)
.into_iter()
.map(|a| a.0)
.collect();
anchors.sort_by(|a, b| a.cmp(&b, &multibuffer).unwrap());
}
_ => { _ => {
let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) { let buffer_handle = if buffers.is_empty() || rng.gen_bool(0.4) {
let base_text = RandomCharIter::new(&mut rng).take(10).collect::<String>(); let base_text = RandomCharIter::new(&mut rng).take(10).collect::<String>();