diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 49cc4abe6999dee3156fc390afbee8cd7a6f325d..2344d97fe273d03feda349ca498d4efceabf276f 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -4903,6 +4903,55 @@ impl Editor { ); } + pub fn set_selections_from_remote( + &mut self, + mut selections: Vec>, + cx: &mut ViewContext, + ) { + let buffer = self.buffer.read(cx); + let buffer = buffer.read(cx); + selections.sort_by(|a, b| { + a.start + .cmp(&b.start, &*buffer) + .unwrap() + .then_with(|| b.end.cmp(&a.end, &*buffer).unwrap()) + }); + + // Merge overlapping selections + let mut i = 1; + while i < selections.len() { + if selections[i - 1] + .end + .cmp(&selections[i].start, &*buffer) + .unwrap() + .is_ge() + { + let removed = selections.remove(i); + if removed + .start + .cmp(&selections[i - 1].start, &*buffer) + .unwrap() + .is_lt() + { + selections[i - 1].start = removed.start; + } + if removed + .end + .cmp(&selections[i - 1].end, &*buffer) + .unwrap() + .is_gt() + { + selections[i - 1].end = removed.end; + } + } else { + i += 1; + } + } + + drop(buffer); + self.set_selections(selections.into(), None, false, cx); + } + /// Compute new ranges for any selections that were located in excerpts that have /// since been removed. /// @@ -9109,6 +9158,29 @@ mod tests { assert!(follower.autoscroll_request.is_some()); }); assert_eq!(follower.read(cx).selected_ranges(cx), vec![0..0]); + + // Creating a pending selection that precedes another selection + leader.update(cx, |leader, cx| { + leader.select_ranges([1..1], None, cx); + leader.begin_selection(DisplayPoint::new(0, 0), true, 1, cx); + }); + follower.update(cx, |follower, cx| { + follower + .apply_update_proto(pending_update.borrow_mut().take().unwrap(), cx) + .unwrap(); + }); + assert_eq!(follower.read(cx).selected_ranges(cx), vec![0..0, 1..1]); + + // Extend the pending selection so that it surrounds another selection + leader.update(cx, |leader, cx| { + leader.extend_selection(DisplayPoint::new(0, 2), 1, cx); + }); + follower.update(cx, |follower, cx| { + follower + .apply_update_proto(pending_update.borrow_mut().take().unwrap(), cx) + .unwrap(); + }); + assert_eq!(follower.read(cx).selected_ranges(cx), vec![0..2]); } #[test] diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 5971cbc07bb5dfbb87cf826418e546551d60637c..2cea9f0f9a5be5669e8f3345eacf2bb1245de582 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -65,7 +65,7 @@ impl FollowableItem for Editor { }) .collect::>>()?; if !selections.is_empty() { - editor.set_selections(selections.into(), None, false, cx); + editor.set_selections_from_remote(selections.into(), cx); } if let Some(anchor) = state.scroll_top_anchor { @@ -173,8 +173,9 @@ impl FollowableItem for Editor { deserialize_selection(&excerpt_id, buffer_id, selection) }) .collect::>(); + if !selections.is_empty() { - self.set_selections(selections.into(), None, false, cx); + self.set_selections_from_remote(selections, cx); self.request_autoscroll_remotely(Autoscroll::Newest, cx); } else { if let Some(anchor) = message.scroll_top_anchor {