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 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 ("jsonld", server_config.config.jsonld.unwrap_or(true)),
137 ]
138 .into_iter()
139 .filter(|(_, x)| *x)
140 .map(|(x, _)| DocumentFilter {
141 language: Some(String::from(x)),
142 scheme: None,
143 pattern: None,
144 })
145 .collect();
146
147 self.run(|world| {
148 world.insert_resource(server_config);
149 world.run_schedule(Startup);
150 })
151 .await;
152
153 Ok(InitializeResult {
155 server_info: None,
156 capabilities: ServerCapabilities {
157 inlay_hint_provider: Some(OneOf::Left(true)),
158 text_document_sync: Some(TextDocumentSyncCapability::Kind(
159 TextDocumentSyncKind::FULL,
160 )),
161 code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
162 completion_provider: Some(CompletionOptions {
163 resolve_provider: Some(false),
164 trigger_characters: Some(vec![String::from(":")]),
165 work_done_progress_options: Default::default(),
166 all_commit_characters: None,
167 completion_item: None,
168 }),
169 type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
171 references_provider: Some(OneOf::Left(true)),
172 hover_provider: Some(HoverProviderCapability::Simple(true)),
173 definition_provider: Some(OneOf::Left(true)),
174 document_formatting_provider: Some(OneOf::Left(true)),
175 semantic_tokens_provider: Some(
176 SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(
177 SemanticTokensRegistrationOptions {
178 text_document_registration_options: {
179 TextDocumentRegistrationOptions {
180 document_selector: Some(document_selectors),
181 }
182 },
183 semantic_tokens_options: SemanticTokensOptions {
184 work_done_progress_options: WorkDoneProgressOptions::default(),
185 legend: SemanticTokensLegend {
186 token_types: self.semantic_tokens.clone(),
187 token_modifiers: vec![],
188 },
189 range: Some(false),
190 full: Some(SemanticTokensFullOptions::Bool(true)),
191 },
192 static_registration_options: StaticRegistrationOptions::default(),
193 },
194 ),
195 ),
196 rename_provider: Some(OneOf::Right(RenameOptions {
197 prepare_provider: Some(true),
198 work_done_progress_options: Default::default(),
199 })),
200 ..ServerCapabilities::default()
201 },
202 })
203 }
204
205 async fn did_change_workspace_folders(&self, params: DidChangeWorkspaceFoldersParams) -> () {
206 self.run(move |world| {
207 let mut config = world.resource_mut::<ServerConfig>();
208 let WorkspaceFoldersChangeEvent { added, removed } = params.event;
209
210 for r in removed {
211 if let Some(idx) = config.workspaces.iter().position(|x| x == &r) {
212 config.workspaces.remove(idx);
213 }
214 }
215
216 config.workspaces.extend(added);
218 })
219 .await;
220 ()
221 }
222
223 #[instrument(skip(self, params), fields(uri = %params.text_document.uri.as_str()))]
224 async fn semantic_tokens_full(
225 &self,
226 params: SemanticTokensParams,
227 ) -> Result<Option<SemanticTokensResult>> {
228 debug!("semantic tokens full");
229 let uri = params.text_document.uri.as_str();
230 let Some(entity) = self.get_entity(uri).await else {
231 info!("Didn't find entity {} stopping", uri);
232 return Ok(None);
233 };
234
235 if let Some(res) = self
236 .run_schedule::<HighlightRequest>(entity, SemanticLabel, HighlightRequest(vec![]))
237 .await
238 {
239 Ok(Some(SemanticTokensResult::Tokens(
240 crate::lsp_types::SemanticTokens {
241 result_id: None,
242 data: res.0,
243 },
244 )))
245 } else {
246 debug!("resulting in no tokens");
247 Ok(None)
248 }
249 }
250
251 #[instrument(skip(self))]
252 async fn shutdown(&self) -> Result<()> {
253 info!("Shutting down!");
254
255 Ok(())
256 }
257
258 #[instrument(skip(self, params), fields(uri = %params.text_document_position.text_document.uri.as_str()))]
259 async fn references(&self, params: ReferenceParams) -> Result<Option<Vec<Location>>> {
260 let Some(entity) = self
261 .get_entity(params.text_document_position.text_document.uri.as_str())
262 .await
263 else {
264 return Ok(None);
265 };
266
267 let mut pos = params.text_document_position.position;
268 Self::adjust_position(&mut pos);
269
270 let arr = self
271 .run_schedule::<ReferencesRequest>(
272 entity,
273 ReferencesLabel,
274 (PositionComponent(pos), ReferencesRequest(Vec::new())),
275 )
276 .await
277 .map(|x| x.0);
278
279 Ok(arr)
280 }
281
282 #[instrument(skip(self, params), fields(uri = %params.text_document.uri.as_str()))]
283 async fn prepare_rename(
284 &self,
285 params: TextDocumentPositionParams,
286 ) -> Result<Option<PrepareRenameResponse>> {
287 let Some(entity) = self.get_entity(params.text_document.uri.as_str()).await else {
288 return Ok(None);
289 };
290
291 let mut pos = params.position;
292 Self::adjust_position(&mut pos);
293
294 let resp = self
295 .run_schedule::<PrepareRenameRequest>(
296 entity,
297 PrepareRenameLabel,
298 PositionComponent(pos),
299 )
300 .await
301 .map(|x| PrepareRenameResponse::RangeWithPlaceholder {
302 range: x.range,
303 placeholder: x.placeholder,
304 });
305
306 Ok(resp)
307 }
308
309 #[instrument(skip(self, params), fields(uri = %params.text_document_position.text_document.uri.as_str()))]
310 async fn rename(&self, params: RenameParams) -> Result<Option<WorkspaceEdit>> {
311 let Some(entity) = self
312 .get_entity(params.text_document_position.text_document.uri.as_str())
313 .await
314 else {
315 return Ok(None);
316 };
317
318 let mut pos = params.text_document_position.position;
319 Self::adjust_position(&mut pos);
320
321 let mut change_map: HashMap<crate::lsp_types::Url, Vec<TextEdit>> = HashMap::new();
322 if let Some(changes) = self
323 .run_schedule::<RenameEdits>(
324 entity,
325 RenameLabel,
326 (
327 PositionComponent(pos),
328 RenameEdits(Vec::new(), params.new_name),
329 ),
330 )
331 .await
332 {
333 for (url, change) in changes.0 {
334 let entry = change_map.entry(url);
335 entry.or_default().push(change);
336 }
337 }
338 Ok(Some(WorkspaceEdit::new(change_map)))
339 }
340
341 async fn hover(&self, params: HoverParams) -> Result<Option<crate::lsp_types::Hover>> {
342 let request: HoverRequest = HoverRequest::default();
343
344 let Some(entity) = self
345 .get_entity(
346 params
347 .text_document_position_params
348 .text_document
349 .uri
350 .as_str(),
351 )
352 .await
353 else {
354 return Ok(None);
355 };
356
357 let mut pos = params.text_document_position_params.position;
358 Self::adjust_position(&mut pos);
359
360 if let Some(hover) = self
361 .run_schedule::<HoverRequest>(entity, HoverLabel, (request, PositionComponent(pos)))
362 .await
363 {
364 if hover.0.len() > 0 {
365 return Ok(Some(crate::lsp_types::Hover {
366 contents: crate::lsp_types::HoverContents::Markup(MarkupContent {
367 kind: MarkupKind::Markdown,
368 value: hover.0.join("\n\n---\n\n"),
369 }),
370 range: hover.1,
371 }));
372 }
373 }
374
375 Ok(None)
376 }
377
378 async fn inlay_hint(&self, params: InlayHintParams) -> Result<Option<Vec<InlayHint>>> {
379 debug!("Inlay hints called");
380 let uri = params.text_document.uri.as_str();
381 let Some(entity) = self.get_entity(uri).await else {
382 info!("Didn't find entity {}", uri);
383 return Ok(None);
384 };
385
386 let request = self
387 .run_schedule::<InlayRequest>(entity, InlayLabel, InlayRequest::default())
388 .await;
389
390 debug!(
391 "Inlay hints resolved {} hints",
392 request.as_ref().map(|x| x.0.len()).unwrap_or(0)
393 );
394
395 Ok(request.and_then(|x| Some(x.0)))
396 }
397
398 #[instrument(skip(self))]
399 async fn formatting(&self, params: DocumentFormattingParams) -> Result<Option<Vec<TextEdit>>> {
400 let uri = params.text_document.uri.as_str();
401 let Some(entity) = self.get_entity(uri).await else {
402 info!("Didn't find entity {}", uri);
403 return Ok(None);
404 };
405
406 let request = self
407 .run_schedule::<FormatRequest>(entity, FormatLabel, FormatRequest(None))
408 .await;
409 Ok(request.and_then(|x| x.0))
410 }
411
412 #[instrument(skip(self, params), fields(uri = %params.text_document.uri.as_str()))]
413 async fn did_open(&self, params: DidOpenTextDocumentParams) {
414 let item = params.text_document;
415 let url = item.uri.as_str().to_string();
416
417 let lang_id = Some(item.language_id.clone());
418 let spawn = spawn_or_insert(
419 item.uri.clone(),
420 (
421 Source(item.text.clone()),
422 Label(item.uri.clone()),
423 RopeC(Rope::from_str(&item.text)),
424 Wrapped(item),
425 DocumentLinks(Vec::new()),
426 Open,
427 Types(HashMap::new()),
428 ),
429 lang_id,
430 (),
431 );
432
433 let entity = self
434 .run(|world| {
435 let id = spawn(world);
436 world.run_schedule(ParseLabel);
437 world.flush();
438 world.run_schedule(DiagnosticsLabel);
439 id
440 })
441 .await;
442
443 if let Some(entity) = entity {
444 self.entities.lock().await.insert(url, entity);
445 }
446
447 debug!("Requesting tokens refresh");
448 let _ = self.client.send_request::<SemanticTokensRefresh>(()).await;
449 debug!("Semantic tokens refresh");
450 }
451
452 #[instrument(skip(self, params), fields(uri = %params.text_document.uri.as_str()))]
453 async fn did_change(&self, params: DidChangeTextDocumentParams) {
454 let Some(entity) = self.get_entity(params.text_document.uri.as_str()).await else {
455 info!("Didn't find entity {}", params.text_document.uri.as_str());
456 return;
457 };
458
459 let change = {
460 if let Some(c) = params.content_changes.into_iter().next() {
461 c
462 } else {
463 return;
464 }
465 };
466
467 self.run(move |world| {
468 let rope_c = RopeC(Rope::from_str(&change.text));
469 world
470 .entity_mut(entity)
471 .insert((Source(change.text), rope_c));
472 world.run_schedule(ParseLabel);
473 world.flush();
474 world.run_schedule(DiagnosticsLabel);
475 })
476 .await;
477 }
478
479 #[instrument(skip(self, params), fields(uri = %params.text_document.uri.as_str()))]
480 async fn did_save(&self, params: DidSaveTextDocumentParams) {
481 let _ = params;
482
483 self.run(move |world| {
484 world.run_schedule(SaveLabel);
485
486 debug!("Ran OnSave Schedule");
487 })
488 .await;
489 }
490
491 #[instrument(skip(self, params), fields(uri = %params.text_document_position_params.text_document.uri.as_str()))]
492 async fn goto_definition(
493 &self,
494 params: GotoDefinitionParams,
495 ) -> Result<Option<GotoDefinitionResponse>> {
496 let Some(entity) = self
497 .get_entity(
498 params
499 .text_document_position_params
500 .text_document
501 .uri
502 .as_str(),
503 )
504 .await
505 else {
506 return Ok(None);
507 };
508
509 let mut pos = params.text_document_position_params.position;
510 Self::adjust_position(&mut pos);
511
512 let arr = self
513 .run_schedule::<GotoDefinitionRequest>(
514 entity,
515 GotoDefinitionLabel,
516 (PositionComponent(pos), GotoDefinitionRequest(Vec::new())),
517 )
518 .await
519 .map(|x| GotoDefinitionResponse::Array(x.0));
520
521 Ok(arr)
522 }
523
524 #[instrument(skip(self, params), fields(uri = %params.text_document_position_params.text_document.uri.as_str()))]
525 async fn goto_type_definition(
526 &self,
527 params: GotoTypeDefinitionParams,
528 ) -> Result<Option<GotoTypeDefinitionResponse>> {
529 let Some(entity) = self
530 .get_entity(
531 params
532 .text_document_position_params
533 .text_document
534 .uri
535 .as_str(),
536 )
537 .await
538 else {
539 return Ok(None);
540 };
541
542 let mut pos = params.text_document_position_params.position;
543 Self::adjust_position(&mut pos);
544
545 let arr = self
546 .run_schedule::<GotoTypeRequest>(
547 entity,
548 GotoTypeLabel,
549 (PositionComponent(pos), GotoTypeRequest(Vec::new())),
550 )
551 .await
552 .map(|x| GotoTypeDefinitionResponse::Array(x.0));
553
554 Ok(arr)
555 }
556
557 #[instrument(skip(self, params), fields(uri = %params.text_document.uri.as_str()))]
558 async fn code_action(
559 &self,
560 params: CodeActionParams,
561 ) -> Result<Option<CodeActionResponse>> {
562 let uri = params.text_document.uri.as_str();
563 let Some(entity) = self.get_entity(uri).await else {
564 return Ok(None);
565 };
566
567 let request = self
568 .run_schedule::<CodeActionRequest>(
569 entity,
570 CodeActionLabel,
571 CodeActionRequest::default(),
572 )
573 .await;
574
575 Ok(request.map(|r| {
576 r.0.into_iter()
577 .map(CodeActionOrCommand::CodeAction)
578 .collect()
579 }))
580 }
581
582 #[instrument(skip(self, params), fields(uri = %params.text_document_position.text_document.uri.as_str()))]
583 async fn completion(&self, params: CompletionParams) -> Result<Option<CompletionResponse>> {
584 let Some(entity) = self
585 .get_entity(params.text_document_position.text_document.uri.as_str())
586 .await
587 else {
588 return Ok(None);
589 };
590
591 let mut pos = params.text_document_position.position;
594 Self::adjust_position(&mut pos);
595
596 let completions: Option<Vec<crate::lsp_types::CompletionItem>> = self
597 .run_schedule::<CompletionRequest>(
598 entity,
599 CompletionLabel,
600 (CompletionRequest(vec![]), PositionComponent(pos)),
601 )
602 .await
603 .map(|x| x.0.into_iter().map(|x| x.into()).collect());
604
605 Ok(completions.map(|mut c| {
606 c.sort_by(|a, b| a.sort_text.cmp(&b.sort_text));
607
608 CompletionResponse::Array(c)
609 }))
610 }
611}