inline_completion.rs

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