lsp_core/feature/
goto_definition.rs

1use bevy_ecs::{
2    component::Component,
3    schedule::{IntoSystemConfigs, Schedule, ScheduleLabel},
4    world::World,
5};
6
7pub use crate::{
8    systems::{hover_class, hover_property, hover_types, infer_types},
9    util::{token::get_current_token, triple::get_current_triple},
10};
11
12/// [`Component`] indicating that the current document is currently handling a GotoImplementation request.
13#[derive(Component, Debug, Default)]
14pub struct GotoDefinitionRequest(pub Vec<lsp_types::Location>);
15
16/// [`ScheduleLabel`] related to the GotoImplementation schedule
17#[derive(ScheduleLabel, Clone, Eq, PartialEq, Debug, Hash)]
18pub struct Label;
19
20pub fn setup_schedule(world: &mut World) {
21    let mut references = Schedule::new(Label);
22    references.add_systems((
23        get_current_token,
24        get_current_triple.after(get_current_token),
25        system::goto_definition.after(get_current_triple),
26    ));
27    world.add_schedule(references);
28}
29
30mod system {
31    use std::collections::HashSet;
32
33    use bevy_ecs::prelude::*;
34    use goto_definition::GotoDefinitionRequest;
35    use sophia_api::{quad::Quad as _, term::TermKind};
36
37    use crate::{prelude::*, util::token_to_location};
38
39    pub fn goto_definition(
40        mut query: Query<(
41            &TripleComponent,
42            &Triples,
43            &Label,
44            &RopeC,
45            &mut GotoDefinitionRequest,
46        )>,
47        project: Query<(&Triples, &RopeC, &Label)>,
48    ) {
49        for (triple, triples, label, rope, mut req) in &mut query {
50            let target = triple.kind();
51            let Some(term) = triple.term() else {
52                continue;
53            };
54
55            tracing::debug!("Found {} with kind {:?}", term.value, target);
56            if target == TermKind::Iri {
57                // This is a named node, we should look project wide
58                for (triples, rope, label) in &project {
59                    let subs: HashSet<_> = triples
60                        .iter()
61                        .map(|x| x.s())
62                        .filter(|x| &x.value == &term.value)
63                        .collect();
64
65                    req.0.extend(
66                        subs.into_iter()
67                            .flat_map(|t| token_to_location(&t.span, label, &rope)),
68                    );
69                }
70            } else if target == TermKind::BlankNode {
71                // Blank node is constrained to current document
72                let subs: HashSet<_> = triples
73                    .iter()
74                    .map(|x| x.s())
75                    .filter(|x| &x.value == &term.value)
76                    .collect();
77                req.0.extend(
78                    subs.into_iter()
79                        .flat_map(|t| token_to_location(&t.span, label, &rope)),
80                );
81            }
82        }
83    }
84}