From 8baa4c5d07690dc908b6299471c936c0d87ad871 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 3 Jun 2020 12:22:01 +0200 Subject: Groundwork for specifying the set of projects via config --- crates/rust-analyzer/src/bin/main.rs | 41 ++++++++++++++++------- crates/rust-analyzer/src/cli/load_cargo.rs | 3 +- crates/rust-analyzer/src/config.rs | 25 ++++++++++++-- crates/rust-analyzer/src/main_loop.rs | 29 +++++++--------- crates/rust-analyzer/tests/heavy_tests/support.rs | 31 +++++++++-------- 5 files changed, 83 insertions(+), 46 deletions(-) (limited to 'crates') diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index e82fd57de..8d071ab1c 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs @@ -4,9 +4,14 @@ mod args; use lsp_server::Connection; -use rust_analyzer::{cli, config::Config, from_json, Result}; +use rust_analyzer::{ + cli, + config::{Config, LinkedProject}, + from_json, Result, +}; use crate::args::HelpPrinted; +use ra_project_model::ProjectManifest; fn main() -> Result<()> { setup_logging()?; @@ -97,17 +102,6 @@ fn run_server() -> Result<()> { log::info!("Client '{}' {}", client_info.name, client_info.version.unwrap_or_default()); } - let cwd = std::env::current_dir()?; - let root = initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd); - - let workspace_roots = initialize_params - .workspace_folders - .map(|workspaces| { - workspaces.into_iter().filter_map(|it| it.uri.to_file_path().ok()).collect::>() - }) - .filter(|workspaces| !workspaces.is_empty()) - .unwrap_or_else(|| vec![root]); - let config = { let mut config = Config::default(); if let Some(value) = &initialize_params.initialization_options { @@ -115,10 +109,31 @@ fn run_server() -> Result<()> { } config.update_caps(&initialize_params.capabilities); + if config.linked_projects.is_empty() { + let cwd = std::env::current_dir()?; + let root = + initialize_params.root_uri.and_then(|it| it.to_file_path().ok()).unwrap_or(cwd); + let workspace_roots = initialize_params + .workspace_folders + .map(|workspaces| { + workspaces + .into_iter() + .filter_map(|it| it.uri.to_file_path().ok()) + .collect::>() + }) + .filter(|workspaces| !workspaces.is_empty()) + .unwrap_or_else(|| vec![root]); + + config.linked_projects = ProjectManifest::discover_all(&workspace_roots) + .into_iter() + .map(LinkedProject::from) + .collect(); + } + config }; - rust_analyzer::main_loop(workspace_roots, config, connection)?; + rust_analyzer::main_loop(config, connection)?; log::info!("shutting down IO..."); io_threads.join()?; diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs index 67491b42a..c7e86fe0c 100644 --- a/crates/rust-analyzer/src/cli/load_cargo.rs +++ b/crates/rust-analyzer/src/cli/load_cargo.rs @@ -8,7 +8,8 @@ use crossbeam_channel::{unbounded, Receiver}; use ra_db::{ExternSourceId, FileId, SourceRootId}; use ra_ide::{AnalysisChange, AnalysisHost}; use ra_project_model::{ - get_rustc_cfg_options, CargoConfig, PackageRoot, ProcMacroClient, ProjectManifest, ProjectWorkspace, + get_rustc_cfg_options, CargoConfig, PackageRoot, ProcMacroClient, ProjectManifest, + ProjectWorkspace, }; use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch}; use rustc_hash::{FxHashMap, FxHashSet}; diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 9c6e369d2..761bc9c2d 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -12,14 +12,13 @@ use std::{ffi::OsString, path::PathBuf}; use lsp_types::ClientCapabilities; use ra_flycheck::FlycheckConfig; use ra_ide::{AssistConfig, CompletionConfig, InlayHintsConfig}; -use ra_project_model::CargoConfig; +use ra_project_model::{CargoConfig, JsonProject, ProjectManifest}; use serde::Deserialize; #[derive(Debug, Clone)] pub struct Config { pub client_caps: ClientCapsConfig, - pub with_sysroot: bool, pub publish_diagnostics: bool, pub lru_capacity: Option, pub proc_macro_srv: Option<(PathBuf, Vec)>, @@ -35,6 +34,27 @@ pub struct Config { pub assist: AssistConfig, pub call_info_full: bool, pub lens: LensConfig, + + pub with_sysroot: bool, + pub linked_projects: Vec, +} + +#[derive(Debug, Clone)] +pub enum LinkedProject { + ProjectManifest(ProjectManifest), + JsonProject(JsonProject), +} + +impl From for LinkedProject { + fn from(v: ProjectManifest) -> Self { + LinkedProject::ProjectManifest(v) + } +} + +impl From for LinkedProject { + fn from(v: JsonProject) -> Self { + LinkedProject::JsonProject(v) + } } #[derive(Clone, Debug, PartialEq, Eq)] @@ -141,6 +161,7 @@ impl Default for Config { assist: AssistConfig::default(), call_info_full: true, lens: LensConfig::default(), + linked_projects: Vec::new(), } } } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index ea5b4c91c..d901f21d7 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -12,13 +12,11 @@ use std::{ fmt, ops::Range, panic, - path::PathBuf, sync::Arc, time::{Duration, Instant}, }; use crossbeam_channel::{never, select, unbounded, RecvError, Sender}; -use itertools::Itertools; use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; use lsp_types::{ DidChangeTextDocumentParams, NumberOrString, TextDocumentContentChangeEvent, WorkDoneProgress, @@ -28,7 +26,7 @@ use lsp_types::{ use ra_flycheck::{CheckTask, Status}; use ra_ide::{Canceled, FileId, LibraryData, LineIndex, SourceRootId}; use ra_prof::profile; -use ra_project_model::{PackageRoot, ProjectManifest, ProjectWorkspace}; +use ra_project_model::{PackageRoot, ProjectWorkspace}; use ra_vfs::{VfsFile, VfsTask, Watch}; use relative_path::RelativePathBuf; use rustc_hash::FxHashSet; @@ -36,7 +34,7 @@ use serde::{de::DeserializeOwned, Serialize}; use threadpool::ThreadPool; use crate::{ - config::{Config, FilesWatcher}, + config::{Config, FilesWatcher, LinkedProject}, diagnostics::{to_proto::url_from_path_with_drive_lowercasing, DiagnosticTask}, from_proto, global_state::{GlobalState, GlobalStateSnapshot}, @@ -70,7 +68,7 @@ impl fmt::Display for LspError { impl Error for LspError {} -pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) -> Result<()> { +pub fn main_loop(config: Config, connection: Connection) -> Result<()> { log::info!("initial config: {:#?}", config); // Windows scheduler implements priority boosts: if thread waits for an @@ -95,25 +93,24 @@ pub fn main_loop(ws_roots: Vec, config: Config, connection: Connection) let mut loop_state = LoopState::default(); let mut global_state = { let workspaces = { - // FIXME: support dynamic workspace loading. - let project_roots = ProjectManifest::discover_all(&ws_roots); - - if project_roots.is_empty() && config.notifications.cargo_toml_not_found { + if config.linked_projects.is_empty() && config.notifications.cargo_toml_not_found { show_message( lsp_types::MessageType::Error, - format!( - "rust-analyzer failed to discover workspace, no Cargo.toml found, dirs searched: {}", - ws_roots.iter().format_with(", ", |it, f| f(&it.display())) - ), + "rust-analyzer failed to discover workspace".to_string(), &connection.sender, ); }; - project_roots - .into_iter() + config + .linked_projects + .iter() + .filter_map(|project| match project { + LinkedProject::ProjectManifest(it) => Some(it), + LinkedProject::JsonProject(_) => None, + }) .filter_map(|root| { ra_project_model::ProjectWorkspace::load( - root, + root.clone(), &config.cargo, config.with_sysroot, ) diff --git a/crates/rust-analyzer/tests/heavy_tests/support.rs b/crates/rust-analyzer/tests/heavy_tests/support.rs index 66a6f4d54..30d03b622 100644 --- a/crates/rust-analyzer/tests/heavy_tests/support.rs +++ b/crates/rust-analyzer/tests/heavy_tests/support.rs @@ -19,8 +19,9 @@ use serde_json::{to_string_pretty, Value}; use tempfile::TempDir; use test_utils::{find_mismatch, parse_fixture}; +use ra_project_model::ProjectManifest; use rust_analyzer::{ - config::{ClientCapsConfig, Config}, + config::{ClientCapsConfig, Config, LinkedProject}, main_loop, }; @@ -42,7 +43,7 @@ impl<'a> Project<'a> { self } - pub fn root(mut self, path: &str) -> Project<'a> { + pub(crate) fn root(mut self, path: &str) -> Project<'a> { self.roots.push(path.into()); self } @@ -74,7 +75,16 @@ impl<'a> Project<'a> { paths.push((path, entry.text)); } - let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect(); + let mut roots = + self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect::>(); + if roots.is_empty() { + roots.push(tmp_dir.path().to_path_buf()); + } + let linked_projects = roots + .into_iter() + .map(|it| ProjectManifest::discover_single(&it).unwrap()) + .map(LinkedProject::from) + .collect::>(); let mut config = Config { client_caps: ClientCapsConfig { @@ -84,6 +94,7 @@ impl<'a> Project<'a> { ..Default::default() }, with_sysroot: self.with_sysroot, + linked_projects, ..Config::default() }; @@ -91,7 +102,7 @@ impl<'a> Project<'a> { f(&mut config) } - Server::new(tmp_dir, config, roots, paths) + Server::new(tmp_dir, config, paths) } } @@ -109,20 +120,12 @@ pub struct Server { } impl Server { - fn new( - dir: TempDir, - config: Config, - roots: Vec, - files: Vec<(PathBuf, String)>, - ) -> Server { - let path = dir.path().to_path_buf(); - - let roots = if roots.is_empty() { vec![path] } else { roots }; + fn new(dir: TempDir, config: Config, files: Vec<(PathBuf, String)>) -> Server { let (connection, client) = Connection::memory(); let _thread = jod_thread::Builder::new() .name("test server".to_string()) - .spawn(move || main_loop(roots, config, connection).unwrap()) + .spawn(move || main_loop(config, connection).unwrap()) .expect("failed to spawn a thread"); let res = -- cgit v1.2.3