From 9d15e8fc4f875f6da2cd2bd89c62bb96fa64ef1b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 26 Jun 2020 17:07:14 +0200 Subject: Type safer requests --- crates/rust-analyzer/src/global_state.rs | 53 ++++++++++++++++++++++++++++---- crates/rust-analyzer/src/lsp_utils.rs | 21 +++++-------- crates/rust-analyzer/src/main_loop.rs | 40 ++++++++++-------------- crates/rust-analyzer/src/reload.rs | 8 ++--- 4 files changed, 73 insertions(+), 49 deletions(-) diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index 41659f99d..3c9752259 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -7,7 +7,7 @@ use std::{sync::Arc, time::Instant}; use crossbeam_channel::{unbounded, Receiver, Sender}; use flycheck::FlycheckHandle; -use lsp_types::Url; +use lsp_types::{request::Request as _, Url}; use parking_lot::RwLock; use ra_db::{CrateId, VfsPath}; use ra_ide::{Analysis, AnalysisChange, AnalysisHost, FileId}; @@ -18,6 +18,7 @@ use crate::{ diagnostics::{CheckFixes, DiagnosticCollection}, from_proto, line_endings::LineEndings, + lsp_utils::notification_new, main_loop::Task, reload::SourceRootConfig, request_metrics::{LatestRequests, RequestMetrics}, @@ -57,6 +58,7 @@ pub(crate) type ReqQueue = lsp_server::ReqQueue<(String, Instant), ReqHandler>; /// Note that this struct has more than on impl in various modules! pub(crate) struct GlobalState { sender: Sender, + req_queue: ReqQueue, pub(crate) task_pool: Handle, Receiver>, pub(crate) loader: Handle, Receiver>, pub(crate) flycheck: Option>>, @@ -66,7 +68,6 @@ pub(crate) struct GlobalState { pub(crate) mem_docs: FxHashSet, pub(crate) vfs: Arc)>>, pub(crate) status: Status, - pub(crate) req_queue: ReqQueue, pub(crate) source_root_config: SourceRootConfig, pub(crate) proc_macro_client: ProcMacroClient, pub(crate) workspaces: Arc>, @@ -102,16 +103,16 @@ impl GlobalState { let analysis_host = AnalysisHost::new(config.lru_capacity); GlobalState { sender, + req_queue: ReqQueue::default(), task_pool, loader, + flycheck: None, config, analysis_host, - flycheck: None, diagnostics: Default::default(), mem_docs: FxHashSet::default(), vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), status: Status::default(), - req_queue: ReqQueue::default(), source_root_config: SourceRootConfig::default(), proc_macro_client: ProcMacroClient::dummy(), workspaces: Arc::new(Vec::new()), @@ -168,8 +169,39 @@ impl GlobalState { } } - pub(crate) fn send(&mut self, message: lsp_server::Message) { - self.sender.send(message).unwrap() + pub(crate) fn send_request( + &mut self, + params: R::Params, + handler: ReqHandler, + ) { + let request = self.req_queue.outgoing.register( + lsp_types::request::WorkDoneProgressCreate::METHOD.to_string(), + params, + handler, + ); + self.send(request.into()); + } + pub(crate) fn complete_request(&mut self, response: lsp_server::Response) { + let handler = self.req_queue.outgoing.complete(response.id.clone()); + handler(self, response) + } + + pub(crate) fn send_notification( + &mut self, + params: N::Params, + ) { + let not = notification_new::(params); + self.send(not.into()); + } + + pub(crate) fn register_request( + &mut self, + request: &lsp_server::Request, + request_received: Instant, + ) { + self.req_queue + .incoming + .register(request.id.clone(), (request.method.clone(), request_received)); } pub(crate) fn respond(&mut self, response: lsp_server::Response) { if let Some((method, start)) = self.req_queue.incoming.complete(response.id.clone()) { @@ -181,6 +213,15 @@ impl GlobalState { self.send(response.into()); } } + pub(crate) fn cancel(&mut self, request_id: lsp_server::RequestId) { + if let Some(response) = self.req_queue.incoming.cancel(request_id) { + self.send(response.into()); + } + } + + fn send(&mut self, message: lsp_server::Message) { + self.sender.send(message).unwrap() + } } impl Drop for GlobalState { diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs index fd793a17c..99f4998a9 100644 --- a/crates/rust-analyzer/src/lsp_utils.rs +++ b/crates/rust-analyzer/src/lsp_utils.rs @@ -2,7 +2,6 @@ use std::{error::Error, ops::Range}; use lsp_server::Notification; -use lsp_types::request::Request; use ra_db::Canceled; use ra_ide::LineIndex; use serde::Serialize; @@ -43,9 +42,9 @@ impl Progress { impl GlobalState { pub(crate) fn show_message(&mut self, typ: lsp_types::MessageType, message: String) { let message = message.into(); - let params = lsp_types::ShowMessageParams { typ, message }; - let not = notification_new::(params); - self.send(not.into()); + self.send_notification::( + lsp_types::ShowMessageParams { typ, message }, + ) } pub(crate) fn report_progress( @@ -61,12 +60,10 @@ impl GlobalState { let token = lsp_types::ProgressToken::String(format!("rustAnalyzer/{}", title)); let work_done_progress = match state { Progress::Begin => { - let work_done_progress_create = self.req_queue.outgoing.register( - lsp_types::request::WorkDoneProgressCreate::METHOD.to_string(), + self.send_request::( lsp_types::WorkDoneProgressCreateParams { token: token.clone() }, |_, _| (), ); - self.send(work_done_progress_create.into()); lsp_types::WorkDoneProgress::Begin(lsp_types::WorkDoneProgressBegin { title: title.into(), @@ -86,12 +83,10 @@ impl GlobalState { lsp_types::WorkDoneProgress::End(lsp_types::WorkDoneProgressEnd { message }) } }; - let notification = - notification_new::(lsp_types::ProgressParams { - token, - value: lsp_types::ProgressParamsValue::WorkDone(work_done_progress), - }); - self.send(notification.into()); + self.send_notification::(lsp_types::ProgressParams { + token, + value: lsp_types::ProgressParamsValue::WorkDone(work_done_progress), + }); } } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index ae3c7e30e..e5194fe41 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -7,7 +7,7 @@ use std::{ use crossbeam_channel::{never, select, Receiver}; use lsp_server::{Connection, Notification, Request, Response}; -use lsp_types::{notification::Notification as _, request::Request as _}; +use lsp_types::notification::Notification as _; use ra_db::VfsPath; use ra_ide::{Canceled, FileId}; use ra_prof::profile; @@ -18,7 +18,7 @@ use crate::{ from_proto, global_state::{file_id_to_url, url_to_file_id, GlobalState, Status}, handlers, lsp_ext, - lsp_utils::{apply_document_changes, is_canceled, notification_is, notification_new, Progress}, + lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, Result, }; @@ -143,10 +143,7 @@ impl GlobalState { lsp_server::Message::Notification(not) => { self.on_notification(not)?; } - lsp_server::Message::Response(resp) => { - let handler = self.req_queue.outgoing.complete(resp.id.clone()); - handler(self, resp) - } + lsp_server::Message::Response(resp) => self.complete_request(resp), }, Event::Task(task) => { match task { @@ -250,10 +247,9 @@ impl GlobalState { for file_id in diagnostic_changes { let url = file_id_to_url(&self.vfs.read().0, file_id); let diagnostics = self.diagnostics.diagnostics_for(file_id).cloned().collect(); - let params = - lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version: None }; - let not = notification_new::(params); - self.send(not.into()); + self.send_notification::( + lsp_types::PublishDiagnosticsParams { uri: url, diagnostics, version: None }, + ); } } @@ -271,7 +267,7 @@ impl GlobalState { } fn on_request(&mut self, request_received: Instant, req: Request) -> Result<()> { - self.req_queue.incoming.register(req.id.clone(), (req.method.clone(), request_received)); + self.register_request(&req, request_received); RequestDispatcher { req: Some(req), global_state: self } .on_sync::(|s, ()| Ok(s.analysis_host.collect_garbage()))? @@ -335,9 +331,7 @@ impl GlobalState { lsp_types::NumberOrString::Number(id) => id.into(), lsp_types::NumberOrString::String(id) => id.into(), }; - if let Some(response) = this.req_queue.incoming.cancel(id) { - this.send(response.into()); - } + this.cancel(id); Ok(()) })? .on::(|this, params| { @@ -372,13 +366,13 @@ impl GlobalState { this.loader.handle.invalidate(path.to_path_buf()); } } - let params = lsp_types::PublishDiagnosticsParams { - uri: params.text_document.uri, - diagnostics: Vec::new(), - version: None, - }; - let not = notification_new::(params); - this.send(not.into()); + this.send_notification::( + lsp_types::PublishDiagnosticsParams { + uri: params.text_document.uri, + diagnostics: Vec::new(), + version: None, + }, + ); Ok(()) })? .on::(|this, _params| { @@ -390,8 +384,7 @@ impl GlobalState { .on::(|this, _params| { // As stated in https://github.com/microsoft/language-server-protocol/issues/676, // this notification's parameters should be ignored and the actual config queried separately. - let request = this.req_queue.outgoing.register( - lsp_types::request::WorkspaceConfiguration::METHOD.to_string(), + this.send_request::( lsp_types::ConfigurationParams { items: vec![lsp_types::ConfigurationItem { scope_uri: None, @@ -419,7 +412,6 @@ impl GlobalState { } }, ); - this.send(request.into()); return Ok(()); })? diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs index fece6176e..a1850b286 100644 --- a/crates/rust-analyzer/src/reload.rs +++ b/crates/rust-analyzer/src/reload.rs @@ -3,7 +3,6 @@ use std::sync::Arc; use crossbeam_channel::unbounded; use flycheck::FlycheckHandle; -use lsp_types::request::Request; use ra_db::{CrateGraph, SourceRoot, VfsPath}; use ra_ide::AnalysisChange; use ra_project_model::{PackageRoot, ProcMacroClient, ProjectWorkspace}; @@ -78,13 +77,10 @@ impl GlobalState { method: "workspace/didChangeWatchedFiles".to_string(), register_options: Some(serde_json::to_value(registration_options).unwrap()), }; - let params = lsp_types::RegistrationParams { registrations: vec![registration] }; - let request = self.req_queue.outgoing.register( - lsp_types::request::RegisterCapability::METHOD.to_string(), - params, + self.send_request::( + lsp_types::RegistrationParams { registrations: vec![registration] }, |_, _| (), ); - self.send(request.into()); } let mut change = AnalysisChange::new(); -- cgit v1.2.3