injection_map.rs

  1use std::{
  2    cmp, mem,
  3    sync::atomic::{AtomicUsize, Ordering::SeqCst},
  4};
  5
  6use buffer::{Anchor, Bias, Edit, Point, Rope, TextSummary};
  7use gpui::{fonts::HighlightStyle, AppContext, ModelHandle};
  8use language::Buffer;
  9use parking_lot::Mutex;
 10use sum_tree::SumTree;
 11
 12#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)]
 13pub struct InjectionId(usize);
 14
 15pub struct InjectionMap {
 16    buffer: ModelHandle<Buffer>,
 17    transforms: Mutex<SumTree<Transform>>,
 18    injections: SumTree<Injection>,
 19    injection_contents: SumTree<InjectionContent>,
 20    version: AtomicUsize,
 21    last_sync: Mutex<SyncState>,
 22}
 23
 24pub struct InjectionSnapshot {
 25    transforms: SumTree<Transform>,
 26    injection_contents: SumTree<InjectionContent>,
 27    buffer_snapshot: language::Snapshot,
 28    pub version: usize,
 29}
 30
 31pub struct InjectionMapWriter<'a>(&'a mut InjectionMap);
 32
 33#[derive(Clone)]
 34struct SyncState {
 35    version: clock::Global,
 36    parse_count: usize,
 37    diagnostics_update_count: usize,
 38}
 39
 40#[derive(Clone, Debug)]
 41struct Injection {
 42    id: InjectionId,
 43    position: Anchor,
 44    is_block: bool,
 45}
 46
 47#[derive(Clone, Debug)]
 48struct InjectionSummary {
 49    min_id: InjectionId,
 50    max_id: InjectionId,
 51    min_position: Anchor,
 52    max_position: Anchor,
 53}
 54
 55#[derive(Clone, Debug)]
 56struct InjectionContent {
 57    injection_id: InjectionId,
 58    runs: Vec<(usize, HighlightStyle)>,
 59    text: Rope,
 60}
 61
 62#[derive(Clone, Debug, Default, PartialEq)]
 63struct Transform {
 64    summary: TransformSummary,
 65    injection_id: Option<InjectionId>,
 66}
 67
 68#[derive(Clone, Debug, Default, Eq, PartialEq)]
 69struct TransformSummary {
 70    output: TextSummary,
 71    input: TextSummary,
 72}
 73
 74#[derive(Copy, Clone)]
 75struct InjectionOffset(usize);
 76
 77impl sum_tree::Summary for InjectionId {
 78    type Context = ();
 79
 80    fn add_summary(&mut self, summary: &Self, cx: &Self::Context) {
 81        *self = *summary
 82    }
 83}
 84
 85impl InjectionMap {
 86    pub fn read(&self, cx: &AppContext) -> (InjectionSnapshot, Vec<Edit<InjectionOffset>>) {
 87        let edits = self.sync(cx);
 88        // self.check_invariants(cx);
 89        let snapshot = InjectionSnapshot {
 90            transforms: self.transforms.lock().clone(),
 91            injection_contents: self.injection_contents.clone(),
 92            buffer_snapshot: self.buffer.read(cx).snapshot(),
 93            version: self.version.load(SeqCst),
 94        };
 95        (snapshot, edits)
 96    }
 97
 98    pub fn write(
 99        &mut self,
100        cx: &AppContext,
101    ) -> (
102        InjectionMapWriter,
103        InjectionSnapshot,
104        Vec<Edit<InjectionOffset>>,
105    ) {
106        let (snapshot, edits) = self.read(cx);
107        (InjectionMapWriter(self), snapshot, edits)
108    }
109
110    fn sync(&self, cx: &AppContext) -> Vec<Edit<InjectionOffset>> {
111        let buffer = self.buffer.read(cx);
112        let last_sync = mem::replace(
113            &mut *self.last_sync.lock(),
114            SyncState {
115                version: buffer.version(),
116                parse_count: buffer.parse_count(),
117                diagnostics_update_count: buffer.diagnostics_update_count(),
118            },
119        );
120        let edits = buffer
121            .edits_since(&last_sync.version)
122            .map(Into::into)
123            .collect::<Vec<_>>();
124        if edits.is_empty() {
125            if last_sync.parse_count != buffer.parse_count()
126                || last_sync.diagnostics_update_count != buffer.diagnostics_update_count()
127            {
128                self.version.fetch_add(1, SeqCst);
129            }
130            Vec::new()
131        } else {
132            self.apply_edits(edits, cx)
133        }
134    }
135
136    fn apply_edits(
137        &self,
138        buffer_edits: Vec<buffer::Edit<usize>>,
139        cx: &AppContext,
140    ) -> Vec<Edit<InjectionOffset>> {
141        let buffer = self.buffer.read(cx).snapshot();
142        let mut buffer_edits_iter = buffer_edits.iter().cloned().peekable();
143
144        let mut new_transforms = SumTree::<Transform>::new();
145        let mut transforms = self.transforms.lock();
146        let mut cursor = transforms.cursor::<usize>();
147
148        while let Some(mut edit) = buffer_edits_iter.next() {
149            new_transforms.push_tree(cursor.slice(&edit.old.start, Bias::Left, &()), &());
150            edit.new.start -= edit.old.start - cursor.start();
151            edit.old.start = *cursor.start();
152
153            cursor.seek(&edit.old.end, Bias::Right, &());
154            cursor.next(&());
155
156            let mut delta = edit.new.len() as isize - edit.old.len() as isize;
157            loop {
158                edit.old.end = *cursor.start();
159
160                if let Some(next_edit) = buffer_edits_iter.peek() {
161                    if next_edit.old.start > edit.old.end {
162                        break;
163                    }
164
165                    let next_edit = buffer_edits_iter.next().unwrap();
166                    delta += next_edit.new.len() as isize - next_edit.old.len() as isize;
167
168                    if next_edit.old.end >= edit.old.end {
169                        edit.old.end = next_edit.old.end;
170                        cursor.seek(&edit.old.end, Bias::Right, &());
171                        cursor.next(&());
172                    }
173                } else {
174                    break;
175                }
176            }
177
178            edit.new.end = ((edit.new.start + edit.old.len()) as isize + delta) as usize;
179
180            let anchor = buffer.anchor_before(edit.new.start);
181            let mut injections_cursor = self.injections.cursor::<Anchor>();
182            // folds_cursor.seek(&Fold(anchor..Anchor::max()), Bias::Left, &buffer);
183        }
184
185        todo!()
186    }
187}
188
189impl sum_tree::Item for Injection {
190    type Summary = InjectionSummary;
191
192    fn summary(&self) -> Self::Summary {
193        InjectionSummary {
194            min_id: self.id,
195            max_id: self.id,
196            min_position: self.position.clone(),
197            max_position: self.position.clone(),
198        }
199    }
200}
201
202impl sum_tree::Summary for InjectionSummary {
203    type Context = buffer::Snapshot;
204
205    fn add_summary(&mut self, summary: &Self, _: &buffer::Snapshot) {
206        self.max_position = summary.max_position.clone();
207        self.min_id = cmp::min(self.min_id, summary.min_id);
208        self.max_id = cmp::max(self.max_id, summary.max_id);
209    }
210}
211
212impl Default for InjectionSummary {
213    fn default() -> Self {
214        Self {
215            min_id: InjectionId(0),
216            max_id: InjectionId(usize::MAX),
217            min_position: Anchor::max(),
218            max_position: Anchor::min(),
219        }
220    }
221}
222
223impl sum_tree::Item for InjectionContent {
224    type Summary = InjectionId;
225
226    fn summary(&self) -> Self::Summary {
227        self.injection_id
228    }
229}
230
231impl sum_tree::Item for Transform {
232    type Summary = TransformSummary;
233
234    fn summary(&self) -> Self::Summary {
235        self.summary.clone()
236    }
237}
238
239impl sum_tree::Summary for TransformSummary {
240    type Context = ();
241
242    fn add_summary(&mut self, other: &Self, _: &()) {
243        self.input += &other.input;
244        self.output += &other.output;
245    }
246}
247
248impl<'a> sum_tree::Dimension<'a, TransformSummary> for usize {
249    fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) {
250        *self += summary.input.bytes
251    }
252}