Skip to main content

swls_core/feature/
goto_definition.rs

1use bevy_ecs::{
2    component::Component,
3    schedule::{IntoScheduleConfigs, Schedule, ScheduleLabel},
4    world::World,
5};
6
7use crate::prelude::get_current_cst_token;
8pub use crate::systems::{get_current_prefix, goto_prefix};
9pub use crate::util::triple::get_current_triple;
10
11/// [`Component`] indicating that the current document is handling a GotoDefinition request.
12#[derive(Component, Debug, Default)]
13pub struct GotoDefinitionRequest(pub Vec<crate::lsp_types::Location>);
14
15/// [`ScheduleLabel`] related to the GotoDefinition schedule
16#[derive(ScheduleLabel, Clone, Eq, PartialEq, Debug, Hash)]
17pub struct Label;
18
19pub fn setup_schedule(world: &mut World) {
20    let mut references = Schedule::new(Label);
21    references.add_systems((
22        get_current_cst_token.before(get_current_triple),
23        get_current_triple,
24        // Drops the (wrong) triple when the cursor is on a prefix declaration, so
25        // the subject-locator below skips it and `goto_prefix` jumps to the
26        // ontology file instead.
27        get_current_prefix.after(get_current_triple),
28        goto_prefix.after(get_current_prefix),
29        system::goto_definition.after(get_current_prefix),
30    ));
31    world.add_schedule(references);
32}
33
34mod system {
35    use std::collections::HashSet;
36
37    use bevy_ecs::prelude::*;
38    use goto_definition::GotoDefinitionRequest;
39    use sophia_api::{quad::Quad as _, term::TermKind};
40
41    use crate::{prelude::*, util::token_to_location};
42
43    pub fn goto_definition(
44        mut query: Query<(
45            &TripleComponent,
46            &Triples,
47            &Label,
48            &RopeC,
49            &PositionComponent,
50            &mut GotoDefinitionRequest,
51        )>,
52        project: Query<(&Triples, &RopeC, &Label)>,
53    ) {
54        for (triple, triples, label, rope, pos, mut req) in &mut query {
55            let target = triple.kind();
56            let Some(term) = triple.term() else {
57                continue;
58            };
59            let _span = tracing::debug_span!("goto_definition", term = %term.value).entered();
60            let Some(idx) = position_to_offset(pos.0, rope) else {
61                continue;
62            };
63            if !term.span.contains(&idx) {
64                continue;
65            }
66
67            tracing::debug!("kind {:?}", target);
68            if target == TermKind::Iri {
69                for (triples, rope, label) in &project {
70                    tracing::debug!("Looking into buffer {}", label.as_str());
71                    let subs: HashSet<_> = triples
72                        .iter()
73                        .map(|x| x.s())
74                        .filter(|x| &x.value == &term.value)
75                        .collect();
76
77                    req.0.extend(
78                        subs.into_iter()
79                            .flat_map(|t| token_to_location(&t.span, label, &rope)),
80                    );
81                }
82            } else if target == TermKind::BlankNode {
83                let subs: HashSet<_> = triples
84                    .iter()
85                    .map(|x| x.s())
86                    .filter(|x| &x.value == &term.value)
87                    .collect();
88                req.0.extend(
89                    subs.into_iter()
90                        .flat_map(|t| token_to_location(&t.span, label, &rope)),
91                );
92            }
93        }
94    }
95}