1use gpui::{App, Context, Entity};
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 pub edits: Vec<(Range<language::Anchor>, String)>,
19 pub edit_preview: Option<language::EditPreview>,
20}
21
22pub enum DataCollectionState {
23 /// The provider doesn't support data collection.
24 Unsupported,
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_enabled(&self) -> bool {
37 matches!(self, DataCollectionState::Enabled)
38 }
39}
40
41pub trait InlineCompletionProvider: 'static + Sized {
42 fn name() -> &'static str;
43 fn display_name() -> &'static str;
44 fn show_completions_in_menu() -> 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 project: Option<Entity<Project>>,
62 buffer: Entity<Buffer>,
63 cursor_position: language::Anchor,
64 debounce: bool,
65 cx: &mut Context<Self>,
66 );
67 fn needs_terms_acceptance(&self, _cx: &App) -> bool {
68 false
69 }
70 fn cycle(
71 &mut self,
72 buffer: Entity<Buffer>,
73 cursor_position: language::Anchor,
74 direction: Direction,
75 cx: &mut Context<Self>,
76 );
77 fn accept(&mut self, cx: &mut Context<Self>);
78 fn discard(&mut self, cx: &mut Context<Self>);
79 fn suggest(
80 &mut self,
81 buffer: &Entity<Buffer>,
82 cursor_position: language::Anchor,
83 cx: &mut Context<Self>,
84 ) -> Option<InlineCompletion>;
85}
86
87pub trait InlineCompletionProviderHandle {
88 fn name(&self) -> &'static str;
89 fn display_name(&self) -> &'static str;
90 fn is_enabled(
91 &self,
92 buffer: &Entity<Buffer>,
93 cursor_position: language::Anchor,
94 cx: &App,
95 ) -> bool;
96 fn show_completions_in_menu(&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 project: Option<Entity<Project>>,
105 buffer: Entity<Buffer>,
106 cursor_position: language::Anchor,
107 debounce: bool,
108 cx: &mut App,
109 );
110 fn cycle(
111 &self,
112 buffer: Entity<Buffer>,
113 cursor_position: language::Anchor,
114 direction: Direction,
115 cx: &mut App,
116 );
117 fn accept(&self, cx: &mut App);
118 fn discard(&self, cx: &mut App);
119 fn suggest(
120 &self,
121 buffer: &Entity<Buffer>,
122 cursor_position: language::Anchor,
123 cx: &mut App,
124 ) -> Option<InlineCompletion>;
125}
126
127impl<T> InlineCompletionProviderHandle for Entity<T>
128where
129 T: InlineCompletionProvider,
130{
131 fn name(&self) -> &'static str {
132 T::name()
133 }
134
135 fn display_name(&self) -> &'static str {
136 T::display_name()
137 }
138
139 fn show_completions_in_menu(&self) -> bool {
140 T::show_completions_in_menu()
141 }
142
143 fn show_tab_accept_marker(&self) -> bool {
144 T::show_tab_accept_marker()
145 }
146
147 fn data_collection_state(&self, cx: &App) -> DataCollectionState {
148 self.read(cx).data_collection_state(cx)
149 }
150
151 fn toggle_data_collection(&self, cx: &mut App) {
152 self.update(cx, |this, cx| this.toggle_data_collection(cx))
153 }
154
155 fn is_enabled(
156 &self,
157 buffer: &Entity<Buffer>,
158 cursor_position: language::Anchor,
159 cx: &App,
160 ) -> bool {
161 self.read(cx).is_enabled(buffer, cursor_position, cx)
162 }
163
164 fn needs_terms_acceptance(&self, cx: &App) -> bool {
165 self.read(cx).needs_terms_acceptance(cx)
166 }
167
168 fn is_refreshing(&self, cx: &App) -> bool {
169 self.read(cx).is_refreshing()
170 }
171
172 fn refresh(
173 &self,
174 project: Option<Entity<Project>>,
175 buffer: Entity<Buffer>,
176 cursor_position: language::Anchor,
177 debounce: bool,
178 cx: &mut App,
179 ) {
180 self.update(cx, |this, cx| {
181 this.refresh(project, buffer, cursor_position, debounce, cx)
182 })
183 }
184
185 fn cycle(
186 &self,
187 buffer: Entity<Buffer>,
188 cursor_position: language::Anchor,
189 direction: Direction,
190 cx: &mut App,
191 ) {
192 self.update(cx, |this, cx| {
193 this.cycle(buffer, cursor_position, direction, cx)
194 })
195 }
196
197 fn accept(&self, cx: &mut App) {
198 self.update(cx, |this, cx| this.accept(cx))
199 }
200
201 fn discard(&self, cx: &mut App) {
202 self.update(cx, |this, cx| this.discard(cx))
203 }
204
205 fn suggest(
206 &self,
207 buffer: &Entity<Buffer>,
208 cursor_position: language::Anchor,
209 cx: &mut App,
210 ) -> Option<InlineCompletion> {
211 self.update(cx, |this, cx| this.suggest(buffer, cursor_position, cx))
212 }
213}