mod error;
mod log;
mod server;
mod spec;
mod util;
use std::io::{self, BufRead, Read};
use error::LSError;
use lsp_types::InitializeParams;
use serde::de::Error;
use serde::Deserialize;
use serde_json::{json, Value};
use util::{format_uri, send_stdout};
use crate::log::Log;
use crate::server::TestingLS;
use crate::util::send_error;
fn extract_textdocument_uri(params: &Value) -> Result<String, serde_json::Error> {
let uri = params["textDocument"]["uri"]
.as_str()
.ok_or(serde_json::Error::custom("`textDocument.uri` is not set"))?;
Ok(format_uri(uri))
}
fn extract_uri(params: &Value) -> Result<String, serde_json::Error> {
let uri = params["uri"]
.as_str()
.ok_or(serde_json::Error::custom("`uri` is not set"))?;
Ok(format_uri(uri))
}
fn main_loop(server: &mut TestingLS) -> Result<(), LSError> {
let mut is_workspace_checked = false;
loop {
let mut size = 0;
'read_header: loop {
let mut buffer = String::new();
let stdin = io::stdin();
let mut handle = stdin.lock();
handle.read_line(&mut buffer)?;
if buffer.is_empty() {
tracing::warn!("buffer is empty")
}
if buffer == "\r\n" {
break 'read_header;
}
let split: Vec<&str> = buffer.split(' ').collect();
if split.len() != 2 {
tracing::warn!("unexpected");
}
let header_name = split[0].to_lowercase();
let header_value = split[1].trim();
match header_name.as_ref() {
"content-length" => {}
"content-type:" => {}
_ => {}
}
size = header_value.parse::<usize>().unwrap();
}
let stdin = io::stdin();
let mut handle = stdin.lock();
let mut buf = vec![0u8; size];
handle.read_exact(&mut buf).unwrap();
let message = String::from_utf8(buf).unwrap();
let received_json: Value = serde_json::from_str(&message)?;
tracing::info!("received json={:#?}", received_json);
let method = &received_json["method"].as_str();
let params = &received_json["params"];
if let Some(method) = method {
match *method {
"$/cancelRequest" => {}
"initialized" => {
is_workspace_checked = true;
server.diagnose_workspace()?;
}
"initialize" => {
let initialize_params = InitializeParams::deserialize(params)?;
let id = received_json["id"].as_i64().unwrap();
server.initialize(id, initialize_params)?;
}
"shutdown" => {
let id = received_json["id"].as_i64().unwrap();
server.shutdown(id)?;
}
"exit" => {
std::process::exit(0);
}
"workspace/diagnostic" => {
is_workspace_checked = true;
server.diagnose_workspace()?;
}
"textDocument/diagnostic" | "textDocument/didSave" => {
let uri = extract_textdocument_uri(params)?;
server.check_file(&uri, false)?;
}
"textDocument/didOpen" => {
if !is_workspace_checked {
is_workspace_checked = true;
server.diagnose_workspace()?;
}
let uri = extract_textdocument_uri(params)?;
if server.refreshing_needed(&uri) {
server.refresh_workspaces_cache()?;
}
}
"$/runFileTest" => {
let uri = extract_uri(params)?;
server.check_file(&uri, false)?;
}
"$/runWorkspaceTest" => {
server.diagnose_workspace()?;
}
"$/discoverFileTest" => {
let id = received_json["id"].as_i64().unwrap();
let uri = extract_uri(params)?;
let result = server.discover_file(&uri)?;
send_stdout(&json!({
"jsonrpc": "2.0",
"id": id,
"result": result,
}))?;
}
_ => {
let id = received_json["id"].as_i64();
if id.is_some() {
send_error(
id,
-32601, format!("method not found: {}", method),
)?;
}
}
}
}
}
}
fn main() {
let mut server = TestingLS::new();
let _guard = Log::init().expect("Failed to initialize logger");
if let Err(ls_error) = main_loop(&mut server) {
tracing::error!("Error: {:?}", ls_error);
}
}