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