swls_core/feature/
inlay.rs1use std::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::{
13 prelude::{Prefixes, RopeC, Triples, TypeHierarchy, Types},
14 util::offset_to_position,
15};
16
17#[derive(Component, AsRef, Deref, AsMut, DerefMut, Debug, Default)]
19pub struct InlayRequest(pub Vec<crate::lsp_types::InlayHint>);
20
21#[derive(ScheduleLabel, Clone, Eq, PartialEq, Debug, Hash)]
23pub struct Label;
24pub fn setup_schedule(world: &mut World) {
25 let mut inlay = bevy_ecs::schedule::Schedule::new(Label);
26 inlay.add_systems(inlay_types);
27 world.add_schedule(inlay);
28}
29
30#[tracing::instrument(skip(query, hierarchy))]
31fn inlay_types(
32 query: Query<(&Triples, &Types, &RopeC, &Prefixes, &mut InlayRequest)>,
33 hierarchy: Res<TypeHierarchy<'static>>,
34) {
35 for (triples, types, rope, prefixes, mut request) in query {
36 let subjects: HashSet<_> = triples.subjects().flatten().collect();
37
38 let t = &mut request.0;
39
40 for s in subjects {
41 if let Some(types) = types.get(s.as_str()) {
42 let types: Vec<_> = types.iter().map(|e| hierarchy.type_name(*e)).collect();
43 let defined: HashSet<_> = triples.objects([s], [rdf::type_]).collect();
44 let defined_strings: HashSet<String> =
45 defined.iter().map(|x| x.value.to_string()).collect();
46
47 let mut inlay_str = String::new();
48 for t in &types {
49 if defined_strings.contains(t.as_ref()) {
50 continue;
51 }
52 if !inlay_str.is_empty() {
53 inlay_str += ", ";
54 }
55 if let Some(short) = prefixes.shorten(t.as_ref()) {
56 inlay_str += short.as_str();
57 } else {
58 inlay_str += t.as_ref();
59 }
60 }
61
62 if inlay_str.is_empty() {
63 continue;
64 }
65 if let Some(pos) = defined.iter().max_by_key(|x| x.span.end) {
66 if let Some(pos) = offset_to_position(pos.span.end, &rope) {
67 t.push(crate::lsp_types::InlayHint {
68 position: pos,
69 label: crate::lsp_types::InlayHintLabel::String(format!(
70 ", {}",
71 inlay_str
72 )),
73 kind: None,
74 text_edits: None,
75 tooltip: None,
76 padding_left: None,
77 padding_right: None,
78 data: None,
79 });
80 } else {
81 tracing::warn!("Failed to convert pos to position {}", pos.span.end);
82 }
83 } else {
84 let offset = if rope.get_char(s.span.start) == Some('[') {
85 s.span.start + 1
86 } else {
87 s.span.end
88 };
89
90 if let Some(pos) = offset_to_position(offset, &rope) {
91 t.push(crate::lsp_types::InlayHint {
92 position: pos,
93 label: crate::lsp_types::InlayHintLabel::String(format!(
94 " a {};",
95 inlay_str
96 )),
97 kind: None,
98 text_edits: None,
99 tooltip: None,
100 padding_left: None,
101 padding_right: None,
102 data: None,
103 });
104 } else {
105 tracing::warn!("Failed to convert pos to position {}", s.span.end);
106 }
107 }
108 }
109 }
110 }
111}