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}