From 72a3722470e5297c72dcaccaf2f113e7b758606d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 30 Aug 2019 17:24:11 +0300 Subject: move lsp-server to a separate repository --- crates/gen_lsp_server/src/lib.rs | 136 ------------------------ crates/gen_lsp_server/src/msg.rs | 205 ------------------------------------- crates/gen_lsp_server/src/stdio.rs | 57 ----------- 3 files changed, 398 deletions(-) delete mode 100644 crates/gen_lsp_server/src/lib.rs delete mode 100644 crates/gen_lsp_server/src/msg.rs delete mode 100644 crates/gen_lsp_server/src/stdio.rs (limited to 'crates/gen_lsp_server/src') diff --git a/crates/gen_lsp_server/src/lib.rs b/crates/gen_lsp_server/src/lib.rs deleted file mode 100644 index 0984e3e25..000000000 --- a/crates/gen_lsp_server/src/lib.rs +++ /dev/null @@ -1,136 +0,0 @@ -//! A language server scaffold, exposing a synchronous crossbeam-channel based API. -//! This crate handles protocol handshaking and parsing messages, while you -//! control the message dispatch loop yourself. -//! -//! Run with `RUST_LOG=gen_lsp_server=debug` to see all the messages. -//! -//! ```no_run -//! use std::error::Error; -//! use crossbeam_channel::{Sender, Receiver}; -//! use lsp_types::{ServerCapabilities, InitializeParams, request::{GotoDefinition, GotoDefinitionResponse}}; -//! use gen_lsp_server::{run_server, stdio_transport, handle_shutdown, RawMessage, RawResponse}; -//! -//! fn main() -> Result<(), Box> { -//! let (receiver, sender, io_threads) = stdio_transport(); -//! run_server( -//! ServerCapabilities::default(), -//! receiver, -//! sender, -//! main_loop, -//! )?; -//! io_threads.join()?; -//! Ok(()) -//! } -//! -//! fn main_loop( -//! _params: InitializeParams, -//! receiver: &Receiver, -//! sender: &Sender, -//! ) -> Result<(), Box> { -//! for msg in receiver { -//! match msg { -//! RawMessage::Request(req) => { -//! let req = match handle_shutdown(req, sender) { -//! None => return Ok(()), -//! Some(req) => req, -//! }; -//! match req.cast::() { -//! Ok((id, _params)) => { -//! let resp = RawResponse::ok::( -//! id, -//! &Some(GotoDefinitionResponse::Array(Vec::new())), -//! ); -//! sender.send(RawMessage::Response(resp))?; -//! continue; -//! }, -//! Err(req) => req, -//! }; -//! // ... -//! } -//! RawMessage::Response(_resp) => (), -//! RawMessage::Notification(_not) => (), -//! } -//! } -//! Ok(()) -//! } -//! ``` - -use std::error::Error; - -mod msg; -mod stdio; - -use crossbeam_channel::{Receiver, Sender}; -use lsp_types::{ - notification::{Exit, Initialized}, - request::{Initialize, Shutdown}, - InitializeParams, InitializeResult, ServerCapabilities, -}; - -pub type Result = std::result::Result>; -pub use crate::{ - msg::{ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse, RawResponseError}, - stdio::{stdio_transport, Threads}, -}; - -/// Main entry point: runs the server from initialization to shutdown. -/// To attach server to standard input/output streams, use the `stdio_transport` -/// function to create corresponding `sender` and `receiver` pair. -/// -/// `server` should use the `handle_shutdown` function to handle the `Shutdown` -/// request. -pub fn run_server( - caps: ServerCapabilities, - receiver: Receiver, - sender: Sender, - server: impl FnOnce(InitializeParams, &Receiver, &Sender) -> Result<()>, -) -> Result<()> { - log::info!("lsp server initializes"); - let params = initialize(&receiver, &sender, caps)?; - log::info!("lsp server initialized, serving requests"); - server(params, &receiver, &sender)?; - log::info!("lsp server waiting for exit notification"); - match receiver.recv() { - Ok(RawMessage::Notification(n)) => n - .cast::() - .map_err(|n| format!("unexpected notification during shutdown: {:?}", n))?, - m => Err(format!("unexpected message during shutdown: {:?}", m))?, - } - log::info!("lsp server shutdown complete"); - Ok(()) -} - -/// If `req` is `Shutdown`, respond to it and return `None`, otherwise return `Some(req)` -pub fn handle_shutdown(req: RawRequest, sender: &Sender) -> Option { - match req.cast::() { - Ok((id, ())) => { - let resp = RawResponse::ok::(id, &()); - let _ = sender.send(RawMessage::Response(resp)); - None - } - Err(req) => Some(req), - } -} - -fn initialize( - receiver: &Receiver, - sender: &Sender, - caps: ServerCapabilities, -) -> Result { - let (id, params) = match receiver.recv() { - Ok(RawMessage::Request(req)) => match req.cast::() { - Err(req) => Err(format!("expected initialize request, got {:?}", req))?, - Ok(req) => req, - }, - msg => Err(format!("expected initialize request, got {:?}", msg))?, - }; - let resp = RawResponse::ok::(id, &InitializeResult { capabilities: caps }); - sender.send(RawMessage::Response(resp)).unwrap(); - match receiver.recv() { - Ok(RawMessage::Notification(n)) => { - n.cast::().map_err(|_| "expected initialized notification")?; - } - _ => Err("expected initialized notification".to_string())?, - } - Ok(params) -} diff --git a/crates/gen_lsp_server/src/msg.rs b/crates/gen_lsp_server/src/msg.rs deleted file mode 100644 index 2928e4f8b..000000000 --- a/crates/gen_lsp_server/src/msg.rs +++ /dev/null @@ -1,205 +0,0 @@ -use std::io::{BufRead, Write}; - -use lsp_types::{notification::Notification, request::Request}; -use serde::{Deserialize, Serialize}; -use serde_json::{from_str, from_value, to_string, to_value, Value}; - -use crate::Result; - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(untagged)] -pub enum RawMessage { - Request(RawRequest), - Notification(RawNotification), - Response(RawResponse), -} - -impl From for RawMessage { - fn from(raw: RawRequest) -> RawMessage { - RawMessage::Request(raw) - } -} - -impl From for RawMessage { - fn from(raw: RawNotification) -> RawMessage { - RawMessage::Notification(raw) - } -} - -impl From for RawMessage { - fn from(raw: RawResponse) -> RawMessage { - RawMessage::Response(raw) - } -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct RawRequest { - pub id: u64, - pub method: String, - pub params: Value, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct RawResponse { - // JSON RPC allows this to be null if it was impossible - // to decode the request's id. Ignore this special case - // and just die horribly. - pub id: u64, - #[serde(skip_serializing_if = "Option::is_none")] - pub result: Option, - #[serde(skip_serializing_if = "Option::is_none")] - pub error: Option, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct RawResponseError { - pub code: i32, - pub message: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option, -} - -#[derive(Clone, Copy, Debug)] -#[allow(unused)] -pub enum ErrorCode { - ParseError = -32700, - InvalidRequest = -32600, - MethodNotFound = -32601, - InvalidParams = -32602, - InternalError = -32603, - ServerErrorStart = -32099, - ServerErrorEnd = -32000, - ServerNotInitialized = -32002, - UnknownErrorCode = -32001, - RequestCanceled = -32800, - ContentModified = -32801, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct RawNotification { - pub method: String, - pub params: Value, -} - -impl RawMessage { - pub fn read(r: &mut impl BufRead) -> Result> { - let text = match read_msg_text(r)? { - None => return Ok(None), - Some(text) => text, - }; - let msg = from_str(&text)?; - Ok(Some(msg)) - } - pub fn write(self, w: &mut impl Write) -> Result<()> { - #[derive(Serialize)] - struct JsonRpc { - jsonrpc: &'static str, - #[serde(flatten)] - msg: RawMessage, - } - let text = to_string(&JsonRpc { jsonrpc: "2.0", msg: self })?; - write_msg_text(w, &text)?; - Ok(()) - } -} - -impl RawRequest { - pub fn new(id: u64, params: &R::Params) -> RawRequest - where - R: Request, - R::Params: serde::Serialize, - { - RawRequest { id, method: R::METHOD.to_string(), params: to_value(params).unwrap() } - } - pub fn cast(self) -> ::std::result::Result<(u64, R::Params), RawRequest> - where - R: Request, - R::Params: serde::de::DeserializeOwned, - { - if self.method != R::METHOD { - return Err(self); - } - let id = self.id; - let params: R::Params = from_value(self.params).unwrap(); - Ok((id, params)) - } -} - -impl RawResponse { - pub fn ok(id: u64, result: &R::Result) -> RawResponse - where - R: Request, - R::Result: serde::Serialize, - { - RawResponse { id, result: Some(to_value(&result).unwrap()), error: None } - } - pub fn err(id: u64, code: i32, message: String) -> RawResponse { - let error = RawResponseError { code, message, data: None }; - RawResponse { id, result: None, error: Some(error) } - } -} - -impl RawNotification { - pub fn new(params: &N::Params) -> RawNotification - where - N: Notification, - N::Params: serde::Serialize, - { - RawNotification { method: N::METHOD.to_string(), params: to_value(params).unwrap() } - } - pub fn is(&self) -> bool - where - N: Notification, - { - self.method == N::METHOD - } - pub fn cast(self) -> ::std::result::Result - where - N: Notification, - N::Params: serde::de::DeserializeOwned, - { - if !self.is::() { - return Err(self); - } - Ok(from_value(self.params).unwrap()) - } -} - -fn read_msg_text(inp: &mut impl BufRead) -> Result> { - let mut size = None; - let mut buf = String::new(); - loop { - buf.clear(); - if inp.read_line(&mut buf)? == 0 { - return Ok(None); - } - if !buf.ends_with("\r\n") { - Err(format!("malformed header: {:?}", buf))?; - } - let buf = &buf[..buf.len() - 2]; - if buf.is_empty() { - break; - } - let mut parts = buf.splitn(2, ": "); - let header_name = parts.next().unwrap(); - let header_value = parts.next().ok_or_else(|| format!("malformed header: {:?}", buf))?; - if header_name == "Content-Length" { - size = Some(header_value.parse::()?); - } - } - let size = size.ok_or("no Content-Length")?; - let mut buf = buf.into_bytes(); - buf.resize(size, 0); - inp.read_exact(&mut buf)?; - let buf = String::from_utf8(buf)?; - log::debug!("< {}", buf); - Ok(Some(buf)) -} - -fn write_msg_text(out: &mut impl Write, msg: &str) -> Result<()> { - log::debug!("> {}", msg); - write!(out, "Content-Length: {}\r\n\r\n", msg.len())?; - out.write_all(msg.as_bytes())?; - out.flush()?; - Ok(()) -} diff --git a/crates/gen_lsp_server/src/stdio.rs b/crates/gen_lsp_server/src/stdio.rs deleted file mode 100644 index f8931f2dc..000000000 --- a/crates/gen_lsp_server/src/stdio.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::{ - io::{stdin, stdout}, - thread, -}; - -use crossbeam_channel::{bounded, Receiver, Sender}; -use lsp_types::notification::Exit; - -use crate::{RawMessage, Result}; - -pub fn stdio_transport() -> (Receiver, Sender, Threads) { - let (writer_sender, writer_receiver) = bounded::(16); - let writer = thread::spawn(move || { - let stdout = stdout(); - let mut stdout = stdout.lock(); - writer_receiver.into_iter().try_for_each(|it| it.write(&mut stdout))?; - Ok(()) - }); - let (reader_sender, reader_receiver) = bounded::(16); - let reader = thread::spawn(move || { - let stdin = stdin(); - let mut stdin = stdin.lock(); - while let Some(msg) = RawMessage::read(&mut stdin)? { - let is_exit = match &msg { - RawMessage::Notification(n) => n.is::(), - _ => false, - }; - - reader_sender.send(msg).unwrap(); - - if is_exit { - break; - } - } - Ok(()) - }); - let threads = Threads { reader, writer }; - (reader_receiver, writer_sender, threads) -} - -pub struct Threads { - reader: thread::JoinHandle>, - writer: thread::JoinHandle>, -} - -impl Threads { - pub fn join(self) -> Result<()> { - match self.reader.join() { - Ok(r) => r?, - Err(_) => Err("reader panicked")?, - } - match self.writer.join() { - Ok(r) => r, - Err(_) => Err("writer panicked")?, - } - } -} -- cgit v1.2.3