injection_map.rs

  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}