From 3d0f78213879be78064d70a54411e40a6392a224 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 25 Jun 2020 23:26:21 +0200 Subject: Prep dynamic workspace loading --- crates/rust-analyzer/src/global_state.rs | 80 +++++++++++++++++++++++---- crates/rust-analyzer/src/main_loop.rs | 95 ++++---------------------------- 2 files changed, 79 insertions(+), 96 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs index be5a3f8a7..ca4a248f1 100644 --- a/crates/rust-analyzer/src/global_state.rs +++ b/crates/rust-analyzer/src/global_state.rs @@ -7,16 +7,16 @@ use std::{convert::TryFrom, sync::Arc}; use crossbeam_channel::{unbounded, Receiver, Sender}; use flycheck::{FlycheckConfig, FlycheckHandle}; -use lsp_types::Url; +use lsp_types::{request::Request, Url}; use parking_lot::RwLock; use ra_db::{CrateId, SourceRoot, VfsPath}; use ra_ide::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId}; -use ra_project_model::{CargoWorkspace, ProcMacroClient, ProjectWorkspace, Target}; +use ra_project_model::{CargoWorkspace, PackageRoot, ProcMacroClient, ProjectWorkspace, Target}; use stdx::format_to; use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf}; use crate::{ - config::{Config, FilesWatcher}, + config::{Config, FilesWatcher, LinkedProject}, diagnostics::{CheckFixes, DiagnosticCollection}, from_proto, line_endings::LineEndings, @@ -98,10 +98,8 @@ pub(crate) struct GlobalStateSnapshot { impl GlobalState { pub(crate) fn new( sender: Sender, - workspaces: Vec, lru_capacity: Option, config: Config, - req_queue: ReqQueue, ) -> GlobalState { let (task_sender, task_receiver) = unbounded::(); @@ -117,7 +115,7 @@ impl GlobalState { (TaskPool::new(sender), receiver) }; - let mut res = GlobalState { + GlobalState { sender, config, task_pool, @@ -129,17 +127,75 @@ impl GlobalState { mem_docs: FxHashSet::default(), vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))), status: Status::default(), - req_queue, + req_queue: ReqQueue::default(), latest_requests: Default::default(), source_root_config: SourceRootConfig::default(), proc_macro_client: ProcMacroClient::dummy(), workspaces: Arc::new(Vec::new()), - }; - res.reload(workspaces); - res + } } - pub(crate) fn reload(&mut self, workspaces: Vec) { + pub(crate) fn reload(&mut self) { + let workspaces = { + if self.config.linked_projects.is_empty() + && self.config.notifications.cargo_toml_not_found + { + self.show_message( + lsp_types::MessageType::Error, + "rust-analyzer failed to discover workspace".to_string(), + ); + }; + + self.config + .linked_projects + .iter() + .filter_map(|project| match project { + LinkedProject::ProjectManifest(manifest) => { + ra_project_model::ProjectWorkspace::load( + manifest.clone(), + &self.config.cargo, + self.config.with_sysroot, + ) + .map_err(|err| { + log::error!("failed to load workspace: {:#}", err); + self.show_message( + lsp_types::MessageType::Error, + format!("rust-analyzer failed to load workspace: {:#}", err), + ); + }) + .ok() + } + LinkedProject::InlineJsonProject(it) => { + Some(ra_project_model::ProjectWorkspace::Json { project: it.clone() }) + } + }) + .collect::>() + }; + + if let FilesWatcher::Client = self.config.files.watcher { + let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { + watchers: workspaces + .iter() + .flat_map(ProjectWorkspace::to_roots) + .filter(PackageRoot::is_member) + .map(|root| format!("{}/**/*.rs", root.path().display())) + .map(|glob_pattern| lsp_types::FileSystemWatcher { glob_pattern, kind: None }) + .collect(), + }; + let registration = lsp_types::Registration { + id: "file-watcher".to_string(), + 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.into()); + } + let mut change = AnalysisChange::new(); let project_folders = ProjectFolders::new(&workspaces); @@ -275,7 +331,7 @@ impl GlobalState { self.send(response.into()); } } - pub(crate) fn show_message(&mut self, typ: lsp_types::MessageType, message: String) { + pub(crate) fn show_message(&self, typ: lsp_types::MessageType, message: String) { show_message(typ, message, &self.sender) } } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 1bd9d6389..6ac50745a 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -11,17 +11,14 @@ use lsp_types::{notification::Notification as _, request::Request as _}; use ra_db::VfsPath; use ra_ide::{Canceled, FileId}; use ra_prof::profile; -use ra_project_model::{PackageRoot, ProjectWorkspace}; use crate::{ - config::{Config, FilesWatcher, LinkedProject}, + config::Config, dispatch::{NotificationDispatcher, RequestDispatcher}, from_proto, global_state::{file_id_to_url, GlobalState, Status}, handlers, lsp_ext, - lsp_utils::{ - apply_document_changes, is_canceled, notification_is, notification_new, show_message, - }, + lsp_utils::{apply_document_changes, is_canceled, notification_is, notification_new}, Result, }; @@ -47,81 +44,8 @@ pub fn main_loop(config: Config, connection: Connection) -> Result<()> { SetThreadPriority(thread, thread_priority_above_normal); } - let global_state = { - let workspaces = { - if config.linked_projects.is_empty() && config.notifications.cargo_toml_not_found { - show_message( - lsp_types::MessageType::Error, - "rust-analyzer failed to discover workspace".to_string(), - &connection.sender, - ); - }; - - config - .linked_projects - .iter() - .filter_map(|project| match project { - LinkedProject::ProjectManifest(manifest) => { - ra_project_model::ProjectWorkspace::load( - manifest.clone(), - &config.cargo, - config.with_sysroot, - ) - .map_err(|err| { - log::error!("failed to load workspace: {:#}", err); - show_message( - lsp_types::MessageType::Error, - format!("rust-analyzer failed to load workspace: {:#}", err), - &connection.sender, - ); - }) - .ok() - } - LinkedProject::InlineJsonProject(it) => { - Some(ra_project_model::ProjectWorkspace::Json { project: it.clone() }) - } - }) - .collect::>() - }; - - let mut req_queue = ReqQueue::default(); - - if let FilesWatcher::Client = config.files.watcher { - let registration_options = lsp_types::DidChangeWatchedFilesRegistrationOptions { - watchers: workspaces - .iter() - .flat_map(ProjectWorkspace::to_roots) - .filter(PackageRoot::is_member) - .map(|root| format!("{}/**/*.rs", root.path().display())) - .map(|glob_pattern| lsp_types::FileSystemWatcher { glob_pattern, kind: None }) - .collect(), - }; - let registration = lsp_types::Registration { - id: "file-watcher".to_string(), - 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 = req_queue.outgoing.register( - lsp_types::request::RegisterCapability::METHOD.to_string(), - params, - DO_NOTHING, - ); - connection.sender.send(request.into()).unwrap(); - } - - GlobalState::new( - connection.sender.clone(), - workspaces, - config.lru_capacity, - config, - req_queue, - ) - }; - - log::info!("server initialized, serving requests"); - global_state.run(connection.receiver)?; - Ok(()) + GlobalState::new(connection.sender.clone(), config.lru_capacity, config) + .run(connection.receiver) } enum Event { @@ -188,23 +112,26 @@ impl GlobalState { } fn run(mut self, inbox: Receiver) -> Result<()> { + self.reload(); + while let Some(event) = self.next_event(&inbox) { if let Event::Lsp(lsp_server::Message::Notification(not)) = &event { if not.method == lsp_types::notification::Exit::METHOD { return Ok(()); } } - self.loop_turn(event)? + self.handle_event(event)? } + Err("client exited without proper shutdown sequence")? } - fn loop_turn(&mut self, event: Event) -> Result<()> { + fn handle_event(&mut self, event: Event) -> Result<()> { let loop_start = Instant::now(); // NOTE: don't count blocking select! call as a loop-turn time - let _p = profile("main_loop_inner/loop-turn"); + let _p = profile("GlobalState::handle_event"); - log::info!("loop turn = {:?}", event); + log::info!("handle_event({:?})", event); let queue_count = self.task_pool.0.len(); if queue_count > 0 { log::info!("queued count = {}", queue_count); -- cgit v1.2.3