Use the new buffer subscription API to keep DisplayMap
in sync
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
3b536f153f
commit
733e0cb21b
6 changed files with 34 additions and 103 deletions
|
@ -10,11 +10,9 @@ use gpui::{
|
||||||
fonts::{FontId, HighlightStyle},
|
fonts::{FontId, HighlightStyle},
|
||||||
AppContext, Entity, ModelContext, ModelHandle,
|
AppContext, Entity, ModelContext, ModelHandle,
|
||||||
};
|
};
|
||||||
use language::{Anchor, Buffer, Patch, Point, ToOffset, ToPoint};
|
use language::{Anchor, Buffer, Point, Subscription as BufferSubscription, ToOffset, ToPoint};
|
||||||
use parking_lot::Mutex;
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
mem,
|
|
||||||
ops::Range,
|
ops::Range,
|
||||||
};
|
};
|
||||||
use sum_tree::Bias;
|
use sum_tree::Bias;
|
||||||
|
@ -29,11 +27,11 @@ pub trait ToDisplayPoint {
|
||||||
|
|
||||||
pub struct DisplayMap {
|
pub struct DisplayMap {
|
||||||
buffer: ModelHandle<Buffer>,
|
buffer: ModelHandle<Buffer>,
|
||||||
|
buffer_subscription: BufferSubscription,
|
||||||
fold_map: FoldMap,
|
fold_map: FoldMap,
|
||||||
tab_map: TabMap,
|
tab_map: TabMap,
|
||||||
wrap_map: ModelHandle<WrapMap>,
|
wrap_map: ModelHandle<WrapMap>,
|
||||||
block_map: BlockMap,
|
block_map: BlockMap,
|
||||||
buffer_edits_since_sync: Mutex<Patch<usize>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Entity for DisplayMap {
|
impl Entity for DisplayMap {
|
||||||
|
@ -49,28 +47,26 @@ impl DisplayMap {
|
||||||
wrap_width: Option<f32>,
|
wrap_width: Option<f32>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let buffer_subscription = buffer.update(cx, |buffer, _| buffer.subscribe());
|
||||||
let (fold_map, snapshot) = FoldMap::new(buffer.read(cx).snapshot());
|
let (fold_map, snapshot) = FoldMap::new(buffer.read(cx).snapshot());
|
||||||
let (tab_map, snapshot) = TabMap::new(snapshot, tab_size);
|
let (tab_map, snapshot) = TabMap::new(snapshot, tab_size);
|
||||||
let (wrap_map, snapshot) = WrapMap::new(snapshot, font_id, font_size, wrap_width, cx);
|
let (wrap_map, snapshot) = WrapMap::new(snapshot, font_id, font_size, wrap_width, cx);
|
||||||
let block_map = BlockMap::new(buffer.clone(), snapshot);
|
let block_map = BlockMap::new(buffer.clone(), snapshot);
|
||||||
cx.observe(&wrap_map, |_, _, cx| cx.notify()).detach();
|
cx.observe(&wrap_map, |_, _, cx| cx.notify()).detach();
|
||||||
cx.subscribe(&buffer, Self::handle_buffer_event).detach();
|
|
||||||
DisplayMap {
|
DisplayMap {
|
||||||
buffer,
|
buffer,
|
||||||
|
buffer_subscription,
|
||||||
fold_map,
|
fold_map,
|
||||||
tab_map,
|
tab_map,
|
||||||
wrap_map,
|
wrap_map,
|
||||||
block_map,
|
block_map,
|
||||||
buffer_edits_since_sync: Default::default(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn snapshot(&self, cx: &mut ModelContext<Self>) -> DisplayMapSnapshot {
|
pub fn snapshot(&self, cx: &mut ModelContext<Self>) -> DisplayMapSnapshot {
|
||||||
let buffer_snapshot = self.buffer.read(cx).snapshot();
|
let buffer_snapshot = self.buffer.read(cx).snapshot();
|
||||||
let (folds_snapshot, edits) = self.fold_map.read(
|
let edits = self.buffer_subscription.consume().into_inner();
|
||||||
buffer_snapshot,
|
let (folds_snapshot, edits) = self.fold_map.read(buffer_snapshot, edits);
|
||||||
mem::take(&mut *self.buffer_edits_since_sync.lock()).into_inner(),
|
|
||||||
);
|
|
||||||
let (tabs_snapshot, edits) = self.tab_map.sync(folds_snapshot.clone(), edits);
|
let (tabs_snapshot, edits) = self.tab_map.sync(folds_snapshot.clone(), edits);
|
||||||
let (wraps_snapshot, edits) = self
|
let (wraps_snapshot, edits) = self
|
||||||
.wrap_map
|
.wrap_map
|
||||||
|
@ -92,10 +88,8 @@ impl DisplayMap {
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) {
|
) {
|
||||||
let snapshot = self.buffer.read(cx).snapshot();
|
let snapshot = self.buffer.read(cx).snapshot();
|
||||||
let (mut fold_map, snapshot, edits) = self.fold_map.write(
|
let edits = self.buffer_subscription.consume().into_inner();
|
||||||
snapshot,
|
let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
|
||||||
mem::take(&mut *self.buffer_edits_since_sync.lock()).into_inner(),
|
|
||||||
);
|
|
||||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
|
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
|
||||||
let (snapshot, edits) = self
|
let (snapshot, edits) = self
|
||||||
.wrap_map
|
.wrap_map
|
||||||
|
@ -115,10 +109,8 @@ impl DisplayMap {
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) {
|
) {
|
||||||
let snapshot = self.buffer.read(cx).snapshot();
|
let snapshot = self.buffer.read(cx).snapshot();
|
||||||
let (mut fold_map, snapshot, edits) = self.fold_map.write(
|
let edits = self.buffer_subscription.consume().into_inner();
|
||||||
snapshot,
|
let (mut fold_map, snapshot, edits) = self.fold_map.write(snapshot, edits);
|
||||||
mem::take(&mut *self.buffer_edits_since_sync.lock()).into_inner(),
|
|
||||||
);
|
|
||||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
|
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
|
||||||
let (snapshot, edits) = self
|
let (snapshot, edits) = self
|
||||||
.wrap_map
|
.wrap_map
|
||||||
|
@ -142,10 +134,8 @@ impl DisplayMap {
|
||||||
T: Into<Rope> + Clone,
|
T: Into<Rope> + Clone,
|
||||||
{
|
{
|
||||||
let snapshot = self.buffer.read(cx).snapshot();
|
let snapshot = self.buffer.read(cx).snapshot();
|
||||||
let (snapshot, edits) = self.fold_map.read(
|
let edits = self.buffer_subscription.consume().into_inner();
|
||||||
snapshot,
|
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||||
mem::take(&mut *self.buffer_edits_since_sync.lock()).into_inner(),
|
|
||||||
);
|
|
||||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
|
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
|
||||||
let (snapshot, edits) = self
|
let (snapshot, edits) = self
|
||||||
.wrap_map
|
.wrap_map
|
||||||
|
@ -164,10 +154,8 @@ impl DisplayMap {
|
||||||
|
|
||||||
pub fn remove_blocks(&mut self, ids: HashSet<BlockId>, cx: &mut ModelContext<Self>) {
|
pub fn remove_blocks(&mut self, ids: HashSet<BlockId>, cx: &mut ModelContext<Self>) {
|
||||||
let snapshot = self.buffer.read(cx).snapshot();
|
let snapshot = self.buffer.read(cx).snapshot();
|
||||||
let (snapshot, edits) = self.fold_map.read(
|
let edits = self.buffer_subscription.consume().into_inner();
|
||||||
snapshot,
|
let (snapshot, edits) = self.fold_map.read(snapshot, edits);
|
||||||
mem::take(&mut *self.buffer_edits_since_sync.lock()).into_inner(),
|
|
||||||
);
|
|
||||||
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
|
let (snapshot, edits) = self.tab_map.sync(snapshot, edits);
|
||||||
let (snapshot, edits) = self
|
let (snapshot, edits) = self
|
||||||
.wrap_map
|
.wrap_map
|
||||||
|
@ -190,21 +178,6 @@ impl DisplayMap {
|
||||||
pub fn is_rewrapping(&self, cx: &gpui::AppContext) -> bool {
|
pub fn is_rewrapping(&self, cx: &gpui::AppContext) -> bool {
|
||||||
self.wrap_map.read(cx).is_rewrapping()
|
self.wrap_map.read(cx).is_rewrapping()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_buffer_event(
|
|
||||||
&mut self,
|
|
||||||
_: ModelHandle<Buffer>,
|
|
||||||
event: &language::Event,
|
|
||||||
_: &mut ModelContext<Self>,
|
|
||||||
) {
|
|
||||||
match event {
|
|
||||||
language::Event::Edited(patch) => {
|
|
||||||
let mut edits_since_sync = self.buffer_edits_since_sync.lock();
|
|
||||||
*edits_since_sync = edits_since_sync.compose(patch);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DisplayMapSnapshot {
|
pub struct DisplayMapSnapshot {
|
||||||
|
|
|
@ -3466,7 +3466,7 @@ impl Editor {
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
language::Event::Edited(_) => cx.emit(Event::Edited),
|
language::Event::Edited => cx.emit(Event::Edited),
|
||||||
language::Event::Dirtied => cx.emit(Event::Dirtied),
|
language::Event::Dirtied => cx.emit(Event::Dirtied),
|
||||||
language::Event::Saved => cx.emit(Event::Saved),
|
language::Event::Saved => cx.emit(Event::Saved),
|
||||||
language::Event::FileHandleChanged => cx.emit(Event::FileHandleChanged),
|
language::Event::FileHandleChanged => cx.emit(Event::FileHandleChanged),
|
||||||
|
|
|
@ -109,7 +109,7 @@ pub enum Operation {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
Edited(Patch<usize>),
|
Edited,
|
||||||
Dirtied,
|
Dirtied,
|
||||||
Saved,
|
Saved,
|
||||||
FileHandleChanged,
|
FileHandleChanged,
|
||||||
|
@ -1138,6 +1138,10 @@ impl Buffer {
|
||||||
.map_or(false, |file| file.mtime() > self.saved_mtime)
|
.map_or(false, |file| file.mtime() > self.saved_mtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn subscribe(&mut self) -> Subscription {
|
||||||
|
self.text.subscribe()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn start_transaction(
|
pub fn start_transaction(
|
||||||
&mut self,
|
&mut self,
|
||||||
selection_set_ids: impl IntoIterator<Item = SelectionSetId>,
|
selection_set_ids: impl IntoIterator<Item = SelectionSetId>,
|
||||||
|
@ -1330,7 +1334,7 @@ impl Buffer {
|
||||||
self.reparse(cx);
|
self.reparse(cx);
|
||||||
self.update_language_server();
|
self.update_language_server();
|
||||||
|
|
||||||
cx.emit(Event::Edited(patch));
|
cx.emit(Event::Edited);
|
||||||
if !was_dirty {
|
if !was_dirty {
|
||||||
cx.emit(Event::Dirtied);
|
cx.emit(Event::Dirtied);
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,34 +110,11 @@ fn test_edit_events(cx: &mut gpui::MutableAppContext) {
|
||||||
let buffer_1_events = buffer_1_events.borrow();
|
let buffer_1_events = buffer_1_events.borrow();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*buffer_1_events,
|
*buffer_1_events,
|
||||||
vec![
|
vec![Event::Edited, Event::Dirtied, Event::Edited, Event::Edited]
|
||||||
Event::Edited(Patch::new(vec![Edit {
|
|
||||||
old: 2..4,
|
|
||||||
new: 2..5
|
|
||||||
}])),
|
|
||||||
Event::Dirtied,
|
|
||||||
Event::Edited(Patch::new(vec![Edit {
|
|
||||||
old: 5..5,
|
|
||||||
new: 5..7
|
|
||||||
}])),
|
|
||||||
Event::Edited(Patch::new(vec![Edit {
|
|
||||||
old: 5..7,
|
|
||||||
new: 5..5,
|
|
||||||
}]))
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let buffer_2_events = buffer_2_events.borrow();
|
let buffer_2_events = buffer_2_events.borrow();
|
||||||
assert_eq!(
|
assert_eq!(*buffer_2_events, vec![Event::Edited, Event::Dirtied]);
|
||||||
*buffer_2_events,
|
|
||||||
vec![
|
|
||||||
Event::Edited(Patch::new(vec![Edit {
|
|
||||||
old: 2..4,
|
|
||||||
new: 2..5
|
|
||||||
}])),
|
|
||||||
Event::Dirtied
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
|
|
|
@ -3016,7 +3016,7 @@ mod tests {
|
||||||
fmt::Write,
|
fmt::Write,
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
use text::{Patch, Point};
|
use text::Point;
|
||||||
use util::test::temp_tree;
|
use util::test::temp_tree;
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
|
@ -3469,13 +3469,7 @@ mod tests {
|
||||||
assert!(buffer.is_dirty());
|
assert!(buffer.is_dirty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*events.borrow(),
|
*events.borrow(),
|
||||||
&[
|
&[language::Event::Edited, language::Event::Dirtied]
|
||||||
language::Event::Edited(Patch::new(vec![text::Edit {
|
|
||||||
old: 1..2,
|
|
||||||
new: 1..1
|
|
||||||
}])),
|
|
||||||
language::Event::Dirtied
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
events.borrow_mut().clear();
|
events.borrow_mut().clear();
|
||||||
buffer.did_save(buffer.version(), buffer.file().unwrap().mtime(), None, cx);
|
buffer.did_save(buffer.version(), buffer.file().unwrap().mtime(), None, cx);
|
||||||
|
@ -3498,15 +3492,9 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
*events.borrow(),
|
*events.borrow(),
|
||||||
&[
|
&[
|
||||||
language::Event::Edited(Patch::new(vec![text::Edit {
|
language::Event::Edited,
|
||||||
old: 1..1,
|
|
||||||
new: 1..2
|
|
||||||
}])),
|
|
||||||
language::Event::Dirtied,
|
language::Event::Dirtied,
|
||||||
language::Event::Edited(Patch::new(vec![text::Edit {
|
language::Event::Edited,
|
||||||
old: 2..2,
|
|
||||||
new: 2..3
|
|
||||||
}])),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
events.borrow_mut().clear();
|
events.borrow_mut().clear();
|
||||||
|
@ -3518,13 +3506,7 @@ mod tests {
|
||||||
assert!(buffer.is_dirty());
|
assert!(buffer.is_dirty());
|
||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(*events.borrow(), &[language::Event::Edited]);
|
||||||
*events.borrow(),
|
|
||||||
&[language::Event::Edited(Patch::new(vec![text::Edit {
|
|
||||||
old: 1..3,
|
|
||||||
new: 1..1
|
|
||||||
}]))]
|
|
||||||
);
|
|
||||||
|
|
||||||
// When a file is deleted, the buffer is considered dirty.
|
// When a file is deleted, the buffer is considered dirty.
|
||||||
let events = Rc::new(RefCell::new(Vec::new()));
|
let events = Rc::new(RefCell::new(Vec::new()));
|
||||||
|
|
|
@ -46,7 +46,7 @@ pub struct Buffer {
|
||||||
remote_id: u64,
|
remote_id: u64,
|
||||||
local_clock: clock::Local,
|
local_clock: clock::Local,
|
||||||
lamport_clock: clock::Lamport,
|
lamport_clock: clock::Lamport,
|
||||||
subscriptions: Vec<Weak<Subscription>>,
|
subscriptions: Vec<Weak<Mutex<Vec<Patch<usize>>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -342,7 +342,7 @@ impl<D1, D2> Edit<(D1, D2)> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct Subscription(Arc<Mutex<Vec<Patch<usize>>>>);
|
pub struct Subscription(Arc<Mutex<Vec<Patch<usize>>>>);
|
||||||
|
|
||||||
impl Subscription {
|
impl Subscription {
|
||||||
|
@ -354,11 +354,6 @@ impl Subscription {
|
||||||
}
|
}
|
||||||
changes
|
changes
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn publish(&self, patch: Patch<usize>) {
|
|
||||||
let mut changes = self.0.lock();
|
|
||||||
changes.push(patch);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
||||||
|
@ -1200,16 +1195,16 @@ impl Buffer {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscribe(&mut self) -> Arc<Subscription> {
|
pub fn subscribe(&mut self) -> Subscription {
|
||||||
let subscription = Arc::new(Default::default());
|
let subscription = Subscription(Default::default());
|
||||||
self.subscriptions.push(Arc::downgrade(&subscription));
|
self.subscriptions.push(Arc::downgrade(&subscription.0));
|
||||||
subscription
|
subscription
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_subscriptions(&mut self, edits: Patch<usize>) {
|
fn update_subscriptions(&mut self, edits: Patch<usize>) {
|
||||||
self.subscriptions.retain(|subscription| {
|
self.subscriptions.retain(|subscription| {
|
||||||
if let Some(subscription) = subscription.upgrade() {
|
if let Some(subscription) = subscription.upgrade() {
|
||||||
subscription.publish(edits.clone());
|
subscription.lock().push(edits.clone());
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue