Skip to main content

swls_core/
backend.rs

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        // let triggers = L::TRIGGERS.iter().copied().map(String::from).collect();
155        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                // implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
171                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            // This is nice and all, but we don't bubble this event up in the world
226            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        // Problem: when the cursor is at the end of an ident, that ident is not in range of the
602        // cursor
603        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}