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