Add method matcher for notifications

This commit is contained in:
Tad Hardesty 2018-03-08 19:19:53 -08:00
parent 5b51f84dd4
commit 3a4153ae08

View file

@ -16,20 +16,30 @@ mod io;
use std::io::Write;
use jsonrpc::{Request, Call, Response, Output};
use langserver::MessageType;
fn main() {
let stdio = io::StdIo;
Engine {
read: &stdio,
write: &stdio,
status: InitStatus::Starting,
}.run()
}
const VERSION: Option<jsonrpc::Version> = Some(jsonrpc::Version::V2);
#[derive(PartialEq)]
enum InitStatus {
Starting,
Running,
ShuttingDown,
}
struct Engine<'a, R: 'a, W: 'a> {
read: &'a R,
write: &'a W,
status: InitStatus,
}
impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
@ -65,16 +75,19 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
let request = Request::Single(Call::Notification(jsonrpc::Notification {
jsonrpc: VERSION,
method: T::METHOD.to_owned(),
params: Some(match params {
serde_json::Value::Null => jsonrpc::Params::None,
serde_json::Value::Array(x) => jsonrpc::Params::Array(x),
serde_json::Value::Object(x) => jsonrpc::Params::Map(x),
_ => panic!("notification bad value to params conversion")
})
params: Some(value_to_params(params)),
}));
self.write.write(serde_json::to_string(&request).expect("notification bad to_string"))
}
fn show_message<S>(&mut self, typ: langserver::MessageType, message: S) where
S: Into<String>
{
self.issue_notification::<langserver::notification::ShowMessage>(
langserver::ShowMessageParams { typ, message: message.into() }
)
}
fn handle_call(&mut self, call: Call) -> Option<Output> {
match call {
Call::Invalid(id) => {
@ -84,8 +97,8 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
let id = method_call.id.clone();
Some(Output::from(self.handle_method_call(method_call), id, VERSION))
},
Call::Notification(_notification) => {
// TODO
Call::Notification(notification) => {
self.handle_notification(notification);
None
},
}
@ -94,12 +107,7 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
fn handle_method_call(&mut self, call: jsonrpc::MethodCall) -> Result<serde_json::Value, jsonrpc::Error> {
use langserver::request::*;
let params_value = match call.params {
Some(jsonrpc::Params::None) |
None => serde_json::Value::Null,
Some(jsonrpc::Params::Array(x)) => serde_json::Value::Array(x),
Some(jsonrpc::Params::Map(x)) => serde_json::Value::Object(x),
};
let params_value = params_to_value(call.params);
macro_rules! match_call {
($(|$name:ident: $what:ty| $body:block;)*) => (
@ -108,6 +116,7 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
let result: <$what as Request>::Result = $body;
Ok(serde_json::to_value(result).expect("blah 2"))
} else)* {
self.show_message(MessageType::Warning, format!("Call NYI: {}", call.method));
Err(jsonrpc::Error {
code: jsonrpc::ErrorCode::InternalError,
message: "Not yet implemented".to_owned(),
@ -119,12 +128,51 @@ impl<'a, R: io::RequestRead, W: io::ResponseWrite> Engine<'a, R, W> {
match_call! {
|_init: Initialize| {
self.issue_notification::<langserver::notification::ShowMessage>(langserver::ShowMessageParams {
typ: langserver::MessageType::Info,
message: "Hello, world!".to_owned(),
});
self.show_message(MessageType::Info, "Hello, world!");
self.status = InitStatus::Running;
Default::default()
};
}
}
fn handle_notification(&mut self, notification: jsonrpc::Notification) {
use langserver::notification::*;
let params_value = params_to_value(notification.params);
macro_rules! match_notify {
($(|$name:ident: $what:ty| $body:block;)*) => (
$(if notification.method == <$what>::METHOD {
let $name: <$what as Notification>::Params = serde_json::from_value(params_value).expect("blah");
$body
} else)* {
self.show_message(MessageType::Warning, format!("Notify NYI: {}", notification.method));
}
)
}
match_notify! {
|_empty: Exit| {
std::process::exit(if self.status == InitStatus::ShuttingDown { 0 } else { 1 });
};
}
}
}
fn params_to_value(params: Option<jsonrpc::Params>) -> serde_json::Value {
match params {
Some(jsonrpc::Params::None) |
None => serde_json::Value::Null,
Some(jsonrpc::Params::Array(x)) => serde_json::Value::Array(x),
Some(jsonrpc::Params::Map(x)) => serde_json::Value::Object(x),
}
}
fn value_to_params(value: serde_json::Value) -> jsonrpc::Params {
match value {
serde_json::Value::Null => jsonrpc::Params::None,
serde_json::Value::Array(x) => jsonrpc::Params::Array(x),
serde_json::Value::Object(x) => jsonrpc::Params::Map(x),
_ => panic!("bad value to params conversion")
}
}