edit_prediction.rs

  1use std::ops::Range;
  2
  3use client::EditPredictionUsage;
  4use gpui::{App, Context, Entity, SharedString};
  5use language::Buffer;
  6use project::Project;
  7
  8// TODO: Find a better home for `Direction`.
  9//
 10// This should live in an ancestor crate of `editor` and `edit_prediction`,
 11// but at time of writing there isn't an obvious spot.
 12#[derive(Copy, Clone, PartialEq, Eq)]
 13pub enum Direction {
 14    Prev,
 15    Next,
 16}
 17
 18#[derive(Clone)]
 19pub struct EditPrediction {
 20    /// The ID of the completion, if it has one.
 21    pub id: Option<SharedString>,
 22    pub edits: Vec<(Range<language::Anchor>, String)>,
 23    pub edit_preview: Option<language::EditPreview>,
 24}
 25
 26pub enum DataCollectionState {
 27    /// The provider doesn't support data collection.
 28    Unsupported,
 29    /// Data collection is enabled.
 30    Enabled { is_project_open_source: bool },
 31    /// Data collection is disabled or unanswered.
 32    Disabled { is_project_open_source: bool },
 33}
 34
 35impl DataCollectionState {
 36    pub fn is_supported(&self) -> bool {
 37        !matches!(self, DataCollectionState::Unsupported)
 38    }
 39
 40    pub fn is_enabled(&self) -> bool {
 41        matches!(self, DataCollectionState::Enabled { .. })
 42    }
 43
 44    pub fn is_project_open_source(&self) -> bool {
 45        match self {
 46            Self::Enabled {
 47                is_project_open_source,
 48            }
 49            | Self::Disabled {
 50                is_project_open_source,
 51            } => *is_project_open_source,
 52            _ => false,
 53        }
 54    }
 55}
 56
 57pub trait EditPredictionProvider: 'static + Sized {
 58    fn name() -> &'static str;
 59    fn display_name() -> &'static str;
 60    fn show_completions_in_menu() -> bool;
 61    fn show_tab_accept_marker() -> bool {
 62        false
 63    }
 64    fn supports_jump_to_edit() -> bool {
 65        true
 66    }
 67
 68    fn data_collection_state(&self, _cx: &App) -> DataCollectionState {
 69        DataCollectionState::Unsupported
 70    }
 71
 72    fn usage(&self, _cx: &App) -> Option<EditPredictionUsage> {
 73        None
 74    }
 75
 76    fn toggle_data_collection(&mut self, _cx: &mut App) {}
 77    fn is_enabled(
 78        &self,
 79        buffer: &Entity<Buffer>,
 80        cursor_position: language::Anchor,
 81        cx: &App,
 82    ) -> bool;
 83    fn is_refreshing(&self) -> bool;
 84    fn refresh(
 85        &mut self,
 86        project: Option<Entity<Project>>,
 87        buffer: Entity<Buffer>,
 88        cursor_position: language::Anchor,
 89        debounce: bool,
 90        cx: &mut Context<Self>,
 91    );
 92    fn cycle(
 93        &mut self,
 94        buffer: Entity<Buffer>,
 95        cursor_position: language::Anchor,
 96        direction: Direction,
 97        cx: &mut Context<Self>,
 98    );
 99    fn accept(&mut self, cx: &mut Context<Self>);
100    fn discard(&mut self, cx: &mut Context<Self>);
101    fn suggest(
102        &mut self,
103        buffer: &Entity<Buffer>,
104        cursor_position: language::Anchor,
105        cx: &mut Context<Self>,
106    ) -> Option<EditPrediction>;
107}
108
109pub trait EditPredictionProviderHandle {
110    fn name(&self) -> &'static str;
111    fn display_name(&self) -> &'static str;
112    fn is_enabled(
113        &self,
114        buffer: &Entity<Buffer>,
115        cursor_position: language::Anchor,
116        cx: &App,
117    ) -> bool;
118    fn show_completions_in_menu(&self) -> bool;
119    fn show_tab_accept_marker(&self) -> bool;
120    fn supports_jump_to_edit(&self) -> bool;
121    fn data_collection_state(&self, cx: &App) -> DataCollectionState;
122    fn usage(&self, cx: &App) -> Option<EditPredictionUsage>;
123    fn toggle_data_collection(&self, cx: &mut App);
124    fn is_refreshing(&self, cx: &App) -> bool;
125    fn refresh(
126        &self,
127        project: Option<Entity<Project>>,
128        buffer: Entity<Buffer>,
129        cursor_position: language::Anchor,
130        debounce: bool,
131        cx: &mut App,
132    );
133    fn cycle(
134        &self,
135        buffer: Entity<Buffer>,
136        cursor_position: language::Anchor,
137        direction: Direction,
138        cx: &mut App,
139    );
140    fn accept(&self, cx: &mut App);
141    fn discard(&self, cx: &mut App);
142    fn suggest(
143        &self,
144        buffer: &Entity<Buffer>,
145        cursor_position: language::Anchor,
146        cx: &mut App,
147    ) -> Option<EditPrediction>;
148}
149
150impl<T> EditPredictionProviderHandle for Entity<T>
151where
152    T: EditPredictionProvider,
153{
154    fn name(&self) -> &'static str {
155        T::name()
156    }
157
158    fn display_name(&self) -> &'static str {
159        T::display_name()
160    }
161
162    fn show_completions_in_menu(&self) -> bool {
163        T::show_completions_in_menu()
164    }
165
166    fn show_tab_accept_marker(&self) -> bool {
167        T::show_tab_accept_marker()
168    }
169
170    fn supports_jump_to_edit(&self) -> bool {
171        T::supports_jump_to_edit()
172    }
173
174    fn data_collection_state(&self, cx: &App) -> DataCollectionState {
175        self.read(cx).data_collection_state(cx)
176    }
177
178    fn usage(&self, cx: &App) -> Option<EditPredictionUsage> {
179        self.read(cx).usage(cx)
180    }
181
182    fn toggle_data_collection(&self, cx: &mut App) {
183        self.update(cx, |this, cx| this.toggle_data_collection(cx))
184    }
185
186    fn is_enabled(
187        &self,
188        buffer: &Entity<Buffer>,
189        cursor_position: language::Anchor,
190        cx: &App,
191    ) -> bool {
192        self.read(cx).is_enabled(buffer, cursor_position, cx)
193    }
194
195    fn is_refreshing(&self, cx: &App) -> bool {
196        self.read(cx).is_refreshing()
197    }
198
199    fn refresh(
200        &self,
201        project: Option<Entity<Project>>,
202        buffer: Entity<Buffer>,
203        cursor_position: language::Anchor,
204        debounce: bool,
205        cx: &mut App,
206    ) {
207        self.update(cx, |this, cx| {
208            this.refresh(project, buffer, cursor_position, debounce, cx)
209        })
210    }
211
212    fn cycle(
213        &self,
214        buffer: Entity<Buffer>,
215        cursor_position: language::Anchor,
216        direction: Direction,
217        cx: &mut App,
218    ) {
219        self.update(cx, |this, cx| {
220            this.cycle(buffer, cursor_position, direction, cx)
221        })
222    }
223
224    fn accept(&self, cx: &mut App) {
225        self.update(cx, |this, cx| this.accept(cx))
226    }
227
228    fn discard(&self, cx: &mut App) {
229        self.update(cx, |this, cx| this.discard(cx))
230    }
231
232    fn suggest(
233        &self,
234        buffer: &Entity<Buffer>,
235        cursor_position: language::Anchor,
236        cx: &mut App,
237    ) -> Option<EditPrediction> {
238        self.update(cx, |this, cx| this.suggest(buffer, cursor_position, cx))
239    }
240}