lsp_core/lib.rs
1#![doc(
2 html_logo_url = "https://ajuvercr.github.io/semantic-web-lsp/assets/icons/favicon.png",
3 html_favicon_url = "https://ajuvercr.github.io/semantic-web-lsp/assets/icons/favicon.ico"
4)]
5//! Core and common implementation for the semantic web language server.
6//!
7//! Proivdes the backbone for the [semantic web lsp binary](../lsp_bin/index.html) and [semantic web
8//! lsp wasm](../lsp_web/index.html).
9//!
10//! With the language server protocol, each different request is handled by an ECS schedule,
11//! combining different systems together.
12//! A system can generate new data and attach it to an entity, a document, or use this data to
13//! respond to requests.
14//!
15//! Language specific implementations that handle things like tokenizing and parsing are
16//! implemented in separate crates. The binary currently supports [Turtle](../lang_turtle/index.html), [JSON-LD](../lang_jsonld/index.html) and [SPARQL](../lang_sparql/index.html).
17//! The goal is that each language at least generates [`Tokens`], [`Triples`] and
18//! [`Prefixes`].
19//! These components are then used to derive properties for autcompletion but also derive
20//! [`TokenComponent`] and [`TripleComponent`] enabling completion.
21//!
22//! The different schedules can be found at [`prelude::feature`].
23//!
24//! ## Example add completion for all subjects that start with `a`
25//! ```
26//! use bevy_ecs::prelude::*;
27//! use lsp_core::prelude::*;
28//! # use sophia_api::dataset::Dataset;
29//! # use sophia_api::prelude::Quad;
30//!
31//! // Define the extra data struct
32//! #[derive(Component)]
33//! struct MyCompletions {
34//! subjects: Vec<String>,
35//! }
36//!
37//! // Define the generating system
38//! // Don't forget to add it to the ecs later
39//! fn generate_my_completion(
40//! // Only derive the completions when the document is parsed fully, aka is not Dirty
41//! query: Query<(Entity, &Triples), (Changed<Triples>, Without<Dirty>)>,
42//! mut commands: Commands,
43//! ) {
44//! for (e, triples) in &query {
45//! let mut subjects = Vec::new();
46//! for q in triples.quads().flatten() {
47//! if q.s().as_str().starts_with('a') {
48//! subjects.push(q.s().as_str().to_string());
49//! }
50//! }
51//! commands.entity(e).insert(MyCompletions { subjects });
52//! }
53//! }
54//!
55//! // Define a system that adds these completions to the completion request
56//! fn complete_my_completion(
57//! mut query: Query<(
58//! &TokenComponent, &TripleComponent, &MyCompletions, &mut CompletionRequest
59//! )>,
60//! ) {
61//! for (token, this_triple, completions, mut request) in &mut query {
62//! if this_triple.target == TripleTarget::Subject {
63//! for my_completion in &completions.subjects {
64//! request.push(
65//! SimpleCompletion::new(
66//! lsp_types::CompletionItemKind::FIELD,
67//! my_completion.clone(),
68//! lsp_types::TextEdit {
69//! range: token.range.clone(),
70//! new_text: my_completion.clone(),
71//! }
72//! )
73//! )
74//! }
75//! }
76//! }
77//! }
78//! ```
79//! Note that [`Prefixes`] can help expand and shorten iri's in a document.
80//!
81//!
82
83use bevy_ecs::{prelude::*, schedule::ScheduleLabel};
84use prelude::SemanticTokensDict;
85use systems::{init_onology_extractor, OntologyExtractor};
86
87use crate::prelude::*;
88
89/// Main language tower_lsp server implementation.
90///
91/// [`Backend`](struct@backend::Backend) implements [`LanguageServer`](tower_lsp::LanguageServer).
92/// Each incoming request a schedule is ran on the main [`World`].
93pub mod backend;
94
95/// Handle platform specific implementations for fetching and spawning tasks.
96pub mod client;
97/// Common utils
98///
99/// Includes range transformations between [`std::ops::Range`] and [`lsp_types::Range`].
100/// And commonly used [`Spanned`].
101pub mod util;
102
103/// Defines all common [`Component`]s and [`Resource`]s
104///
105/// In this [`World`], [Entity]s are documents and [`Components`](`Component`) are derived from these documents.
106/// Different [`System`]s derive new [`Components`](`Component`) from existing [`Components`](`Component`), that are added to
107/// the [`Entity`].
108/// For example, if [`Triples`] are defined, [systems::derive_classes] will
109/// derive [`DefinedClass`](struct@systems::DefinedClass) from them and add them to the [`Entity`].
110pub mod components;
111/// Hosts all common features of the semantic language server.
112pub mod feature;
113/// Defines common language traits
114pub mod lang;
115pub mod prelude;
116pub mod systems;
117
118/// Initializes a [`World`], including [`Resources`](`Resource`) and [`Schedules`].
119/// All systems defined in [`crate`] are added to the [`World`].
120pub fn setup_schedule_labels<C: Client + Resource>(world: &mut World) {
121 world.init_resource::<SemanticTokensDict>();
122 world.init_resource::<TypeHierarchy<'static>>();
123 world.insert_resource(OntologyExtractor::new());
124
125 parse::setup_schedule::<C>(world);
126 hover::setup_schedule(world);
127 completion::setup_schedule(world);
128 rename::setup_schedules(world);
129 diagnostics::setup_schedule(world);
130 save::setup_schedule(world);
131 format::setup_schedule(world);
132 references::setup_schedule(world);
133 inlay::setup_schedule(world);
134 goto_definition::setup_schedule(world);
135 goto_type::setup_schedule(world);
136
137 semantic::setup_world(world);
138
139 world.add_schedule(Schedule::new(Tasks));
140
141 let mut schedule = Schedule::new(Startup);
142 schedule.add_systems(init_onology_extractor);
143 world.add_schedule(schedule);
144}
145
146/// Event triggers when a document is opened
147///
148/// Example
149/// ```rust
150/// # use lsp_core::components::DynLang;
151/// # use lsp_core::CreateEvent;
152/// # use lsp_core::lang::LangHelper;
153/// # use bevy_ecs::prelude::{Commands, Trigger, World, Component};
154///
155/// #[derive(Component)]
156/// pub struct TurtleLang;
157///
158/// #[derive(Debug)]
159/// pub struct TurtleHelper;
160/// impl LangHelper for TurtleHelper {
161/// fn keyword(&self) -> &[&'static str] {
162/// &[
163/// "@prefix",
164/// "@base",
165/// "a",
166/// ]
167/// }
168/// }
169///
170/// let mut world = World::new();
171/// // This example tells the ECS system that the document is Turtle,
172/// // adding Turtle specific components
173/// world.observe(|trigger: Trigger<CreateEvent>, mut commands: Commands| {
174/// match &trigger.event().language_id {
175/// Some(x) if x == "turtle" => {
176/// commands
177/// .entity(trigger.entity())
178/// .insert((TurtleLang, DynLang(Box::new(TurtleHelper))));
179/// return;
180/// }
181/// _ => {}
182/// }
183/// if trigger.event().url.as_str().ends_with(".ttl") {
184/// commands
185/// .entity(trigger.entity())
186/// .insert((TurtleLang, DynLang(Box::new(TurtleHelper))));
187/// return;
188/// }
189/// });
190/// ```
191///
192#[derive(Event)]
193pub struct CreateEvent {
194 pub url: lsp_types::Url,
195 pub language_id: Option<String>,
196}
197
198/// [`ScheduleLabel`] related to the Tasks schedule
199/// This schedule is used for async tasks, things that should be done at some point.
200///
201/// For example [`systems::handle_tasks`] spawns command queues sent with
202/// [`CommandSender`]
203#[derive(ScheduleLabel, Clone, Eq, PartialEq, Debug, Hash)]
204pub struct Tasks;
205
206#[derive(ScheduleLabel, Clone, Eq, PartialEq, Debug, Hash)]
207pub struct Startup;