lsp_core/
components.rs

1use std::{
2    borrow::Cow,
3    collections::{HashMap, HashSet},
4    fmt::Debug,
5};
6
7use bevy_ecs::{prelude::*, world::CommandQueue};
8use derive_more::{AsMut, AsRef, Deref, DerefMut};
9use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
10use lsp_types::Position;
11
12use crate::{
13    lang::{Lang, LangHelper},
14    prelude::*,
15    systems::TypeId,
16};
17
18#[derive(Component, Default, Debug, Clone, Eq, Hash, PartialEq, PartialOrd, Ord)]
19pub struct CurrentType(pub Vec<TypeId>);
20
21/// [`Component`] that contains the parsed semantic element (i.e. Turtle, JSONLD).
22#[derive(Component, AsRef, Deref, AsMut, DerefMut, Debug)]
23pub struct Element<L: Lang>(pub Spanned<L::Element>);
24
25/// Simple wrapper structure that derives [`Component`]
26#[derive(Component, AsRef, Deref, AsMut, DerefMut, Debug)]
27pub struct Wrapped<E>(pub E);
28
29/// Simple wrapper for errors that derives [`Component`]
30#[derive(Component, AsRef, Deref, AsMut, DerefMut, Debug)]
31pub struct Errors<E>(pub Vec<E>);
32
33/// [`Component`] containing the current source code as [`String`]
34#[derive(Component, AsRef, Deref, AsMut, DerefMut, Debug)]
35pub struct Source(pub String);
36
37/// [`Component`] containing the current source code as [`ropey::Rope`]
38#[derive(Component, AsRef, Deref, AsMut, DerefMut, Debug)]
39pub struct RopeC(pub ropey::Rope);
40
41/// [`Component`] that allows for language specific implementation for certain things, reducing
42/// code duplication.
43#[derive(Component, Debug, AsRef, Deref)]
44pub struct DynLang(pub Box<dyn LangHelper + 'static + Send + Sync>);
45
46/// [`Component`] indicating whether or not the document is actually open.
47///
48/// Documents that are not [`Open`] don't publish diagnostics for example
49#[derive(Component, Debug)]
50pub struct Open;
51
52/// [`Component`] indicating whether or not the document is dirty, a dirty document parsed with
53/// errors.
54///
55/// A document is often Dirty, computational intens calculation can be done on documents that are
56/// not dirty, like [`derive_classes`](crate::prelude::systems::derive_classes) and [`derive_properties`](crate::prelude::systems::derive_properties).
57#[derive(Component, Debug)]
58pub struct Dirty;
59
60/// [`Component`] containing the [`lsp_types::Url`] of the current document.
61#[derive(Component, AsRef, Deref, AsMut, DerefMut, Debug)]
62pub struct Label(pub lsp_types::Url);
63
64/// [`Resource`] used to receive command queues. These command queues are handled with [`handle_tasks`](crate::prelude::systems::handle_tasks).
65#[derive(Resource, AsRef, Deref, AsMut, DerefMut, Debug)]
66pub struct CommandReceiver(pub UnboundedReceiver<CommandQueue>);
67
68/// [`Resource`] used to send command queues, allowing for async operations.
69#[derive(Resource, AsRef, Deref, AsMut, DerefMut, Debug, Clone)]
70pub struct CommandSender(pub UnboundedSender<CommandQueue>);
71
72/// [`Component`] used to remember the linked documents.
73///
74/// This is used, for example, to only suggest properties defined in a linked document.
75/// Or only validate with shapes found in linked documents.
76#[derive(Component, AsRef, Deref, AsMut, DerefMut, Debug, Clone)]
77pub struct DocumentLinks(pub Vec<(lsp_types::Url, &'static str)>);
78
79/// [`Component`] used to wrap an incoming [`lsp_types::Position`].
80///
81/// This component is translated into [`TokenComponent`] and [`TripleComponent`]
82/// with [`get_current_token`]
83/// and [get_current_triple] respectively.
84#[derive(Component, AsRef, Deref, AsMut, DerefMut, Debug)]
85pub struct PositionComponent(pub Position);
86
87/// [`Component`] containing the typical keywords for the current language.
88#[derive(Component, AsRef, Deref, AsMut, DerefMut, Debug)]
89pub struct KeyWords(pub Vec<&'static str>);
90
91/// maps terms to all known correct types.
92#[derive(Component, AsRef, Deref, AsMut, DerefMut, Debug)]
93pub struct Types(pub HashMap<Cow<'static, str>, Vec<TypeId>>);
94
95/// [`Resource`] used to set and get all super and subtypes starting from a [`TypeId`]
96///
97/// Example
98/// ```
99/// use lsp_core::components::TypeHierarchy;
100///
101/// let mut hierarchy = TypeHierarchy::default();
102/// let image_id = hierarchy.get_id("http://xmlns.com/foaf/0.1/Image");
103/// let document_id = hierarchy.get_id("http://xmlns.com/foaf/0.1/Document");
104/// hierarchy.set_subclass_of(image_id, document_id);
105///
106/// for ty in hierarchy.iter_superclass(document_id) {
107///     // first "http://xmlns.com/foaf/0.1/Document"
108///     // then "http://xmlns.com/foaf/0.1/Image"
109///     println!("Type {}", ty);
110/// }
111/// ```
112#[derive(Resource, Debug, Default)]
113pub struct TypeHierarchy<'a> {
114    numbers: HashMap<Cow<'a, str>, TypeId>,
115    nodes: Vec<Cow<'a, str>>,
116    subclass: Vec<HashSet<TypeId>>,
117    superclass: Vec<HashSet<TypeId>>,
118}
119
120impl<'a> TypeHierarchy<'a> {
121    pub fn get_id(&mut self, class: &str) -> TypeId {
122        if let Some(id) = self.numbers.get(class) {
123            *id
124        } else {
125            let new_id = TypeId(self.nodes.len());
126            let class_cow: Cow<'a, str> = Cow::Owned(class.to_string());
127            self.nodes.push(class_cow.clone());
128            self.numbers.insert(class_cow, new_id);
129            self.subclass.push(HashSet::new());
130            self.superclass.push(HashSet::new());
131            new_id
132        }
133    }
134
135    pub fn get_id_ref(&self, class: &str) -> Option<TypeId> {
136        self.numbers.get(class).copied()
137    }
138
139    pub fn set_subclass_of(&mut self, class: TypeId, to: TypeId) {
140        self.subclass[class.0].insert(to);
141        self.superclass[to.0].insert(class);
142    }
143
144    pub fn iter_subclass<'b>(&'b self, id: TypeId) -> impl Iterator<Item = Cow<'a, str>> + 'b {
145        let mut stack = std::collections::VecDeque::new();
146        stack.push_back(id);
147        let mut done = HashSet::new();
148        std::iter::from_fn(move || {
149            while let Some(id) = stack.pop_front() {
150                if done.contains(&id) {
151                    continue;
152                }
153                done.insert(id);
154
155                self.subclass[id.0].iter().for_each(|i| stack.push_back(*i));
156                return Some(self.nodes[id.0].clone());
157            }
158
159            None
160        })
161    }
162
163    pub fn type_name(&self, id: TypeId) -> Cow<'a, str> {
164        self.nodes[id.0].clone()
165    }
166
167    pub fn iter_superclass<'b>(&'b self, id: TypeId) -> impl Iterator<Item = Cow<'a, str>> + 'b {
168        let mut stack = std::collections::VecDeque::new();
169        stack.push_back(id);
170        let mut done = HashSet::new();
171        std::iter::from_fn(move || {
172            while let Some(id) = stack.pop_front() {
173                if done.contains(&id) {
174                    continue;
175                }
176                done.insert(id);
177
178                self.superclass[id.0]
179                    .iter()
180                    .for_each(|i| stack.push_back(*i));
181                return Some(self.nodes[id.0].clone());
182            }
183
184            None
185        })
186    }
187}