From 1e02ebbd11bdb3faede5a92a593e73051ef195b0 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Sat, 17 Dec 2022 14:00:53 -0800 Subject: [PATCH] Replicate pending selections separately from other selections This fixes a panic that would occur when a leader created a pending selection that overlapped another selection, because the follower would attempt to treat that pending selection as non-pending, which would violate the invariant that selections are sorted and disjoint. --- crates/editor/src/editor.rs | 6 ++++++ crates/editor/src/items.rs | 27 ++++++++++++++++++++++----- crates/rpc/proto/zed.proto | 14 ++++++++------ crates/rpc/src/rpc.rs | 2 +- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 8a3c7452ef..d8ee49866b 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -5453,11 +5453,17 @@ impl Editor { pub fn set_selections_from_remote( &mut self, selections: Vec>, + pending_selection: Option>, cx: &mut ViewContext, ) { let old_cursor_position = self.selections.newest_anchor().head(); self.selections.change_with(cx, |s| { s.select_anchors(selections); + if let Some(pending_selection) = pending_selection { + s.set_pending(pending_selection, SelectMode::Character); + } else { + s.clear_pending(); + } }); self.selections_did_change(false, &old_cursor_position, cx); } diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 0057df778b..9bf7106c68 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -130,13 +130,17 @@ impl FollowableItem for Editor { .ok_or_else(|| anyhow!("invalid selection")) }) .collect::>>()?; + let pending_selection = state + .pending_selection + .map(|selection| deserialize_selection(&buffer, selection)) + .flatten(); let scroll_top_anchor = state .scroll_top_anchor .and_then(|anchor| deserialize_anchor(&buffer, anchor)); drop(buffer); - if !selections.is_empty() { - editor.set_selections_from_remote(selections, cx); + if !selections.is_empty() || pending_selection.is_some() { + editor.set_selections_from_remote(selections, pending_selection, cx); } if let Some(scroll_top_anchor) = scroll_top_anchor { @@ -216,6 +220,11 @@ impl FollowableItem for Editor { .iter() .map(serialize_selection) .collect(), + pending_selection: self + .selections + .pending_anchor() + .as_ref() + .map(serialize_selection), })) } @@ -269,9 +278,13 @@ impl FollowableItem for Editor { .selections .disjoint_anchors() .iter() - .chain(self.selections.pending_anchor().as_ref()) .map(serialize_selection) .collect(); + update.pending_selection = self + .selections + .pending_anchor() + .as_ref() + .map(serialize_selection); true } _ => false, @@ -307,6 +320,10 @@ impl FollowableItem for Editor { .into_iter() .filter_map(|selection| deserialize_selection(&multibuffer, selection)) .collect::>(); + let pending_selection = message + .pending_selection + .and_then(|selection| deserialize_selection(&multibuffer, selection)); + let scroll_top_anchor = message .scroll_top_anchor .and_then(|anchor| deserialize_anchor(&multibuffer, anchor)); @@ -361,8 +378,8 @@ impl FollowableItem for Editor { multibuffer.remove_excerpts(removals, cx); }); - if !selections.is_empty() { - this.set_selections_from_remote(selections, cx); + if !selections.is_empty() || pending_selection.is_some() { + this.set_selections_from_remote(selections, pending_selection, cx); this.request_autoscroll_remotely(Autoscroll::newest(), cx); } else if let Some(anchor) = scroll_top_anchor { this.set_scroll_anchor_remote(ScrollAnchor { diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index 9528bd10b7..75b8d4d457 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -853,9 +853,10 @@ message UpdateView { repeated ExcerptInsertion inserted_excerpts = 1; repeated uint64 deleted_excerpts = 2; repeated Selection selections = 3; - EditorAnchor scroll_top_anchor = 4; - float scroll_x = 5; - float scroll_y = 6; + optional Selection pending_selection = 4; + EditorAnchor scroll_top_anchor = 5; + float scroll_x = 6; + float scroll_y = 7; } } @@ -872,9 +873,10 @@ message View { optional string title = 2; repeated Excerpt excerpts = 3; repeated Selection selections = 4; - EditorAnchor scroll_top_anchor = 5; - float scroll_x = 6; - float scroll_y = 7; + optional Selection pending_selection = 5; + EditorAnchor scroll_top_anchor = 6; + float scroll_x = 7; + float scroll_y = 8; } } diff --git a/crates/rpc/src/rpc.rs b/crates/rpc/src/rpc.rs index 01dda55cef..7fc59d86fb 100644 --- a/crates/rpc/src/rpc.rs +++ b/crates/rpc/src/rpc.rs @@ -6,4 +6,4 @@ pub use conn::Connection; pub use peer::*; mod macros; -pub const PROTOCOL_VERSION: u32 = 43; +pub const PROTOCOL_VERSION: u32 = 44;