1use std::{collections::HashMap, sync::Arc};
2
3use bevy_ecs::{
4 bundle::Bundle,
5 component::Component,
6 entity::Entity,
7 schedule::ScheduleLabel,
8 world::{CommandQueue, World},
9};
10use completion::CompletionRequest;
11use futures::lock::Mutex;
12use goto_type::GotoTypeRequest;
13use references::ReferencesRequest;
14use request::{GotoTypeDefinitionParams, GotoTypeDefinitionResponse};
15use ropey::Rope;
16use tower_lsp::{jsonrpc::Result, LanguageServer};
17use tracing::{debug, error, info, instrument};
18
19use crate::{
20 feature::{
21 code_action::{CodeActionRequest, Label as CodeActionLabel},
22 goto_definition::GotoDefinitionRequest,
23 },
24 lsp_types::{request::SemanticTokensRefresh, *},
25 prelude::*,
26 Started, Startup,
27};
28
29#[derive(Debug)]
30pub struct Backend {
31 entities: Arc<Mutex<HashMap<String, Entity>>>,
32 sender: CommandSender,
33 #[allow(unused)]
34 client: tower_lsp::Client,
35 semantic_tokens: Vec<SemanticTokenType>,
36}
37
38impl Backend {
39 pub fn new(
40 sender: CommandSender,
41 client: tower_lsp::Client,
42 tokens: Vec<SemanticTokenType>,
43 ) -> Self {
44 Self {
45 entities: Default::default(),
46 sender,
47 client,
48 semantic_tokens: tokens,
49 }
50 }
51
52 async fn run<T: Send + Sync + 'static>(
53 &self,
54 f: impl FnOnce(&mut World) -> T + Send + Sync + 'static,
55 ) -> Option<T> {
56 let (tx, rx) = futures::channel::oneshot::channel();
57 let mut commands = CommandQueue::default();
58 commands.push(move |world: &mut World| {
59 let o = f(world);
60 if let Err(_) = tx.send(o) {
61 error!("Failed to run schedule for {}", stringify!(T));
62 };
63 });
64
65 if let Err(e) = self.sender.0.unbounded_send(commands) {
66 error!("Failed to send commands {}", e);
67 return None;
68 }
69
70 rx.await.ok()
71 }
72
73 async fn run_schedule<T: Component>(
74 &self,
75 entity: Entity,
76 schedule: impl ScheduleLabel + Clone,
77 param: impl Bundle,
78 ) -> Option<T> {
79 let (tx, rx) = futures::channel::oneshot::channel();
80
81 let mut commands = CommandQueue::default();
82 commands.push(move |world: &mut World| {
83 world.entity_mut(entity).insert(param);
84 world.run_schedule(schedule.clone());
85 if let Err(_) = tx.send(world.entity_mut(entity).take::<T>()) {
86 error!(name: "Failed to run schedule", "Failed to run schedule {:?}", schedule);
87 };
88 });
89
90 if let Err(e) = self.sender.0.unbounded_send(commands) {
91 error!("Failed to send commands {}", e);
92 return None;
93 }
94
95 rx.await.unwrap_or_default()
96 }
97
98 async fn get_entity(&self, uri: &str) -> Option<Entity> {
99 let map = self.entities.lock().await;
100 map.get(uri).copied()
101 }
102
103 fn adjust_position(pos: &mut Position) {
104 pos.character = pos.character.saturating_sub(1);
105 }
106}
107
108#[tower_lsp::async_trait]
109impl LanguageServer for Backend {
110 #[instrument(skip(self, init))]
111 async fn initialize(&self, init: InitializeParams) -> Result<InitializeResult> {
112 info!("Initialize");
113
114 let workspaces = init.workspace_folders.clone().unwrap_or_default();
115 let config: Config =
116 serde_json::from_value(init.initialization_options.clone().unwrap_or_default())
117 .unwrap_or_default();
118
119 let mut server_config = ServerConfig { config, workspaces };
120
121 let fs = self.run(|w| w.resource::<Fs>().clone()).await.unwrap();
122 if let Some(global) = LocalConfig::global(&fs).await {
123 server_config.config.local.combine(global);
124 }
125
126 if let Some(root) = init.root_uri.as_ref() {
127 if let Some(local) = LocalConfig::local(&fs, root).await {
128 server_config.config.local.combine(local);
129 }
130 }
131
132 info!("Initialize {:?}", server_config);
133 let document_selectors: Vec<_> = [
134 ("sparql", server_config.config.sparql.unwrap_or(true)),
135 ("turtle", server_config.config.turtle.unwrap_or(true)),
136 ("trig", server_config.config.trig.unwrap_or(true)),
137 ("jsonld", server_config.config.jsonld.unwrap_or(true)),
138 ]
139 .into_iter()
140 .filter(|(_, x)| *x)
141 .map(|(x, _)| DocumentFilter {
142 language: Some(String::from(x)),
143 scheme: None,
144 pattern: None,
145 })
146 .collect();
147
148 self.run(|world| {
149 world.insert_resource(server_config);
150 world.run_schedule(Startup);
151 })
152 .await;
153
154 Ok(InitializeResult {
156 server_info: None,
157 capabilities: ServerCapabilities {
158 inlay_hint_provider: Some(OneOf::Left(true)),
159 text_document_sync: Some(TextDocumentSyncCapability::Kind(
160 TextDocumentSyncKind::FULL,
161 )),
162 code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
163 completion_provider: Some(CompletionOptions {
164 resolve_provider: Some(false),
165 trigger_characters: Some(vec![String::from(":")]),
166 work_done_progress_options: Default::default(),
167 all_commit_characters: None,
168 completion_item: None,
169 }),
170 type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
172 references_provider: Some(OneOf::Left(true)),
173 hover_provider: Some(HoverProviderCapability::Simple(true)),
174 definition_provider: Some(OneOf::Left(true)),
175 document_formatting_provider: Some(OneOf::Left(true)),
176 semantic_tokens_provider: Some(
177 SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(
178 SemanticTokensRegistrationOptions {
179 text_document_registration_options: {
180 TextDocumentRegistrationOptions {
181 document_selector: Some(document_selectors),
182 }
183 },
184 semantic_tokens_options: SemanticTokensOptions {
185 work_done_progress_options: WorkDoneProgressOptions::default(),
186 legend: SemanticTokensLegend {
187 token_types: self.semantic_tokens.clone(),
188 token_modifiers: vec![],
189 },
190 range: Some(false),
191 full: Some(SemanticTokensFullOptions::Bool(true)),
192 },
193 static_registration_options: StaticRegistrationOptions::default(),
194 },
195 ),
196 ),
197 rename_provider: Some(OneOf::Right(RenameOptions {
198 prepare_provider: Some(true),
199 work_done_progress_options: Default::default(),
200 })),
201 ..ServerCapabilities::default()
202 },
203 })
204 }
205
206 async fn initialized(&self, _params: InitializedParams) {
207 self.run(|world| {
208 tracing::info!("initialized");
209 world.run_schedule(Started);
210 })
211 .await;
212 }
213
214 async fn did_change_workspace_folders(&self, params: DidChangeWorkspaceFoldersParams) -> () {
215 self.run(move |world| {
216 let mut config = world.resource_mut::<ServerConfig>();
217 let WorkspaceFoldersChangeEvent { added, removed } = params.event;
218
219 for r in removed {
220 if let Some(idx) = config.workspaces.iter().position(|x| x == &r) {
221 config.workspaces.remove(idx);
222 }
223 }
224
225 config.workspaces.extend(added);
227 })
228 .await;
229 ()
230 }
231
232 #[instrument(skip(self, params), fields(uri = %params.text_document.uri.as_str()))]
233 async fn semantic_tokens_full(
234 &self,
235 params: SemanticTokensParams,
236 ) -> Result<Option<SemanticTokensResult>> {
237 debug!("semantic tokens full");
238 let uri = params.text_document.uri.as_str();
239 let Some(entity) = self.get_entity(uri).await else {
240 debug!("Didn't find entity {} stopping", uri);
241 return Ok(None);
242 };
243
244 if let Some(res) = self
245 .run_schedule::<HighlightRequest>(entity, SemanticLabel, HighlightRequest(vec![]))
246 .await
247 {
248 Ok(Some(SemanticTokensResult::Tokens(
249 crate::lsp_types::SemanticTokens {
250 result_id: None,
251 data: res.0,
252 },
253 )))
254 } else {
255 debug!("resulting in no tokens");
256 Ok(None)
257 }
258 }
259
260 #[instrument(skip(self))]
261 async fn shutdown(&self) -> Result<()> {
262 info!("Shutting down!");
263
264 Ok(())
265 }
266
267 #[instrument(skip(self, params), fields(uri = %params.text_document_position.text_document.uri.as_str()))]
268 async fn references(&self, params: ReferenceParams) -> Result<Option<Vec<Location>>> {
269 let Some(entity) = self
270 .get_entity(params.text_document_position.text_document.uri.as_str())
271 .await
272 else {
273 return Ok(None);
274 };
275
276 let mut pos = params.text_document_position.position;
277 Self::adjust_position(&mut pos);
278
279 let arr = self
280 .run_schedule::<ReferencesRequest>(
281 entity,
282 ReferencesLabel,
283 (PositionComponent(pos), ReferencesRequest(Vec::new())),
284 )
285 .await
286 .map(|x| x.0);
287
288 Ok(arr)
289 }
290
291 #[instrument(skip(self, params), fields(uri = %params.text_document.uri.as_str()))]
292 async fn prepare_rename(
293 &self,
294 params: TextDocumentPositionParams,
295 ) -> Result<Option<PrepareRenameResponse>> {
296 let Some(entity) = self.get_entity(params.text_document.uri.as_str()).await else {
297 return Ok(None);
298 };
299
300 let mut pos = params.position;
301 Self::adjust_position(&mut pos);
302
303 let resp = self
304 .run_schedule::<PrepareRenameRequest>(
305 entity,
306 PrepareRenameLabel,
307 PositionComponent(pos),
308 )
309 .await
310 .map(|x| PrepareRenameResponse::RangeWithPlaceholder {
311 range: x.range,
312 placeholder: x.placeholder,
313 });
314
315 Ok(resp)
316 }
317
318 #[instrument(skip(self, params), fields(uri = %params.text_document_position.text_document.uri.as_str()))]
319 async fn rename(&self, params: RenameParams) -> Result<Option<WorkspaceEdit>> {
320 let Some(entity) = self
321 .get_entity(params.text_document_position.text_document.uri.as_str())
322 .await
323 else {
324 return Ok(None);
325 };
326
327 let mut pos = params.text_document_position.position;
328 Self::adjust_position(&mut pos);
329
330 let mut change_map: HashMap<crate::lsp_types::Url, Vec<TextEdit>> = HashMap::new();
331 if let Some(changes) = self
332 .run_schedule::<RenameEdits>(
333 entity,
334 RenameLabel,
335 (
336 PositionComponent(pos),
337 RenameEdits(Vec::new(), params.new_name),
338 ),
339 )
340 .await
341 {
342 for (url, change) in changes.0 {
343 let entry = change_map.entry(url);
344 entry.or_default().push(change);
345 }
346 }
347 Ok(Some(WorkspaceEdit::new(change_map)))
348 }
349
350 async fn hover(&self, params: HoverParams) -> Result<Option<crate::lsp_types::Hover>> {
351 let request: HoverRequest = HoverRequest::default();
352
353 let Some(entity) = self
354 .get_entity(
355 params
356 .text_document_position_params
357 .text_document
358 .uri
359 .as_str(),
360 )
361 .await
362 else {
363 return Ok(None);
364 };
365
366 let mut pos = params.text_document_position_params.position;
367 Self::adjust_position(&mut pos);
368
369 if let Some(hover) = self
370 .run_schedule::<HoverRequest>(entity, HoverLabel, (request, PositionComponent(pos)))
371 .await
372 {
373 tracing::debug!("hover returned {} items", hover.0.len());
374 if hover.0.len() > 0 {
375 return Ok(Some(crate::lsp_types::Hover {
376 contents: crate::lsp_types::HoverContents::Markup(MarkupContent {
377 kind: MarkupKind::Markdown,
378 value: hover.0.join("\n\n---\n\n"),
379 }),
380 range: hover.1,
381 }));
382 }
383 }
384
385 Ok(None)
386 }
387
388 async fn inlay_hint(&self, params: InlayHintParams) -> Result<Option<Vec<InlayHint>>> {
389 debug!("Inlay hints called");
390 let uri = params.text_document.uri.as_str();
391 let Some(entity) = self.get_entity(uri).await else {
392 debug!("Didn't find entity {}", uri);
393 return Ok(None);
394 };
395
396 let request = self
397 .run_schedule::<InlayRequest>(entity, InlayLabel, InlayRequest::default())
398 .await;
399
400 debug!(
401 "Inlay hints resolved {} hints",
402 request.as_ref().map(|x| x.0.len()).unwrap_or(0)
403 );
404
405 Ok(request.and_then(|x| Some(x.0)))
406 }
407
408 #[instrument(skip(self))]
409 async fn formatting(&self, params: DocumentFormattingParams) -> Result<Option<Vec<TextEdit>>> {
410 let uri = params.text_document.uri.as_str();
411 let Some(entity) = self.get_entity(uri).await else {
412 debug!("Didn't find entity {}", uri);
413 return Ok(None);
414 };
415
416 let request = self
417 .run_schedule::<FormatRequest>(entity, FormatLabel, FormatRequest(None))
418 .await;
419 Ok(request.and_then(|x| x.0))
420 }
421
422 #[instrument(skip(self, params), fields(uri = %params.text_document.uri.as_str()))]
423 async fn did_open(&self, params: DidOpenTextDocumentParams) {
424 let item = params.text_document;
425 let url = item.uri.as_str().to_string();
426
427 let lang_id = Some(item.language_id.clone());
428 let spawn = spawn_or_insert(
429 item.uri.clone(),
430 (
431 Source(item.text.clone()),
432 Label(item.uri.clone()),
433 RopeC(Rope::from_str(&item.text)),
434 Wrapped(item),
435 DocumentLinks(Vec::new()),
436 Open,
437 Types(HashMap::new()),
438 ),
439 lang_id,
440 (),
441 );
442
443 let entity = self
444 .run(|world| {
445 let id = spawn(world);
446 world.run_schedule(ParseLabel);
447 world.flush();
448 world.run_schedule(DiagnosticsLabel);
449 id
450 })
451 .await;
452
453 if let Some(entity) = entity {
454 self.entities.lock().await.insert(url, entity);
455 }
456
457 debug!("Requesting tokens refresh");
458 let _ = self.client.send_request::<SemanticTokensRefresh>(()).await;
459 debug!("Semantic tokens refresh");
460 }
461
462 #[instrument(skip(self, params), fields(uri = %params.text_document.uri.as_str()))]
463 async fn did_change(&self, params: DidChangeTextDocumentParams) {
464 let Some(entity) = self.get_entity(params.text_document.uri.as_str()).await else {
465 debug!("Didn't find entity {}", params.text_document.uri.as_str());
466 return;
467 };
468
469 let change = {
470 if let Some(c) = params.content_changes.into_iter().next() {
471 c
472 } else {
473 return;
474 }
475 };
476
477 self.run(move |world| {
478 let rope_c = RopeC(Rope::from_str(&change.text));
479 world
480 .entity_mut(entity)
481 .insert((Source(change.text), rope_c));
482 world.run_schedule(ParseLabel);
483 world.flush();
484 world.run_schedule(DiagnosticsLabel);
485 })
486 .await;
487 }
488
489 #[instrument(skip(self, params), fields(uri = %params.text_document.uri.as_str()))]
490 async fn did_save(&self, params: DidSaveTextDocumentParams) {
491 let _ = params;
492
493 self.run(move |world| {
494 world.run_schedule(SaveLabel);
495
496 debug!("Ran OnSave Schedule");
497 })
498 .await;
499 }
500
501 #[instrument(skip(self, params), fields(uri = %params.text_document_position_params.text_document.uri.as_str()))]
502 async fn goto_definition(
503 &self,
504 params: GotoDefinitionParams,
505 ) -> Result<Option<GotoDefinitionResponse>> {
506 let Some(entity) = self
507 .get_entity(
508 params
509 .text_document_position_params
510 .text_document
511 .uri
512 .as_str(),
513 )
514 .await
515 else {
516 return Ok(None);
517 };
518
519 let mut pos = params.text_document_position_params.position;
520 Self::adjust_position(&mut pos);
521
522 let arr = self
523 .run_schedule::<GotoDefinitionRequest>(
524 entity,
525 GotoDefinitionLabel,
526 (PositionComponent(pos), GotoDefinitionRequest(Vec::new())),
527 )
528 .await
529 .map(|x| {
530 tracing::debug!("goto definition: {} locations", x.0.len());
531 GotoDefinitionResponse::Array(x.0)
532 });
533
534 Ok(arr)
535 }
536
537 #[instrument(skip(self, params), fields(uri = %params.text_document_position_params.text_document.uri.as_str()))]
538 async fn goto_type_definition(
539 &self,
540 params: GotoTypeDefinitionParams,
541 ) -> Result<Option<GotoTypeDefinitionResponse>> {
542 let Some(entity) = self
543 .get_entity(
544 params
545 .text_document_position_params
546 .text_document
547 .uri
548 .as_str(),
549 )
550 .await
551 else {
552 return Ok(None);
553 };
554
555 let mut pos = params.text_document_position_params.position;
556 Self::adjust_position(&mut pos);
557
558 let arr = self
559 .run_schedule::<GotoTypeRequest>(
560 entity,
561 GotoTypeLabel,
562 (PositionComponent(pos), GotoTypeRequest(Vec::new())),
563 )
564 .await
565 .map(|x| GotoTypeDefinitionResponse::Array(x.0));
566
567 Ok(arr)
568 }
569
570 #[instrument(skip(self, params), fields(uri = %params.text_document.uri.as_str()))]
571 async fn code_action(&self, params: CodeActionParams) -> Result<Option<CodeActionResponse>> {
572 let uri = params.text_document.uri.as_str();
573 let Some(entity) = self.get_entity(uri).await else {
574 return Ok(None);
575 };
576
577 let request = self
578 .run_schedule::<CodeActionRequest>(
579 entity,
580 CodeActionLabel,
581 CodeActionRequest::default(),
582 )
583 .await;
584
585 Ok(request.map(|r| {
586 r.0.into_iter()
587 .map(CodeActionOrCommand::CodeAction)
588 .collect()
589 }))
590 }
591
592 #[instrument(skip(self, params), fields(uri = %params.text_document_position.text_document.uri.as_str()))]
593 async fn completion(&self, params: CompletionParams) -> Result<Option<CompletionResponse>> {
594 let Some(entity) = self
595 .get_entity(params.text_document_position.text_document.uri.as_str())
596 .await
597 else {
598 return Ok(None);
599 };
600
601 let mut pos = params.text_document_position.position;
604 Self::adjust_position(&mut pos);
605
606 let completions: Option<Vec<crate::lsp_types::CompletionItem>> = self
607 .run_schedule::<CompletionRequest>(
608 entity,
609 CompletionLabel,
610 (CompletionRequest(vec![]), PositionComponent(pos)),
611 )
612 .await
613 .map(|x| x.0.into_iter().map(|x| x.into()).collect());
614
615 Ok(completions.map(|mut c| {
616 c.sort_by(|a, b| a.sort_text.cmp(&b.sort_text));
617
618 CompletionResponse::Array(c)
619 }))
620 }
621}