mod anaysis;
mod configuration;
mod lsp;
mod state;
mod message_handler;
use configuration::Settings;
use curies::{Converter, Record};
use log::{debug, info};
use lsp::{
capabilities, rpc::BaseMessage, PublishDiagnosticsNotification, PublishDiagnosticsPrarams,
ServerInfo,
};
use message_handler::{collect_diagnostics, dispatch};
#[allow(unused_imports)]
pub use message_handler::format_raw;
use state::ServerState;
pub struct Server {
pub(crate) state: ServerState,
pub(crate) settings: Settings,
pub(crate) capabilities: capabilities::ServerCapabilities,
pub(crate) server_info: ServerInfo,
uri_converter: Converter,
send_message_clusure: Box<dyn Fn(String)>,
}
impl Server {
pub fn new(write_function: impl Fn(String) -> () + 'static) -> Server {
let config = config::Config::builder()
.add_source(config::File::with_name("fichu").required(false))
.build()
.unwrap();
let settings: Settings = config.try_deserialize().expect("could not load Settings");
let capabilities = capabilities::ServerCapabilities {
text_document_sync: capabilities::TextDocumentSyncKind::Incremental,
hover_provider: true,
code_action_provider: true,
diagnostic_provider: capabilities::DiagnosticOptions {
identifier: "fichu".to_string(),
inter_file_dependencies: false,
workspace_diagnostics: false,
},
completion_provider: capabilities::CompletionOptions {
trigger_characters: vec!["?".to_string()],
},
document_formatting_provider: capabilities::DocumentFormattingOptions {},
};
let mut uri_converter = Converter::new(":");
uri_converter.add_record(Record::new("schema", "http://schema.org/"));
uri_converter.add_record(Record::new(
"envTopic",
"https://environment.ld.admin.ch/foen/nfi/Topic/",
));
uri_converter.add_record(Record::new(
"envCube",
"https://environment.ld.admin.ch/foen/nfi/nfi_C-20/cube/",
));
uri_converter.add_record(Record::new("cube", "https://cube.link/"));
uri_converter.add_record(Record::new(
"env",
"https://environment.ld.admin.ch/foen/nfi/",
));
uri_converter.add_record(Record::new("country", "https://ld.admin.ch/country/"));
let version = env!("CARGO_PKG_VERSION");
info!("Started Language Server!!1!");
info!("version: {}", version);
debug!("Capabilities: {:?}", capabilities);
debug!("Settings:\n{:?}", settings);
Self {
state: ServerState::new(),
settings,
capabilities,
server_info: ServerInfo {
name: "fichu".to_string(),
version: Some(version.to_string()),
},
uri_converter,
send_message_clusure: Box::new(write_function),
}
}
pub fn get_version(&self) -> String {
self.server_info
.version
.clone()
.unwrap_or("not-specified".to_string())
}
pub fn handle_message(&mut self, message: String) {
match dispatch(self, message) {
Some(response) => self.send_message(response),
None => {}
}
}
fn send_message(&self, message: String) {
(self.send_message_clusure)(message);
}
pub(crate) fn compress_uri(&self, uri: &str) -> Option<(String, String, String)> {
let record = self.uri_converter.find_by_uri(uri).ok()?;
let curie = self.uri_converter.compress(uri).ok()?;
Some((record.prefix.clone(), record.uri_prefix.clone(), curie))
}
#[allow(dead_code)]
pub fn publish_diagnostic(&self, uri: String) -> String {
let notification = PublishDiagnosticsNotification {
base: BaseMessage::new("textDocument/publishDiagnostics"),
params: PublishDiagnosticsPrarams {
uri: uri.clone(),
diagnostics: collect_diagnostics(&self.state, &uri).collect(),
},
};
serde_json::to_string(¬ification)
.expect("Could not parse PublishDiagnosticsNotification")
}
}