Skip to main content

swls_core/feature/
inlay.rs

1use std::{borrow::Cow, collections::HashSet};
2
3use bevy_ecs::{
4    component::Component,
5    schedule::ScheduleLabel,
6    system::{Query, Res},
7    world::World,
8};
9use derive_more::{AsMut, AsRef, Deref, DerefMut};
10use sophia_api::{ns::rdf, prelude::Dataset};
11
12use crate::prelude::{DynLang, Prefixes, RopeC, Triples, TypeHierarchy, Types};
13
14/// [`Component`] indicating that the current document is currently handling a Inlay request.
15#[derive(Component, AsRef, Deref, AsMut, DerefMut, Debug, Default)]
16pub struct InlayRequest(pub Vec<crate::lsp_types::InlayHint>);
17
18/// [`ScheduleLabel`] related to the Inlay schedule
19#[derive(ScheduleLabel, Clone, Eq, PartialEq, Debug, Hash)]
20pub struct Label;
21pub fn setup_schedule(world: &mut World) {
22    let mut inlay = bevy_ecs::schedule::Schedule::new(Label);
23    inlay.add_systems(inlay_types);
24    world.add_schedule(inlay);
25}
26
27#[tracing::instrument(skip(query, hierarchy))]
28fn inlay_types(
29    query: Query<(
30        &Triples,
31        &Types,
32        &RopeC,
33        &Prefixes,
34        &DynLang,
35        &mut InlayRequest,
36    )>,
37    hierarchy: Res<TypeHierarchy>,
38) {
39    for (triples, types, rope, prefixes, lang, mut request) in query {
40        let subjects: HashSet<_> = triples.subjects().flatten().collect();
41
42        let t = &mut request.0;
43
44        for s in subjects {
45            if let Some(types) = types.get(s.as_str()) {
46                let defined: HashSet<_> = triples.objects([s], [rdf::type_]).collect();
47                let defined_strings: HashSet<String> =
48                    defined.iter().map(|x| x.value.to_string()).collect();
49
50                let types: Vec<_> = types
51                    .iter()
52                    .map(|e| hierarchy.type_name(*e))
53                    .filter(|t| !defined_strings.contains(t.as_ref()))
54                    .map(|t| prefixes.shorten(t.as_ref()).map(Cow::Owned).unwrap_or(t))
55                    .collect();
56
57                if types.is_empty() {
58                    continue;
59                }
60
61                if let Some(hint) = lang.inlay_types_hint(
62                    &s.span,
63                    rope,
64                    defined.iter().max_by_key(|x| x.span.end).map(|x| &x.span),
65                    types,
66                ) {
67                    t.push(hint);
68                }
69            }
70        }
71    }
72}