lsp_core/util/
triple.rs

1use std::{borrow::Cow, hash::Hash, usize};
2
3use bevy_ecs::prelude::*;
4use derive_more::{AsMut, AsRef, Deref, DerefMut};
5use sophia_api::{
6    prelude::{Any, Dataset},
7    quad::Quad,
8    term::{matcher::TermMatcher, BnodeId, GraphName, IriRef, Term, TermKind},
9    MownStr,
10};
11use tracing::{debug, instrument};
12
13use crate::{
14    components::{PositionComponent, RopeC},
15    util::{
16        ns::{owl, rdfs},
17        position_to_offset,
18    },
19};
20
21/// [`Component`] used to indicate the term type of currently targeted
22/// [`Token`](`crate::prelude::Token`) in the Triple.
23#[derive(Debug, PartialEq)]
24pub enum TripleTarget {
25    Subject,
26    Predicate,
27    Object,
28    Graph,
29}
30
31/// [`Component`] used to indicate the currently targeted [`MyQuad<'static>`] during a request.
32#[derive(Component, Debug)]
33pub struct TripleComponent {
34    pub triple: MyQuad<'static>,
35    pub target: TripleTarget,
36}
37impl TripleComponent {
38    pub fn kind(&self) -> TermKind {
39        let target = match self.target {
40            TripleTarget::Subject => self.triple.s().kind(),
41            TripleTarget::Predicate => self.triple.p().kind(),
42            TripleTarget::Object => self.triple.o().kind(),
43            TripleTarget::Graph => self
44                .triple
45                .g()
46                .map(|x| x.kind())
47                .unwrap_or(sophia_api::term::TermKind::Triple),
48        };
49        target
50    }
51
52    pub fn term(&self) -> Option<&MyTerm<'static>> {
53        let target = match self.target {
54            TripleTarget::Subject => self.triple.s(),
55            TripleTarget::Predicate => self.triple.p(),
56            TripleTarget::Object => self.triple.o(),
57            TripleTarget::Graph => return None,
58        };
59        Some(target)
60    }
61}
62
63/// [`Component`] containing all derived Triples from the documents.
64///
65/// These triples are used to derive properties and classes and other things.
66#[derive(Component, AsRef, Deref, AsMut, DerefMut, Debug)]
67pub struct Triples(pub Vec<MyQuad<'static>>);
68
69impl Triples {
70    pub fn object<'s, S, P>(&'s self, subj: S, pred: P) -> Option<&'s MyTerm<'s>>
71    where
72        S: TermMatcher + 's,
73        P: TermMatcher + 's,
74    {
75        self.0
76            .quads_matching(
77                subj,
78                pred,
79                sophia_api::prelude::Any,
80                sophia_api::prelude::Any,
81            )
82            .flatten()
83            .next()
84            .map(|x| x.o())
85    }
86
87    pub fn objects<'s, S, P>(&'s self, subj: S, pred: P) -> impl Iterator<Item = &'s MyTerm<'s>>
88    where
89        S: TermMatcher + 's,
90        P: TermMatcher + 's,
91    {
92        self.0
93            .quads_matching(
94                subj,
95                pred,
96                sophia_api::prelude::Any,
97                sophia_api::prelude::Any,
98            )
99            .flatten()
100            .map(|x| x.o())
101    }
102}
103
104#[instrument(skip(query, commands))]
105pub fn get_current_triple(
106    query: Query<(Entity, &PositionComponent, &Triples, &RopeC)>,
107    mut commands: Commands,
108) {
109    for (e, position, triples, rope) in &query {
110        commands.entity(e).remove::<TripleComponent>();
111
112        let Some(offset) = position_to_offset(position.0, &rope.0) else {
113            debug!("Couldn't transform to an offset");
114            continue;
115        };
116
117        if let Some(t) = triples
118            .0
119            .iter()
120            .filter(|triple| triple.span.contains(&offset))
121            .min_by_key(|x| x.span.end - x.span.start)
122        {
123            let target = [
124                (TripleTarget::Subject, &t.subject.span),
125                (TripleTarget::Predicate, &t.predicate.span),
126                (TripleTarget::Object, &t.object.span),
127            ]
128            .into_iter()
129            .filter(|x| x.1.contains(&offset))
130            .min_by_key(|x| x.1.end - x.1.start)
131            .map(|x| x.0)
132            .unwrap_or(TripleTarget::Subject);
133
134            debug!("Current triple {} {:?}", t, target);
135            commands.entity(e).insert(TripleComponent {
136                triple: t.clone(),
137                target,
138            });
139        } else {
140            debug!("No current triple found");
141        }
142    }
143}
144
145#[derive(Debug, Clone)]
146pub struct MyQuad<'a> {
147    pub subject: MyTerm<'a>,
148    pub predicate: MyTerm<'a>,
149    pub object: MyTerm<'a>,
150    pub span: std::ops::Range<usize>,
151}
152impl<'a> std::fmt::Display for MyQuad<'a> {
153    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
154        write!(
155            f,
156            "{} {} {}. # {:?}",
157            self.subject, self.predicate, self.object, self.span
158        )
159    }
160}
161
162impl<'a> MyQuad<'a> {
163    pub fn to_owned(&self) -> MyQuad<'static> {
164        MyQuad {
165            subject: self.subject.to_owned(),
166            predicate: self.predicate.to_owned(),
167            object: self.object.to_owned(),
168            span: self.span.clone(),
169        }
170    }
171}
172
173impl<'a> Quad for MyQuad<'a> {
174    type Term = MyTerm<'a>;
175
176    fn s(&self) -> sophia_api::quad::QBorrowTerm<Self> {
177        self.subject.borrow_term()
178    }
179
180    fn p(&self) -> sophia_api::quad::QBorrowTerm<Self> {
181        self.predicate.borrow_term()
182    }
183
184    fn o(&self) -> sophia_api::quad::QBorrowTerm<Self> {
185        self.object.borrow_term()
186    }
187
188    fn g(&self) -> GraphName<sophia_api::quad::QBorrowTerm<Self>> {
189        None
190    }
191
192    fn to_spog(self) -> sophia_api::quad::Spog<Self::Term> {
193        ([self.subject, self.predicate, self.object], None)
194    }
195}
196// pub type MyQuad<'a> = ([MyTerm<'a>; 3], GraphName<MyTerm<'a>>);
197
198#[derive(Debug, Clone, Eq)]
199pub struct MyTerm<'a> {
200    pub value: Cow<'a, str>,
201    ty: Option<TermKind>,
202    pub span: std::ops::Range<usize>,
203}
204
205impl Hash for MyTerm<'_> {
206    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
207        // Ignore span
208        self.value.hash(state);
209        self.ty.hash(state);
210    }
211}
212
213impl PartialEq for MyTerm<'_> {
214    fn eq(&self, other: &Self) -> bool {
215        // Ignore span
216        other.value == self.value && other.ty == self.ty
217    }
218}
219
220impl<'a> std::fmt::Display for MyTerm<'a> {
221    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222        match self.kind() {
223            TermKind::Iri => write!(f, "<{}>", self.value),
224            TermKind::Literal => write!(f, "\"{}\"", self.value),
225            TermKind::BlankNode => write!(f, "_:{}", self.value),
226            TermKind::Triple => write!(f, "<{}>", self.value),
227            TermKind::Variable => write!(f, "?{}", self.value),
228        }
229    }
230}
231
232impl<'a> MyTerm<'a> {
233    pub fn to_owned(&self) -> MyTerm<'static> {
234        let value = Cow::Owned(self.value.to_string());
235        MyTerm {
236            value,
237            ty: self.ty.clone(),
238            span: self.span.clone(),
239        }
240    }
241    pub fn variable<T: Into<Cow<'a, str>>>(value: T, span: std::ops::Range<usize>) -> Self {
242        Self {
243            value: value.into(),
244            ty: TermKind::Variable.into(),
245            span,
246        }
247    }
248    pub fn named_node<T: Into<Cow<'a, str>>>(value: T, span: std::ops::Range<usize>) -> Self {
249        Self {
250            value: value.into(),
251            ty: TermKind::Iri.into(),
252            span,
253        }
254    }
255    pub fn blank_node<T: Into<Cow<'a, str>>>(value: T, span: std::ops::Range<usize>) -> Self {
256        Self {
257            value: value.into(),
258            ty: TermKind::BlankNode.into(),
259            span,
260        }
261    }
262    pub fn literal<T: Into<Cow<'a, str>>>(value: T, span: std::ops::Range<usize>) -> Self {
263        Self {
264            value: value.into(),
265            ty: TermKind::Literal.into(),
266            span,
267        }
268    }
269
270    pub fn invalid(span: std::ops::Range<usize>) -> Self {
271        Self {
272            value: Cow::default(),
273            ty: None,
274            span,
275        }
276    }
277
278    pub fn as_str(&'a self) -> &'a str {
279        &self.value
280    }
281}
282
283impl<'a> Term for MyTerm<'a> {
284    type BorrowTerm<'x>
285        = &'x Self
286    where
287        Self: 'x;
288
289    fn kind(&self) -> sophia_api::term::TermKind {
290        self.ty.unwrap_or(TermKind::Triple)
291    }
292
293    fn borrow_term(&self) -> Self::BorrowTerm<'_> {
294        self
295    }
296
297    fn iri(&self) -> Option<sophia_api::term::IriRef<sophia_api::MownStr>> {
298        self.is_iri()
299            .then(|| IriRef::new_unchecked(MownStr::from_str(&self.value)))
300    }
301
302    fn bnode_id(&self) -> Option<sophia_api::term::BnodeId<sophia_api::MownStr>> {
303        self.is_blank_node()
304            .then(|| BnodeId::new_unchecked(MownStr::from_str(&self.value)))
305    }
306
307    fn lexical_form(&self) -> Option<sophia_api::MownStr> {
308        self.is_literal().then(|| MownStr::from_str(&self.value))
309    }
310
311    fn datatype(&self) -> Option<sophia_api::term::IriRef<sophia_api::MownStr>> {
312        None
313    }
314
315    fn language_tag(&self) -> Option<sophia_api::term::LanguageTag<sophia_api::MownStr>> {
316        None
317    }
318
319    fn variable(&self) -> Option<sophia_api::term::VarName<sophia_api::MownStr>> {
320        panic!("MyTerm does not supported variables")
321    }
322
323    fn triple(&self) -> Option<[Self::BorrowTerm<'_>; 3]> {
324        panic!("MyTerm does not supported triples")
325    }
326
327    fn to_triple(self) -> Option<[Self; 3]>
328    where
329        Self: Sized,
330    {
331        panic!("MyTerm does not supported triples")
332    }
333}
334
335#[derive(Default, Debug)]
336pub struct Triples2<'a> {
337    pub base_url: String,
338    pub triples: Vec<MyQuad<'a>>,
339    pub base: Option<MyTerm<'a>>,
340}
341
342impl<'a> Triples2<'a> {
343    pub fn to_owned(&self) -> Triples2<'static> {
344        let triples = self.triples.iter().map(|q| q.to_owned()).collect();
345        let base: Option<MyTerm<'static>> = self.base.as_ref().map(|x| x.to_owned());
346
347        Triples2 {
348            base,
349            triples,
350            base_url: self.base_url.clone(),
351        }
352    }
353
354    pub fn imports(&self, cb: impl FnMut(IriRef<MownStr<'_>>) -> ()) {
355        if let Some(ref base) = self.base {
356            self.triples
357                .quads_matching([base], [owl::imports], Any, Any)
358                .flatten()
359                .flat_map(|s| s.o().iri())
360                .for_each(cb);
361        }
362    }
363
364    pub fn sub_class_of(&self, mut cb: impl FnMut(IriRef<MownStr<'_>>, IriRef<MownStr<'_>>) -> ()) {
365        self.triples
366            .quads_matching(Any, [rdfs::subClassOf], Any, Any)
367            .flatten()
368            .flat_map(|s| match (s.s().iri(), s.o().iri()) {
369                (Some(s), Some(o)) => Some((s, o)),
370                _ => None,
371            })
372            .for_each(|(x, y)| cb(x, y));
373    }
374}
375
376impl<'a> Deref for Triples2<'a> {
377    type Target = Vec<MyQuad<'a>>;
378
379    fn deref(&self) -> &Self::Target {
380        &self.triples
381    }
382}