swls_core/systems/properties/
systems.rs1use 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}