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