Skip to content

Commit ff2059c

Browse files
authored
Merge pull request #95 from HenningHolmDE/use_lsp-server_crate
Use lsp-server crate for RPC channel handling
2 parents 8bd1421 + 7517423 commit ff2059c

File tree

3 files changed

+163
-185
lines changed

3 files changed

+163
-185
lines changed

vhdl_ls/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ edition = "2018"
1515

1616
[dependencies]
1717
vhdl_lang = { version = "^0", path = "../vhdl_lang"}
18-
jsonrpc-core = "^9"
1918
serde_json = "^1"
2019
serde = "^1"
2120
lsp-types = "^0.63"
2221
fnv = "^1"
2322
log = "0.4.6"
2423
env_logger = "0.6.0"
2524
clap = "^2"
25+
lsp-server = "^0.3"
2626

2727
[dev-dependencies]
2828
tempfile = "^3"

vhdl_ls/src/stdio_server.rs

Lines changed: 157 additions & 173 deletions
Original file line numberDiff line numberDiff line change
@@ -4,210 +4,194 @@
44
//
55
// Copyright (c) 2018, Olof Kraigher olof.kraigher@gmail.com
66

7-
use jsonrpc_core::request::Notification;
8-
use jsonrpc_core::{IoHandler, Params};
9-
use std::io::prelude::*;
10-
use std::io::{self, BufRead};
7+
//! This module handles setting up `VHDLServer` for `stdio` communication.
8+
//! It also contains the main event loop for handling incoming messages from the LSP client and
9+
//! dispatching them to the appropriate server methods.
1110
12-
use std::sync::mpsc::{sync_channel, SyncSender};
13-
use std::thread::spawn;
14-
15-
use std::sync::{Arc, Mutex};
11+
use lsp_server::Connection;
12+
use lsp_types::{
13+
notification::{self, Notification},
14+
request, InitializeParams,
15+
};
16+
use std::rc::Rc;
1617

1718
use crate::rpc_channel::RpcChannel;
1819
use crate::vhdl_server::VHDLServer;
1920

21+
/// Set up the IO channel for `stdio` and start the VHDL language server.
2022
pub fn start() {
21-
let (request_sender, request_receiver) = sync_channel(1);
22-
let (response_sender, response_receiver) = sync_channel(1);
23-
let mut io = IoHandler::new();
24-
25-
// @TODO handle jsonrpc synchronously
26-
let lang_server = Arc::new(Mutex::new(VHDLServer::new(response_sender.clone())));
27-
let server = lang_server.clone();
28-
io.add_method("initialize", move |params: Params| {
29-
let value = server.lock().unwrap().initialize_request(params.parse()?)?;
30-
serde_json::to_value(value).map_err(|_| jsonrpc_core::Error::internal_error())
31-
});
32-
33-
let server = lang_server.clone();
34-
io.add_method("shutdown", move |params: Params| {
35-
server.lock().unwrap().shutdown_server(params.parse()?)?;
36-
Ok(serde_json::Value::Null)
37-
});
38-
39-
let server = lang_server.clone();
40-
io.add_notification("initialized", move |_params: Params| {
41-
server.lock().unwrap().initialized_notification()
42-
});
43-
44-
let server = lang_server.clone();
45-
io.add_notification("exit", move |_params: Params| {
46-
server.lock().unwrap().exit_notification(())
47-
});
48-
49-
let server = lang_server.clone();
50-
io.add_notification("textDocument/didChange", move |params: Params| {
51-
server
52-
.lock()
53-
.unwrap()
54-
.text_document_did_change_notification(&params.parse().unwrap())
55-
});
56-
57-
let server = lang_server.clone();
58-
io.add_notification("textDocument/didOpen", move |params: Params| {
59-
server
60-
.lock()
61-
.unwrap()
62-
.text_document_did_open_notification(&params.parse().unwrap())
63-
});
64-
65-
let server = lang_server.clone();
66-
io.add_method("textDocument/declaration", move |params: Params| {
67-
let value = server
68-
.lock()
69-
.unwrap()
70-
.text_document_declaration(&params.parse().unwrap());
71-
serde_json::to_value(value).map_err(|_| jsonrpc_core::Error::internal_error())
72-
});
73-
74-
let server = lang_server.clone();
75-
io.add_method("textDocument/definition", move |params: Params| {
76-
let value = server
77-
.lock()
78-
.unwrap()
79-
.text_document_definition(&params.parse().unwrap());
80-
serde_json::to_value(value).map_err(|_| jsonrpc_core::Error::internal_error())
81-
});
82-
83-
let server = lang_server;
84-
io.add_method("textDocument/references", move |params: Params| {
85-
let value = server
86-
.lock()
87-
.unwrap()
88-
.text_document_references(&params.parse().unwrap());
89-
serde_json::to_value(value).map_err(|_| jsonrpc_core::Error::internal_error())
90-
});
91-
92-
// Spawn thread to read requests from stdin
93-
spawn(move || {
94-
let stdin = io::stdin();
95-
loop {
96-
let request = read_request(&mut stdin.lock());
97-
match request_sender.send(request) {
98-
Ok(_) => continue,
99-
Err(_) => {
100-
info!("Channel hung up. Unlocking stdin handle.");
101-
break;
102-
}
103-
}
104-
}
105-
});
106-
107-
// Spawn thread to write notifications to stdout
108-
spawn(move || {
109-
let mut stdout = io::stdout();
110-
loop {
111-
match response_receiver.recv() {
112-
Ok(response) => {
113-
send_response(&mut stdout, &response);
114-
}
115-
Err(_) => {
116-
info!("Channel hung up.");
117-
break;
118-
}
23+
let (connection, io_threads) = Connection::stdio();
24+
let connection = Rc::new(connection);
25+
let mut server = VHDLServer::new(connection.clone());
26+
27+
handle_initialization(&connection, &mut server);
28+
main_event_loop(connection, server);
29+
io_threads.join().unwrap();
30+
}
31+
32+
/// Wait for initialize request from the client and let the server respond to it.
33+
fn handle_initialization<T: RpcChannel + Clone>(
34+
connection: &Connection,
35+
server: &mut VHDLServer<T>,
36+
) {
37+
let (initialize_id, initialize_params) = connection.initialize_start().unwrap();
38+
let initialize_params = serde_json::from_value::<InitializeParams>(initialize_params).unwrap();
39+
let initialize_result = server.initialize_request(initialize_params);
40+
connection
41+
.initialize_finish(
42+
initialize_id,
43+
serde_json::to_value(initialize_result).unwrap(),
44+
)
45+
.unwrap();
46+
47+
server.initialized_notification();
48+
}
49+
50+
/// Main event loop handling incoming messages from the client.
51+
fn main_event_loop<T: RpcChannel + Clone>(connection: Rc<Connection>, mut server: VHDLServer<T>) {
52+
info!("Language server initialized, waiting for messages ...");
53+
while let Ok(message) = connection.receiver.recv() {
54+
trace!("Received message: {:?}", message);
55+
if let lsp_server::Message::Notification(notification) = &message {
56+
if notification.method == notification::Exit::METHOD {
57+
return;
11958
}
12059
}
121-
});
122-
123-
loop {
124-
match request_receiver.recv() {
125-
Ok(request) => {
126-
let response = io.handle_request_sync(&request);
127-
if let Some(response) = response {
128-
response_sender.send(response).unwrap();
129-
}
60+
match message {
61+
lsp_server::Message::Request(request) => {
62+
handle_request(&mut server, connection.as_ref(), request)
13063
}
131-
Err(_) => {
132-
info!("Channel hung up.");
133-
break;
64+
lsp_server::Message::Notification(notification) => {
65+
handle_notification(&mut server, notification);
13466
}
135-
}
67+
lsp_server::Message::Response(response) => handle_response(&mut server, response),
68+
};
13669
}
13770
}
13871

139-
fn read_request(reader: &mut dyn BufRead) -> String {
140-
let content_length = read_header(reader);
141-
142-
let mut request = String::new();
143-
reader
144-
.take(content_length)
145-
.read_to_string(&mut request)
146-
.unwrap();
147-
trace!("GOT REQUEST: {:?}", request);
148-
request
149-
}
150-
151-
fn send_response(writer: &mut dyn Write, response: &str) {
152-
trace!("SEND RESPONSE: {:?}", response);
153-
writeln!(writer, "Content-Length: {}\r", response.len()).unwrap();
154-
writeln!(writer, "\r").unwrap();
155-
write!(writer, "{}", response).unwrap();
156-
writer.flush().expect("Could not flush stdout");
72+
/// Send responses (to requests sent by the client) back to the client.
73+
fn send_response(connection: &Connection, response: lsp_server::Response) {
74+
trace!("Sending response: {:?}", response);
75+
connection.sender.send(response.into()).unwrap();
15776
}
15877

159-
impl RpcChannel for SyncSender<String> {
78+
impl RpcChannel for Rc<Connection> {
79+
/// Send notifications to the client.
16080
fn send_notification(
16181
&self,
16282
method: impl Into<String>,
16383
notification: impl serde::ser::Serialize,
16484
) {
165-
let params_json = match serde_json::to_value(notification).unwrap() {
166-
serde_json::Value::Object(map) => map,
167-
map => panic!("{:?}", map),
168-
};
169-
170-
let notification_json = Notification {
171-
jsonrpc: Some(jsonrpc_core::Version::V2),
85+
let notification = lsp_server::Notification {
17286
method: method.into(),
173-
params: Params::Map(params_json),
87+
params: serde_json::to_value(notification).unwrap(),
17488
};
17589

176-
self.send(serde_json::to_string(&notification_json).unwrap())
177-
.unwrap();
90+
trace!("Sending notification: {:?}", notification);
91+
self.sender.send(notification.into()).unwrap();
17892
}
17993
}
18094

181-
fn read_header(reader: &mut dyn BufRead) -> u64 {
182-
let mut buffer = String::new();
183-
reader.read_line(&mut buffer).unwrap();
184-
let fields = buffer.trim_end().split(": ").collect::<Vec<&str>>();
185-
if fields.get(0) != Some(&"Content-Length") {
186-
trace!("{:?}", fields);
187-
panic!();
95+
/// Handle incoming requests from the client.
96+
fn handle_request<T: RpcChannel + Clone>(
97+
server: &mut VHDLServer<T>,
98+
connection: &Connection,
99+
request: lsp_server::Request,
100+
) {
101+
fn extract<R>(
102+
request: lsp_server::Request,
103+
) -> Result<(lsp_server::RequestId, R::Params), lsp_server::Request>
104+
where
105+
R: request::Request,
106+
R::Params: serde::de::DeserializeOwned,
107+
{
108+
request.extract(R::METHOD)
188109
}
189-
let content_length = fields[1].parse::<u64>().unwrap();
190110

191-
let mut buffer = String::new();
192-
reader.read_line(&mut buffer).unwrap();
193-
if buffer == "\r\n" {
194-
return content_length;
195-
}
111+
trace!("Handling request: {:?}", request);
112+
let request = match extract::<request::GotoDeclaration>(request) {
113+
Ok((id, params)) => {
114+
let result = server.text_document_declaration(&params);
115+
send_response(connection, lsp_server::Response::new_ok(id, result));
116+
return;
117+
}
118+
Err(request) => request,
119+
};
120+
let request = match extract::<request::GotoDefinition>(request) {
121+
Ok((id, params)) => {
122+
let result = server.text_document_definition(&params);
123+
send_response(connection, lsp_server::Response::new_ok(id, result));
124+
return;
125+
}
126+
Err(request) => request,
127+
};
128+
let request = match extract::<request::References>(request) {
129+
Ok((id, params)) => {
130+
let result = server.text_document_references(&params);
131+
send_response(connection, lsp_server::Response::new_ok(id, result));
132+
return;
133+
}
134+
Err(request) => request,
135+
};
136+
let request = match extract::<request::Shutdown>(request) {
137+
Ok((id, _params)) => {
138+
server.shutdown_server();
139+
send_response(connection, lsp_server::Response::new_ok(id, ()));
140+
return;
141+
}
142+
Err(request) => request,
143+
};
144+
145+
debug!("Unhandled request: {:?}", request);
146+
send_response(
147+
connection,
148+
lsp_server::Response::new_err(
149+
request.id,
150+
lsp_server::ErrorCode::MethodNotFound as i32,
151+
"Unknown request".to_string(),
152+
),
153+
);
154+
}
196155

197-
let fields = buffer.trim_end().split(": ").collect::<Vec<&str>>();
198-
if fields.get(0) != Some(&"Content-Type") {
199-
trace!("{:?}", fields);
200-
panic!();
201-
} else {
202-
trace!("got Content-Type: {}", &fields[1]);
156+
/// Handle incoming notifications from the client.
157+
fn handle_notification<T: RpcChannel + Clone>(
158+
server: &mut VHDLServer<T>,
159+
notification: lsp_server::Notification,
160+
) {
161+
fn extract<N>(
162+
notification: lsp_server::Notification,
163+
) -> Result<N::Params, lsp_server::Notification>
164+
where
165+
N: notification::Notification,
166+
N::Params: serde::de::DeserializeOwned,
167+
{
168+
notification.extract(N::METHOD)
203169
}
204170

205-
let mut buffer = String::new();
206-
reader.read_line(&mut buffer).unwrap();
207-
if buffer != "\r\n" {
208-
trace!("{:?}", buffer);
209-
panic!();
171+
trace!("Handling notification: {:?}", notification);
172+
let notification = match extract::<notification::DidChangeTextDocument>(notification) {
173+
Ok(params) => return server.text_document_did_change_notification(&params),
174+
Err(notification) => notification,
175+
};
176+
let notification = match extract::<notification::DidOpenTextDocument>(notification) {
177+
Ok(params) => return server.text_document_did_open_notification(&params),
178+
Err(notification) => notification,
179+
};
180+
let notification = match extract::<notification::Exit>(notification) {
181+
Ok(_params) => return server.exit_notification(),
182+
Err(notification) => notification,
183+
};
184+
185+
if !notification.method.starts_with("$/") {
186+
debug!("Unhandled notification: {:?}", notification);
210187
}
188+
}
211189

212-
content_length
190+
/// Handle incoming responses (to requests sent by us) from the client.
191+
fn handle_response<T: RpcChannel + Clone>(
192+
_server: &mut VHDLServer<T>,
193+
response: lsp_server::Response,
194+
) {
195+
trace!("Handling response: {:?}", response);
196+
debug!("Unhandled response: {:?}", response);
213197
}

0 commit comments

Comments
 (0)