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 /// Data collection is enabled
25 Enabled,
26 /// Data collection is disabled or unanswered.
27 Disabled,
28}
29
30impl DataCollectionState {
31 pub fn is_supported(&self) -> bool {
32 !matches!(self, DataCollectionState::Unsupported)
33 }
34
35 pub fn is_enabled(&self) -> bool {
36 matches!(self, DataCollectionState::Enabled)
37 }
38}
39
40pub trait InlineCompletionProvider: 'static + Sized {
41 fn name() -> &'static str;
42 fn display_name() -> &'static str;
43 fn show_completions_in_menu() -> bool;
44 fn show_completions_in_normal_mode() -> bool;
45 fn show_tab_accept_marker() -> bool {
46 false
47 }
48 fn data_collection_state(&self, _cx: &App) -> DataCollectionState {
49 DataCollectionState::Unsupported
50 }
51 fn toggle_data_collection(&mut self, _cx: &mut App) {}
52 fn is_enabled(
53 &self,
54 buffer: &Entity<Buffer>,
55 cursor_position: language::Anchor,
56 cx: &App,
57 ) -> bool;
58 fn is_refreshing(&self) -> bool;
59 fn refresh(
60 &mut self,
61 buffer: Entity<Buffer>,
62 cursor_position: language::Anchor,
63 debounce: bool,
64 cx: &mut Context<Self>,
65 );
66 fn needs_terms_acceptance(&self, _cx: &App) -> bool {
67 false
68 }
69 fn cycle(
70 &mut self,
71 buffer: Entity<Buffer>,
72 cursor_position: language::Anchor,
73 direction: Direction,
74 cx: &mut Context<Self>,
75 );
76 fn accept(&mut self, cx: &mut Context<Self>);
77 fn discard(&mut self, cx: &mut Context<Self>);
78 fn suggest(
79 &mut self,
80 buffer: &Entity<Buffer>,
81 cursor_position: language::Anchor,
82 cx: &mut Context<Self>,
83 ) -> Option<InlineCompletion>;
84}
85
86pub trait InlineCompletionProviderHandle {
87 fn name(&self) -> &'static str;
88 fn display_name(&self) -> &'static str;
89 fn is_enabled(
90 &self,
91 buffer: &Entity<Buffer>,
92 cursor_position: language::Anchor,
93 cx: &App,
94 ) -> bool;
95 fn show_completions_in_menu(&self) -> bool;
96 fn show_completions_in_normal_mode(&self) -> bool;
97 fn show_tab_accept_marker(&self) -> bool;
98 fn data_collection_state(&self, cx: &App) -> DataCollectionState;
99 fn toggle_data_collection(&self, cx: &mut App);
100 fn needs_terms_acceptance(&self, cx: &App) -> bool;
101 fn is_refreshing(&self, cx: &App) -> bool;
102 fn refresh(
103 &self,
104 buffer: Entity<Buffer>,
105 cursor_position: language::Anchor,
106 debounce: bool,
107 cx: &mut App,
108 );
109 fn cycle(
110 &self,
111 buffer: Entity<Buffer>,
112 cursor_position: language::Anchor,
113 direction: Direction,
114 cx: &mut App,
115 );
116 fn accept(&self, cx: &mut App);
117 fn discard(&self, cx: &mut App);
118 fn suggest(
119 &self,
120 buffer: &Entity<Buffer>,
121 cursor_position: language::Anchor,
122 cx: &mut App,
123 ) -> Option<InlineCompletion>;
124}
125
126impl<T> InlineCompletionProviderHandle for Entity<T>
127where
128 T: InlineCompletionProvider,
129{
130 fn name(&self) -> &'static str {
131 T::name()
132 }
133
134 fn display_name(&self) -> &'static str {
135 T::display_name()
136 }
137
138 fn show_completions_in_menu(&self) -> bool {
139 T::show_completions_in_menu()
140 }
141
142 fn show_completions_in_normal_mode(&self) -> bool {
143 T::show_completions_in_normal_mode()
144 }
145
146 fn show_tab_accept_marker(&self) -> bool {
147 T::show_tab_accept_marker()
148 }
149
150 fn data_collection_state(&self, cx: &App) -> DataCollectionState {
151 self.read(cx).data_collection_state(cx)
152 }
153
154 fn toggle_data_collection(&self, cx: &mut App) {
155 self.update(cx, |this, cx| this.toggle_data_collection(cx))
156 }
157
158 fn is_enabled(
159 &self,
160 buffer: &Entity<Buffer>,
161 cursor_position: language::Anchor,
162 cx: &App,
163 ) -> bool {
164 self.read(cx).is_enabled(buffer, cursor_position, cx)
165 }
166
167 fn needs_terms_acceptance(&self, cx: &App) -> bool {
168 self.read(cx).needs_terms_acceptance(cx)
169 }
170
171 fn is_refreshing(&self, cx: &App) -> bool {
172 self.read(cx).is_refreshing()
173 }
174
175 fn refresh(
176 &self,
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(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}