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.
This commit is contained in:
parent
8c64514570
commit
1e02ebbd11
4 changed files with 37 additions and 12 deletions
|
@ -5453,11 +5453,17 @@ impl Editor {
|
||||||
pub fn set_selections_from_remote(
|
pub fn set_selections_from_remote(
|
||||||
&mut self,
|
&mut self,
|
||||||
selections: Vec<Selection<Anchor>>,
|
selections: Vec<Selection<Anchor>>,
|
||||||
|
pending_selection: Option<Selection<Anchor>>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
let old_cursor_position = self.selections.newest_anchor().head();
|
let old_cursor_position = self.selections.newest_anchor().head();
|
||||||
self.selections.change_with(cx, |s| {
|
self.selections.change_with(cx, |s| {
|
||||||
s.select_anchors(selections);
|
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);
|
self.selections_did_change(false, &old_cursor_position, cx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,13 +130,17 @@ impl FollowableItem for Editor {
|
||||||
.ok_or_else(|| anyhow!("invalid selection"))
|
.ok_or_else(|| anyhow!("invalid selection"))
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
let pending_selection = state
|
||||||
|
.pending_selection
|
||||||
|
.map(|selection| deserialize_selection(&buffer, selection))
|
||||||
|
.flatten();
|
||||||
let scroll_top_anchor = state
|
let scroll_top_anchor = state
|
||||||
.scroll_top_anchor
|
.scroll_top_anchor
|
||||||
.and_then(|anchor| deserialize_anchor(&buffer, anchor));
|
.and_then(|anchor| deserialize_anchor(&buffer, anchor));
|
||||||
drop(buffer);
|
drop(buffer);
|
||||||
|
|
||||||
if !selections.is_empty() {
|
if !selections.is_empty() || pending_selection.is_some() {
|
||||||
editor.set_selections_from_remote(selections, cx);
|
editor.set_selections_from_remote(selections, pending_selection, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(scroll_top_anchor) = scroll_top_anchor {
|
if let Some(scroll_top_anchor) = scroll_top_anchor {
|
||||||
|
@ -216,6 +220,11 @@ impl FollowableItem for Editor {
|
||||||
.iter()
|
.iter()
|
||||||
.map(serialize_selection)
|
.map(serialize_selection)
|
||||||
.collect(),
|
.collect(),
|
||||||
|
pending_selection: self
|
||||||
|
.selections
|
||||||
|
.pending_anchor()
|
||||||
|
.as_ref()
|
||||||
|
.map(serialize_selection),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,9 +278,13 @@ impl FollowableItem for Editor {
|
||||||
.selections
|
.selections
|
||||||
.disjoint_anchors()
|
.disjoint_anchors()
|
||||||
.iter()
|
.iter()
|
||||||
.chain(self.selections.pending_anchor().as_ref())
|
|
||||||
.map(serialize_selection)
|
.map(serialize_selection)
|
||||||
.collect();
|
.collect();
|
||||||
|
update.pending_selection = self
|
||||||
|
.selections
|
||||||
|
.pending_anchor()
|
||||||
|
.as_ref()
|
||||||
|
.map(serialize_selection);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -307,6 +320,10 @@ impl FollowableItem for Editor {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|selection| deserialize_selection(&multibuffer, selection))
|
.filter_map(|selection| deserialize_selection(&multibuffer, selection))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
let pending_selection = message
|
||||||
|
.pending_selection
|
||||||
|
.and_then(|selection| deserialize_selection(&multibuffer, selection));
|
||||||
|
|
||||||
let scroll_top_anchor = message
|
let scroll_top_anchor = message
|
||||||
.scroll_top_anchor
|
.scroll_top_anchor
|
||||||
.and_then(|anchor| deserialize_anchor(&multibuffer, anchor));
|
.and_then(|anchor| deserialize_anchor(&multibuffer, anchor));
|
||||||
|
@ -361,8 +378,8 @@ impl FollowableItem for Editor {
|
||||||
multibuffer.remove_excerpts(removals, cx);
|
multibuffer.remove_excerpts(removals, cx);
|
||||||
});
|
});
|
||||||
|
|
||||||
if !selections.is_empty() {
|
if !selections.is_empty() || pending_selection.is_some() {
|
||||||
this.set_selections_from_remote(selections, cx);
|
this.set_selections_from_remote(selections, pending_selection, cx);
|
||||||
this.request_autoscroll_remotely(Autoscroll::newest(), cx);
|
this.request_autoscroll_remotely(Autoscroll::newest(), cx);
|
||||||
} else if let Some(anchor) = scroll_top_anchor {
|
} else if let Some(anchor) = scroll_top_anchor {
|
||||||
this.set_scroll_anchor_remote(ScrollAnchor {
|
this.set_scroll_anchor_remote(ScrollAnchor {
|
||||||
|
|
|
@ -853,9 +853,10 @@ message UpdateView {
|
||||||
repeated ExcerptInsertion inserted_excerpts = 1;
|
repeated ExcerptInsertion inserted_excerpts = 1;
|
||||||
repeated uint64 deleted_excerpts = 2;
|
repeated uint64 deleted_excerpts = 2;
|
||||||
repeated Selection selections = 3;
|
repeated Selection selections = 3;
|
||||||
EditorAnchor scroll_top_anchor = 4;
|
optional Selection pending_selection = 4;
|
||||||
float scroll_x = 5;
|
EditorAnchor scroll_top_anchor = 5;
|
||||||
float scroll_y = 6;
|
float scroll_x = 6;
|
||||||
|
float scroll_y = 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -872,9 +873,10 @@ message View {
|
||||||
optional string title = 2;
|
optional string title = 2;
|
||||||
repeated Excerpt excerpts = 3;
|
repeated Excerpt excerpts = 3;
|
||||||
repeated Selection selections = 4;
|
repeated Selection selections = 4;
|
||||||
EditorAnchor scroll_top_anchor = 5;
|
optional Selection pending_selection = 5;
|
||||||
float scroll_x = 6;
|
EditorAnchor scroll_top_anchor = 6;
|
||||||
float scroll_y = 7;
|
float scroll_x = 7;
|
||||||
|
float scroll_y = 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,4 +6,4 @@ pub use conn::Connection;
|
||||||
pub use peer::*;
|
pub use peer::*;
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
pub const PROTOCOL_VERSION: u32 = 43;
|
pub const PROTOCOL_VERSION: u32 = 44;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue