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_completions_in_normal_mode() -> bool;
46 fn show_tab_accept_marker() -> bool {
47 false
48 }
49 fn data_collection_state(&self, _cx: &App) -> DataCollectionState {
50 DataCollectionState::Unsupported
51 }
52 fn toggle_data_collection(&mut self, _cx: &mut App) {}
53 fn is_enabled(
54 &self,
55 buffer: &Entity<Buffer>,
56 cursor_position: language::Anchor,
57 cx: &App,
58 ) -> bool;
59 fn is_refreshing(&self) -> bool;
60 fn refresh(
61 &mut self,
62 project: Option<Entity<Project>>,
63 buffer: Entity<Buffer>,
64 cursor_position: language::Anchor,
65 debounce: bool,
66 cx: &mut Context<Self>,
67 );
68 fn needs_terms_acceptance(&self, _cx: &App) -> bool {
69 false
70 }
71 fn cycle(
72 &mut self,
73 buffer: Entity<Buffer>,
74 cursor_position: language::Anchor,
75 direction: Direction,
76 cx: &mut Context<Self>,
77 );
78 fn accept(&mut self, cx: &mut Context<Self>);
79 fn discard(&mut self, cx: &mut Context<Self>);
80 fn suggest(
81 &mut self,
82 buffer: &Entity<Buffer>,
83 cursor_position: language::Anchor,
84 cx: &mut Context<Self>,
85 ) -> Option<InlineCompletion>;
86}
87
88pub trait InlineCompletionProviderHandle {
89 fn name(&self) -> &'static str;
90 fn display_name(&self) -> &'static str;
91 fn is_enabled(
92 &self,
93 buffer: &Entity<Buffer>,
94 cursor_position: language::Anchor,
95 cx: &App,
96 ) -> bool;
97 fn show_completions_in_menu(&self) -> bool;
98 fn show_completions_in_normal_mode(&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: InlineCompletionProvider,
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_completions_in_normal_mode(&self) -> bool {
146 T::show_completions_in_normal_mode()
147 }
148
149 fn show_tab_accept_marker(&self) -> bool {
150 T::show_tab_accept_marker()
151 }
152
153 fn data_collection_state(&self, cx: &App) -> DataCollectionState {
154 self.read(cx).data_collection_state(cx)
155 }
156
157 fn toggle_data_collection(&self, cx: &mut App) {
158 self.update(cx, |this, cx| this.toggle_data_collection(cx))
159 }
160
161 fn is_enabled(
162 &self,
163 buffer: &Entity<Buffer>,
164 cursor_position: language::Anchor,
165 cx: &App,
166 ) -> bool {
167 self.read(cx).is_enabled(buffer, cursor_position, cx)
168 }
169
170 fn needs_terms_acceptance(&self, cx: &App) -> bool {
171 self.read(cx).needs_terms_acceptance(cx)
172 }
173
174 fn is_refreshing(&self, cx: &App) -> bool {
175 self.read(cx).is_refreshing()
176 }
177
178 fn refresh(
179 &self,
180 project: Option<Entity<Project>>,
181 buffer: Entity<Buffer>,
182 cursor_position: language::Anchor,
183 debounce: bool,
184 cx: &mut App,
185 ) {
186 self.update(cx, |this, cx| {
187 this.refresh(project, buffer, cursor_position, debounce, cx)
188 })
189 }
190
191 fn cycle(
192 &self,
193 buffer: Entity<Buffer>,
194 cursor_position: language::Anchor,
195 direction: Direction,
196 cx: &mut App,
197 ) {
198 self.update(cx, |this, cx| {
199 this.cycle(buffer, cursor_position, direction, cx)
200 })
201 }
202
203 fn accept(&self, cx: &mut App) {
204 self.update(cx, |this, cx| this.accept(cx))
205 }
206
207 fn discard(&self, cx: &mut App) {
208 self.update(cx, |this, cx| this.discard(cx))
209 }
210
211 fn suggest(
212 &self,
213 buffer: &Entity<Buffer>,
214 cursor_position: language::Anchor,
215 cx: &mut App,
216 ) -> Option<InlineCompletion> {
217 self.update(cx, |this, cx| this.suggest(buffer, cursor_position, cx))
218 }
219}