Skip to main content

swls_core/systems/properties/
systems.rs

1use std::{borrow::Cow, collections::HashSet};
2
3use bevy_ecs::prelude::*;
4use completion::{CompletionRequest, SimpleCompletion};
5use hover::HoverRequest;
6use sophia_api::term::{Term as _, TermKind};
7use tracing::{instrument, trace};
8
9use crate::{
10    lsp_types::{CompletionItemKind, TextEdit},
11    prelude::*,
12};
13
14#[instrument(skip(query, resource))]
15pub fn complete_class(
16    mut query: Query<(
17        &TokenComponent,
18        &TripleComponent,
19        &Prefixes,
20        &Types,
21        &mut CompletionRequest,
22    )>,
23    hierarchy: Res<TypeHierarchy>,
24    resource: Res<Ontologies>,
25) {
26    for (token, triple, prefixes, types, mut request) in &mut query {
27        if triple.triple.predicate.value == "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
28            && triple.target == TripleTarget::Object
29        {
30            let tts = types.get(&triple.triple.subject.value);
31
32            let superclasses: HashSet<_> = tts
33                .iter()
34                .flat_map(|x| x.iter())
35                .flat_map(|t| hierarchy.iter_superclass(*t))
36                .collect();
37
38            for class in resource.classes.values() {
39                let to_beat = prefixes
40                    .shorten(&class.term.value)
41                    .map(|x| Cow::Owned(x))
42                    .unwrap_or(class.term.value.clone());
43
44                if to_beat.starts_with(&token.text) {
45                    let mut completion = SimpleCompletion::new(
46                        CompletionItemKind::CLASS,
47                        format!("{}", to_beat),
48                        TextEdit {
49                            range: token.range.clone(),
50                            new_text: to_beat.to_string(),
51                        },
52                    )
53                    .label_description(class.full_title())
54                    .documentation(class.full_docs(&hierarchy, &prefixes));
55
56                    if superclasses.contains(class.term.as_str()) {
57                        completion.kind = CompletionItemKind::INTERFACE;
58                        request.push(completion.sort_text(format!("0{}", to_beat)));
59                    } else {
60                        request.push(completion.sort_text(format!("1{}", to_beat)));
61                    }
62                }
63            }
64        }
65    }
66}
67
68pub fn hover_class(
69    mut query: Query<(&TripleComponent, &Prefixes, &mut HoverRequest)>,
70    hierarchy: Res<TypeHierarchy>,
71    resource: Res<Ontologies>,
72) {
73    for (triple, prefixes, mut request) in &mut query {
74        let Some(term) = triple.term() else { continue };
75        if term.kind() != TermKind::Iri {
76            continue;
77        }
78        let target = term.as_str();
79        for class in resource.classes.values() {
80            if class.term.value == target {
81                request.0.push(format!(
82                    "## {}\n\n{}",
83                    class.full_title(),
84                    class.full_docs(&hierarchy, &prefixes)
85                ));
86            }
87        }
88    }
89}
90
91#[instrument(skip(query, hierarchy, resource, config))]
92pub fn complete_properties(
93    mut query: Query<(
94        &TokenComponent,
95        &TripleComponent,
96        &Prefixes,
97        &Label,
98        &Types,
99        &mut CompletionRequest,
100        &DynLang,
101    )>,
102    hierarchy: Res<TypeHierarchy>,
103    resource: Res<Ontologies>,
104    config: Res<ServerConfig>,
105) {
106    for (token, triple, prefixes, _this_label, types, mut request, lang) in &mut query {
107        if triple.target == TripleTarget::Predicate {
108            let tts = types.get(&triple.triple.subject.value);
109            let bare_text = lang.unquote(&token.text);
110
111            if let Some(tts) = tts.as_ref() {
112                trace!("Types for {}", triple.triple.subject.value);
113                for t in *tts {
114                    trace!(
115                        "{} {}",
116                        triple.triple.subject.value,
117                        hierarchy.type_name(*t)
118                    );
119                }
120            } else {
121                trace!("No types for {}", triple.triple.subject.value);
122            }
123
124            let subclasses: HashSet<_> = tts
125                .iter()
126                .flat_map(|x| x.iter())
127                .flat_map(|t| hierarchy.iter_subclass(*t))
128                .collect();
129
130            for property in resource.properties.values() {
131                let correct_domain = property
132                    .domains
133                    .iter()
134                    .any(|domain| subclasses.contains(domain.as_str()));
135
136                if !subclasses.is_empty()
137                    && config
138                        .config
139                        .local
140                        .completion
141                        .correct_domain_required(&property.term.value)
142                    && !correct_domain
143                {
144                    continue;
145                }
146
147                let to_beat = prefixes
148                    .shorten(&property.term.value)
149                    .map(|x| Cow::Owned(x))
150                    .unwrap_or(property.term.value.clone());
151
152                if to_beat.starts_with(&bare_text) {
153                    let mut completion = SimpleCompletion::new(
154                        CompletionItemKind::ENUM_MEMBER,
155                        to_beat.to_string(),
156                        TextEdit {
157                            range: token.range.clone(),
158                            new_text: lang.quote(&to_beat),
159                        },
160                    )
161                    .label_description(&property.full_title())
162                    .documentation(&property.full_docs(&prefixes));
163
164                    if correct_domain {
165                        completion.kind = CompletionItemKind::FIELD;
166                        request.push(completion.sort_text(format!("0{}", to_beat)));
167                    } else {
168                        request.push(completion.sort_text(format!("1{}", to_beat)));
169                    }
170                }
171            }
172        }
173    }
174}
175
176#[instrument(skip(query, resource))]
177pub fn hover_property(
178    mut query: Query<(
179        &TripleComponent,
180        &Prefixes,
181        &DocumentLinks,
182        &mut HoverRequest,
183    )>,
184    resource: Res<Ontologies>,
185) {
186    for (triple, prefixes, _links, mut request) in &mut query {
187        let Some(term) = triple.term() else { continue };
188        if term.kind() != TermKind::Iri {
189            continue;
190        }
191        let target = term.as_str();
192        for c in resource
193            .properties
194            .values()
195            .filter(|c| c.term.value == target)
196        {
197            request.0.push(format!(
198                "## {}\n\n{}",
199                c.full_title(),
200                c.full_docs(&prefixes)
201            ));
202        }
203    }
204}