1use bevy_ecs::prelude::*;
2use completion::{CompletionRequest, SimpleCompletion};
3use lsp_core::{components::*, prelude::*, systems::prefix::prefix_completion_helper};
4use lsp_types::CompletionItemKind;
5use tracing::debug;
6
7use crate::{lang::model::NamedNode, TurtleLang};
8
9pub fn turtle_lov_undefined_prefix_completion(
10 mut query: Query<(
11 &TokenComponent,
12 &Element<TurtleLang>,
13 &Prefixes,
14 &mut CompletionRequest,
15 )>,
16) {
17 for (word, turtle, prefixes, mut req) in &mut query {
18 let mut start = Position::new(0, 0);
19
20 if turtle.base.is_some() {
21 start = Position::new(1, 0);
22 }
23
24 use lsp_types::{Position, Range};
25 prefix_completion_helper(word, prefixes, &mut req.0, |name, location| {
26 Some(vec![lsp_types::TextEdit {
27 range: Range::new(start.clone(), start),
28 new_text: format!("@prefix {}: <{}>.\n", name, location),
29 }])
30 });
31 }
32}
33
34pub fn subject_completion(
35 mut query: Query<(
36 &TokenComponent,
37 &Element<TurtleLang>,
38 &mut CompletionRequest,
39 )>,
40 triples: Query<(&Triples, &Label), With<Open>>,
41) {
42 for (word, turtle, mut req) in &mut query {
43 let m_expaned = match word.token.value() {
44 Token::PNameLN(pref, value) => NamedNode::Prefixed {
45 prefix: pref.clone().unwrap_or_default(),
46 value: value.clone(),
47 idx: 0,
48 }
49 .expand(turtle.0.value()),
50 _ => continue,
51 };
52 let Some(expanded) = m_expaned else { continue };
53
54 for (triples, label) in &triples {
55 for triple in &triples.0 {
56 debug!("Triple {} start with {}", triple.subject.as_str(), expanded);
57 let subj = triple.subject.as_str();
58 if subj.starts_with(&expanded) {
59 let new_text = turtle.0.shorten(subj).unwrap_or_else(|| String::from(subj));
60
61 if new_text != word.text {
62 req.push(
63 SimpleCompletion::new(
64 CompletionItemKind::MODULE,
65 subj.to_string(),
66 lsp_types::TextEdit {
67 new_text,
68 range: word.range.clone(),
69 },
70 )
71 .documentation(format!("Subject from {}", label.0)),
72 );
73 }
74 }
75 }
76 }
77 }
78}
79
80#[cfg(test)]
81mod tests {
82
83 use completion::CompletionRequest;
84 use futures::executor::block_on;
85 use lsp_core::{components::*, lang::LangHelper, prelude::*, Tasks};
86 use ropey::Rope;
87 use test_log::test;
88 use test_utils::{create_file, setup_world, TestClient};
89 use tracing::info;
90
91 use crate::TurtleHelper;
92
93 #[test]
94 fn completion_event_works() {
95 println!("completion_event_works");
96 let (mut world, _) = setup_world(TestClient::new(), crate::setup_world);
97
98 let t1 = "
99@prefix foaf: <http://xmlns.com/foaf/0.1/>.
100 ";
101
102 let t2 = "
103@prefix foaf: <http://xmlns.com/foaf/0.1/>.
104foa
105 ";
106
107 let entity = create_file(&mut world, t1, "http://example.com/ns#", "turtle", Open);
108
109 world
110 .entity_mut(entity)
111 .insert((Source(t2.to_string()), RopeC(Rope::from_str(t2))));
112 world.run_schedule(ParseLabel);
113
114 world.entity_mut(entity).insert((
116 CompletionRequest(vec![]),
117 PositionComponent(lsp_types::Position {
118 line: 2,
119 character: 0,
120 }),
121 ));
122
123 world.run_schedule(CompletionLabel);
124 let m_completions = world.entity_mut(entity).take::<CompletionRequest>();
125
126 assert!(m_completions.is_some());
127 let completions = m_completions.unwrap().0;
128 assert_eq!(completions.len(), 4 + TurtleHelper.keyword().len());
129 }
130
131 #[test_log::test]
132 fn completion_event_works_multiple_files() {
133 info!("Testing multiple files");
134 let (mut world, _) = setup_world(TestClient::new(), crate::setup_world);
135 let t1_1 = "
136@prefix foaf: <http://xmlns.com/foaf/0.1/>.
137 ";
138
139 let t1_2 = "
140@prefix foaf: <http://xmlns.com/foaf/0.1/>.
141foaf:
142 ";
143
144 let t2 = "
145@prefix foaf: <http://xmlns.com/foaf/0.1/>.
146
147foaf:me foaf:friend <#me>.
148 ";
149
150 let entity = create_file(
151 &mut world,
152 t1_1,
153 "http://example.com/first_file#",
154 "turtle",
155 Open,
156 );
157
158 create_file(
159 &mut world,
160 t2,
161 "http://example.com/second_file#",
162 "turtle",
163 Open,
164 );
165
166 world.entity_mut(entity).insert((
167 Source(t1_2.to_string()),
168 RopeC(Rope::from_str(t1_2)),
169 Open,
170 ));
171 world.run_schedule(ParseLabel);
172
173 world.entity_mut(entity).insert((
175 CompletionRequest(vec![]),
176 PositionComponent(lsp_types::Position {
177 line: 2,
178 character: 0,
179 }),
180 ));
181 world.run_schedule(CompletionLabel);
182
183 let completions = world
184 .entity_mut(entity)
185 .take::<CompletionRequest>()
186 .expect("Completions exists")
187 .0;
188
189 assert_eq!(completions.len(), 1 + TurtleHelper.keyword().len());
190 }
191
192 #[test_log::test]
193 fn test_autocomplete_classes() {
194 println!("completion_event_works");
195 let (mut world, _) = setup_world(TestClient::new(), crate::setup_world);
196
197 let t1 = "@prefix foaf: <http://xmlns.com/foaf/0.1/>.";
198
199 let t2 = "@prefix foaf: <http://xmlns.com/foaf/0.1/>.
200<> a foa";
201
202 let entity = create_file(&mut world, t1, "http://example.com/ns#", "turtle", Open);
203
204 let c = world.resource::<TestClient>().clone();
205 block_on(c.await_futures(|| world.run_schedule(Tasks)));
206
207 world
208 .entity_mut(entity)
209 .insert((Source(t2.to_string()), RopeC(Rope::from_str(t2)), Open));
210 world.run_schedule(ParseLabel);
211
212 block_on(c.await_futures(|| world.run_schedule(Tasks)));
213
214 world.entity_mut(entity).insert((
216 CompletionRequest(vec![]),
217 PositionComponent(lsp_types::Position {
218 line: 1,
219 character: 6,
220 }),
221 ));
222 world.run_schedule(CompletionLabel);
223 let completions = world
224 .entity_mut(entity)
225 .take::<CompletionRequest>()
226 .expect("competion request")
227 .0;
228
229 for c in &completions {
230 println!("c {:?} {:?}", c.label, c._documentation);
231 }
232 assert_eq!(
233 completions.len(),
234 4 + 14 + TurtleHelper.keyword().len()
235 );
236 }
237
238 #[test_log::test]
239 fn test_autocomplete_properties_3() {
240 println!("completion_event_works");
241 let (mut world, _) = setup_world(TestClient::new(), crate::setup_world);
242
243 let t1 = "@prefix foaf: <http://xmlns.com/foaf/0.1/>.";
244
245 let t2 = "@prefix foaf: <http://xmlns.com/foaf/0.1/>.
246<> foaf:";
247
248 let entity = create_file(&mut world, t1, "http://example.com/ns#", "turtle", Open);
249
250 let c = world.resource::<TestClient>().clone();
251 block_on(c.await_futures(|| world.run_schedule(Tasks)));
252
253 world
254 .entity_mut(entity)
255 .insert((Source(t2.to_string()), RopeC(Rope::from_str(t2)), Open));
256 world.run_schedule(ParseLabel);
257
258 block_on(c.await_futures(|| world.run_schedule(Tasks)));
259
260 world.entity_mut(entity).insert((
262 CompletionRequest(vec![]),
263 PositionComponent(lsp_types::Position {
264 line: 1,
265 character: 4,
266 }),
267 ));
268 world.run_schedule(CompletionLabel);
269 let completions = world
270 .entity_mut(entity)
271 .take::<CompletionRequest>()
272 .expect("competion request")
273 .0;
274
275 assert_eq!(completions.len(), 62 + TurtleHelper.keyword().len());
276 }
277
278 #[test_log::test]
279 fn test_autocomplete_properties_2() {
280 println!("completion_event_works");
281 let (mut world, _) = setup_world(TestClient::new(), crate::setup_world);
282
283 let t1 = "@prefix foaf: <http://xmlns.com/foaf/0.1/>.
284<> a foaf:Person;
285 foaf:name \"Arthur\".";
286
287 let t2 = "@prefix foaf: <http://xmlns.com/foaf/0.1/>.
288<> a foaf:Person;
289 foaf:
290 foaf:name \"Arthur\".";
291
292 let entity = create_file(&mut world, t1, "http://example.com/ns#", "turtle", Open);
293
294 let c = world.resource::<TestClient>().clone();
295 block_on(c.await_futures(|| world.run_schedule(Tasks)));
296
297 world
298 .entity_mut(entity)
299 .insert((Source(t2.to_string()), RopeC(Rope::from_str(t2)), Open));
300 world.run_schedule(ParseLabel);
301
302 block_on(c.await_futures(|| world.run_schedule(Tasks)));
303
304 world.entity_mut(entity).insert((
306 CompletionRequest(vec![]),
307 PositionComponent(lsp_types::Position {
308 line: 2,
309 character: 5,
310 }),
311 ));
312 world.run_schedule(CompletionLabel);
313 let completions = world
314 .entity_mut(entity)
315 .take::<CompletionRequest>()
316 .expect("competion request")
317 .0;
318
319 assert_eq!(completions.len(), 62 + TurtleHelper.keyword().len());
320 }
321}