1use crate::{
2 editor::{display_map::FoldMap, Buffer, Point, TextSummary},
3 sum_tree::{self, SumTree},
4 time,
5 util::Bias,
6};
7use gpui::{Entity, ModelContext, ModelHandle, Task};
8use parking_lot::Mutex;
9use postage::{
10 mpsc,
11 prelude::{Sink, Stream},
12 watch,
13};
14
15#[derive(Clone)]
16struct Snapshot {
17 transforms: SumTree<Transform>,
18 version: time::Global,
19}
20
21struct State {
22 snapshot: Snapshot,
23 interpolated_version: time::Global,
24}
25
26struct WrapMap {
27 buffer: ModelHandle<Buffer>,
28 fold_map: FoldMap,
29 state: Mutex<State>,
30 background_snapshots: watch::Receiver<Snapshot>,
31 _background_task: Task<()>,
32}
33
34impl Entity for WrapMap {
35 type Event = ();
36}
37
38impl WrapMap {
39 fn new(buffer_handle: ModelHandle<Buffer>, cx: &mut ModelContext<Self>) -> Self {
40 let buffer = buffer_handle.read(cx).clone();
41 let version = buffer.version();
42 let snapshot = Snapshot {
43 transforms: SumTree::from_item(
44 Transform {
45 summary: TransformSummary {
46 buffer: buffer.text_summary(),
47 display: buffer.text_summary(),
48 },
49 display_text: None,
50 },
51 &(),
52 ),
53 version: version.clone(),
54 };
55 let (background_snapshots_tx, background_snapshots_rx) =
56 watch::channel_with(snapshot.clone());
57 let (buffers_tx, buffers_rx) = mpsc::channel(32);
58 cx.observe(&buffer_handle, move |_, buffer, cx| {
59 let mut buffers_tx = buffers_tx.clone();
60 // TODO: replace cloning buffers with sending `Buffer::snapshot`.
61 let buffer = buffer.read(cx).clone();
62 cx.spawn_weak(|_, _| async move {
63 let _ = buffers_tx.send(buffer).await;
64 })
65 .detach();
66 });
67 let background_task = cx.background().spawn(async move {
68 let mut wrapper = BackgroundWrapper::new(buffers_rx, background_snapshots_tx);
69 wrapper.run(buffer).await;
70 });
71
72 Self {
73 buffer: buffer_handle.clone(),
74 fold_map: FoldMap::new(buffer_handle, cx.as_ref()),
75 state: Mutex::new(State {
76 snapshot,
77 interpolated_version: version,
78 }),
79 background_snapshots: background_snapshots_rx,
80 _background_task: background_task,
81 }
82 }
83}
84
85struct BackgroundWrapper {
86 buffers_rx: mpsc::Receiver<Buffer>,
87 snapshots_tx: watch::Sender<Snapshot>,
88 snapshot: Snapshot,
89}
90
91impl BackgroundWrapper {
92 fn new(buffers_rx: mpsc::Receiver<Buffer>, snapshots_tx: watch::Sender<Snapshot>) -> Self {
93 Self {
94 buffers_rx,
95 snapshots_tx,
96 snapshot: Snapshot {
97 transforms: Default::default(),
98 version: Default::default(),
99 },
100 }
101 }
102
103 async fn run(&mut self, buffer: Buffer) {
104 if !self.sync(buffer).await {
105 return;
106 }
107
108 while let Some(buffer) = self.buffers_rx.recv().await {
109 if !self.sync(buffer).await {
110 break;
111 }
112 }
113 }
114
115 async fn sync(&mut self, buffer: Buffer) -> bool {
116 let mut new_transforms = SumTree::new();
117 {
118 let mut old_cursor = self.snapshot.transforms.cursor::<Point, ()>();
119 for edit in buffer.edits_since(self.snapshot.version.clone()) {
120 new_transforms.push_tree(
121 old_cursor.slice(&Point::new(edit.old_lines.start.row, 0), Bias::Left, &()),
122 &(),
123 );
124 }
125 }
126
127 self.snapshot.transforms = new_transforms;
128 self.snapshot.version = buffer.version();
129 self.snapshots_tx.send(self.snapshot.clone()).await.is_ok()
130 }
131}
132
133#[derive(Clone, Debug, Default, Eq, PartialEq)]
134struct Transform {
135 summary: TransformSummary,
136 display_text: Option<&'static str>,
137}
138
139impl sum_tree::Item for Transform {
140 type Summary = TransformSummary;
141
142 fn summary(&self) -> Self::Summary {
143 self.summary.clone()
144 }
145}
146
147#[derive(Clone, Debug, Default, Eq, PartialEq)]
148struct TransformSummary {
149 display: TextSummary,
150 buffer: TextSummary,
151}
152
153impl sum_tree::Summary for TransformSummary {
154 type Context = ();
155
156 fn add_summary(&mut self, other: &Self, _: &()) {
157 self.buffer += &other.buffer;
158 self.display += &other.display;
159 }
160}
161
162impl<'a> sum_tree::Dimension<'a, TransformSummary> for Point {
163 fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
164 *self += &summary.buffer.lines;
165 }
166}