Ensure selections stay sorted after refreshing them
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
e70b728758
commit
aa543a4b0a
2 changed files with 42 additions and 25 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue