suggestion_map.rs

  1use std::ops::{Add, AddAssign, Sub};
  2
  3use crate::{ToOffset, ToPoint};
  4
  5use super::fold_map::{FoldEdit, FoldOffset, FoldSnapshot};
  6use gpui::fonts::HighlightStyle;
  7use language::{Bias, Edit, Patch, Rope};
  8use parking_lot::Mutex;
  9
 10pub type SuggestionEdit = Edit<SuggestionOffset>;
 11
 12#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
 13pub struct SuggestionOffset(pub usize);
 14
 15impl Add for SuggestionOffset {
 16    type Output = Self;
 17
 18    fn add(self, rhs: Self) -> Self::Output {
 19        Self(self.0 + rhs.0)
 20    }
 21}
 22
 23impl Sub for SuggestionOffset {
 24    type Output = Self;
 25
 26    fn sub(self, rhs: Self) -> Self::Output {
 27        Self(self.0 - rhs.0)
 28    }
 29}
 30
 31impl AddAssign for SuggestionOffset {
 32    fn add_assign(&mut self, rhs: Self) {
 33        self.0 += rhs.0;
 34    }
 35}
 36
 37#[derive(Clone)]
 38pub struct Suggestion<T> {
 39    position: T,
 40    text: Rope,
 41}
 42
 43pub struct SuggestionMap(Mutex<SuggestionSnapshot>);
 44
 45impl SuggestionMap {
 46    pub fn replace<T>(
 47        &mut self,
 48        new_suggestion: Option<Suggestion<T>>,
 49        fold_snapshot: FoldSnapshot,
 50        fold_edits: Vec<FoldEdit>,
 51    ) -> (SuggestionSnapshot, Vec<SuggestionEdit>)
 52    where
 53        T: ToPoint,
 54    {
 55        let new_suggestion = new_suggestion.map(|new_suggestion| {
 56            let buffer_point = new_suggestion
 57                .position
 58                .to_point(fold_snapshot.buffer_snapshot());
 59            let fold_point = fold_snapshot.to_fold_point(buffer_point, Bias::Left);
 60            let fold_offset = fold_point.to_offset(&fold_snapshot);
 61            Suggestion {
 62                position: fold_offset,
 63                text: new_suggestion.text,
 64            }
 65        });
 66
 67        let (_, edits) = self.sync(fold_snapshot, fold_edits);
 68        let mut snapshot = self.0.lock();
 69
 70        let old = if let Some(suggestion) = snapshot.suggestion.take() {
 71            SuggestionOffset(suggestion.position.0)
 72                ..SuggestionOffset(suggestion.position.0 + suggestion.text.len())
 73        } else if let Some(new_suggestion) = new_suggestion.as_ref() {
 74            SuggestionOffset(new_suggestion.position.0)..SuggestionOffset(new_suggestion.position.0)
 75        } else {
 76            return (snapshot.clone(), edits);
 77        };
 78
 79        let new = if let Some(suggestion) = new_suggestion.as_ref() {
 80            SuggestionOffset(suggestion.position.0)
 81                ..SuggestionOffset(suggestion.position.0 + suggestion.text.len())
 82        } else {
 83            old.start..old.start
 84        };
 85
 86        let patch = Patch::new(edits).compose([SuggestionEdit { old, new }]);
 87        snapshot.suggestion = new_suggestion;
 88        (snapshot.clone(), patch.into_inner())
 89    }
 90
 91    pub fn sync(
 92        &self,
 93        fold_snapshot: FoldSnapshot,
 94        fold_edits: Vec<FoldEdit>,
 95    ) -> (SuggestionSnapshot, Vec<SuggestionEdit>) {
 96        let mut snapshot = self.0.lock();
 97        let mut suggestion_edits = Vec::new();
 98
 99        let mut suggestion_old_len = 0;
100        let mut suggestion_new_len = 0;
101        for fold_edit in fold_edits {
102            let start = fold_edit.new.start;
103            let end = FoldOffset(start.0 + fold_edit.old_len().0);
104            if let Some(suggestion) = snapshot.suggestion.as_mut() {
105                if end < suggestion.position {
106                    suggestion.position.0 += fold_edit.new_len().0;
107                    suggestion.position.0 -= fold_edit.old_len().0;
108                } else if start > suggestion.position {
109                    suggestion_old_len = suggestion.text.len();
110                    suggestion_new_len = suggestion_old_len;
111                } else {
112                    suggestion_old_len = suggestion.text.len();
113                    snapshot.suggestion.take();
114                    suggestion_edits.push(SuggestionEdit {
115                        old: SuggestionOffset(fold_edit.old.start.0)
116                            ..SuggestionOffset(fold_edit.old.end.0 + suggestion_old_len),
117                        new: SuggestionOffset(fold_edit.new.start.0)
118                            ..SuggestionOffset(fold_edit.new.end.0),
119                    });
120                    continue;
121                }
122            }
123
124            suggestion_edits.push(SuggestionEdit {
125                old: SuggestionOffset(fold_edit.old.start.0 + suggestion_old_len)
126                    ..SuggestionOffset(fold_edit.old.end.0 + suggestion_old_len),
127                new: SuggestionOffset(fold_edit.new.start.0 + suggestion_new_len)
128                    ..SuggestionOffset(fold_edit.new.end.0 + suggestion_new_len),
129            });
130        }
131        snapshot.folds_snapshot = fold_snapshot;
132
133        (snapshot.clone(), suggestion_edits)
134    }
135}
136
137#[derive(Clone)]
138pub struct SuggestionSnapshot {
139    folds_snapshot: FoldSnapshot,
140    suggestion: Option<Suggestion<FoldOffset>>,
141}