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 needs_terms_acceptance(&self, _cx: &App) -> bool {
 93        false
 94    }
 95    fn cycle(
 96        &mut self,
 97        buffer: Entity<Buffer>,
 98        cursor_position: language::Anchor,
 99        direction: Direction,
100        cx: &mut Context<Self>,
101    );
102    fn accept(&mut self, cx: &mut Context<Self>);
103    fn discard(&mut self, cx: &mut Context<Self>);
104    fn suggest(
105        &mut self,
106        buffer: &Entity<Buffer>,
107        cursor_position: language::Anchor,
108        cx: &mut Context<Self>,
109    ) -> Option<EditPrediction>;
110}
111
112pub trait EditPredictionProviderHandle {
113    fn name(&self) -> &'static str;
114    fn display_name(&self) -> &'static str;
115    fn is_enabled(
116        &self,
117        buffer: &Entity<Buffer>,
118        cursor_position: language::Anchor,
119        cx: &App,
120    ) -> bool;
121    fn show_completions_in_menu(&self) -> bool;
122    fn show_tab_accept_marker(&self) -> bool;
123    fn supports_jump_to_edit(&self) -> bool;
124    fn data_collection_state(&self, cx: &App) -> DataCollectionState;
125    fn usage(&self, cx: &App) -> Option<EditPredictionUsage>;
126    fn toggle_data_collection(&self, cx: &mut App);
127    fn needs_terms_acceptance(&self, cx: &App) -> bool;
128    fn is_refreshing(&self, cx: &App) -> bool;
129    fn refresh(
130        &self,
131        project: Option<Entity<Project>>,
132        buffer: Entity<Buffer>,
133        cursor_position: language::Anchor,
134        debounce: bool,
135        cx: &mut App,
136    );
137    fn cycle(
138        &self,
139        buffer: Entity<Buffer>,
140        cursor_position: language::Anchor,
141        direction: Direction,
142        cx: &mut App,
143    );
144    fn accept(&self, cx: &mut App);
145    fn discard(&self, cx: &mut App);
146    fn suggest(
147        &self,
148        buffer: &Entity<Buffer>,
149        cursor_position: language::Anchor,
150        cx: &mut App,
151    ) -> Option<EditPrediction>;
152}
153
154impl<T> EditPredictionProviderHandle for Entity<T>
155where
156    T: EditPredictionProvider,
157{
158    fn name(&self) -> &'static str {
159        T::name()
160    }
161
162    fn display_name(&self) -> &'static str {
163        T::display_name()
164    }
165
166    fn show_completions_in_menu(&self) -> bool {
167        T::show_completions_in_menu()
168    }
169
170    fn show_tab_accept_marker(&self) -> bool {
171        T::show_tab_accept_marker()
172    }
173
174    fn supports_jump_to_edit(&self) -> bool {
175        T::supports_jump_to_edit()
176    }
177
178    fn data_collection_state(&self, cx: &App) -> DataCollectionState {
179        self.read(cx).data_collection_state(cx)
180    }
181
182    fn usage(&self, cx: &App) -> Option<EditPredictionUsage> {
183        self.read(cx).usage(cx)
184    }
185
186    fn toggle_data_collection(&self, cx: &mut App) {
187        self.update(cx, |this, cx| this.toggle_data_collection(cx))
188    }
189
190    fn is_enabled(
191        &self,
192        buffer: &Entity<Buffer>,
193        cursor_position: language::Anchor,
194        cx: &App,
195    ) -> bool {
196        self.read(cx).is_enabled(buffer, cursor_position, cx)
197    }
198
199    fn needs_terms_acceptance(&self, cx: &App) -> bool {
200        self.read(cx).needs_terms_acceptance(cx)
201    }
202
203    fn is_refreshing(&self, cx: &App) -> bool {
204        self.read(cx).is_refreshing()
205    }
206
207    fn refresh(
208        &self,
209        project: Option<Entity<Project>>,
210        buffer: Entity<Buffer>,
211        cursor_position: language::Anchor,
212        debounce: bool,
213        cx: &mut App,
214    ) {
215        self.update(cx, |this, cx| {
216            this.refresh(project, buffer, cursor_position, debounce, cx)
217        })
218    }
219
220    fn cycle(
221        &self,
222        buffer: Entity<Buffer>,
223        cursor_position: language::Anchor,
224        direction: Direction,
225        cx: &mut App,
226    ) {
227        self.update(cx, |this, cx| {
228            this.cycle(buffer, cursor_position, direction, cx)
229        })
230    }
231
232    fn accept(&self, cx: &mut App) {
233        self.update(cx, |this, cx| this.accept(cx))
234    }
235
236    fn discard(&self, cx: &mut App) {
237        self.update(cx, |this, cx| this.discard(cx))
238    }
239
240    fn suggest(
241        &self,
242        buffer: &Entity<Buffer>,
243        cursor_position: language::Anchor,
244        cx: &mut App,
245    ) -> Option<EditPrediction> {
246        self.update(cx, |this, cx| this.suggest(buffer, cursor_position, cx))
247    }
248}