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