1use std::{
2 cmp::Ordering,
3 mem,
4 sync::atomic::{AtomicUsize, Ordering::SeqCst},
5};
6
7use buffer::{rope::TextDimension, Anchor, Bias, Edit, Rope, TextSummary, ToOffset};
8use gpui::{fonts::HighlightStyle, AppContext, ModelHandle};
9use language::Buffer;
10use parking_lot::Mutex;
11use sum_tree::{SeekTarget, SumTree};
12use util::post_inc;
13
14#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
15pub struct InjectionId(usize);
16
17pub struct InjectionMap {
18 buffer: ModelHandle<Buffer>,
19 transforms: Mutex<SumTree<Transform>>,
20 injections: SumTree<Injection>,
21 version: AtomicUsize,
22 last_sync: Mutex<SyncState>,
23 next_injection_id: usize,
24}
25
26pub struct InjectionSnapshot {
27 transforms: SumTree<Transform>,
28 injections: SumTree<Injection>,
29 buffer_snapshot: language::Snapshot,
30 pub version: usize,
31}
32
33pub struct InjectionMapWriter<'a>(&'a mut InjectionMap);
34
35#[derive(Clone)]
36struct SyncState {
37 version: clock::Global,
38 parse_count: usize,
39 diagnostics_update_count: usize,
40}
41
42#[derive(Clone, Debug)]
43struct InjectionSummary {
44 min_id: InjectionId,
45 max_id: InjectionId,
46 min_position: Anchor,
47 max_position: Anchor,
48}
49
50#[derive(Clone, Debug)]
51struct Injection {
52 id: InjectionId,
53 text: Rope,
54 runs: Vec<(usize, HighlightStyle)>,
55}
56
57#[derive(Clone, Debug, Default, PartialEq)]
58struct Transform {
59 input: TextSummary,
60 output: TextSummary,
61 injection_id: Option<InjectionId>,
62}
63
64#[derive(Clone, Debug, Default, Eq, PartialEq)]
65struct TransformSummary {
66 input: TextSummary,
67 output: TextSummary,
68 min_injection_id: InjectionId,
69 max_injection_id: InjectionId,
70}
71
72#[derive(Copy, Clone, Debug, Default)]
73struct InjectionOffset(usize);
74
75impl sum_tree::Summary for InjectionId {
76 type Context = ();
77
78 fn add_summary(&mut self, summary: &Self, cx: &Self::Context) {
79 *self = *summary
80 }
81}
82
83impl InjectionMap {
84 pub fn read(&self, cx: &AppContext) -> (InjectionSnapshot, Vec<Edit<InjectionOffset>>) {
85 let edits = self.sync(cx);
86 // self.check_invariants(cx);
87 let snapshot = InjectionSnapshot {
88 transforms: self.transforms.lock().clone(),
89 injections: self.injections.clone(),
90 buffer_snapshot: self.buffer.read(cx).snapshot(),
91 version: self.version.load(SeqCst),
92 };
93 (snapshot, edits)
94 }
95
96 pub fn write(
97 &mut self,
98 cx: &AppContext,
99 ) -> (
100 InjectionMapWriter,
101 InjectionSnapshot,
102 Vec<Edit<InjectionOffset>>,
103 ) {
104 let (snapshot, edits) = self.read(cx);
105 (InjectionMapWriter(self), snapshot, edits)
106 }
107
108 fn sync(&self, cx: &AppContext) -> Vec<Edit<InjectionOffset>> {
109 let buffer = self.buffer.read(cx);
110 let last_sync = mem::replace(
111 &mut *self.last_sync.lock(),
112 SyncState {
113 version: buffer.version(),
114 parse_count: buffer.parse_count(),
115 diagnostics_update_count: buffer.diagnostics_update_count(),
116 },
117 );
118 let edits = buffer
119 .edits_since(&last_sync.version)
120 .map(Into::into)
121 .collect::<Vec<_>>();
122 if edits.is_empty() {
123 if last_sync.parse_count != buffer.parse_count()
124 || last_sync.diagnostics_update_count != buffer.diagnostics_update_count()
125 {
126 self.version.fetch_add(1, SeqCst);
127 }
128 Vec::new()
129 } else {
130 self.apply_edits(edits, cx)
131 }
132 }
133
134 fn apply_edits(
135 &self,
136 buffer_edits: Vec<buffer::Edit<usize>>,
137 cx: &AppContext,
138 ) -> Vec<Edit<InjectionOffset>> {
139 let buffer = self.buffer.read(cx).snapshot();
140 let mut buffer_edits_iter = buffer_edits.iter().cloned().peekable();
141
142 let mut new_transforms = SumTree::<Transform>::new();
143 let mut transforms = self.transforms.lock();
144 let mut cursor = transforms.cursor::<usize>();
145
146 while let Some(mut edit) = buffer_edits_iter.next() {
147 new_transforms.push_tree(cursor.slice(&edit.old.start, Bias::Right, &()), &());
148 edit.new.start -= edit.old.start - cursor.start();
149 edit.old.start = *cursor.start();
150
151 cursor.seek(&edit.old.end, Bias::Left, &());
152 cursor.next(&());
153
154 let mut delta = edit.new.len() as isize - edit.old.len() as isize;
155 loop {
156 edit.old.end = *cursor.start();
157
158 if let Some(next_edit) = buffer_edits_iter.peek() {
159 if next_edit.old.start >= edit.old.end {
160 break;
161 }
162
163 let next_edit = buffer_edits_iter.next().unwrap();
164 delta += next_edit.new.len() as isize - next_edit.old.len() as isize;
165
166 if next_edit.old.end >= edit.old.end {
167 edit.old.end = next_edit.old.end;
168 cursor.seek(&edit.old.end, Bias::Left, &());
169 cursor.next(&());
170 }
171 } else {
172 break;
173 }
174 }
175
176 edit.new.end = ((edit.new.start + edit.old.len()) as isize + delta) as usize;
177
178 if !edit.new.is_empty() {
179 let text_summary = buffer.text_summary_for_range(edit.new.start..edit.new.end);
180 new_transforms.push(
181 Transform {
182 input: text_summary.clone(),
183 output: text_summary,
184 injection_id: None,
185 },
186 &(),
187 );
188 }
189 }
190 new_transforms.push_tree(cursor.suffix(&()), &());
191 drop(cursor);
192
193 let injection_edits = {
194 let mut old_transforms = transforms.cursor::<(usize, InjectionOffset)>();
195 let mut new_transforms = new_transforms.cursor::<(usize, InjectionOffset)>();
196
197 buffer_edits
198 .into_iter()
199 .map(|edit| {
200 old_transforms.seek(&edit.old.start, Bias::Right, &());
201 let old_start =
202 old_transforms.start().1 .0 + (edit.old.start - old_transforms.start().0);
203
204 old_transforms.seek_forward(&edit.old.end, Bias::Left, &());
205 let old_end =
206 old_transforms.start().1 .0 + (edit.old.end - old_transforms.start().0);
207
208 new_transforms.seek(&edit.new.start, Bias::Right, &());
209 let new_start =
210 new_transforms.start().1 .0 + (edit.new.start - new_transforms.start().0);
211
212 new_transforms.seek_forward(&edit.new.end, Bias::Left, &());
213 let new_end =
214 new_transforms.start().1 .0 + (edit.new.end - new_transforms.start().0);
215
216 Edit {
217 old: InjectionOffset(old_start)..InjectionOffset(old_end),
218 new: InjectionOffset(new_start)..InjectionOffset(new_end),
219 }
220 })
221 .collect()
222 };
223
224 *transforms = new_transforms;
225 injection_edits
226 }
227}
228
229impl<'a> InjectionMapWriter<'a> {
230 pub fn insert<'b, T, U>(
231 &mut self,
232 injections: T,
233 cx: &AppContext,
234 ) -> (
235 Vec<InjectionId>,
236 InjectionSnapshot,
237 Vec<Edit<InjectionOffset>>,
238 )
239 where
240 T: IntoIterator<Item = (U, &'b str, Vec<(usize, HighlightStyle)>)>,
241 U: ToOffset,
242 {
243 let buffer = self.0.buffer.read(cx);
244 let mut injections = injections
245 .into_iter()
246 .map(|(position, text, runs)| (position.to_offset(buffer), text, runs))
247 .peekable();
248 let mut edits = Vec::new();
249 let mut injection_ids = Vec::new();
250 let mut new_transforms = SumTree::new();
251 let mut transforms = self.0.transforms.lock();
252 let mut cursor = transforms.cursor::<usize>();
253
254 while let Some((injection_offset, text, runs)) = injections.next() {
255 new_transforms.push_tree(cursor.slice(&injection_offset, Bias::Right, &()), &());
256 let new_transforms_end = new_transforms.summary().input.bytes;
257 if injection_offset > new_transforms_end {
258 new_transforms.push(
259 Transform::isomorphic(
260 buffer.text_summary_for_range(new_transforms_end..injection_offset),
261 ),
262 &(),
263 );
264 }
265
266 let injection = Injection {
267 id: InjectionId(post_inc(&mut self.0.next_injection_id)),
268 runs,
269 text: text.into(),
270 };
271 new_transforms.push(
272 Transform {
273 input: Default::default(),
274 output: injection.text.summary(),
275 injection_id: Some(injection.id),
276 },
277 &(),
278 );
279 self.0.injections.push(injection, &());
280
281 if let Some((next_injection_offset, _, _)) = injections.peek() {
282 let old_transform_end = cursor.end(&());
283 if *next_injection_offset > old_transform_end {
284 new_transforms.push(
285 Transform::isomorphic(
286 buffer.text_summary_for_range(new_transforms_end..old_transform_end),
287 ),
288 &(),
289 );
290 cursor.next(&());
291 }
292 }
293 }
294
295 (injection_ids, todo!(), edits)
296 }
297}
298
299impl sum_tree::Item for Injection {
300 type Summary = InjectionId;
301
302 fn summary(&self) -> Self::Summary {
303 self.id
304 }
305}
306
307impl Transform {
308 fn isomorphic(text_summary: TextSummary) -> Self {
309 Self {
310 input: text_summary.clone(),
311 output: text_summary,
312 injection_id: None,
313 }
314 }
315}
316
317impl sum_tree::Item for Transform {
318 type Summary = TransformSummary;
319
320 fn summary(&self) -> Self::Summary {
321 let min_injection_id;
322 let max_injection_id;
323 if let Some(id) = self.injection_id {
324 min_injection_id = id;
325 max_injection_id = id;
326 } else {
327 min_injection_id = InjectionId(usize::MAX);
328 max_injection_id = InjectionId(0);
329 }
330
331 TransformSummary {
332 input: self.input.clone(),
333 output: self.output.clone(),
334 min_injection_id,
335 max_injection_id,
336 }
337 }
338}
339
340impl sum_tree::Summary for TransformSummary {
341 type Context = ();
342
343 fn add_summary(&mut self, other: &Self, _: &()) {
344 self.input += &other.input;
345 self.output += &other.output;
346 }
347}
348
349impl<'a> sum_tree::Dimension<'a, TransformSummary> for usize {
350 fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
351 *self += summary.input.bytes
352 }
353}
354
355impl<'a> sum_tree::Dimension<'a, TransformSummary> for InjectionOffset {
356 fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
357 self.0 += summary.output.bytes
358 }
359}