aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-08-30 15:24:39 +0100
committerGitHub <[email protected]>2019-08-30 15:24:39 +0100
commitffc95759c7b538d8dacc336912b62857d4919cdd (patch)
tree3f0e4056ba2e4b3799b72d71d709783aa6dffc49 /crates/ra_lsp_server
parent7d72ca80003b7915ed7fc64907b5b6dc5c88dacd (diff)
parent72a3722470e5297c72dcaccaf2f113e7b758606d (diff)
Merge #1739
1739: move lsp-server to a separate repository r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_lsp_server')
-rw-r--r--crates/ra_lsp_server/Cargo.toml2
-rw-r--r--crates/ra_lsp_server/src/main.rs14
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs141
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop/pending_requests.rs19
-rw-r--r--crates/ra_lsp_server/src/world.rs2
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/support.rs57
7 files changed, 127 insertions, 110 deletions
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index e271c257b..084a20cd9 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -21,7 +21,7 @@ thread_worker = { path = "../thread_worker" }
21ra_syntax = { path = "../ra_syntax" } 21ra_syntax = { path = "../ra_syntax" }
22ra_text_edit = { path = "../ra_text_edit" } 22ra_text_edit = { path = "../ra_text_edit" }
23ra_ide_api = { path = "../ra_ide_api" } 23ra_ide_api = { path = "../ra_ide_api" }
24gen_lsp_server = { path = "../gen_lsp_server" } 24lsp-server = "0.1.0"
25ra_project_model = { path = "../ra_project_model" } 25ra_project_model = { path = "../ra_project_model" }
26ra_prof = { path = "../ra_prof" } 26ra_prof = { path = "../ra_prof" }
27ra_vfs_glob = { path = "../ra_vfs_glob" } 27ra_vfs_glob = { path = "../ra_vfs_glob" }
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs
index ae1392cb5..1debe7660 100644
--- a/crates/ra_lsp_server/src/main.rs
+++ b/crates/ra_lsp_server/src/main.rs
@@ -1,5 +1,5 @@
1use flexi_logger::{Duplicate, Logger}; 1use flexi_logger::{Duplicate, Logger};
2use gen_lsp_server::{run_server, stdio_transport}; 2use lsp_server::{run_server, stdio_transport, LspServerError};
3 3
4use ra_lsp_server::{show_message, Result, ServerConfig}; 4use ra_lsp_server::{show_message, Result, ServerConfig};
5use ra_prof; 5use ra_prof;
@@ -29,9 +29,11 @@ fn main() -> Result<()> {
29} 29}
30 30
31fn main_inner() -> Result<()> { 31fn main_inner() -> Result<()> {
32 let (receiver, sender, threads) = stdio_transport(); 32 let (sender, receiver, io_threads) = stdio_transport();
33 let cwd = std::env::current_dir()?; 33 let cwd = std::env::current_dir()?;
34 run_server(ra_lsp_server::server_capabilities(), receiver, sender, |params, r, s| { 34 let caps = serde_json::to_value(ra_lsp_server::server_capabilities()).unwrap();
35 run_server(caps, sender, receiver, |params, s, r| {
36 let params: lsp_types::InitializeParams = serde_json::from_value(params)?;
35 let root = params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd); 37 let root = params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd);
36 38
37 let workspace_roots = params 39 let workspace_roots = params
@@ -62,9 +64,13 @@ fn main_inner() -> Result<()> {
62 .unwrap_or_default(); 64 .unwrap_or_default();
63 65
64 ra_lsp_server::main_loop(workspace_roots, params.capabilities, server_config, r, s) 66 ra_lsp_server::main_loop(workspace_roots, params.capabilities, server_config, r, s)
67 })
68 .map_err(|err| match err {
69 LspServerError::ProtocolError(err) => err.into(),
70 LspServerError::ServerError(err) => err,
65 })?; 71 })?;
66 log::info!("shutting down IO..."); 72 log::info!("shutting down IO...");
67 threads.join()?; 73 io_threads.join()?;
68 log::info!("... IO is down"); 74 log::info!("... IO is down");
69 Ok(()) 75 Ok(())
70} 76}
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 45bd52769..fb357b36b 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -5,9 +5,7 @@ pub(crate) mod pending_requests;
5use std::{error::Error, fmt, path::PathBuf, sync::Arc, time::Instant}; 5use std::{error::Error, fmt, path::PathBuf, sync::Arc, time::Instant};
6 6
7use crossbeam_channel::{select, unbounded, Receiver, RecvError, Sender}; 7use crossbeam_channel::{select, unbounded, Receiver, RecvError, Sender};
8use gen_lsp_server::{ 8use lsp_server::{handle_shutdown, ErrorCode, Message, Notification, Request, RequestId, Response};
9 handle_shutdown, ErrorCode, RawMessage, RawNotification, RawRequest, RawResponse,
10};
11use lsp_types::{ClientCapabilities, NumberOrString}; 9use lsp_types::{ClientCapabilities, NumberOrString};
12use ra_ide_api::{Canceled, FeatureFlags, FileId, LibraryData}; 10use ra_ide_api::{Canceled, FeatureFlags, FileId, LibraryData};
13use ra_prof::profile; 11use ra_prof::profile;
@@ -53,8 +51,8 @@ pub fn main_loop(
53 ws_roots: Vec<PathBuf>, 51 ws_roots: Vec<PathBuf>,
54 client_caps: ClientCapabilities, 52 client_caps: ClientCapabilities,
55 config: ServerConfig, 53 config: ServerConfig,
56 msg_receiver: &Receiver<RawMessage>, 54 msg_receiver: &Receiver<Message>,
57 msg_sender: &Sender<RawMessage>, 55 msg_sender: &Sender<Message>,
58) -> Result<()> { 56) -> Result<()> {
59 log::info!("server_config: {:#?}", config); 57 log::info!("server_config: {:#?}", config);
60 // FIXME: support dynamic workspace loading. 58 // FIXME: support dynamic workspace loading.
@@ -146,12 +144,12 @@ pub fn main_loop(
146 144
147#[derive(Debug)] 145#[derive(Debug)]
148enum Task { 146enum Task {
149 Respond(RawResponse), 147 Respond(Response),
150 Notify(RawNotification), 148 Notify(Notification),
151} 149}
152 150
153enum Event { 151enum Event {
154 Msg(RawMessage), 152 Msg(Message),
155 Task(Task), 153 Task(Task),
156 Vfs(VfsTask), 154 Vfs(VfsTask),
157 Lib(LibraryData), 155 Lib(LibraryData),
@@ -159,24 +157,28 @@ enum Event {
159 157
160impl fmt::Debug for Event { 158impl fmt::Debug for Event {
161 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 159 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162 let debug_verbose_not = |not: &RawNotification, f: &mut fmt::Formatter| { 160 let debug_verbose_not = |not: &Notification, f: &mut fmt::Formatter| {
163 f.debug_struct("RawNotification").field("method", &not.method).finish() 161 f.debug_struct("Notification").field("method", &not.method).finish()
164 }; 162 };
165 163
166 match self { 164 match self {
167 Event::Msg(RawMessage::Notification(not)) => { 165 Event::Msg(Message::Notification(not)) => {
168 if not.is::<req::DidOpenTextDocument>() || not.is::<req::DidChangeTextDocument>() { 166 if notification_is::<req::DidOpenTextDocument>(not)
167 || notification_is::<req::DidChangeTextDocument>(not)
168 {
169 return debug_verbose_not(not, f); 169 return debug_verbose_not(not, f);
170 } 170 }
171 } 171 }
172 Event::Task(Task::Notify(not)) => { 172 Event::Task(Task::Notify(not)) => {
173 if not.is::<req::PublishDecorations>() || not.is::<req::PublishDiagnostics>() { 173 if notification_is::<req::PublishDecorations>(not)
174 || notification_is::<req::PublishDiagnostics>(not)
175 {
174 return debug_verbose_not(not, f); 176 return debug_verbose_not(not, f);
175 } 177 }
176 } 178 }
177 Event::Task(Task::Respond(resp)) => { 179 Event::Task(Task::Respond(resp)) => {
178 return f 180 return f
179 .debug_struct("RawResponse") 181 .debug_struct("Response")
180 .field("id", &resp.id) 182 .field("id", &resp.id)
181 .field("error", &resp.error) 183 .field("error", &resp.error)
182 .finish(); 184 .finish();
@@ -194,8 +196,8 @@ impl fmt::Debug for Event {
194 196
195fn main_loop_inner( 197fn main_loop_inner(
196 pool: &ThreadPool, 198 pool: &ThreadPool,
197 msg_sender: &Sender<RawMessage>, 199 msg_sender: &Sender<Message>,
198 msg_receiver: &Receiver<RawMessage>, 200 msg_receiver: &Receiver<Message>,
199 task_sender: Sender<Task>, 201 task_sender: Sender<Task>,
200 task_receiver: Receiver<Task>, 202 task_receiver: Receiver<Task>,
201 state: &mut WorldState, 203 state: &mut WorldState,
@@ -249,10 +251,9 @@ fn main_loop_inner(
249 in_flight_libraries -= 1; 251 in_flight_libraries -= 1;
250 } 252 }
251 Event::Msg(msg) => match msg { 253 Event::Msg(msg) => match msg {
252 RawMessage::Request(req) => { 254 Message::Request(req) => {
253 let req = match handle_shutdown(req, msg_sender) { 255 if handle_shutdown(&req, msg_sender) {
254 Some(req) => req, 256 return Ok(());
255 None => return Ok(()),
256 }; 257 };
257 on_request( 258 on_request(
258 state, 259 state,
@@ -264,11 +265,11 @@ fn main_loop_inner(
264 req, 265 req,
265 )? 266 )?
266 } 267 }
267 RawMessage::Notification(not) => { 268 Message::Notification(not) => {
268 on_notification(msg_sender, state, pending_requests, &mut subs, not)?; 269 on_notification(msg_sender, state, pending_requests, &mut subs, not)?;
269 state_changed = true; 270 state_changed = true;
270 } 271 }
271 RawMessage::Response(resp) => log::error!("unexpected response: {:?}", resp), 272 Message::Response(resp) => log::error!("unexpected response: {:?}", resp),
272 }, 273 },
273 }; 274 };
274 275
@@ -313,13 +314,13 @@ fn main_loop_inner(
313 314
314fn on_task( 315fn on_task(
315 task: Task, 316 task: Task,
316 msg_sender: &Sender<RawMessage>, 317 msg_sender: &Sender<Message>,
317 pending_requests: &mut PendingRequests, 318 pending_requests: &mut PendingRequests,
318 state: &mut WorldState, 319 state: &mut WorldState,
319) { 320) {
320 match task { 321 match task {
321 Task::Respond(response) => { 322 Task::Respond(response) => {
322 if let Some(completed) = pending_requests.finish(response.id) { 323 if let Some(completed) = pending_requests.finish(&response.id) {
323 log::info!("handled req#{} in {:?}", completed.id, completed.duration); 324 log::info!("handled req#{} in {:?}", completed.id, completed.duration);
324 state.complete_request(completed); 325 state.complete_request(completed);
325 msg_sender.send(response.into()).unwrap(); 326 msg_sender.send(response.into()).unwrap();
@@ -336,9 +337,9 @@ fn on_request(
336 pending_requests: &mut PendingRequests, 337 pending_requests: &mut PendingRequests,
337 pool: &ThreadPool, 338 pool: &ThreadPool,
338 sender: &Sender<Task>, 339 sender: &Sender<Task>,
339 msg_sender: &Sender<RawMessage>, 340 msg_sender: &Sender<Message>,
340 request_received: Instant, 341 request_received: Instant,
341 req: RawRequest, 342 req: Request,
342) -> Result<()> { 343) -> Result<()> {
343 let mut pool_dispatcher = PoolDispatcher { 344 let mut pool_dispatcher = PoolDispatcher {
344 req: Some(req), 345 req: Some(req),
@@ -388,22 +389,20 @@ fn on_request(
388} 389}
389 390
390fn on_notification( 391fn on_notification(
391 msg_sender: &Sender<RawMessage>, 392 msg_sender: &Sender<Message>,
392 state: &mut WorldState, 393 state: &mut WorldState,
393 pending_requests: &mut PendingRequests, 394 pending_requests: &mut PendingRequests,
394 subs: &mut Subscriptions, 395 subs: &mut Subscriptions,
395 not: RawNotification, 396 not: Notification,
396) -> Result<()> { 397) -> Result<()> {
397 let not = match not.cast::<req::Cancel>() { 398 let not = match notification_cast::<req::Cancel>(not) {
398 Ok(params) => { 399 Ok(params) => {
399 let id = match params.id { 400 let id: RequestId = match params.id {
400 NumberOrString::Number(id) => id, 401 NumberOrString::Number(id) => id.into(),
401 NumberOrString::String(id) => { 402 NumberOrString::String(id) => id.into(),
402 panic!("string id's not supported: {:?}", id);
403 }
404 }; 403 };
405 if pending_requests.cancel(id) { 404 if pending_requests.cancel(&id) {
406 let response = RawResponse::err( 405 let response = Response::new_err(
407 id, 406 id,
408 ErrorCode::RequestCanceled as i32, 407 ErrorCode::RequestCanceled as i32,
409 "canceled by client".to_string(), 408 "canceled by client".to_string(),
@@ -414,7 +413,7 @@ fn on_notification(
414 } 413 }
415 Err(not) => not, 414 Err(not) => not,
416 }; 415 };
417 let not = match not.cast::<req::DidOpenTextDocument>() { 416 let not = match notification_cast::<req::DidOpenTextDocument>(not) {
418 Ok(params) => { 417 Ok(params) => {
419 let uri = params.text_document.uri; 418 let uri = params.text_document.uri;
420 let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?; 419 let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
@@ -427,7 +426,7 @@ fn on_notification(
427 } 426 }
428 Err(not) => not, 427 Err(not) => not,
429 }; 428 };
430 let not = match not.cast::<req::DidChangeTextDocument>() { 429 let not = match notification_cast::<req::DidChangeTextDocument>(not) {
431 Ok(mut params) => { 430 Ok(mut params) => {
432 let uri = params.text_document.uri; 431 let uri = params.text_document.uri;
433 let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?; 432 let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
@@ -438,7 +437,7 @@ fn on_notification(
438 } 437 }
439 Err(not) => not, 438 Err(not) => not,
440 }; 439 };
441 let not = match not.cast::<req::DidCloseTextDocument>() { 440 let not = match notification_cast::<req::DidCloseTextDocument>(not) {
442 Ok(params) => { 441 Ok(params) => {
443 let uri = params.text_document.uri; 442 let uri = params.text_document.uri;
444 let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?; 443 let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
@@ -446,13 +445,13 @@ fn on_notification(
446 subs.remove_sub(FileId(file_id.0)); 445 subs.remove_sub(FileId(file_id.0));
447 } 446 }
448 let params = req::PublishDiagnosticsParams { uri, diagnostics: Vec::new() }; 447 let params = req::PublishDiagnosticsParams { uri, diagnostics: Vec::new() };
449 let not = RawNotification::new::<req::PublishDiagnostics>(&params); 448 let not = notification_new::<req::PublishDiagnostics>(params);
450 msg_sender.send(not.into()).unwrap(); 449 msg_sender.send(not.into()).unwrap();
451 return Ok(()); 450 return Ok(());
452 } 451 }
453 Err(not) => not, 452 Err(not) => not,
454 }; 453 };
455 let not = match not.cast::<req::DidChangeConfiguration>() { 454 let not = match notification_cast::<req::DidChangeConfiguration>(not) {
456 Ok(_params) => { 455 Ok(_params) => {
457 return Ok(()); 456 return Ok(());
458 } 457 }
@@ -463,11 +462,11 @@ fn on_notification(
463} 462}
464 463
465struct PoolDispatcher<'a> { 464struct PoolDispatcher<'a> {
466 req: Option<RawRequest>, 465 req: Option<Request>,
467 pool: &'a ThreadPool, 466 pool: &'a ThreadPool,
468 world: &'a mut WorldState, 467 world: &'a mut WorldState,
469 pending_requests: &'a mut PendingRequests, 468 pending_requests: &'a mut PendingRequests,
470 msg_sender: &'a Sender<RawMessage>, 469 msg_sender: &'a Sender<Message>,
471 sender: &'a Sender<Task>, 470 sender: &'a Sender<Task>,
472 request_received: Instant, 471 request_received: Instant,
473} 472}
@@ -522,13 +521,13 @@ impl<'a> PoolDispatcher<'a> {
522 Ok(self) 521 Ok(self)
523 } 522 }
524 523
525 fn parse<R>(&mut self) -> Option<(u64, R::Params)> 524 fn parse<R>(&mut self) -> Option<(RequestId, R::Params)>
526 where 525 where
527 R: req::Request + 'static, 526 R: req::Request + 'static,
528 R::Params: DeserializeOwned + Send + 'static, 527 R::Params: DeserializeOwned + Send + 'static,
529 { 528 {
530 let req = self.req.take()?; 529 let req = self.req.take()?;
531 let (id, params) = match req.cast::<R>() { 530 let (id, params) = match req.extract::<R::Params>(R::METHOD) {
532 Ok(it) => it, 531 Ok(it) => it,
533 Err(req) => { 532 Err(req) => {
534 self.req = Some(req); 533 self.req = Some(req);
@@ -536,7 +535,7 @@ impl<'a> PoolDispatcher<'a> {
536 } 535 }
537 }; 536 };
538 self.pending_requests.start(PendingRequest { 537 self.pending_requests.start(PendingRequest {
539 id, 538 id: id.clone(),
540 method: R::METHOD.to_string(), 539 method: R::METHOD.to_string(),
541 received: self.request_received, 540 received: self.request_received,
542 }); 541 });
@@ -548,7 +547,7 @@ impl<'a> PoolDispatcher<'a> {
548 None => (), 547 None => (),
549 Some(req) => { 548 Some(req) => {
550 log::error!("unknown request: {:?}", req); 549 log::error!("unknown request: {:?}", req);
551 let resp = RawResponse::err( 550 let resp = Response::new_err(
552 req.id, 551 req.id,
553 ErrorCode::MethodNotFound as i32, 552 ErrorCode::MethodNotFound as i32,
554 "unknown request".to_string(), 553 "unknown request".to_string(),
@@ -559,34 +558,30 @@ impl<'a> PoolDispatcher<'a> {
559 } 558 }
560} 559}
561 560
562fn result_to_task<R>(id: u64, result: Result<R::Result>) -> Task 561fn result_to_task<R>(id: RequestId, result: Result<R::Result>) -> Task
563where 562where
564 R: req::Request + 'static, 563 R: req::Request + 'static,
565 R::Params: DeserializeOwned + Send + 'static, 564 R::Params: DeserializeOwned + Send + 'static,
566 R::Result: Serialize + 'static, 565 R::Result: Serialize + 'static,
567{ 566{
568 let response = match result { 567 let response = match result {
569 Ok(resp) => RawResponse::ok::<R>(id, &resp), 568 Ok(resp) => Response::new_ok(id, &resp),
570 Err(e) => match e.downcast::<LspError>() { 569 Err(e) => match e.downcast::<LspError>() {
571 Ok(lsp_error) => RawResponse::err(id, lsp_error.code, lsp_error.message), 570 Ok(lsp_error) => Response::new_err(id, lsp_error.code, lsp_error.message),
572 Err(e) => { 571 Err(e) => {
573 if is_canceled(&e) { 572 if is_canceled(&e) {
574 // FIXME: When https://github.com/Microsoft/vscode-languageserver-node/issues/457 573 // FIXME: When https://github.com/Microsoft/vscode-languageserver-node/issues/457
575 // gets fixed, we can return the proper response. 574 // gets fixed, we can return the proper response.
576 // This works around the issue where "content modified" error would continuously 575 // This works around the issue where "content modified" error would continuously
577 // show an message pop-up in VsCode 576 // show an message pop-up in VsCode
578 // RawResponse::err( 577 // Response::err(
579 // id, 578 // id,
580 // ErrorCode::ContentModified as i32, 579 // ErrorCode::ContentModified as i32,
581 // "content modified".to_string(), 580 // "content modified".to_string(),
582 // ) 581 // )
583 RawResponse { 582 Response::new_ok(id, ())
584 id,
585 result: Some(serde_json::to_value(&()).unwrap()),
586 error: None,
587 }
588 } else { 583 } else {
589 RawResponse::err(id, ErrorCode::InternalError as i32, e.to_string()) 584 Response::new_err(id, ErrorCode::InternalError as i32, e.to_string())
590 } 585 }
591 } 586 }
592 }, 587 },
@@ -613,7 +608,7 @@ fn update_file_notifications_on_threadpool(
613 } 608 }
614 } 609 }
615 Ok(params) => { 610 Ok(params) => {
616 let not = RawNotification::new::<req::PublishDiagnostics>(&params); 611 let not = notification_new::<req::PublishDiagnostics>(params);
617 sender.send(Task::Notify(not)).unwrap(); 612 sender.send(Task::Notify(not)).unwrap();
618 } 613 }
619 } 614 }
@@ -626,7 +621,7 @@ fn update_file_notifications_on_threadpool(
626 } 621 }
627 } 622 }
628 Ok(params) => { 623 Ok(params) => {
629 let not = RawNotification::new::<req::PublishDecorations>(&params); 624 let not = notification_new::<req::PublishDecorations>(params);
630 sender.send(Task::Notify(not)).unwrap(); 625 sender.send(Task::Notify(not)).unwrap();
631 } 626 }
632 } 627 }
@@ -635,17 +630,33 @@ fn update_file_notifications_on_threadpool(
635 }); 630 });
636} 631}
637 632
638pub fn show_message( 633pub fn show_message(typ: req::MessageType, message: impl Into<String>, sender: &Sender<Message>) {
639 typ: req::MessageType,
640 message: impl Into<String>,
641 sender: &Sender<RawMessage>,
642) {
643 let message = message.into(); 634 let message = message.into();
644 let params = req::ShowMessageParams { typ, message }; 635 let params = req::ShowMessageParams { typ, message };
645 let not = RawNotification::new::<req::ShowMessage>(&params); 636 let not = notification_new::<req::ShowMessage>(params);
646 sender.send(not.into()).unwrap(); 637 sender.send(not.into()).unwrap();
647} 638}
648 639
649fn is_canceled(e: &Box<dyn std::error::Error + Send + Sync>) -> bool { 640fn is_canceled(e: &Box<dyn std::error::Error + Send + Sync>) -> bool {
650 e.downcast_ref::<Canceled>().is_some() 641 e.downcast_ref::<Canceled>().is_some()
651} 642}
643
644fn notification_is<N: lsp_types::notification::Notification>(notification: &Notification) -> bool {
645 notification.method == N::METHOD
646}
647
648fn notification_cast<N>(notification: Notification) -> std::result::Result<N::Params, Notification>
649where
650 N: lsp_types::notification::Notification,
651 N::Params: DeserializeOwned,
652{
653 notification.extract(N::METHOD)
654}
655
656fn notification_new<N>(params: N::Params) -> Notification
657where
658 N: lsp_types::notification::Notification,
659 N::Params: Serialize,
660{
661 Notification::new(N::METHOD.to_string(), params)
662}
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 3a559e845..eb805a6d3 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -1,6 +1,6 @@
1use std::{fmt::Write as _, io::Write as _}; 1use std::{fmt::Write as _, io::Write as _};
2 2
3use gen_lsp_server::ErrorCode; 3use lsp_server::ErrorCode;
4use lsp_types::{ 4use lsp_types::{
5 CodeAction, CodeActionResponse, CodeLens, Command, CompletionItem, Diagnostic, 5 CodeAction, CodeActionResponse, CodeLens, Command, CompletionItem, Diagnostic,
6 DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeKind, 6 DocumentFormattingParams, DocumentHighlight, DocumentSymbol, FoldingRange, FoldingRangeKind,
diff --git a/crates/ra_lsp_server/src/main_loop/pending_requests.rs b/crates/ra_lsp_server/src/main_loop/pending_requests.rs
index 741770e45..7a99fc679 100644
--- a/crates/ra_lsp_server/src/main_loop/pending_requests.rs
+++ b/crates/ra_lsp_server/src/main_loop/pending_requests.rs
@@ -1,17 +1,18 @@
1use std::time::{Duration, Instant}; 1use std::time::{Duration, Instant};
2 2
3use lsp_server::RequestId;
3use rustc_hash::FxHashMap; 4use rustc_hash::FxHashMap;
4 5
5#[derive(Debug)] 6#[derive(Debug)]
6pub struct CompletedRequest { 7pub struct CompletedRequest {
7 pub id: u64, 8 pub id: RequestId,
8 pub method: String, 9 pub method: String,
9 pub duration: Duration, 10 pub duration: Duration,
10} 11}
11 12
12#[derive(Debug)] 13#[derive(Debug)]
13pub(crate) struct PendingRequest { 14pub(crate) struct PendingRequest {
14 pub(crate) id: u64, 15 pub(crate) id: RequestId,
15 pub(crate) method: String, 16 pub(crate) method: String,
16 pub(crate) received: Instant, 17 pub(crate) received: Instant,
17} 18}
@@ -28,20 +29,20 @@ impl From<PendingRequest> for CompletedRequest {
28 29
29#[derive(Debug, Default)] 30#[derive(Debug, Default)]
30pub(crate) struct PendingRequests { 31pub(crate) struct PendingRequests {
31 map: FxHashMap<u64, PendingRequest>, 32 map: FxHashMap<RequestId, PendingRequest>,
32} 33}
33 34
34impl PendingRequests { 35impl PendingRequests {
35 pub(crate) fn start(&mut self, request: PendingRequest) { 36 pub(crate) fn start(&mut self, request: PendingRequest) {
36 let id = request.id; 37 let id = request.id.clone();
37 let prev = self.map.insert(id, request); 38 let prev = self.map.insert(id.clone(), request);
38 assert!(prev.is_none(), "duplicate request with id {}", id); 39 assert!(prev.is_none(), "duplicate request with id {}", id);
39 } 40 }
40 pub(crate) fn cancel(&mut self, id: u64) -> bool { 41 pub(crate) fn cancel(&mut self, id: &RequestId) -> bool {
41 self.map.remove(&id).is_some() 42 self.map.remove(id).is_some()
42 } 43 }
43 pub(crate) fn finish(&mut self, id: u64) -> Option<CompletedRequest> { 44 pub(crate) fn finish(&mut self, id: &RequestId) -> Option<CompletedRequest> {
44 self.map.remove(&id).map(CompletedRequest::from) 45 self.map.remove(id).map(CompletedRequest::from)
45 } 46 }
46} 47}
47 48
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index cc7964469..73d7f8fb9 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -4,7 +4,7 @@ use std::{
4}; 4};
5 5
6use crossbeam_channel::{unbounded, Receiver}; 6use crossbeam_channel::{unbounded, Receiver};
7use gen_lsp_server::ErrorCode; 7use lsp_server::ErrorCode;
8use lsp_types::Url; 8use lsp_types::Url;
9use parking_lot::RwLock; 9use parking_lot::RwLock;
10use ra_ide_api::{ 10use ra_ide_api::{
diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs
index 055c8fff2..45b4cacf6 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/support.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs
@@ -8,13 +8,10 @@ use std::{
8 8
9use crossbeam_channel::{after, select, Receiver}; 9use crossbeam_channel::{after, select, Receiver};
10use flexi_logger::Logger; 10use flexi_logger::Logger;
11use gen_lsp_server::{RawMessage, RawNotification, RawRequest}; 11use lsp_server::{Message, Notification, Request};
12use lsp_types::{ 12use lsp_types::{
13 notification::DidOpenTextDocument, 13 request::Shutdown, ClientCapabilities, DidOpenTextDocumentParams, GotoCapability,
14 notification::{Notification, ShowMessage}, 14 TextDocumentClientCapabilities, TextDocumentIdentifier, TextDocumentItem, Url,
15 request::{Request, Shutdown},
16 ClientCapabilities, DidOpenTextDocumentParams, GotoCapability, TextDocumentClientCapabilities,
17 TextDocumentIdentifier, TextDocumentItem, Url,
18}; 15};
19use serde::Serialize; 16use serde::Serialize;
20use serde_json::{to_string_pretty, Value}; 17use serde_json::{to_string_pretty, Value};
@@ -84,9 +81,9 @@ pub fn project(fixture: &str) -> Server {
84 81
85pub struct Server { 82pub struct Server {
86 req_id: Cell<u64>, 83 req_id: Cell<u64>,
87 messages: RefCell<Vec<RawMessage>>, 84 messages: RefCell<Vec<Message>>,
88 dir: TempDir, 85 dir: TempDir,
89 worker: Worker<RawMessage, RawMessage>, 86 worker: Worker<Message, Message>,
90} 87}
91 88
92impl Server { 89impl Server {
@@ -100,7 +97,7 @@ impl Server {
100 97
101 let roots = if roots.is_empty() { vec![path] } else { roots }; 98 let roots = if roots.is_empty() { vec![path] } else { roots };
102 99
103 let worker = Worker::<RawMessage, RawMessage>::spawn( 100 let worker = Worker::<Message, Message>::spawn(
104 "test server", 101 "test server",
105 128, 102 128,
106 move |msg_receiver, msg_sender| { 103 move |msg_receiver, msg_sender| {
@@ -128,7 +125,8 @@ impl Server {
128 let res = Server { req_id: Cell::new(1), dir, messages: Default::default(), worker }; 125 let res = Server { req_id: Cell::new(1), dir, messages: Default::default(), worker };
129 126
130 for (path, text) in files { 127 for (path, text) in files {
131 res.send_notification(RawNotification::new::<DidOpenTextDocument>( 128 res.send_notification(Notification::new(
129 "textDocument/didOpen".to_string(),
132 &DidOpenTextDocumentParams { 130 &DidOpenTextDocumentParams {
133 text_document: TextDocumentItem { 131 text_document: TextDocumentItem {
134 uri: Url::from_file_path(path).unwrap(), 132 uri: Url::from_file_path(path).unwrap(),
@@ -149,16 +147,16 @@ impl Server {
149 147
150 pub fn notification<N>(&self, params: N::Params) 148 pub fn notification<N>(&self, params: N::Params)
151 where 149 where
152 N: Notification, 150 N: lsp_types::notification::Notification,
153 N::Params: Serialize, 151 N::Params: Serialize,
154 { 152 {
155 let r = RawNotification::new::<N>(&params); 153 let r = Notification::new(N::METHOD.to_string(), params);
156 self.send_notification(r) 154 self.send_notification(r)
157 } 155 }
158 156
159 pub fn request<R>(&self, params: R::Params, expected_resp: Value) 157 pub fn request<R>(&self, params: R::Params, expected_resp: Value)
160 where 158 where
161 R: Request, 159 R: lsp_types::request::Request,
162 R::Params: Serialize, 160 R::Params: Serialize,
163 { 161 {
164 let actual = self.send_request::<R>(params); 162 let actual = self.send_request::<R>(params);
@@ -175,23 +173,23 @@ impl Server {
175 173
176 pub fn send_request<R>(&self, params: R::Params) -> Value 174 pub fn send_request<R>(&self, params: R::Params) -> Value
177 where 175 where
178 R: Request, 176 R: lsp_types::request::Request,
179 R::Params: Serialize, 177 R::Params: Serialize,
180 { 178 {
181 let id = self.req_id.get(); 179 let id = self.req_id.get();
182 self.req_id.set(id + 1); 180 self.req_id.set(id + 1);
183 181
184 let r = RawRequest::new::<R>(id, &params); 182 let r = Request::new(id.into(), R::METHOD.to_string(), params);
185 self.send_request_(r) 183 self.send_request_(r)
186 } 184 }
187 fn send_request_(&self, r: RawRequest) -> Value { 185 fn send_request_(&self, r: Request) -> Value {
188 let id = r.id; 186 let id = r.id.clone();
189 self.worker.sender().send(RawMessage::Request(r)).unwrap(); 187 self.worker.sender().send(r.into()).unwrap();
190 while let Some(msg) = self.recv() { 188 while let Some(msg) = self.recv() {
191 match msg { 189 match msg {
192 RawMessage::Request(req) => panic!("unexpected request: {:?}", req), 190 Message::Request(req) => panic!("unexpected request: {:?}", req),
193 RawMessage::Notification(_) => (), 191 Message::Notification(_) => (),
194 RawMessage::Response(res) => { 192 Message::Response(res) => {
195 assert_eq!(res.id, id); 193 assert_eq!(res.id, id);
196 if let Some(err) = res.error { 194 if let Some(err) = res.error {
197 panic!("error response: {:#?}", err); 195 panic!("error response: {:#?}", err);
@@ -203,15 +201,16 @@ impl Server {
203 panic!("no response"); 201 panic!("no response");
204 } 202 }
205 pub fn wait_until_workspace_is_loaded(&self) { 203 pub fn wait_until_workspace_is_loaded(&self) {
206 self.wait_for_message_cond(1, &|msg: &RawMessage| match msg { 204 self.wait_for_message_cond(1, &|msg: &Message| match msg {
207 RawMessage::Notification(n) if n.method == ShowMessage::METHOD => { 205 Message::Notification(n) if n.method == "window/showMessage" => {
208 let msg = n.clone().cast::<req::ShowMessage>().unwrap(); 206 let msg =
207 n.clone().extract::<req::ShowMessageParams>("window/showMessage").unwrap();
209 msg.message.starts_with("workspace loaded") 208 msg.message.starts_with("workspace loaded")
210 } 209 }
211 _ => false, 210 _ => false,
212 }) 211 })
213 } 212 }
214 fn wait_for_message_cond(&self, n: usize, cond: &dyn Fn(&RawMessage) -> bool) { 213 fn wait_for_message_cond(&self, n: usize, cond: &dyn Fn(&Message) -> bool) {
215 let mut total = 0; 214 let mut total = 0;
216 for msg in self.messages.borrow().iter() { 215 for msg in self.messages.borrow().iter() {
217 if cond(msg) { 216 if cond(msg) {
@@ -225,14 +224,14 @@ impl Server {
225 } 224 }
226 } 225 }
227 } 226 }
228 fn recv(&self) -> Option<RawMessage> { 227 fn recv(&self) -> Option<Message> {
229 recv_timeout(&self.worker.receiver()).map(|msg| { 228 recv_timeout(&self.worker.receiver()).map(|msg| {
230 self.messages.borrow_mut().push(msg.clone()); 229 self.messages.borrow_mut().push(msg.clone());
231 msg 230 msg
232 }) 231 })
233 } 232 }
234 fn send_notification(&self, not: RawNotification) { 233 fn send_notification(&self, not: Notification) {
235 self.worker.sender().send(RawMessage::Notification(not)).unwrap(); 234 self.worker.sender().send(Message::Notification(not)).unwrap();
236 } 235 }
237 236
238 pub fn path(&self) -> &Path { 237 pub fn path(&self) -> &Path {
@@ -246,7 +245,7 @@ impl Drop for Server {
246 } 245 }
247} 246}
248 247
249fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> { 248fn recv_timeout(receiver: &Receiver<Message>) -> Option<Message> {
250 let timeout = Duration::from_secs(120); 249 let timeout = Duration::from_secs(120);
251 select! { 250 select! {
252 recv(receiver) -> msg => msg.ok(), 251 recv(receiver) -> msg => msg.ok(),