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