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