diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index a4f2ccd22d..211585b9ad 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -1991,8 +1991,8 @@ impl Editor { pub fn undo(&mut self, _: &Undo, cx: &mut ViewContext) { if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) { - if let Some((selections, _)) = self.selection_history.get(&tx_id) { - self.selections = selections.clone(); + if let Some((selections, _)) = self.selection_history.get(&tx_id).cloned() { + self.set_selections(selections, cx); } self.request_autoscroll(Autoscroll::Fit, cx); } @@ -2000,8 +2000,8 @@ impl Editor { pub fn redo(&mut self, _: &Redo, cx: &mut ViewContext) { if let Some(tx_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) { - if let Some((_, Some(selections))) = self.selection_history.get(&tx_id) { - self.selections = selections.clone(); + if let Some((_, Some(selections))) = self.selection_history.get(&tx_id).cloned() { + self.set_selections(selections, cx); } self.request_autoscroll(Autoscroll::Fit, cx); } @@ -3256,13 +3256,23 @@ impl Editor { } self.pause_cursor_blinking(cx); - self.selections = Arc::from_iter(selections.into_iter().map(|selection| Selection { - id: selection.id, - start: buffer.anchor_before(selection.start), - end: buffer.anchor_before(selection.end), - reversed: selection.reversed, - goal: selection.goal, - })); + self.set_selections( + Arc::from_iter(selections.into_iter().map(|selection| Selection { + id: selection.id, + start: buffer.anchor_before(selection.start), + end: buffer.anchor_before(selection.end), + reversed: selection.reversed, + goal: selection.goal, + })), + cx, + ); + } + + fn set_selections(&mut self, selections: Arc<[Selection]>, cx: &mut ViewContext) { + self.selections = selections; + self.buffer.update(cx, |buffer, cx| { + buffer.set_active_selections(&self.selections, cx) + }); } fn request_autoscroll(&mut self, autoscroll: Autoscroll, cx: &mut ViewContext) { @@ -3651,11 +3661,16 @@ impl View for Editor { fn on_focus(&mut self, cx: &mut ViewContext) { self.focused = true; self.blink_cursors(self.blink_epoch, cx); + self.buffer.update(cx, |buffer, cx| { + buffer.set_active_selections(&self.selections, cx) + }); } fn on_blur(&mut self, cx: &mut ViewContext) { self.focused = false; self.show_local_cursors = false; + self.buffer + .update(cx, |buffer, cx| buffer.remove_active_selections(cx)); cx.emit(Event::Blurred); cx.notify(); } diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index 1ba453b0d0..58bd41ffcf 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -12,7 +12,7 @@ use language::{ use std::{ cell::{Ref, RefCell}, cmp, io, - iter::Peekable, + iter::{FromIterator, Peekable}, ops::{Range, Sub}, sync::Arc, time::{Duration, Instant, SystemTime}, @@ -242,6 +242,34 @@ impl MultiBuffer { .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx)) } + pub fn set_active_selections( + &mut self, + selections: &[Selection], + cx: &mut ModelContext, + ) { + // TODO + let this = self.read(cx); + self.as_singleton().unwrap().update(cx, |buffer, cx| { + let buffer_snapshot = buffer.snapshot(); + let selections = selections.iter().map(|selection| Selection { + id: selection.id, + start: buffer_snapshot.anchor_before(selection.start.to_offset(&this)), + end: buffer_snapshot.anchor_before(selection.end.to_offset(&this)), + reversed: selection.reversed, + goal: selection.goal, + }); + buffer.set_active_selections(Arc::from_iter(selections), cx); + }); + } + + pub fn remove_active_selections(&mut self, cx: &mut ModelContext) { + for buffer in self.buffers.values() { + buffer + .buffer + .update(cx, |buffer, cx| buffer.remove_active_selections(cx)); + } + } + pub fn undo(&mut self, cx: &mut ModelContext) -> Option { // TODO self.as_singleton() diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 9ed8d784f3..120f1b710f 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -289,6 +289,12 @@ impl Buffer { .map(|op| text::Operation::Edit(proto::deserialize_edit_operation(op))); buffer.apply_ops(ops)?; let mut this = Self::build(buffer, file); + for selection_set in message.selections { + this.remote_selections.insert( + selection_set.replica_id as ReplicaId, + proto::deserialize_selections(selection_set.selections), + ); + } this.apply_diagnostic_update( Arc::from(proto::deserialize_diagnostics(message.diagnostics)), cx, @@ -306,7 +312,14 @@ impl Buffer { .history() .map(proto::serialize_edit_operation) .collect(), - selections: Vec::new(), + selections: self + .remote_selections + .iter() + .map(|(replica_id, selections)| proto::SelectionSet { + replica_id: *replica_id as u32, + selections: proto::serialize_selections(selections), + }) + .collect(), diagnostics: proto::serialize_diagnostics(self.diagnostics.iter()), } } @@ -835,7 +848,7 @@ impl Buffer { cx.emit(Event::DiagnosticsUpdated); Ok(Operation::UpdateDiagnostics { diagnostics: Arc::from(self.diagnostics.iter().cloned().collect::>()), - lamport_timestamp: self.lamport_timestamp(), + lamport_timestamp: self.text.lamport_clock.tick(), }) } @@ -1084,6 +1097,35 @@ impl Buffer { } } + pub fn set_active_selections( + &mut self, + selections: Arc<[Selection]>, + cx: &mut ModelContext, + ) { + let lamport_timestamp = self.text.lamport_clock.tick(); + self.remote_selections + .insert(self.text.replica_id(), selections.clone()); + self.send_operation( + Operation::UpdateSelections { + replica_id: self.text.replica_id(), + selections, + lamport_timestamp, + }, + cx, + ); + } + + pub fn remove_active_selections(&mut self, cx: &mut ModelContext) { + let lamport_timestamp = self.text.lamport_clock.tick(); + self.send_operation( + Operation::RemoveSelections { + replica_id: self.text.replica_id(), + lamport_timestamp, + }, + cx, + ); + } + fn update_language_server(&mut self) { let language_server = if let Some(language_server) = self.language_server.as_mut() { language_server @@ -1321,14 +1363,14 @@ impl Buffer { lamport_timestamp, } => { self.remote_selections.insert(replica_id, selections); - self.text.observe_lamport_timestamp(lamport_timestamp); + self.text.lamport_clock.observe(lamport_timestamp); } Operation::RemoveSelections { - replica_id: set_id, + replica_id, lamport_timestamp, } => { - self.remote_selections.remove(&set_id); - self.text.observe_lamport_timestamp(lamport_timestamp); + self.remote_selections.remove(&replica_id); + self.text.lamport_clock.observe(lamport_timestamp); } } } @@ -1655,6 +1697,7 @@ impl BufferSnapshot { { self.remote_selections .iter() + .filter(|(replica_id, _)| **replica_id != self.text.replica_id()) .map(move |(replica_id, selections)| { let start_ix = match selections .binary_search_by(|probe| probe.end.cmp(&range.start, self).unwrap()) diff --git a/crates/language/src/proto.rs b/crates/language/src/proto.rs index 8921ffa421..25e2dfe223 100644 --- a/crates/language/src/proto.rs +++ b/crates/language/src/proto.rs @@ -1,13 +1,12 @@ -use std::sync::Arc; - use crate::{diagnostic_set::DiagnosticEntry, Diagnostic, Operation}; use anyhow::{anyhow, Result}; use clock::ReplicaId; use lsp::DiagnosticSeverity; use rpc::proto; +use std::sync::Arc; use text::*; -pub use proto::Buffer; +pub use proto::{Buffer, SelectionSet}; pub fn serialize_operation(operation: &Operation) -> proto::Operation { proto::Operation { @@ -48,15 +47,7 @@ pub fn serialize_operation(operation: &Operation) -> proto::Operation { } => proto::operation::Variant::UpdateSelections(proto::operation::UpdateSelections { replica_id: *replica_id as u32, lamport_timestamp: lamport_timestamp.value, - selections: selections - .iter() - .map(|selection| proto::Selection { - id: selection.id as u64, - start: Some(serialize_anchor(&selection.start)), - end: Some(serialize_anchor(&selection.end)), - reversed: selection.reversed, - }) - .collect(), + selections: serialize_selections(selections), }), Operation::RemoveSelections { replica_id, diff --git a/crates/rpc/proto/zed.proto b/crates/rpc/proto/zed.proto index 7a06abb122..5ea70b7d8a 100644 --- a/crates/rpc/proto/zed.proto +++ b/crates/rpc/proto/zed.proto @@ -234,9 +234,7 @@ message Buffer { message SelectionSet { uint32 replica_id = 1; - uint32 lamport_timestamp = 2; - bool is_active = 3; - repeated Selection selections = 4; + repeated Selection selections = 2; } message Selection { diff --git a/crates/rpc/src/rpc.rs b/crates/rpc/src/rpc.rs index 110b6a6659..3263ad8063 100644 --- a/crates/rpc/src/rpc.rs +++ b/crates/rpc/src/rpc.rs @@ -5,4 +5,4 @@ pub mod proto; pub use conn::Connection; pub use peer::*; -pub const PROTOCOL_VERSION: u32 = 3; +pub const PROTOCOL_VERSION: u32 = 4; diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index 2c2de7dfe5..30fd985319 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -49,12 +49,13 @@ pub struct Buffer { replica_id: ReplicaId, remote_id: u64, local_clock: clock::Local, - lamport_clock: clock::Lamport, + pub lamport_clock: clock::Lamport, subscriptions: Topic, } #[derive(Clone, Debug)] pub struct BufferSnapshot { + replica_id: ReplicaId, visible_text: Rope, deleted_text: Rope, undo_map: UndoMap, @@ -464,6 +465,7 @@ impl Buffer { Buffer { snapshot: BufferSnapshot { + replica_id, visible_text, deleted_text: Rope::new(), fragments, @@ -495,14 +497,6 @@ impl Buffer { self.local_clock.replica_id } - pub fn lamport_timestamp(&self) -> clock::Lamport { - self.lamport_clock - } - - pub fn observe_lamport_timestamp(&mut self, timestamp: clock::Lamport) { - self.lamport_clock.observe(timestamp); - } - pub fn remote_id(&self) -> u64 { self.remote_id } @@ -1219,6 +1213,10 @@ impl BufferSnapshot { &self.visible_text } + pub fn replica_id(&self) -> ReplicaId { + self.replica_id + } + pub fn row_count(&self) -> u32 { self.max_point().row + 1 } diff --git a/script/seed-db b/script/seed-db index 195dc5fb8d..f42a33ba00 100755 --- a/script/seed-db +++ b/script/seed-db @@ -1,5 +1,4 @@ #!/bin/bash set -e -cd server -cargo run --features seed-support --bin seed +cargo run --package=zed-server --features seed-support --bin seed