1mod analysis;
30mod capabilities;
31mod common;
32pub(crate) mod configuration;
33mod lsp;
34mod sparql_operations;
35mod state;
36mod tools;
37
38pub(crate) mod message_handler;
39
40use capabilities::create_capabilities;
41use configuration::Settings;
42use futures::lock::Mutex;
43use log::{error, info};
44use lsp::{
45 ServerInfo,
46 errors::{ErrorCode, LSPError},
47 rpc::{RecoverId, ResponseMessage},
48};
49use message_handler::dispatch;
50use serde::Serialize;
51use state::ServerState;
52use std::{any::type_name, collections::HashMap, fmt::Debug, rc::Rc};
53use tools::Tools;
54use wasm_bindgen::prelude::wasm_bindgen;
55
56use crate::server::{configuration::CompletionTemplate, lsp::LspMessage};
57
58#[wasm_bindgen]
59pub struct Server {
60 pub(crate) state: ServerState,
61 pub(crate) settings: Settings,
62 pub(crate) capabilities: lsp::capabilities::ServerCapabilities,
63 pub(crate) client_capabilities: Option<lsp::capabilities::ClientCapabilities>,
64 pub(crate) server_info: ServerInfo,
65 tools: Tools,
66 send_message_closure: Box<dyn Fn(String)>,
67}
68
69impl Server {
70 pub fn new(write_function: impl Fn(String) + 'static) -> Server {
71 let version = env!("CARGO_PKG_VERSION");
72 info!("Started Language Server: Qlue-ls - version: {}", version);
73 Self {
74 state: ServerState::new(),
75 settings: Settings::new(),
76 capabilities: create_capabilities(),
77 client_capabilities: None,
78 server_info: ServerInfo {
79 name: "Qlue-ls".to_string(),
80 version: Some(version.to_string()),
81 },
82 tools: Tools::init(),
83 send_message_closure: Box::new(write_function),
84 }
85 }
86
87 pub(crate) fn bump_request_id(&mut self) -> u32 {
88 self.state.bump_request_id()
89 }
90
91 pub fn get_version(&self) -> String {
92 self.server_info
93 .version
94 .clone()
95 .unwrap_or("not-specified".to_string())
96 }
97
98 fn send_message<T>(&self, message: T) -> Result<(), LSPError>
99 where
100 T: Serialize + LspMessage + Debug,
101 {
102 let message_string = serde_json::to_string(&message).map_err(|error| {
103 LSPError::new(
104 ErrorCode::ParseError,
105 &format!(
106 "Could not deserialize RPC-message \"{}\"\n\n{}",
107 type_name::<T>(),
108 error
109 ),
110 )
111 })?;
112 (self.send_message_closure)(message_string);
113 Ok(())
114 }
115
116 pub(crate) fn shorten_uri(
134 &self,
135 uri: &str,
136 backend_name: Option<&str>,
137 ) -> Option<(String, String, String)> {
138 let converter = backend_name
139 .and_then(|name| self.state.get_converter(name))
140 .or(self.state.get_default_converter())?;
141 let record = converter.find_by_uri(uri).ok()?;
142 let curie = converter.compress(uri).ok()?;
143 Some((record.prefix.clone(), record.uri_prefix.clone(), curie))
144 }
145
146 pub(crate) fn load_templates(
147 &mut self,
148 backend_name: &str,
149 templates: HashMap<CompletionTemplate, String>,
150 ) -> Result<(), LSPError> {
151 for (key, value) in templates {
152 self.tools
153 .tera
154 .add_raw_template(&format!("{}-{}", &backend_name, &key), &value)
155 .map_err(|err| {
156 log::error!("{}", err);
157 LSPError::new(
158 ErrorCode::InvalidParams,
159 &format!(
160 "Could not load template: {} of backend {}",
161 &key, &backend_name
162 ),
163 )
164 })?;
165 }
166 Ok(())
167 }
168}
169
170async fn handle_error(server_rc: Rc<Mutex<Server>>, message: &str, error: LSPError) {
171 log::error!(
172 "Error occurred while handling message:\n\"{}\"\n\n{:?}\n{}",
173 message,
174 error.code,
175 error.message
176 );
177 if let Ok(id) = serde_json::from_str::<RecoverId>(message).map(|msg| msg.id)
178 && let Err(error) = server_rc
179 .lock()
180 .await
181 .send_message(ResponseMessage::error(&id, error))
182 {
183 error!(
184 "CRITICAL: could not serialize error message (this very bad):\n{:?}",
185 error
186 )
187 }
188}
189
190pub async fn handle_message(server_rc: Rc<Mutex<Server>>, message: String) {
191 if let Err(err) = dispatch(server_rc.clone(), &message).await {
192 handle_error(server_rc.clone(), &message, err).await;
193 }
194}