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